Gson 自定义序列化

Che*_*tah 5 java serialization json gson

我希望有一个自定义的 GSON 反序列化器,这样无论何时反序列化 JSON 对象(即大括号内的任何内容{ ... }),它都会查找一个$type节点并使用其内置的反序列化功能对该类型进行反序列化。如果没有$type找到对象,它只是做它通常做的事情。

例如,我希望它起作用:

{
    "$type": "my.package.CustomMessage"
    "payload" : {
        "$type": "my.package.PayloadMessage",
        "key": "value"
    }
}

public class CustomMessage {

    public Object payload;
}

public class PayloadMessage implements Payload {

    public String key;
}
Run Code Online (Sandbox Code Playgroud)

调用:Object customMessage = gson.fromJson(jsonString, Object.class)

所以目前如果我将payload类型更改为Payload接口:

public class CustomMessage {

    public Payload payload;
}
Run Code Online (Sandbox Code Playgroud)

然后以下TypeAdapaterFactory将做我想要的:

final TypeAdapter<T> delegate = gson.getDelegateAdapter(this, type);
final TypeAdapter<JsonElement> elementAdapter = gson.getAdapter(JsonElement.class);
final PojoTypeAdapter thisAdapter = this;

public T read(JsonReader reader) throws IOException {

    JsonElement jsonElement = (JsonElement)elementAdapter.read(reader);

    if (!jsonElement.isJsonObject()) {
        return delegate.fromJsonTree(jsonElement);
    }

    JsonObject jsonObject = jsonElement.getAsJsonObject();
    JsonElement typeElement = jsonObject.get("$type");

    if (typeElement == null) {
        return delegate.fromJsonTree(jsonElement);
    }

    try {
        return (T) gson.getDelegateAdapter(
                thisAdapter,
                TypeToken.get(Class.forName(typeElement.getAsString()))).fromJsonTree(jsonElement);
    } catch (ClassNotFoundException ex) {
        throw new IOException(ex.getMessage());
    }
}
Run Code Online (Sandbox Code Playgroud)

但是,我希望它在payload类型Object或任何类型时工作,如果它不能分配变量,则抛出某种类型匹配异常。

Che*_*tah 4

查看 Gson 的来源,我发现了我认为的问题所在:

// built-in type adapters that cannot be overridden
factories.add(TypeAdapters.JSON_ELEMENT_FACTORY);
factories.add(ObjectTypeAdapter.FACTORY);

// user's type adapters
factories.addAll(typeAdapterFactories);
Run Code Online (Sandbox Code Playgroud)

正如你所看到的,ObjectTypeAdapter意志优先于我的工厂。

据我所知,唯一的解决方案是使用反射ObjectTypeAdapter从列表中删除 或在它之前插入我的工厂。我已经这样做了并且有效。