Gson Advanced — Custom Deserialization Basics

In this blog post, we'll look on how to implement custom Gson deserialization. If your server sends you data in a format, which doesn't match your client's application data model, keep reading!

Of course, this will not be the only post in our Gson series. If you're interested in the other topics, check out our series outline:

Gson Series Overview

Custom Deserialization

It's quite common in modern applications that an API sends data in a structure that either doesn't have a Java equivalent or isn't a good fit for your application. In those cases it's quite useful to have a custom deserializer, which takes the data format of the JSON message and transforms it into something useful on the Java side.

For example, let's look at the following JSON:

{
    "year": 116,
    "month": 5,
    "day": 21,
    "age": 26,
    "email": "norman@futurestud.io",
    "isDeveloper": true,
    "name": "Norman"
}

The bottom four properties make sense and have a direct equivalent in Java. The first three, however, represent a simple date object. Of course, we could just create a Java model, which also has three int values. But that would be highly inconvenient in your application, since you always have to deal with combining those three into a purposeful date object.

The better way is to customize the deserialization and combine them to a date object right away. Within your application you'll never know that the server send it in that format and you can abstract differences between server and client away.

In this example our goal is to use the following Java model:

public class UserDate {  
    private String name;
    private String email;
    private boolean isDeveloper;
    private int age;
    private Date registerDate;
}

The approach for custom deserialization is almost identical to custom serialization. Thus it might help to read the custom serialization.

In short, you'll need to use a custom Gson instance and call the registerTypeAdapter() method. The registerTypeAdapter() expects two parameters. The first one is the type of the overall model we want to customize. The second parameter is an instance of a typed JsonDeserializer.

GsonBuilder gsonBuilder = new GsonBuilder();

JsonDeserializer<UserDate> deserializer = ...; // will implement in a second  
gsonBuilder.registerTypeAdapter(UserDate.class, deserializer);

Gson customGson = gsonBuilder.create();  
UserDate customObject = customGson.fromJson(userJson, UserDate.class);  

The critical part is the implementation of the JsonDeserializer. You'll need to implement a single deserialize() method. It passes you a JsonElement, which contains the actual input JSON and the expected type you've to return.

Based on the input JSON you'll have to create your Java model. In most cases, Gson can do all of this automatically for you. When you require custom deserialization, you might need to do some stuff manually.

Continuing in our example, we need to create a Java Date object from the three year, month and day properties next. We would also map all the other four properties and instantiate our complete Java model:

// change serialization for specific types
JsonDeserializer<UserDate> deserializer = new JsonDeserializer<UserDate>() {  
    @Override
    public UserDate deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
        JsonObject jsonObject = json.getAsJsonObject();

        Date date = new Date(
                jsonObject.get("year").getAsInt(),
                jsonObject.get("month").getAsInt(),
                jsonObject.get("day").getAsInt()
        );

        return new UserDate(
                jsonObject.get("name").getAsString(),
                jsonObject.get("email").getAsString(),
                jsonObject.get("isDeveloper").getAsBoolean(),
                jsonObject.get("age").getAsInt(),
                date
        );
    }
};

As you can see above, we're calling getAsJsonObject() to get access to a more convenient wrapping of the JsonElement. We can then call get() to access the value of a model property. We can access the value of that model property with various methods depending on the type, for example getAsBoolean(). Finally, we're returning a new instance of the UserDate class.

Depending on the guarantees of your data, you might want to check with has() if the model property exists at all in the JsonObject. Otherwise you might run into NullPointerExceptions, if you're accessing a property and then try to get a value of it.

Outlook

In this blog post, you've learned how you can customize Gson deserialization. It's often easier and much more efficient to adjust the mapping once instead of dealing with a weird data format throughout your application. Custom deserialization can do that for you.

If you've feedback or a question, let us know in the comments or on twitter @futurestud_io.

Make it rock & enjoy coding!

Explore the Library

Find interesting tutorials and solutions for your problems.