The below is a working code that helps to convert JSON in Object accordingly. If the String is nil
, it will be treated as null.
There’s 2 custom deserializer i.e. MyOwnStringDeserializer
and MyOwnListDeserializer
. I am not happy with MyOwnListDeserializer
deserializer, as essentially what it is doing is in term of the String comparison to the rule defined in MyOwnStringDeserializer
. But I just can’t and don’t know how to apply the MyOwnStringDeserializer
into MyOwnListDeserializer
.
Is there a way for me to do so, that simplify the MyOwnListDeserializer
? Or even better if there’s a way to use just a single custom deserializer and could still achieve the same result?
@Test public void myTestFunction() { String myJson1 = "{"item1":"nil","item2":"nil","subItemList":[{"subItem1":"nil","subItem2":"nil"}]}"; String myJson2 = "{"subItemList":[]}"; GsonBuilder gsonBuilder = new GsonBuilder(); gsonBuilder.registerTypeAdapter(new TypeToken<List<MySubItems>>(){ }.getType(), new MyOwnListDeserializer()); gsonBuilder.registerTypeAdapter(String.class, new MyOwnStringDeserializer()); Gson gson = gsonBuilder.create(); MySimpleObject myObj1 = gson.fromJson(myJson1, MySimpleObject.class); MySimpleObject myObj2 = gson.fromJson(myJson2, MySimpleObject.class); assertThat(myObj1.equals((myObj2))).isTrue(); } class MySimpleObject implements Serializable { String item1 = null; String item2 = null; List<MySubItems> subItemList; @Override public int hashCode() { int hash = 17; hash = 31*hash + ((item1 == null)? 0 :item1.hashCode()); hash = 31*hash + ((item2 == null)? 0 :item2.hashCode()); return hash; } @Override public boolean equals(Object obj) { if (obj instanceof MySimpleObject) { return this.hashCode() == obj.hashCode(); } return super.equals(obj); } } class MySubItems implements Serializable { String subItem1 = null; String subItem2 = null; @Override public int hashCode() { int hash = 17; hash = 31*hash + ((subItem1 == null)? 0 :subItem1.hashCode()); hash = 31*hash + ((subItem2 == null)? 0 :subItem2.hashCode()); return hash; } @Override public boolean equals(Object obj) { if (obj instanceof MySubItems) { return this.hashCode() == obj.hashCode(); } return super.equals(obj); } } class MyOwnStringDeserializer implements JsonDeserializer<String> { @Override public String deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { return (json.getAsString().equals("nil"))? null : json.getAsString(); } } class MyOwnListDeserializer implements JsonDeserializer<List<MySubItems>> { @Override public List<MySubItems> deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { List<MySubItems> list = new ArrayList<>(); for (JsonElement element : json.getAsJsonArray()) { JsonObject subObj = element.getAsJsonObject(); MySubItems subItems = new MySubItems(); if (!subObj.get("subItem1").getAsString().equals("nil")) { subItems.subItem1 = subObj.get("subItem1").getAsString(); } if (!subObj.get("subItem2").getAsString().equals("nil")) { subItems.subItem2 = subObj.get("subItem1").getAsString(); } if (subItems.subItem1 != null || subItems.subItem2 != null) { list.add(subItems); } } return (list.size() == 0)? null : list; } }
Advertisement
Answer
The method you’re looking for is JsonDeserializationContext.deserialize()
. Per the warning about how to cause an infinite loop, this invokes any relevant custom deserializers you’ve set up.
I believe replacing the initialization of subItems
inside the loop with a one-liner MySubItems subItems = context.deserialize(element, MySubItems.class);
will do the trick, leaving only that and the check around list.add(subItems)
in the loop body.