Jackson Unmarshalling json with Unknown Properties

1. Overview

In this article, we’re going to take a look at the unmarshalling process with Jackson 2.x – specifically at how to deal with JSONs with unknown properties.

2. Unmarshall a json with additional/unknown fields

JSON input comes in all shapes and sizes – and most of the time, we need to map it to predefined java objects with a set number of fields. The goal is to simply ignore any json properties that cannot be mapped to an existing java field.

For example, say we need to unmarshall JSON to the following java entity:

public class MyDto {

    private String stringValue;
    private int intValue;
    private boolean booleanValue;

    public MyDto() {
        super();
    }

    // standard getters and setters and not included
}

2.1. UnrecognizedPropertyException on Unknown Fields

Trying to unmarshall a JSON with unknown properties to this simple Java Entity will lead to a com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException:

@Test(expected = UnrecognizedPropertyException.class)
public void givenJsonHasUnknownValues_whenDeserializing_thenException()
  throws JsonParseException, JsonMappingException, IOException {
    String jsonAsString = 
        "{\"stringValue\":\"a\"," +
        "\"intValue\":1," +
        "\"booleanValue\":true," +
        "\"stringValue2\":\"something\"}";
    ObjectMapper mapper = new ObjectMapper();

    MyDto readValue = mapper.readValue(jsonAsString, MyDto.class);

    assertNotNull(readValue);
}

This will fail with the following exception:

com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: 
Unrecognized field "stringValue2" (class org.baeldung.jackson.ignore.MyDto), 
not marked as ignorable (3 known properties: "stringValue", "booleanValue", "intValue"])

2.2. Dealing with Unknown Fields on the ObjectMapper

We can now configure the full ObjectMapper to ignore unknown properties in the JSON:

new ObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)

We should then be able to read this kind of JSON into a predefined java entity:

@Test
public void givenJsonHasUnknownValuesButJacksonIsIgnoringUnknowns_whenDeserializing_thenCorrect()
  throws JsonParseException, JsonMappingException, IOException {
    String jsonAsString = 
        "{\"stringValue\":\"a\"," +
        "\"intValue\":1," +
        "\"booleanValue\":true," +
        "\"stringValue2\":\"something\"}";
    ObjectMapper mapper = 
      new ObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);

    MyDto readValue = mapper.readValue(jsonAsString, MyDto.class);

    assertNotNull(readValue);
    assertThat(readValue.getStringValue(), equalTo("a"));
    assertThat(readValue.isBooleanValue(), equalTo(true));
    assertThat(readValue.getIntValue(), equalTo(1));
}

2.3. Dealing with Unknown Fields on the Class

We can also mark a single class as accepting unknown fields, instead of the entire Jackson ObjectMapper:

@JsonIgnoreProperties(ignoreUnknown = true)
public class MyDtoIgnoreUnknown { ... }

Now, we should be able to test the same behavior as before – unknown fields are simply ignored and only known fields are mapped:

@Test
public void givenJsonHasUnknownValuesButIgnoredOnClass_whenDeserializing_thenCorrect() 
  throws JsonParseException, JsonMappingException, IOException {
    String jsonAsString =
        "{\"stringValue\":\"a\"," +
        "\"intValue\":1," +
        "\"booleanValue\":true," +
        "\"stringValue2\":\"something\"}";
    ObjectMapper mapper = new ObjectMapper();

    MyDtoIgnoreUnknown readValue = mapper.readValue(jsonAsString, MyDtoIgnoreUnknown.class);

    assertNotNull(readValue);
    assertThat(readValue.getStringValue(), equalTo("a"));
    assertThat(readValue.isBooleanValue(), equalTo(true));
    assertThat(readValue.getIntValue(), equalTo(1));
}

3. Unmarshall an incomplete json

Similarly to additional unknown fields, unmarshalling an incomplete JSON – a JSON that doesn’t contain all the fields in the java class – is not a problem with Jackson:

@Test
public void givenNotAllFieldsHaveValuesInJson_whenDeserializingAJsonToAClass_thenCorrect() 
  throws JsonParseException, JsonMappingException, IOException {
    String jsonAsString = "{\"stringValue\":\"a\",\"booleanValue\":true}";
    ObjectMapper mapper = new ObjectMapper();

    MyDto readValue = mapper.readValue(jsonAsString, MyDto.class);

    assertNotNull(readValue);
    assertThat(readValue.getStringValue(), equalTo("a"));
    assertThat(readValue.isBooleanValue(), equalTo(true));
}

4. Conclusion

This article covered deserializing a JSON with additional, unknown properties, using Jackson.

This is one of the most common things to configure when working with Jackson, since it’s often the case to map JSONs of external REST APIs to an internal java representation of the entities of the API.

The implementation of all these examples and code snippets can be found in my github project – this is an Eclipse based project, so it should be easy to import and run as it is.

I usually post about Dev stuff on Google+ - you can follow me there:

Free eBook - REST Services with Spring
Join more than 2,200 engineers!
  • Jesus Mata

    Great article, this is exactly what I need, keep going!!!