1

Having the following types:

A

public interface A {    
}

Aa

class Aa implements A {
    private int aInt;
    private String aString;
    private boolean aBoolean;

    //getters and setters
}

Bb

public class Bb implements A {
    private int bInt;
    private String bString;
    private boolean bBoolean;

    //getters and setters
}

and C

public class C implements serializable {
    private int cInt;
    private String cString;
    private boolean cBoolean;
    private List<A> aList;

    //getters and setters
}

How to write customized deserializer and serializer for class C? Instance of class C contains list of both class Aa and Bb objects.

pirho
  • 11,565
  • 12
  • 43
  • 70
stallion
  • 1,901
  • 9
  • 33
  • 52
  • Does this answer your question? [Deserialize JSON with Jackson into Polymorphic Types - A Complete Example is giving me a compile error](https://stackoverflow.com/questions/30362446/deserialize-json-with-jackson-into-polymorphic-types-a-complete-example-is-giv) – Adwait Kumar Dec 30 '19 at 19:45
  • `Bb implements B`? Should not it be `Bb implements A`? In your example, all implementations have different set of properties. Does it look the same in your app? Do you have a `type` property in a base class like in this [example](https://stackoverflow.com/questions/18757431/jackson-jsontypeinfo-as-external-property-doesnt-work-as-expected)? If you have a control over serialisation you should use it. – Michał Ziober Dec 30 '19 at 20:10
  • yes, its a typo, it should be implements A.. corrected – stallion Dec 30 '19 at 20:11
  • What about other questions? Can you add extra `type` field which will be used as determinant of given type? – Michał Ziober Dec 30 '19 at 21:46
  • no, i cannot add extra type parameter.. – stallion Dec 31 '19 at 06:45

1 Answers1

0

For serializer: I do not see any reason (except see at the bottom at my answer) why you should need any custom serializer. Gson serializes fluently almost anything.

The problem comes with deserialization because your List<A> aList - after serialized to JSON object - does not contain information in its objects that what was the implementing class. I am afraid that the only available option is by peeking what are the fields (or any similar spying, values perhaps) in the JSON objects you are currently serializing.

For example, you could have deserialiser like:

public class PeekingDeserializer implements JsonDeserializer<A> {

    private final Gson gson = new Gson();

    @Override
    public A deserialize(JsonElement je, Type typeOfT, 
                            JsonDeserializationContext context)
            throws JsonParseException {
        return buildInstance(je);
    }

    private A buildInstance(JsonElement je) {
        Class<? extends A> classA;
        if (null != je.getAsJsonObject().getAsJsonPrimitive("aInt")) {
            classA = Aa.class;
        } else if (null != je.getAsJsonObject().getAsJsonPrimitive("bInt")) {
            classA = Bb.class;
        } else {
            throw new IllegalArgumentException("Could not resolve class");
        }
        return gson.fromJson(je, classA);
    }
}

And as you see above implementation trusts that fields aInt, bInt always exist. They can be null I think but they must exist in JSON object. The main thing is that there must be something that you can use to recognize the type of object. If you cannot recognize the type, if you cannot code the deserializer it cannot be expected that Gson could do it in some automagical way.

I think that Michał Ziober in his comment was thinking either using RuntimeTypeAdapterFactory or possibility to add the type information when serializing C (or List<A>). For the latter you could have use of custome serializer - using it to stamp the type information as field type - but if your JSON comes elsewhere and not serialized by you this option does not help.

pirho
  • 11,565
  • 12
  • 43
  • 70
  • I will try this out! On the other hand what if the variable name is same in 2 implementations and both are different primitives like String and Integer.. je.getAsJsonObject().getAsJsonPrimitive("aInt").. How would this change in such case? – stallion Dec 31 '19 at 19:54
  • Class extends A> classA; this line should contain implements not extends in my case.. but " implements A>" is giving compile errors.. do u have any alternatives for this? – stallion Dec 31 '19 at 20:10
  • Ignore the above , By mistake the refered A in my package was not the one i intended.. It had import from different package. Hence the issue. – stallion Jan 01 '20 at 08:57
  • @stallion yes anyway you can only use `extends` or `super` with wildcards in generics. String is not a primitive and I think that almost any JSON value can be instantiated as a String. But for numeric & other types you can try to instantiate it from JSON catch the exception and then try the next possible type (so class) for vars that hold the same name. You can also compare check multiple fields it does not have to be just one. – pirho Jan 01 '20 at 09:53