Jackson deserialize based on type

后端 未结 4 1624
夕颜
夕颜 2020-12-15 22:09

Lets say I have JSON of the following format:

{
    \"type\" : \"Foo\"
    \"data\" : {
        \"object\" : {
            \"id\" : \"1\"
            \"fizz\         


        
4条回答
  •  情深已故
    2020-12-15 22:47

    Custom deserializer approach

    You could use a custom deserializer that checks the type property to parse the object property into the most suitable class.

    First define an interface that will be implemented by Foo and Bar classes:

    public interface Model {
    
    }
    
    public class Foo implements Model {
    
        // Fields, getters and setters
    }
    
    public class Bar implements Model {
    
        // Fields, getters and setters
    }
    

    Then define your Wrapper and Data classes:

    public class Wrapper {
    
        private String type;
    
        private Data data;
    
        // Getters and setters
    }
    
    public class Data {
    
        @JsonDeserialize(using = ModelDeserializer.class)
        private Model object;
    
        private Metadata metadata;
    
        private Owner owner;
    
        // Getters and setters
    }
    

    The object field is annotated with @JsonDeserialize, indicating the deserializer that will be used for the object property.

    The deserializer is defined as following:

    public class ModelDeserializer extends JsonDeserializer {
    
        @Override
        public Model deserialize(JsonParser jp, DeserializationContext ctxt)
            throws IOException, JsonMappingException {
    
            // Get reference to ObjectCodec
            ObjectCodec codec = jp.getCodec();
    
            // Parse "object" node into Jackson's tree model
            JsonNode node = codec.readTree(jp);
    
            // Get value of the "type" property
            String type = ((Wrapper) jp.getParsingContext().getParent()
                .getCurrentValue()).getType();
    
            // Check the "type" property and map "object" to the suitable class
            switch (type) {
    
                case "Foo":
                    return codec.treeToValue(node, Foo.class);
    
                case "Bar":
                    return codec.treeToValue(node, Bar.class);
    
                default:
                    throw new JsonMappingException(jp, 
                        "Invalid value for the \"type\" property");
            }
        }
    }
    

    The JSON document can be deserialized as following:

    ObjectMapper mapper = new ObjectMapper();
    Wrapper wrapper = mapper.readValue(json, Wrapper.class);  
    

    Alternatively to this custom deserializer, consider an annotations-only approach.

提交回复
热议问题