在GSON中反序列化递归多态类
class Complex implements Recursive { Map map; ... } class Simple implements Recursive { ... }
如何反序列化这个json:
{ "type" : "complex", "map" : { "a" : { "type" : "simple" }, "b" : { "type" : "complex", "map" : { "ba" : { "type" : "simple" } } } }
使用谷歌GSON?
要反序列化您的JSON,您需要为Recursive接口提供自定义反序列化器。 在这种类中,您需要检查您的JSON并确定要实例化为JSON本身中的类型字段的类。 在这里,您有一个我为您编写的基本反序列化示例。
当然,可以改进管理边界情况(例如,如果你没有类型字段会发生什么?)。
package stackoverflow.questions; import java.lang.reflect.Type; import java.util.*; import stackoverflow.questions.Q20254329.*; import com.google.gson.*; import com.google.gson.reflect.TypeToken; public class Q20327670 { static class Complex implements Recursive { Map map; @Override public String toString() { return "Complex [map=" + map + "]"; } } static class Simple implements Recursive { @Override public String toString() { return "Simple []"; } } public static class RecursiveDeserializer implements JsonDeserializer { public Recursive deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { Recursive r = null; if (json == null) r = null; else { JsonElement t = json.getAsJsonObject().get("type"); String type = null; if (t != null) { type = t.getAsString(); switch (type) { case "complex": { Complex c = new Complex(); JsonElement e = json.getAsJsonObject().get("map"); if (e != null) { Type mapType = new TypeToken
这是我的代码的结果:
Complex [map={a=Simple [], b=Complex [map={ba=Simple []}]}]
很抱歉回复得太晚了(因为这个问题已经回答了)。 但我想我可以给这个问题2美分。
正如@Parobay之前所说,你可以添加一个特殊的{"type": "complex"}
参数,以便知道你要反序列化哪个类。 但如前所述,您必须将所有数据移动到{"instance": {}}
子对象,因为您必须手动控制在大型switch
创建的实例,因此感觉很麻烦。
您可以使用TypeFactory
类来更好地处理这种情况。 更准确地说,有一个名为RuntimeTypeAdapterFactory
特殊工厂(目前没有与Gson捆绑在一起)。 复制有关此课程的文档说明:
调整运行时类型可能与其声明类型不同的值。 当字段的类型与GSON在反序列化该字段时应创建的类型不同时,这是必需的。 例如,请考虑以下类型:
{ 抽象类Shape { int x; int y; } class Circle扩展Shape { int radius; } class Rectangle extends Shape { int宽度; int height; } class Diamond扩展Shape { int宽度; int height; } class Drawing { 形状底部形状; 形状topShape; }}没有其他类型信息,序列化的JSON是不明确的。 此图纸中的底部形状是矩形还是菱形?
{ { “bottomShape”:{ “宽度”:10, “身高”:5, “x”:0, “y”:0 }, “topShape”:{ “半径”:2, “x”:4, “y”:1 } }}此类通过向序列化JSON添加类型信息并在反序列化JSON时表彰该类型信息来解决此问题:
{ { “bottomShape”:{ “类型”:“钻石”, “宽度”:10, “身高”:5, “x”:0, “y”:0 }, “topShape”:{ “type”:“Circle”, “半径”:2, “x”:4, “y”:1 } }}类型字段名称({@code“type”})和类型标签({@code“Rectangle”})都是可配置的。
所以你只需要创建你的Gson对象:
RuntimeTypeAdapter shapeAdapter = RuntimeTypeAdapter.of(Shape.class, "type") .registerSubtype(Rectangle.class, "Rectangle"); Gson gson = new GsonBuilder() .registerTypeAdapter(Shape.class, shapeAdapter) .create();
瞧,你有对象的自动(反)序列化。 我创建了这个Factory的变体,而不是期望一个type
参数,尝试通过运行自定义正则表达式来发现什么类型的对象(这样你可以避免创建额外的参数,或者当你没有完全控制时的API)。
在这里,我给你两个来源链接:
- 原始RuntimeTypeAdapterFactory源 。
- 我修改了RuntimeRegexTypeAdapterFactory源码 。