简体   繁体   中英

Jackson determine subclass for list field

@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.

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, eg 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 {
    ...
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM