Gson的RuntimeTypeAdapterFactory没有序列化类型

时间:2018-12-07 08:03:21

标签: java json gson

我已经愉快地使用gson多年了,需要序列化和反序列化一些多态类型,并碰到了gson extra ,这似乎正是我所需要的:

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

但是无论我尝试什么,它都不会序列化类型字段,因此当它尝试反序列化时,自然会出现以下错误:

  

无法反序列化类<...>,因为它未定义名为type的字段

即使使用文件中的演示代码对我也不起作用:

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);

哪个会产生:

  

{“宽度”:25,“高度”:35,“ x”:10,“ y”:20}

请注意,我尝试为 of() register()指定自定义字符串,并将类型添加到 toJson()调用中,甚至将对象嵌入到外部集合中,但这没什么区别。

实际上,标准 Gson 对象与使用构建器和类型工厂创建的对象之间的输出没有差异。

我注意到,如果我调试代码并在 RuntimeTypeAdapterFactory 读写方法中设置断点,它将命中read()(然后到达上面的错误),但它从未命中写方法。只是完全跳过了。

这是怎么回事?我正在使用的代码是最新的,并且直接来自上面的链接(截至今天)。

2 个答案:

答案 0 :(得分:2)

感谢贡献者对公共存储库的帮助,问题是需要包含基本类型的序列化步骤。因此,除了简单地:

g.toJson(d);

它必须是:

g.toJson(d, Shape.class);

我尝试过g.toJson(d, Diamond.class),但这对输出没有影响。希望这可以帮助其他人!

答案 1 :(得分:0)

rjcarr(在对toJson的调用中包含类对象)的解决方案不切实际,因为通常将多态对象作为其他对象的成员或作为列表中的元素。

实际上RuntimeTypeAdapterFactory中有一个错误。在this github post中,user ultraon提出了一个对我有用的解决方案:

替换

if (type.getRawType() != baseType)

使用

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

第185行中的类create的方法RuntimeTypeAdapterFactory

现在type属性包含在JSON中。