rjcarr
rjcarr

Reputation: 2091

Gson's RuntimeTypeAdapterFactory isn't serializing the type

I've happily used gson for years and needed to serialize and deserialize some polymorphic types and came across this gson extra which seems exactly what I need:

https://github.com/google/gson/blob/master/extras/src/main/java/com/google/gson/typeadapters/RuntimeTypeAdapterFactory.java

But no matter what I try it isn't serializing the type field, so when it tries to deserialize, naturally, it gives this error:

cannot deserialize class <...> because it does not define a field named type

Even using the demo code from the file doesn't work for me:

class Shape {
  int x;
  int y;
}

class Diamond extends Shape {
  int width;
  int height;
}

...

Gson g = (new GsonBuilder()).registerTypeAdapterFactory(
    RuntimeTypeAdapterFactory
        .of(Shape.class)
        .registerSubtype(Diamond.class)
).create();

Diamond d = new Diamond();
d.x = 10;
d.y = 20;
d.width = 25;
d.height = 35;

String json = g.toJson(d);

Which produces:

{"width":25,"height":35,"x":10,"y":20}

Note I've tried specifying custom strings for of() and register(), adding the type to the toJson() call, and even embedding the object it an outer collection, but it makes no difference.

Actually, there is no difference in output between a standard Gson object and this one created with the builder and type factory.

I notice if I debug the code and set breakpoints in the RuntimeTypeAdapterFactory read and write methods, it will hit the read() (and then get to the failure above), but it never hits the write method. Just totally skips it.

What is going on here? The code I'm using is all the latest and directly from that above link (as of today).

Upvotes: 1

Views: 1397

Answers (2)

Martin Pabst
Martin Pabst

Reputation: 921

The solution from rjcarr (include class object in call to toJson) is not practical as you normally have polymorphic objects as members of other objects or as elements in lists.

In fact there's a bug in RuntimeTypeAdapterFactory. In this github post user ultraon proposes a solution which worked for me:

Replace

if (type.getRawType() != baseType)

with

if (null == type || !baseType.isAssignableFrom(type.getRawType()))

in line 185, method create of class RuntimeTypeAdapterFactory.

Now the type attribute is included in JSON.

Upvotes: 0

rjcarr
rjcarr

Reputation: 2091

Thanks to help from a contributor to the public repository, the problem was the serialization step needed to include the base type. So instead of simply:

g.toJson(d);

It needs to be:

g.toJson(d, Shape.class);

I had tried g.toJson(d, Diamond.class), but that made no difference to the output. Hopefully this can help somebody else!

Upvotes: 5

Related Questions