Course – LS (cat=JSON/Jackson)

Get started with Spring and Spring Boot, through the Learn Spring course:

>> CHECK OUT THE COURSE

1. Overview

In this tutorial, we’ll look at different ways to handle null or missing values in JSON Strings when parsing them using Jackson. There are three options that offer varying levels of control that we’ll explore in detail.

2. Setting a Default Value at the Class Level

The first example we’ll see is how we can get default values into our POJOs when they are missing entirely from incoming JSON Strings. Let’s create an object with two fields, one which is required and one which we’ll set a default for:

class NonAnnotatedDefaultValue {
    String required;
    String optional = "defaultValue";
    // Standard getters and setters
}

We’ve assigned a value to the field called optional here. This will result in Jackson using that String if the field is missing in the JSON. Let’s use that object now by asking Jackson to map a JSON String with no field called optional in it. We’ll use the ObjectMapper object and its readValue() method:

@Test
void givenAClassWithADefaultValue_whenReadingJsonWithoutOptionalValue_thenExpectDefaultValueInResult()
  throws JsonProcessingException {
    String noOptionalField = "{\"required\": \"value\"}";
    ObjectMapper objectMapper = new ObjectMapper();
    NonAnnotatedDefaultValue createdObject = objectMapper.readValue(noOptionalField, NonAnnotatedDefaultValue.class);
    assert(createdObject.getRequired()).equals("value");
    assert(createdObject.getOptional()).equals("defaultValue");
}

We can see from the assertions that the resulting object has both the value from the JSON and the default value we specified earlier.

The drawback of this method is that it only works if the property is missing entirely from the incoming JSON. If the property is present with a null value, then Jackson will not apply the default. In the following sections, we’ll see approaches that let us handle nulls better.

3. Implementing a Setter Method for Maximum Control

We can take complete control of the mapping process by implementing a setter method for our field. Let’s create an object with the required setter that Jackson will use when creating our objects:

class SetterDefaultValue {
   String required;
   String optional = "valueIfMissingEntirely";

    public void setOptional(String optional) {
        if (optional == null) {
            this.optional = "valueIfNull";
        }
    }
   // Standard getters and setters
}

Here we’ve provided a default value at the class level like before. However, we’ve also provided a setter method. Within that setter method, we can now do anything we like. In this example, we’ve explicitly provided the expected behavior if the value is null. Jackson will now set optional to valueIfMissingEntirely if we don’t include the property in our JSON, or valueIfNull should it be included but set to null.

We could have made both values the same if that met our requirements. Let’s see that in action:

@Test
void givenAClassWithASetter_whenReadingJsonWithNullOptionalValue_thenExpectDefaultValueInResult()
  throws JsonProcessingException {
    String nullOptionalField = "{\"required\": \"value\", \"optional\": null}";
    ObjectMapper objectMapper = new ObjectMapper();
    JsonSetterDefaultValue createdObject = objectMapper.readValue(nullOptionalField, JsonSetterDefaultValue.class);
    assert(createdObject.getRequired()).equals("value");
    assert(createdObject.getOptional()).equals("valueIfNull");
}

Here we’ve provided JSON, which has the field named optional set to null. We can see from the assertions that in the resulting object created by Jackson, the field has been set to valueIfNull, thanks to our annotation. This option gives us a huge amount of flexibility in our approach. We could also check for empty Strings and apply a default in the same way if we wanted to.

4. Using @JsonSetter With Nulls.SKIP

Our final option to look utilizes @JsonSetter and extends the usage to tell it to ignore nulls. Let’s create a new class:

class NullsSkipDefaultValue {
    private String required;
    @JsonSetter(nulls = Nulls.SKIP)
    private String optional = "defaultValue";
    // standard getters and setters
}

The Nulls.SKIP argument tells @JsonSetter to skip any input with a null value. Jackson then uses the provided default value instead. There are several other options within the Nulls enum we can use. For example, Nulls.SET will tell Jackson to translate a null in the JSON to the Java null in the POJO. Today we’ll stick with Nulls.SKIP:

@Test
void givenAClassWithAJsonSetterNullsSkip_whenReadingJsonWithNullOptionalValue_thenExpectDefaultValueInResult() throws JsonProcessingException {
    String nullOptionalField = "{\"required\": \"value\", \"optional\": null}";
    ObjectMapper objectMapper = new ObjectMapper();
    NullsSkipDefaultValue createdObject = objectMapper.readValue(nullOptionalField, NullsSkipDefaultValue.class);
    assert(createdObject.getRequired()).equals("value");
    assert(createdObject.getOptional()).equals("defaultValue");
}

Above, we can see that given the same input JSON as in section 3, where the optional field is assigned to null, we get the default value we wanted. This also gives the same result if we don’t provide an optional field.

5. Conclusion

In this article, we explored three ways of dealing with missing or null values in JSON that we want to parse using Jackson.

Setting the value at the class level is useful but fails if we have a null value. We can instead implement a setter method for maximum control. Alternatively, we can use @JsonSetter over the field declaration to simply ignore nulls. All three may be suitable depending on our use case. The most important consideration is how we want our application to handle a property with the value null.

As always, the full code for the examples is available over on GitHub.

Course – LS (cat=JSON/Jackson)

Get started with Spring and Spring Boot, through the Learn Spring course:

>> CHECK OUT THE COURSE
res – Jackson (eBook) (cat=Jackson)
2 Comments
Oldest
Newest
Inline Feedbacks
View all comments
Comments are open for 30 days after publishing a post. For any issues past this date, use the Contact form on the site.