Search code examples
javajsonjackson

Mix of standard and dynamic properties in Jackson mapping


We are working with a REST service that provides json that will consist of some standard properties, as well as a number of dynamic properties.

For example:

{
  id: 123,
  name: "some name",
  custom_name: "Some value",
  some_other_custom_name: "Some other value",
}

Ideally, I'd like to have the class designed as follows:

public class MyObject{
  @JsonProperty int id;
  @JsonProperty String name;
  private Map<String, String> customVals;

  public int getId(){
    return id;
  }

  public String getName(){
    return name;
  }

  public String getCustomVal(String key){
    return customVals.get(key);
  }
}

Is there any way to convince Jackson to push the custom values into the Map (or achieve equivalent functionality)?

Right now, I'm just deserializing the whole object into a Map, and wrapping that in my business object, but it's not nearly as elegant as it would be if the deserialization would take care of it.


Solution

  • You can use Jackson @JsonAnySetter and @JsonAnyGetter annotations.

    Here is a complete example:

    public class JacksonAnyGetter {
    
        static final String JSON = "{"
                + "  \"id\": 123,"
                + "  \"name\": \"some name\","
                + "  \"custom_name\": \"Some value\","
                + "  \"some_other_custom_name\": \"Some other value\""
                + "}";
    
        static class Bean {
            public int id;
            public String name;
            private Map<String, Object> properties = new HashMap<>();
    
            @JsonAnySetter
            public void add(String key, String value) {
                properties.put(key, value);
            }
    
            @JsonAnyGetter
            public Map<String, Object> getProperties() {
                return properties;
            }
    
            @Override
            public String toString() {
                return "Bean{" +
                        "id=" + id +
                        ", name='" + name + '\'' +
                        ", properties=" + properties +
                        '}';
            }
        }
    
        public static void main(String[] args) throws IOException {
            final ObjectMapper mapper = new ObjectMapper();
            final Bean bean = mapper.readValue(JSON, Bean.class);
            System.out.println(bean);
            final String json = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(bean);
            System.out.println(json);
        }
    }
    

    Output:

    Bean{id=123, name='some name', properties={custom_name=Some value, some_other_custom_name=Some other value}}
    
    {
      "id" : 123,
      "name" : "some name",
      "custom_name" : "Some value",
      "some_other_custom_name" : "Some other value"
    }