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.

If you want to dig deeper and learn other cool things you can do with the Jackson 2 – head on over to the main Jackson tutorial.

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:

Get My 3 Spring eBooks
There’s no “one single way” to build an app. This is one way that I found works well.
×
Build Your Web App with Spring (and quickly prototype it to 90%)
  • Jesus Mata

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

  • http://www.codebits.com David Medinets

    Nice article. If you’ve working with Google’s GSON library it would be nice to read a contrast between them.

    • http://www.baeldung.com/ Eugen Paraschiv

      Sounds interesting – I’m adding it to my TODO list – thanks for the suggestion. Cheers,
      Eugen.