No matter being public or private, Restful APIs are the most popular way to integrate our applications with the world outside. This means you do not have a chance to alter the services you consume, instead, you should adapt to them most of the time.
Since Java is a static-typed language, it can be a challenge while you are consuming and mapping the data into your model objects, especially if the response data changes depending on the use case.
In this article, we will show how to handle variable response structures with the Gson Library.
Maven Dependency
Before we start, we need to add the Gson dependency into our project’s pom.xml:
Sample Response
Let’s pick a sample API for a blog which services detailed information about its articles along with the comments which may be more than one:
However, if there is only one single comment then its structure changes into object hash form:
Writing a Response Model
In order to map the data, we need a POJO as a response model. Let’s start by defining a simple class that matches the main response structure:
And we need to define another class corresponds to comment response structure:
Consuming the Response
Since we use List<CommentModel> for the comments field, we can easily map multiple values which Gson already does the heavy lifting for us:
Although this configuration works for the multiple values of comments, if it changes to a single value then we need to define a custom TypeAdapter in order to handle both single and multiple values.
Custom TypeAdapter in Gson
In order to achieve a custom JSON deserialization behavior, we need to create a TypeAdapter. This behavior will be responsible for adding any single value to the list as the same as multiple values are being added automatically by Gson.
For the beginning, let’s create a Gson TypeAdapter for this purpose:
We need to access Gson instance inside our TypeAdapter to preserve and reuse default deserialization behavior for Object and Collection types.
So, let’s define a constructor and fields of Gson instance and some default adapters:
Since we aim to deserialize only, we can omit the write method of our adapter. However, we can implement in any case by simply delegating it to the default adapters.
Next, let’s implement write method by using listTypeAdapter:
Then, we implement the read method of our adapter to come up with our expected deserialization behavior:
TypeAdapterFactory in Gson
We may consider using TypeAdapterFactory in Gson. There are two benefits of this; one of them is we can implement a generic factory method to create different TypeAdapter classes for different types. The other one is we can access the underlying Gson instance and reuse it which we are primarily looking for now.
So, let’s create a custom TypeAdapterFactory:
As we can see, we delegated the existing Gson instance to our CommentListTypeAdapter by the help of our custom TypeAdapterFactory.
Registering TypeAdapterFactory into Gson
Finally, we need to register our custom TypeAdapterFactory into the Gson context to make it work.
Let’s update our ArticleModel:
Now we can consume single value structures like multiple values with the same ArticleModel:
Further Improvements With the Power of Generics
We can go further by refactoring our code with the help of generics and reflection in the benefit of reusability. To prevent creating a new adapter for each type it might be essential to follow this method on some occasions.
Similarly, we implement another TypeAdapter because we need to handle it in a generic way:
Thus, we can use the same adapter for different element types when we need the same behavior.
We should also create another TypeAdapterFactory implementation which will use our new generic SingleAwareListTypeAdapter:
It is important to let the Gson know the list element’s type information in runtime otherwise our models are deserialized as LinkedTreeSet by default.
Since we need the runtime class of incoming list elements, first we obtained the ParameterizedType, then the runtime Class type of the element inside the Collection.
In this way, we passed the type information of the element into the SingleAwareListTypeAdapter as a parameter in the constructor.
Finally, let’s change our ArticleModel to use our new generic adapter factory:
As a result, with the help of generics and reflection, we can use the same adapter, SingleAwareListTypeAdapterFactory, for the other properties with different element types as well.
Consequently, this will provide an effective way of reusability and lead us to our goal.
Conclusion
In this tutorial, we learned how to implement custom adapters to handle variable responses in Gson.
All the source code of examples shown in this tutorial are available over on GitHub.