Jackson Deserialization and the Builder Pattern
The builder design pattern is one of those patterns that are widely used by developers. It’s very helpful when we have to create objects of classes that have many properties, especially when some of them are optional. It’s common that when we use builders the constructors of our classes are private and instances can only be created through the builder. Therefore, if we use these classes for deserialization purposes with Jackson we may face some issues since Jackson can’t instantiate our classes due to the lack of a public constructor.
In this tutorial, we’ll show how to use our builders with Jackson for JSON deserialization. We’ll also cover how to do this if we’re using Lombok to generate the builders.
Jackson Deserialization Using a Builder
Let’s first create a class to use it in our examples!
We’ll create a simple Address class:
As we can see, this class is immutable and we can only instantiate it through its builder.
If we try to deserialize a JSON into our Address class, Jackson will throw an exception saying that it can’t find a creator to construct an instance of our class:
This happens because the constructor of our class is private.
What we need to do is to tell Jackson to use our builder for the deserialization. We can do this by annotating our class with @JsonDeserialize and specify our Builder class there:
However, we’ll still get an exception if we try to use the class as it is right now:
Now Jackson is telling us that it can’t recognize the properties of our Builder class. This happens because Jackson expects that our builder uses the prefix with in the setter methods. In our case, we don’t use any prefix.
One option to fix this is to change our builder to use the with prefix. Another option is to instruct Jackson to use a different prefix by using the @JsonPOJOBuilder annotation in our Builder class:
In our case, we leave the prefix as an empty string since we’re not using any prefix.
Also, keep in mind that Jackson expects that the name of the method that creates the instances in our builder is build. Luckily, we can also customize this in the same annotation:
As seen, we’ve just supposed that our builder build method is now called create.
Jackson Deserialization Using Lombok Builders
Now we’re gonna do the same as in the previous section but working with a class that uses Lombok to generate the builder.
First, let’s change our Address class to add the proper lombok annotations:
This class is also immutable and it has a private constructor. Hence, we can create instances only through its builder.
As we can see above, our builder now uses the prefix with in the setter methods. Therefore, we only need to tell Jackson to use this builder to create instances and we’re good to go:
This is enough to use this class for deserialization with Jackson.
However, let’s suppose that we’re not using with as setter prefix, how can we let Jackson know? We have to declare the Builder class ourselves and use the same @JsonPOJOBuilder annotation as before:
Also notice that Lombok uses build as the default name of the build method. If we want to use another one we have to specify it in the buildMethodName property of the @JsonPOJOBuilder annotation as we did in the previous section.
@Jacksonized
Lombok has introduced an experimental feature @Jacksonized in its 1.18.14 version. The goal of this feature is to simplify the integration between Lombok and Jackson.
Let’s modify our previous example to use this annotation! It’s as simple as just replacing all the Jackson annotations with @Jacksonized:
That’s it! Our class is ready!
Notice that if we change the setter prefix or the build method name of our builder Lombok will take care of it and will change the generated Jackson annotations accordingly.
This annotation is great and helps us save code and time when working with builders and Jackson. But remember that at the time of writing this tutorial it’s still experimental.
Conclusion
In this tutorial, we’ve explained how to use Jackson to deserialize classes that can only be instantiated by using a builder. We’ve shown examples of how to do this and we’ve also shown how to customize the default behavior of the Jackson annotations. Additionally, we’ve also covered how to do this if we’re using the popular library Lombok.
The source code of the examples is available at Github.
Leave a comment