How to map unknown JSON properties with Jackson?

For a current project, I need to map a JSON object that have some known fields, and some “dynamics” fields. I don’t want to ignore these fields, just to get them in a map inside my bean. After digging for 20 minutes, I finally found the right annotations to use: @JsonAnyGetter and @JsonAnySetter.

@JsonAnySetter is a simple marker that can be used to define a two-argument method (first argument name of property, second value to set), to be used as a “fallback” handler for all otherwise unrecognized properties found from JSON content.

Here is a simple test:

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

import org.junit.Test;

import com.fasterxml.jackson.annotation.JsonAnyGetter;
import com.fasterxml.jackson.annotation.JsonAnySetter;
import com.fasterxml.jackson.databind.ObjectMapper;

public class DummyClass {

 @Test
 public void check() throws IOException {
  ObjectMapper objectMapper = new ObjectMapper();

  // ---------------------------SER
  // Classic
  MyClass myClass1 = new MyClass();
  myClass1.setProperty("John");

  assertFalse(myClass1.hasUnknowProperties());
  System.err.println(objectMapper.writeValueAsString(myClass1));

  // With unknown properties
  MyClass myClass2 = new MyClass();
  myClass2.set("other-property", "a simple value");
  myClass2.setProperty("John");

  assertTrue(myClass2.hasUnknowProperties());
  System.err.println(objectMapper.writeValueAsString(myClass2));

  // ---------------------------DESER
  MyClass mClass3 = objectMapper.readValue("{\"property\":\"John\"}",
    MyClass.class);
  assertFalse(mClass3.hasUnknowProperties());
  assertEquals("John", mClass3.getProperty());

  MyClass mClass4 = objectMapper
    .readValue(
      "{\"property\":\"John\",\"other-property\":\"a simple value\"}",
      MyClass.class);
  assertTrue(mClass4.hasUnknowProperties());
  assertEquals("a simple value", mClass4.any().get("other-property"));
  assertEquals("John", mClass4.getProperty());

 }

 public static class MyClass {

  private String property;

  private Map<String, String> other = new HashMap<String, String>();

  public String getProperty() {
   return property;
  }

  public void setProperty(String property) {
   this.property = property;
  }

  @JsonAnyGetter
  public Map<String, String> any() {
   return other;
  }

   @JsonAnySetter
  public void set(String name, String value) {
   other.put(name, value);
  }

  public boolean hasUnknowProperties() {
   return !other.isEmpty();
  }
 }
}

Related Posts

Comments (9)

Intéressant ! Mais vu que tout l'article est en anglais, pourquoi utiliser des noms de classe et de propriété en français ?

Comme dirait Renault dans ses pubs, "la French Touch quoi". Blague à part, c'est à jour avec des noms plus anglophones! Merci pour la remarque 🙂

Excellent tutorial. very helpful.

Exactly what I needed, thx

You are "truly" a legend!
I started poking around with mapping JSON objects to Java-based domain objects using Gson. However, it didn't take me more than a day to hit roadblocks because of the limitation of Gson. Then I switched to Jackson and I have been very impressed to learn about its annotations. And you have just brought to my attention another one!

Hey, thanks for the post.. it was really helpful.
But, would like to know how we could add bean validation here.. lets say i want to restrict the length to 100 characters for the object “other”.

Leave a comment