Search code examples
javajsonjacksonjson-deserialization

How to map a dynamic JSON property to a fixed POJO field


I have some json that i want to parse into pojo

{
  "groups": [
    {
      "g1": [
        1,2,5,6,7
      ]
    },
    {
      "g2": [
        2,3,48,79
      ]
    }
  ]
}   

Of course, g1 and g2 are the identifiers, so what i would imagine as pojos would be sth like

class Container {
    List<Group> groups;
}

class Group {
    String id;
    List<Integer> values;
}

So it boils down to this question: How to use jackson to map a json-property to the pojo?


Solution

  • This kind of structure can be parsed using a custom deserializer added with the JsonDeserialize annotation.

    POJOs

    public static class Container {
        private List<Group> groups;
        public List<Group> getGroups() {
            return groups;
        }
        public void setGroups(List<Group> groups) {
            this.groups = groups;
        }
        @Override
        public String toString() {
            return String.format("Container [groups=%s]", groups);
        }
    }
    
    @JsonDeserialize(using=CustomDeserializer.class)
    public static class Group {
        String id;
        List<Integer> values;
        @Override
        public String toString() {
            return String.format("Group [id=%s, values=%s]", id, values);
        }
    }
    

    Deserializer, note use of ObjectMapper.readTree rather than using the low level JsonParser API...

    public static class CustomDeserializer extends JsonDeserializer<Group> {
    
        @Override
        public Group deserialize(JsonParser jp, DeserializationContext ctxt)
                throws IOException, JsonProcessingException {
            Group group = new Group();
            ObjectNode objectNode = new ObjectMapper().readTree(jp);
            // assume only a single field...
            Entry<String, JsonNode> field = objectNode.fields().next();
            group.id = field.getKey();
    
            // there might be a nicer way to do this...
            group.values = new ArrayList<Integer>();
            for (JsonNode node : ((ArrayNode)field.getValue())) {
                group.values.add(node.asInt());
            }
            return group;
        }
    }
    

    Test

    public static void main(String[] args) throws Exception {
        String json = "{\"groups\": [{\"g1\":[1,2,5,6,7]},{\"g2\": [2,3,48,79]}]}";
        JsonFactory f = new JsonFactory();
        JsonParser jp = f.createParser(json);
        ObjectMapper mapper = new ObjectMapper();
    
        System.out.println(mapper.readValue(jp, Container.class));
    }
    

    Output

    Container [groups=[Group [id=g1, values=[1, 2, 5, 6, 7]], Group [id=g2, values=[2, 3, 48, 79]]]]