Sorry for replying too late (as this question is already answered). But I think I can give my 2 cents to this issue.
As @Parobay has said before you can add an special {"type": "complex"}
parameter in order to know which class do you want to deserialize. But as said before, you have to move all your data to an {"instance": {}}
subobject which feels akward as you have to keep control manually of the instances created in a big switch
.
You can use instead a TypeFactory
class to handle this situation better. More precisely, there are one special factory (which is not bundled currently with Gson and should) called RuntimeTypeAdapterFactory
. Copying what documentation says about this class:
Adapts values whose runtime type may differ from their declaration
type. This is necessary when a field's type is not the same type that
GSON should create when deserializing that field. For example,
consider these types:
{
abstract class Shape {
int x;
int y;
}
class Circle extends Shape {
int radius;
}
class Rectangle extends Shape {
int width;
int height;
}
class Diamond extends Shape {
int width;
int height;
}
class Drawing {
Shape bottomShape;
Shape topShape;
} }
Without additional type information, the serialized JSON is ambiguous. Is the bottom shape in this drawing a
rectangle or a diamond?
{
{
"bottomShape": {
"width": 10,
"height": 5,
"x": 0,
"y": 0
},
"topShape": {
"radius": 2,
"x": 4,
"y": 1
}
}}
This class addresses this problem by adding type information to the serialized JSON and honoring that type
information when the JSON is deserialized: {
{
"bottomShape": {
"type": "Diamond",
"width": 10,
"height": 5,
"x": 0,
"y": 0
},
"topShape": {
"type": "Circle",
"radius": 2,
"x": 4,
"y": 1
}
}}
Both the type field name ({@code "type"}) and the type labels ({@code "Rectangle"}) are configurable.
So you only have to create your Gson object with:
RuntimeTypeAdapter<Shape> shapeAdapter
= RuntimeTypeAdapter.of(Shape.class, "type")
.registerSubtype(Rectangle.class, "Rectangle");
Gson gson = new GsonBuilder()
.registerTypeAdapter(Shape.class, shapeAdapter)
.create();
And voilá, you have automatic (de)serialization of objects. I created a variation of this Factory that instead of expecting a type
parameter, tries to discover what kind of object is by running a custom regular expression (that way you can avoid to create that extra parameter, or when you don't have full control of the API).
Here I give you the two links with the sources: