反序列化Gson中的抽象类

use*_*480 40 java json abstract-class gson

我有一个JSON格式的树对象我试图用Gson反序列化.每个节点包含其子节点作为对象类型Node的字段.Node是一个接口,它有几个具体的类实现.在反序列化过程中,如果我不知道该节点属于哪种类型的先验,我如何与Gson通信哪个具体类在反序列化节点时要实现?每个节点都有一个指定类型的成员字段.当对象是序列化形式时,有没有办法访问该字段,并以某种方式将类型传递给Gson?

谢谢!

Col*_*inD 47

我建议为s 添加一个自定义的JsonDeserializerNode:

Gson gson = new GsonBuilder()
    .registerTypeAdapter(Node.class, new NodeDeserializer())
    .create();
Run Code Online (Sandbox Code Playgroud)

您将能够访问JsonElement在反序列化器方法中表示节点,将其转换为a JsonObject,并检索指定类型的字段.然后,您可以基于此创建正确类型的实例Node.


Gur*_* GV 30

您需要注册JSONSerializer和JSONDeserializer.您还可以通过以下方式为所有接口实现通用适配器:

  • 在序列化期间:添加实际impl类类型的META-info.
  • 在DeSerialization期间:检索该元信息并调用该类的JSONDeserailize

这是我自己使用的实现,并且工作正常.

public class PropertyBasedInterfaceMarshal implements
        JsonSerializer<Object>, JsonDeserializer<Object> {

    private static final String CLASS_META_KEY = "CLASS_META_KEY";

    @Override
    public Object deserialize(JsonElement jsonElement, Type type,
            JsonDeserializationContext jsonDeserializationContext)
            throws JsonParseException {
        JsonObject jsonObj = jsonElement.getAsJsonObject();
        String className = jsonObj.get(CLASS_META_KEY).getAsString();
        try {
            Class<?> clz = Class.forName(className);
            return jsonDeserializationContext.deserialize(jsonElement, clz);
        } catch (ClassNotFoundException e) {
            throw new JsonParseException(e);
        }
    }

    @Override
    public JsonElement serialize(Object object, Type type,
            JsonSerializationContext jsonSerializationContext) {
        JsonElement jsonEle = jsonSerializationContext.serialize(object, object.getClass());
        jsonEle.getAsJsonObject().addProperty(CLASS_META_KEY,
                object.getClass().getCanonicalName());
        return jsonEle;
    }

}
Run Code Online (Sandbox Code Playgroud)

然后,您可以为所有接口注册此适配器,如下所示

Gson gson = new GsonBuilder()
        .registerTypeAdapter(IInterfaceOne.class,
                new PropertyBasedInterfaceMarshal())
        .registerTypeAdapter(IInterfaceTwo.class,
                new PropertyBasedInterfaceMarshal()).create();
Run Code Online (Sandbox Code Playgroud)