Skip to content
Advertisement

Can I apply a custom deserializer to within another custom deserializer for GSON

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.

User contributions licensed under: CC BY-SA
8 People found this is helpful
Advertisement