0
@Data
public class Parent {
    private String type;
    private List<ChildBase> children;
}
public abstract class ChildBase {
    public void someMethod(){};
}
@Data
public class ChildA extends ChildBase {
    private String bar;
}
@Data
public class ChildB extends ChildBase {
    private String foo;
}

Then, the original JSON string is:

{
  "type": "childA",
  "children": [
    {
       "bar": "baaaar"
    }
  ]
}

How can I deserialize this JSON string, the deserialized object(instance of Parent), its children field's actual type should be ChildA, because the type field specified;

In the question use-property-of-parent-object-to-determine-subclass-when-deserializing, the answer blow shows the way to determine subclass, by it doesn't work with a list field.

LHCHIN
  • 3,679
  • 2
  • 16
  • 34
mt eee
  • 80
  • 10
  • In the link which you have given, he has created custom deserialization using annotations as `@JsonTypeInfo(use=Id.NAME, property="kind") @JsonSubTypes({ @Type(value=ExampleNodeT3.class, name="t3"), @Type(value=ExampleNodeT4.class, name="t4")})` where you have done that in your code? – P3arl Dec 31 '19 at 06:43

1 Answers1

0

For abstract class, one way is to create a custom deserializer to achieve what you want as follows.

Because I am not sure whether all the keys in JSON array children are going to be identical, e.g. all the keys are bar or foo if the type is childA or childB, respectively. Therefore, I use the field name to determine the JSON object is supposed to be deserialized to which class (ChildA or ChildB).

Code snippet

class ParentDeserializer extends StdDeserializer<Parent> {
    public ParentDeserializer() {
        this(null);
    }

    public ParentDeserializer(Class<?> vc) {
        super(vc);
    }

    @Override
    public Parent deserialize(JsonParser jp, DeserializationContext ctx)
        throws IOException, JsonProcessingException {
        JsonNode node = jp.getCodec().readTree(jp);
        String type = node.get("type").asText();

        List<ChildBase> children = new ArrayList<>();
        node.get("children").forEach(e -> {
            if (e.has("bar")) {
                children.add(new ChildA(e.get("bar").asText()));
            }

            if (e.has("foo")) {
                children.add(new ChildB(e.get("foo").asText()));
            }
        });

        Parent parent = new Parent();
        parent.setType(type);
        parent.setChildren(children);

        return parent;
    }
}

Then use @JsonDeserialize(using = ParentDeserializer.class) to register the deserializer directly on the class Parent.

@JsonDeserialize(using = ParentDeserializer.class)
class Parent {
    ...
}
LHCHIN
  • 3,679
  • 2
  • 16
  • 34