Search code examples
javajackson2

jackson get list from map where key contains the path (like "child_1_name")


Our integration point returns to us the following structure

{
  "veryImportantProperty":"some value",
  "child_1_name": "Name1",
  "child_1_age": 15,
  "child_2_name": "Name2",
  "child_2_age": 18
}

We have would like to parse this to the following classes:

class Child {
  @NotEmpty
  private String name;
  @NotNull
  private Integer age;
}

class Wrapper{
  @NotEmpty
  private String veryImportantProperty;
  @Valid
  private List<Child> children;
}

Is there any plugin/configuration for Jackson which can do this for me?

Thanks


Solution

  • You could define a custom Deserializer by extending StdDeserializer:

    class WrapperDeserializer extends StdDeserializer<Wrapper> {
    
        public WrapperDeserializer() {
            this(null);
        }
    
        public WrapperDeserializer(Class<?> vc) {
            super(vc);
        }
    
        @Override
        public Wrapper deserialize(JsonParser jp, DeserializationContext ctxt)
                throws IOException, JsonProcessingException {
            JsonNode node = jp.getCodec().readTree(jp);
    
    
            String veryImportantProperty = node.get("veryImportantProperty").asText();
            List<Child> children = new ArrayList<Child>();
            int iChild = 1;
            Child child;
            while(node.has("child_"+iChild+"_name")) {
                child = new Child();
                child.setName(node.get("child_"+iChild+"_name").asText());
                child.setAge(node.get("child_"+iChild+"_age").asInt());
                children.add(child);
                iChild++;
            }
    
            Wrapper wrapper = new Wrapper();
            wrapper.setVeryImportantProperty(veryImportantProperty);
            wrapper.setChildren(children);
            return wrapper;
        }
    }
    

    And annotate your Wrapper class with @JsonDeserialize to use your custom Deserializer

    @JsonDeserialize(using = WrapperDeserializer.class)
    class Wrapper {
        ...
    }
    

    Then you can deserialize in one line using the ObjectMapper.readValue method

    ObjectMapper mapper = new ObjectMapper();
    Wrapper wrapper = null;
    try {
        wrapper = mapper.readValue(json, Wrapper.class);
    } catch (Exception e) {
        System.out.println("Something went wrong:" + e.getMessage());
    }