Consuming Variable Responses in Jackson
Consuming Variable Responses in Jackson
In this article, we demonstrate using the Jackson Library for the same solution used previously to handle variable responses in Gson.
Join the DZone community and get the full member experience.Join For Free
In addition to being another popular library of JSON in Java, the Jackson Library is another well-known library, primarily recognized for its ability to offer deep customization in an opinionated way.
In this article, we are going to show an alternate way to use the Jackson Library for the same solution that was demonstrated in this post on how to handle variable responses in Gson.
You may also like: Processing JSON With Jackson
Before we start, we need to add the Maven dependencies into our project's
We should note that if we already use Spring Boot and Spring Web Starter module enabled in our project, then we simply don't need to add any extra dependencies for Jackson.
Let's use this sample API response:
Also, the response changes from Array to Object notation when there is only a single
We'll also use the same models from the previous article:
Consuming the Response
We defined a collection type for the
comment field as
List<CommentModel>. Thus, we can map multiple comments into a single field automatically because Jackson already does the heavy lifting for us:
Certainly, this configuration resolves the multiple comment values unless the response changes to a single value structure. Otherwise, it simply doesn't work.
Consequently, we need to define a custom deserializer to handle both single and multiple values at once.
Custom Deserializers for Jackson
StdDeserializer is an abstract type and also the base class for common deserializers in Jackson.
Therefore, to implement a custom deserialization behavior, we will create an implementation of
StdDeserializer. This behavior will be responsible for adding any single value to the list as the same as multiple values are being added automatically by Jackson.
So, let's create
CommentListDeserializer, which inherits the base class
We need a
TypeReference for Jackson to specify the
Collection type and the type of elements in which are involved as well.
So, let's define a constant for a type of
Next, we implement the
deserialize method to come up with the expected behavior:
Deserialization Features in Jackson
Although writing a custom deserializer offers us great flexibility, there are lots of features bundled in the Jackson Library for conversions. Jackson's predefined features provide practical ways to customize both serialization and deserialization.
ACCEPT_SINGLE_VALUE_AS_ARRAY feature does the exact job for our use case. Certainly, we could use it for the sake of simplicity:
Also, an alternate way is to configure the
@JsonFormat annotation. In our example, we'll go with the
@JsonFormat annotation to set the
Let's remove our custom deserializer and add a simple
@JsonFormat annotation to our
comments field in
Thus, this will automatically add any single value of
CommentModel to our list as if it were already inside an array. Unless we have any further requirements, using Jackson features can be the most elegant solution for our use-case.
We can always have a chance to check the full list of features from the source code.
Going Further With Generic Deserializers
We can write generic deserializers for different requirements that we couldn't handle by predefined features. Besides, for the benefit of reusability, we can go further to refactor our code not to create new deserializers for each element type.
So, we'll implement a new class as
SingleAwareListDeserializer to handle the deserialization in a more customizable way:
Now, we can use the same deserializer for different types as well.
Certainly, we should notice the challenge here, which is about how to obtain the class type of the element inside our collection. Without the element's type information, it is not possible for Jackson to initialize the concrete type but only
However, there is a workaround to obtain type-related information inside our deserializer.
We used the
ContextualDeserializer interface to inform Jackson that we need information about the bean we are dealing with. Thus, an instance of
BeanProperty is automatically injected and we obtained the class type of the collection element.
Finally, to use our generic deserializer, let's change our
As a result, we can provide the same behavior by the
SingleAwareListDeserializer generically for all types as well.
In this tutorial, we learned how to handle variable responses in Jackson by using the builtin features and custom deserializers as well.
All the source code for the examples shown in this tutorial are available over on GitHub.
Published at DZone with permission of Yavuz Tas . See the original article here.
Opinions expressed by DZone contributors are their own.