I’m using Jackson to parse JSON data on a Spring Boot application, but Jackson is unable to select properly the JSON fields to map to the POJO fields.
Details
Firstly, I’m reading data from a third party library, and their data model has a lot of redundancy (namely the several properties can represent the same information), and I can’t ask them to fix it.
Their JSON is something like that:
{ "name" : "name", "full_name" : "name", "fullName" : "name"}
there are 3
properties in JSON containing the same information. But sometimes there would be only one of these properties which is non-null, like:
{ "name" : null, "full_name" : "", "fullName" : "name"}
And that happens to many other properties.
I’ve tried to use @JsonAlias
to extract the required (non-null) data from the incoming JSON, but it doesn’t resolve the issue.
@JsonProperty("name")
@JsonAlias({"full_name","fullName"})
private String name;
First, that @JsonAlias
is taking precedence from the @JsonProperty
value. Second, it’s not ignoring null values.
How can I make Jackson ignore null
values in a situation like described above?
2
Answers
Multiple Setters
One of the possible options is to define a bunch of additional setters for each duplicated property, annotated with
@JsonSetter
to map each setter to a corresponding property flavor.To avoid logic duplication, every additional setter should delegate to a regular setter, which should determine if the existing value needs to be updated (if it’s empty, null, etc.).
Usage example:
Output:
The drawbacks of this approach are the usage of "smart-setters", which might not considered to be clean (because it violates the Single responsibility principle, setters aren’t meant to perform validation) and domain class gets polluted with additional setter methods. Both issues can be solved by externalizing this functionality.
Custom Converter
Another possible solution is to customize deserialization by defining a Converter for the target type.
Note: don’t confuse Converter and Deserializer. Deserializer is meant to provide logic how to construct a POJO based on the information contained in the JsonParser, whilst Converter is used to transform one POJO (which is easier to deserialize) into another POJO.
So we need to create two classes: Converter and auxiliary type reflecting the data model of the incoming JSON.
Consider the following auxiliary POJO:
And that’s the Converter extending
StdConverter
that bridgesAuxiliaryPojo
andMyPojo
:And here’s the domain class (free from any redundant code). Note that Converter has been specified via
converter
property of the@JsonDeserialize
annotation.That would be enough to parse the sample JSON into an instance of
MyPojo
:Output:
An other solution is to ignore additionnal fields ‘fullName’ and ‘full_name’ using annotation
@JsonIgnoreProperties
and a custom deserializer that throws an exception when name property is null (or equal to string "null") so that you can catch that exception in order not to create a person when name is null.See code below:
Class Person
Class CustomNameDeserializer
Hope it helps