Json Deserialization in Java /w Jackson of mixed types, contained in one array

泪湿孤枕 提交于 2019-12-20 02:58:24

问题


Consider the following json, getting from an public API:

 anyObject : {
     attributes: [ 
                    { 
                        "name":"anyName",
                        "value":"anyValue"
                    },
                    { 
                        "name":"anyName",
                        "value": 
                        {
                           "key":"anyKey",
                           "label":"anyLabel"
                        }
                     }
                 ]
              }

As you can see, sometimes the value is a simple string and sometimes its an object. Is it somehow possible to deserialize those kind of json-results, to something like:

 class AnyObject {
     List<Attribute> attributes;
 }

 class Attribute {
     private String key;
     private String label;
 } 

How would I design my model to cover both cases. Is that possible ?


回答1:


Despite being hard to manage as others have pointed out, you can do what you want. Add a custom deserializer to handle this situation. I rewrote your beans because I felt your Attribute class was a bit misleading. The AttributeEntry class in the object that is an entry in that "attributes" list. The ValueObject is the class that represents that "key"/"label" object. Those beans are below, but here's the custom deserializer. The idea is to check the type in the JSON, and instantiate the appropriate AttributeEntry based on its "value" type.

public class AttributeDeserializer extends JsonDeserializer<AttributeEntry> {
    @Override
    public AttributeEntry deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException {
        JsonNode root = p.readValueAsTree();
        String name = root.get("name").asText();
        if (root.get("value").isObject()) {
            // use your object mapper here, this is just an example
            ValueObject attribute = new ObjectMapper().readValue(root.get("value").asText(), ValueObject.class);
            return new AttributeEntry(name, attribute);
        } else if (root.get("value").isTextual()) {
            String stringValue = root.get("value").asText();
            return new AttributeEntry(name, stringValue);
        } else {
            return null; // or whatever
        }
    }
}

Because of this ambiguous type inconvenience, you will have to do some type checking throughout your code base.

You can then add this custom deserializer to your object mapper like so:

ObjectMapper objectMapper = new ObjectMapper();
SimpleModule simpleModule = new SimpleModule();
simpleModule.addDeserializer(AttributeEntry.class, new AttributeDeserializer());
objectMapper.registerModule(simpleModule);

Here's the AttributeEntry:

public class AttributeEntry {
    private String name;
    private Object value;

    public AttributeEntry(String name, String value) {
        this.name = name;
        this.value = value;
    }

    public AttributeEntry(String name, ValueObject attributes) {
        this.name = name;
        this.value = attributes;
    }
    /* getters/setters */
}

Here's the ValueObject:

public class ValueObject {
    private String key;
    private String label;
    /* getters/setters */
}


来源:https://stackoverflow.com/questions/40915356/json-deserialization-in-java-w-jackson-of-mixed-types-contained-in-one-array

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!