Code Monkey home page Code Monkey logo

blog-polymorphism-with-gson's Introduction

Gson and Object Hierarchies

Gson is a small Java library for serializing objects into JSON and deserializing JSON back to java objects. But how can we deal with object polymorphism in Gson?

Serializing a Simple Object

Imagine a POJO named Car.

class Car {
    private int cargoCapacityInLiter;
    //...
}

To serialize objects to JSON, we just create an instance of Gson with the GsonBuilder and use the toJson method.

Gson gson = new GsonBuilder().create();
String jsonResult = gson.toJson(new Car());

This will give us the result as a JSON String: {"cargoCapacityInLiter":0}

To convert this JSON back to a Java object, we use the fromJson method.

Car car = gson.fromJson(jsonResult, Car.class);

That's pretty straight forward!

Serializing Object Hierarchies

Let us extend our structure with an abstract class Vehicle, a Plane and a Bicycle POJO. The existing Car also extends the Vehicle class.

abstract class Vehicle {
    private int maxSpeed;
    //...
}

class Car extends Vehicle {
    private int cargoCapacityInLiter;
    //...
}

class Plane extends Vehicle {
    private int wingspanInMeter;
    //...
}

class Bicycle extends Vehicle {
    private int frameHeight;
    //...
}

If we serialize instances of these three classes to JSON, ...

Gson gson = new GsonBuilder().create();
String carJson = gson.toJson(new Car());
String planeJson = gson.toJson(new Plane());
String bicycleJson = gson.toJson(new Bicycle());

... we get the following strings.

{"cargoCapacityInLiter":0,"maxSpeed":0}
{"wingspanInMeter":0,"maxSpeed":0}
{"frameHeight":0,"maxSpeed":0}

But here is the problem: How we can distinguish these objects during deserialization? The JSON strings have lost the type information. Is this string a Car or a Bicycle? Gson cannot infer that just from the field names. And if we try to deserialize an abstract Vehicle ...

Vehicle vehicle = gson.fromJson(c, Vehicle.class);

... we will get an InstantiationException.

Preserving Runtime Type Information

The solution is to make the type information (e.g. what type of object we are serializing) available during deserialization by including it in the serialized string:

{"type":"Car","cargoCapacityInLiter":0,"maxSpeed":0}

This is a common problem, so it is somewhat surprising that Gson does not already offer an option to do that. The Gson project on GitHub contains an additional library, gson-extras, which provides that functionality in form of TypeAdapters. However this library is not officially released and maintained.

We now have two options. We can locally install the gson-extras library by cloning the official GitHub repo and running mvn install. However, we saw failing tests and a pom.xml incompatibility with our version of Maven. The recommended alternative is to just copy what we need to our project. In our case, this is just RuntimeTypeAdapterFactory.java.

Next, we have to create a RuntimeTypeAdapterFactory of the base type Vehicle and register all subclasses of Vehicle, each with a descriptive label. We then create the Gson instance as we did previously, but this time we also let Gson know about our object hierarchy.

RuntimeTypeAdapterFactory<Vehicle> vehicleAdapterFactory = RuntimeTypeAdapterFactory.of(Vehicle.class, "type")
    .registerSubtype(Car.class, "Car")
    .registerSubtype(Plane.class, "Plane")
    .registerSubtype(Bicycle.class, "Bicycle");

Gson gson = new GsonBuilder().registerTypeAdapterFactory(vehicleAdapterFactory).create();

When we serialize now ...

String carJson = gson.toJson(new Car(), Vehicle.class);
String planeJson = gson.toJson(new Plane(), Vehicle.class);
String bicycleJson = gson.toJson(new Bicycle(), Vehicle.class);

... a type field with the previously specified label is included in the JSON strings.

{"type":"Car","cargoCapacityInLiter":0,"maxSpeed":0}
{"type":"Plane","wingspanInMeter":0,"maxSpeed":0}
{"type":"Bicycle","frameHeight":0,"maxSpeed":0}

Now we can deserialize Vehicle instances without ambiguities. We only have to provide the abstract class as type parameter.

Vehicle car = gson.fromJson(carJson, Vehicle.class);
Vehicle plane = gson.fromJson(planeJson, Vehicle.class);
Vehicle bicycle = gson.fromJson(bicycleJson, Vehicle.class);

It was suprising that Gson doesn't include handling object hierarchies in their core library. This makes such a routine task harder than expected.

If given a choice, we would generally prefer Jackson, which offers annotation-driven polymorphic de-/serialization out-of-the-box. The only annoyance with Jackson is that base class annotations have to reference the subtypes, which introduces circular dependencies and limits reuse. But that is a different topic and for another post.

A working example of the code used in this post is available on GitHub.

blog-polymorphism-with-gson's People

Contributors

balazsatwork avatar

Watchers

 avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.