how to deserialize some specific fields only from Json using Gson? - java
I have the following JSON string
[
{
"channel": "/bvmt/initValues",
"data": {
"value": {
"instrumentIds": "['TN0007250012','TN0007500010']",
"instruments": "[{'mnemonic':'ADWYA','marche':'ADWYA','phaut':5.82,'open':5.82,'nbrTrans':7,'veille':5.82,'time':'11:14:28','recapChange':0.00,'state':'','variation':'.','ref':5.82,'stateGrp':'S','percentChange':-0.34,'last':5.80,'bestTransaction':[{'value':5.82,'qte':'3','time':'10:00:00'},{'value':5.82,'qte':'5','time':'10:02:26'},{'value':5.82,'qte':'145','time':'10:23:27'},{'value':5.81,'qte':'100','time':'10:23:42'},{'value':5.80,'qte':'1000','time':'10:23:42'},{'value':5.73,'qte':'1','time':'10:31:21'},{'value':5.80,'qte':'100','time':'11:14:28'}],'volume':7857.19,'id':'TN0007250012','bestLimits':[{'quantiteAchat':2600,'timeVente':'11:44:10','ordreAchat':1,'prixAchat':5.76,'quantiteVente':100,'timeAchat':'11:44:10','ordreVente':1,'prixVente':5.90},{'quantiteAchat':50,'timeVente':'11:44:10','ordreAchat':1,'prixAchat':5.74,'quantiteVente':210,'timeAchat':'11:44:10','ordreVente':1,'prixVente':5.95},{'quantiteAchat':250,'timeVente':'11:44:10','ordreAchat':2,'prixAchat':5.75,'quantiteVente':187,'timeAchat':'11:44:10','ordreVente':1,'prixVente':5.94},{'quantiteAchat':189,'timeVente':'11:44:10','ordreAchat':3,'prixAchat':5.73,'quantiteVente':1112,'timeAchat':'11:44:10','ordreVente':1,'prixVente':5.97},{'quantiteAchat':44,'timeVente':'11:44:10','ordreAchat':1,'prixAchat':5.72,'quantiteVente':400,'timeAchat':'11:44:10','ordreVente':1,'prixVente':5.98}],'openStatus':'','cto':0,'valuer':'ADWYA','pbas':5.73,'grp':'S','abrv':'ADWYA','houv':'','qto':0,'seuilBas':5.65,'vto':0,'quantite':1354,'seuilHaut':5.99},{'mnemonic':'WIFAK','marche':'WIFAK','phaut':7.11,'open':7.00,'nbrTrans':2,'veille':7.13,'time':'10:24:15','recapChange':0.00,'state':'','variation':'.','ref':7.13,'stateGrp':'S','percentChange':-0.28,'last':7.11,'bestTransaction':[{'value':7.00,'qte':'99','time':'10:17:00'},{'value':7.11,'qte':'100','time':'10:24:15'}],'volume':1404.00,'id':'TN0007200017','bestLimits':[{'quantiteAchat':100,'timeVente':'11:00:19','ordreAchat':1,'prixAchat':6.80,'quantiteVente':100,'timeAchat':'11:00:19','ordreVente':1,'prixVente':7.09},{'quantiteAchat':0,'timeVente':'11:00:19','ordreAchat':0,'prixAchat':0.00,'quantiteVente':82,'timeAchat':'11:00:19','ordreVente':1,'prixVente':7.11},{'quantiteAchat':0,'timeVente':'11:00:19','ordreAchat':0,'prixAchat':0.00,'quantiteVente':284,'timeAchat':'11:00:19','ordreVente':2,'prixVente':7.10},{'quantiteAchat':0,'timeVente':'11:00:19','ordreAchat':0,'prixAchat':0.00,'quantiteVente':222,'timeAchat':'11:00:19','ordreVente':1,'prixVente':7.12},{'quantiteAchat':0,'timeVente':'11:00:19','ordreAchat':0,'prixAchat':0.00,'quantiteVente':110,'timeAchat':'11:00:19','ordreVente':2,'prixVente':7.13}],'openStatus':'','cto':0,'valuer':'WIFACK INT BANK','pbas':7.00,'grp':'S','abrv':'WIFAK','houv':'','qto':0,'seuilBas':6.92,'vto':0,'quantite':199,'seuilHaut':7.34}]"
},
"action": "initValues",
"infoSession": {
"lastInstrumentOrder": 11672,
"state": 1,
"lastInstrumentTime": "12:03:00",
"tradingTime": "08:04:02",
"tradingDate": "2017-04-24"
}
},
"id": "5"
},
{
"channel": "/bvmt/process",
"successful": true,
"id": "5"
}
]
I'm interested only in the content of the "instruments" field , I want to get only the "mnemonic" and "percentChange" fields and deserialize them into an array of Objects like this
public class Data
{
public List<MyObject> objects;
}
public class MyObject
{
String mnemonic;
Float percentChange;
}
How can I do this using Gson ?
Actually you have dozen ways of doing it. It only depends on how you manage your JSON documents. Let's declare a couple of DTOs first:
final class Data {
final List<MyObject> objects;
Data(final List<MyObject> objects) {
this.objects = objects;
}
}
final class MyObject {
final String mnemonic;
final Float percentChange;
MyObject(final String mnemonic, final Float percentChange) {
this.mnemonic = mnemonic;
this.percentChange = percentChange;
}
}
Here are some ways:
Pure JsonElement trees
The following example uses Java 8 Stream API and Gson JSON trees facilities, and it appears to be the simplest way to me:
private static final Gson gson = new Gson();
static Data testUsingJsonTreesOnly(final Reader reader) {
final List<MyObject> objects = StreamSupport.stream(gson.fromJson(reader, JsonElement.class).getAsJsonArray().spliterator(), false)
.map(JsonElement::getAsJsonObject)
.map(jsonObject -> jsonObject.get("data"))
.filter(Objects::nonNull)
.map(JsonElement::getAsJsonObject)
.map(jsonObject -> jsonObject.get("value"))
.filter(Objects::nonNull)
.map(JsonElement::getAsJsonObject)
.map(jsonObject -> jsonObject.get("instruments"))
.filter(Objects::nonNull)
.map(JsonElement::getAsJsonPrimitive)
.map(JsonPrimitive::getAsString)
.map(json -> gson.fromJson(json, JsonElement.class))
.map(JsonElement::getAsJsonArray)
.flatMap(jsonArray -> StreamSupport.stream(jsonArray.spliterator(), false))
.map(jsonElement -> gson.fromJson(jsonElement, MyObject.class))
.collect(toList());
return new Data(objects);
}
Two-pass mappings
This approach way attempts to extract the values in two passes:
deserialize the "outer" object;
get the inner object string and deserialize it in the second pass.
private static final Gson gson = new Gson();
private static final Type channelViewListType = new TypeToken<List<ChannelView>>() {
}.getType();
private static final Type myObjectListType = new TypeToken<List<MyObject>>() {
}.getType();
static Data testUsingDeserializationWithStrings(final Reader reader) {
final List<MyObject> objects = gson.<List<ChannelView>>fromJson(reader, channelViewListType)
.stream()
.filter(Objects::nonNull)
.map(view -> view.data)
.filter(Objects::nonNull)
.map(view -> view.value)
.filter(Objects::nonNull)
.map(view -> view.instruments)
.map((Function<String, List<MyObject>>) instruments -> gson.fromJson(instruments, myObjectListType))
.flatMap(Collection::stream)
.collect(toList());
return new Data(objects);
}
private static final class ChannelView {
final DataView data = null;
}
private static final class DataView {
final ValueView value = null;
}
private static final class ValueView {
final String instruments = null;
}
One-pass mappings using type adapters
This is, I would say, level #3: you can implement a specific type adapter to "unwrap" the encoded JSON document. #JsonAdapter can be used to specified the field that contains the specific "inner" JSON document:
private static final Gson gson = new Gson();
private static final Type channelViewListType = new TypeToken<List<ChannelView>>() {
}.getType();
static Data testUsingDeserializationWithJsonAdapter(final Reader reader) {
final List<MyObject> objects = gson.<List<ChannelView>>fromJson(reader, channelViewListType)
.stream()
.filter(Objects::nonNull)
.map(view -> view.data)
.filter(Objects::nonNull)
.map(view -> view.value)
.filter(Objects::nonNull)
.map(view -> view.instruments)
.flatMap(Collection::stream)
.collect(toList());
return new Data(objects);
}
private static final class ChannelView {
final DataView data = null;
}
private static final class DataView {
final ValueView value = null;
}
private static final class ValueView {
#JsonAdapter(UnpackedJsonTypeAdapterFactory.class)
final List<MyObject> instruments = null;
}
private static final class UnpackedJsonTypeAdapterFactory
implements TypeAdapterFactory {
#Override
public <T> TypeAdapter<T> create(final Gson gson, final TypeToken<T> typeToken) {
return new UnpackedJsonTypeAdapter<>(gson.getAdapter(typeToken));
}
private static final class UnpackedJsonTypeAdapter<T>
extends TypeAdapter<T> {
private final TypeAdapter<T> typeAdapter;
private UnpackedJsonTypeAdapter(final TypeAdapter<T> typeAdapter) {
this.typeAdapter = typeAdapter;
}
#Override
#SuppressWarnings("resource")
public void write(final JsonWriter out, final T value)
throws IOException {
out.value(typeAdapter.toJson(value));
}
#Override
public T read(final JsonReader in)
throws IOException {
final String json = in.nextString();
final JsonReader lenientIn = new JsonReader(new StringReader(json));
lenientIn.setLenient(true);
return typeAdapter.read(lenientIn);
}
}
}
Pure streaming
Probably the easiest by concept way, but not that easy to implement because of creating a high-level parser that deals with JSON token stream directly from the beginning to the end. Note that no even Gson instances are introduced.
static Data testUsingStreaming(final Reader reader)
throws IOException {
final List<MyObject> myObjects = new ArrayList<>();
final JsonReader jsonReader = new JsonReader(reader);
jsonReader.beginArray();
while ( jsonReader.hasNext() ) {
jsonReader.beginObject();
while ( jsonReader.hasNext() ) {
switch ( jsonReader.nextName() ) {
case "data":
jsonReader.beginObject();
while ( jsonReader.hasNext() ) {
switch ( jsonReader.nextName() ) {
case "value":
jsonReader.beginObject();
while ( jsonReader.hasNext() ) {
switch ( jsonReader.nextName() ) {
case "instruments":
final String instrumentsJson = jsonReader.nextString();
parseInstruments(instrumentsJson, myObjects);
break;
default:
jsonReader.skipValue();
break;
}
}
jsonReader.endObject();
break;
default:
jsonReader.skipValue();
break;
}
}
jsonReader.endObject();
break;
default:
jsonReader.skipValue();
break;
}
}
jsonReader.endObject();
}
jsonReader.endArray();
return new Data(myObjects);
}
private static void parseInstruments(final String instrumentsJson, final Collection<MyObject> myObjects)
throws IOException {
final JsonReader jsonReader = new JsonReader(new StringReader(instrumentsJson));
jsonReader.setLenient(true);
jsonReader.beginArray();
while ( jsonReader.hasNext() ) {
String mnemonic = null;
Float percentChange = null;
jsonReader.beginObject();
while ( jsonReader.hasNext() ) {
final String name = jsonReader.nextName();
switch ( name ) {
case "mnemonic":
mnemonic = jsonReader.nextString();
break;
case "percentChange":
percentChange = (float) jsonReader.nextDouble();
break;
default:
jsonReader.skipValue();
break;
}
}
if ( mnemonic != null && percentChange != null ) {
myObjects.add(new MyObject(mnemonic, percentChange));
}
jsonReader.endObject();
}
jsonReader.endArray();
}
All of the approaches above produce the same output:
ADWYA: -0.34
WIFAK: -0.28
Related
New <T> object based on map of attributes
I need to create new T object based on attribute map then I want to somehow feel this object with oneResult values What I tried so far: while (set.next()) { list.add(helper.creteObject(set)); } public <T> T creteObject(ResultSet oneResult) throws SQLException { Set<String> setOfFields = classFieldName.get(aClass.getSimpleName()); Map<String, ColumnType> fieldFieldType = classFieldFiledType.get(aClass.getSimpleName()); //Map attribute attributeType ObjectMapper objectMapper = new ObjectMapper(); T pojo = objectMapper.convertValue(fieldFieldType, new TypeReference<T>() { }); for (Field declaredField : pojo.getClass().getDeclaredFields()) { ColumnType columnType = getColumnType(declaredField.getType()); switch (columnType) { case INT: int anInt = oneResult.getInt(declaredField.getName()); break; case STRING: String string = oneResult.getString(declaredField.getName()); } } } Now how to set this result to pojoobject
Gson Custom TypeAdapter for List Not Called
I am new to using Gson. I am trying to create a specific typeadapter for my class. Here it is: public class AssetSerializer extends TypeAdapter<List<Asset>> { #Override public void write(JsonWriter out, List<Asset> value) throws IOException { out.beginArray(); for (Asset asset : value) { out.beginObject(); out.name("name").value(asset.getName()); out.name("code").value(asset.getCode()); out.endObject(); } out.endArray(); } #Override public List<Asset> read(JsonReader in) throws IOException { String temp_name = ""; String temp_code = ""; List<Asset> list = new LinkedList<>(); in.beginArray(); while (in.hasNext()) { switch (in.peek()) { case BEGIN_OBJECT: in.beginObject(); while (in.hasNext()) { switch (in.nextName()) { case "name": temp_name = in.nextString(); continue; case "code": temp_code = in.nextString(); continue; } } in.endObject(); Asset temp_asset = new Asset(temp_name, temp_code); list.add(temp_asset); continue; } } in.endArray(); return list; } This is the way I am trying to serialize/deserialize a list of Assets: Asset asset1 = new Asset("Asset1", "code_1"); Asset asset2 = new Asset("Asset2", "code_2"); LinkedList<Asset> temp_list = new LinkedList<Asset>(); temp_list.add(asset1); temp_list.add(asset2); Type assetsType = new TypeToken<List<Asset>>(){}.getType(); Gson gson = new GsonBuilder() .setPrettyPrinting() .registerTypeAdapter(assetsType, new AssetSerializer()) .create(); String json = gson.toJson(temp_list); The problem is that my overridden methods are not called in this code, so Gson uses its standard serializer for arrays.
You need to register your custom adapter with GsonBuilder to solve the problem.
Json parsing with nested array using Gson
I have not seen an (answered) example on the web which discusses this kind of nested-json-array. JSON to be parsed: { "Field": { "ObjectsList": [ { "type": "Num", "priority": "Low", "size": 3.43 }, { "type": "Str", "priority": "Med", "size": 2.61 } ] } } I created a class for each 'level' of nested json block. I want to be able to parse the contents of the "ObjectList" array. Can anyone help me to parse this JSON using Gson in Java? Any hints or code-snippets would be greatly appreciated. My approach is the following: public static void main (String... args) throws Exception { URL jsonUrl = new URL("http://jsonUrl.com") // cannot share the url try (InputStream input = jsonUrl.openStream(); BufferedReader buffReader = new BufferedReader (new InputStreamReader (input, "UTF-8"))) { Gson gson = new GsonBuilder().create(); ClassA classA = gson.fromJson(buffReader, ClassA.class); System.out.println(classA); } } } class ClassA { private String field; // getter & setter // } class ClassB { private List<ClassC> objList; // getter & setter // } clas ClassC { private String type; private String priority; private double size; // getters & setters // public String printStr() { return String.format(type, priority, size); } }
The following snippet and source file would help you: https://github.com/matpalm/common-crawl-quick-hacks/blob/master/links_in_metadata/src/com/matpalm/MetaDataToTldLinks.java#L17 private static ParseResult NO_LINKS = new ParseResult(new HashSet<String>(), 0); private JsonParser parser; public static void main(String[] s) throws IOException { BufferedReader reader = new BufferedReader(new FileReader(s[0])); MetaDataToTldLinks metaDataToTldLinks = new MetaDataToTldLinks(); while (reader.ready()) { String[] fields = reader.readLine().split("\t"); ParseResult outboundLinks = metaDataToTldLinks.outboundLinks(fields[1]); System.out.println(tldOf(fields[0]) + " " + outboundLinks.links); } } public MetaDataToTldLinks() { this.parser = new JsonParser(); } public ParseResult outboundLinks(String jsonMetaData) { JsonObject metaData = parser.parse(jsonMetaData.toString()).getAsJsonObject(); if (!"SUCCESS".equals(metaData.get("disposition").getAsString())) return NO_LINKS; JsonElement content = metaData.get("content"); if (content == null) return NO_LINKS; JsonArray links = content.getAsJsonObject().getAsJsonArray("links"); if (links == null) return NO_LINKS; Set<String> outboundLinks = new HashSet<String>(); int numNull = 0; for (JsonElement linke : links) { JsonObject link = linke.getAsJsonObject(); if ("a".equals(link.get("type").getAsString())) { // anchor String tld = tldOf(link.get("href").getAsString()); if (tld == null) ++numNull; else outboundLinks.add(tld); } } return new ParseResult(outboundLinks, numNull); } public static String tldOf(String url) { try { String tld = new URI(url).getHost(); if (tld==null) return null; if (tld.startsWith("www.")) tld = tld.substring(4); tld = tld.trim(); return tld.length()==0 ? null : tld; } catch (URISyntaxException e) { return null; } } public static class ParseResult { public final Set<String> links; public final int numNull; public ParseResult(Set<String> links, int numNull) { this.links = links; this.numNull = numNull; } }
How about this snippet?: if (json.isJsonArray()) { JsonArray array = json.getAsJsonArray(); List<Object> out = Lists.newArrayListWithCapacity(array.size()); for (JsonElement item : array) { out.add(toRawTypes(item)); } }
Copy filtered JSON data from one file to another using gson library in java
I want to copy JSON fields from one file to another but only after the field satisfies a particular condition, as for example {"dataset": [ {"album_id":1, "album_type":"Live Performance", "artist_name":"John Doe",.... } ] } I want to copy only those records which have a user given artist_name or any other property, else skip the tuple for copying. I am using the following code to add the filtered records to a JSONObject "wr" which I then write to my output file. But its not giving me the desired results public static void dumpJSONElement(JsonElement element) { if (element.isJsonObject()) { JsonObject obj = element.getAsJsonObject(); java.util.Set<java.util.Map.Entry<String,JsonElement>> entries = obj.entrySet(); java.util.Iterator<java.util.Map.Entry<String,JsonElement>> iter = entries.iterator(); while (iter.hasNext()) { java.util.Map.Entry<String,JsonElement> entry = iter.next(); if(entry.getKey().equals(filterKey)){ if(! entry.getValue().toString().replace("\"", "").equals(filterValue)){ wr.put(entry.getKey(), entry.getValue()); } } else{ wr.put(entry.getKey(), entry.getValue()); } dumpJSONElement(entry.getValue()); } } else if (element.isJsonArray()) { JsonArray array = element.getAsJsonArray(); java.util.Iterator<JsonElement> iter = array.iterator(); while (iter.hasNext()) { JsonElement entry = iter.next(); dumpJSONElement(entry); } } else if (element.isJsonPrimitive()) { JsonPrimitive value = element.getAsJsonPrimitive(); } else if (element.isJsonNull()) { } else { System.out.println("Error. Unknown type of element"); } }
use code below code to convert your json string to generic java type List<Map<Object, Object>>, use code below. import java.lang.reflect.Type; import java.util.List; import java.util.Map; import com.google.gson.Gson; import com.google.gson.reflect.TypeToken; public class Test { public static void main(String... args) { String str = "[{'id':1,'name':'yogesh'},{'id':2,'name':'aarush', 'degree': 'MCA'}]"; Type type = new TypeToken<List<Map<Object, Object>>>() { }.getType(); List<Map<Object, Object>> list = new Gson().fromJson(str, type); System.out.println(new Gson().toJson(list)); filterList(list, "name", "yogesh"); System.out.println(new Gson().toJson(list)); } public static void filterList(List<Map<Object, Object>> list, String key, Object value) { for (Map<Object, Object> map : list) { if (map.containsKey(key)) { if (map.get(key).equals(value)) { list.remove(map); } } } } } here i filterd name=yogesh record. output: [{"id":1.0,"name":"yogesh"},{"id":2.0,"name":"aarush","degree":"MCA"}] [{"id":2.0,"name":"aarush","degree":"MCA"}]
I had similar issues and I googled, read a lot about this. In conclusion, the best(most efficient) way (with gson) is to write a custom TypeAdapter for your case. You can test sample code below (it is working as you expected): public static void answer() { String jsonAsText = "{\"dataset\":[{\"album_id\":1,\"album_type\":\"Live Performance\",\"artist_name\":\"John Doe\"},{\"album_id\":2,\"album_type\":\"A Dummy Performance\"}]}"; GsonBuilder gsonBuilder = new GsonBuilder(); gsonBuilder.registerTypeAdapter(List.class, new AlbumInfoListTypeAdapter()); Gson gson = gsonBuilder.create(); List<AlbumInfo> dataSet = gson.fromJson(jsonAsText, List.class); System.out.println(gson.toJson(dataSet)); } private static class AlbumInfo { int album_id; String album_type; String artist_name; } private static class AlbumInfoListTypeAdapter extends TypeAdapter<List<AlbumInfo>> { #Override public List<AlbumInfo> read(com.google.gson.stream.JsonReader in) throws IOException { List<AlbumInfo> dataSet = new ArrayList<AlbumInfo>(); in.beginObject(); while (in.hasNext()) { if ("dataset".equals(in.nextName())) { in.beginArray(); while (in.hasNext()) { in.beginObject(); AlbumInfo albumInfo = new AlbumInfo(); while (in.hasNext()) { String jsonTag = in.nextName(); if ("album_id".equals(jsonTag)) { albumInfo.album_id = in.nextInt(); } else if ("album_type".equals(jsonTag)) { albumInfo.album_type = in.nextString(); } else if ("artist_name".equals(jsonTag)) { albumInfo.artist_name = in.nextString(); } } in.endObject(); if (albumInfo.artist_name != null && !"".equals(albumInfo.artist_name.trim())) { dataSet.add(albumInfo); } else { System.out.println("Album info ignored because it has no artist_name value"); } } in.endArray(); } } in.endObject(); return dataSet; } #Override public void write(com.google.gson.stream.JsonWriter out, List<AlbumInfo> dataSet) throws IOException { out.beginObject(); out.name("dataset").beginArray(); for (final AlbumInfo albumInfo : dataSet) { out.beginObject(); out.name("album_id").value(albumInfo.album_id); out.name("album_type").value(albumInfo.album_type); out.name("artist_name").value(albumInfo.artist_name); out.endObject(); } out.endArray(); out.endObject(); } } You can modify the read and the write methods. Gson has many cool functions. I strongly suggest you to read samples at this link. Edit: Incoming json text: { "dataset": [ { "album_id": 1, "album_type": "Live Performance", "artist_name": "John Doe" }, { "album_id": 2, "album_type": "A Dummy Performance" } ] } The output at System.out.println at answer method: [ { "artist_name": "John Doe", "album_type": "Live Performance", "album_id": 1 } ]
Convert json structure to array with Retrofit
I'm in trouble with Retrofit and a ugly json object in the Trakt.tv API: { "season": 1, "episodes": { "1": true, "2": true, "3": false, "4": false, "5": false, "6": false, "7": false } } "episodes" content is obviously dynamic and I'd like to handle it as a simple Boolean array, like this: int season; Boolean[] episodes; How to do that?
You can first convert the JSON string into Map<String,Object> then finally create the desired object. sample code: public class EpisodesDetail { private int season; private Boolean[] episodes; // getter & setter } ... BufferedReader reader = new BufferedReader(new FileReader(new File("json.txt"))); Type type = new TypeToken<Map<String, Object>>() {}.getType(); Map<String, Object> map = new Gson().fromJson(reader, type); EpisodesDetail geometry = new EpisodesDetail(); geometry.setSeason(((Double) map.get("season")).intValue()); geometry.setEpisodes(((Map<String, Boolean>) map.get("episodes")).values().toArray( new Boolean[] {})); System.out.println(new GsonBuilder().setPrettyPrinting().create().toJson(geometry)); output: { "season": 1, "episodes": [ true, true, false, false, false, false, false ] } There is one more approach using GSON Deserialiser sample code: class EpisodesDetailDeserializer implements JsonDeserializer<EpisodesDetail> { #Override public EpisodesDetail deserialize(final JsonElement json, final Type typeOfT, final JsonDeserializationContext context) throws JsonParseException { EpisodesDetail geometry = new EpisodesDetail(); JsonObject jsonObject = json.getAsJsonObject(); int season = jsonObject.get("season").getAsInt(); geometry.setSeason(season); List<Boolean> episodes = new ArrayList<Boolean>(); Set<Entry<String, JsonElement>> set = jsonObject.get("episodes").getAsJsonObject() .entrySet(); Iterator<Entry<String, JsonElement>> it = set.iterator(); while (it.hasNext()) { episodes.add(it.next().getValue().getAsBoolean()); } geometry.setEpisodes(episodes.toArray(new Boolean[] {})); return geometry; } } BufferedReader reader = new BufferedReader(new FileReader(new File("json.txt"))); EpisodesDetail episodesDetail = new GsonBuilder() .registerTypeAdapter(EpisodesDetail.class, new EpisodesDetailDeserializer()) .create().fromJson(reader, EpisodesDetail.class); System.out.println(new GsonBuilder().setPrettyPrinting().create().toJson(episodesDetail)); See How do I write a custom JSON deserializer for Gson?
When I use jackson library to parse that JSON, I use ObjectMapper and DramaInfo class as follows. package jackson; import java.io.IOException; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.stream.Collectors; import com.fasterxml.jackson.databind.ObjectMapper; class DramaInfo { int season; List<Boolean> episodes; public void setSeason(int season) { this.season = season; } public int getSeason() { return this.season; } public List<Boolean> getEpisodes() { return new LinkedList<>( this.episodes ); } public void setEpisodes(Map<String, Boolean> o) { // used Java 1.8 Stream. // just see http://docs.oracle.com/javase/tutorial/collections/streams/reduction.html episodes = o.keySet().stream().map(e -> o.get(e)).collect(Collectors.toList()); } public String toString() { String ret = "season: " + this.season + "\n"; ret += this.episodes.toString(); return ret; } } public class LoadJsonData { public static void main(String[] args) { String toConvert = "{\"season\": 1, \"episodes\": { \"1\": true, \"2\": true, \"3\": false, \"4\": false, \"5\": false, \"6\": false, \"7\": false } }"; ObjectMapper mapper = new ObjectMapper(); try { DramaInfo info = mapper.readValue(toConvert, DramaInfo.class); System.out.println(info); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } So, this is a suggestion because I have never used Retrofit. If you are to use Retrofit as follows, how about trying out the DramaInfo class shown above? public interface DramaService { #GET("/dramas/{drama}/info") DramaInfo listRepos(#Path("drama") String drama); }