Reputation: 2091
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:
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
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
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