Java 如果不能更改类声明,则在序列化时(或多或少是全局性的)如何更改生成的Json?

Java 如果不能更改类声明,则在序列化时(或多或少是全局性的)如何更改生成的Json?,java,json,gson,Java,Json,Gson,假设: 有一堆Java对象需要传递给(例如)一些API 您不愿意或不能更改这些对象的声明 不幸的是,API需要在这些对象中未声明的内容 例如(受问题启发),有一个简单的类: @Getter @RequiredArgsConstructor public class Login { private final String username, password; } 然而,API期望类似JSON的: { "username": "uname", "password": "p

假设:

  • 有一堆Java对象需要传递给(例如)一些API
  • 您不愿意或不能更改这些对象的声明
  • 不幸的是,API需要在这些对象中未声明的内容
例如(受问题启发),有一个简单的类:

@Getter
@RequiredArgsConstructor
public class Login {
    private final String username, password; 
}
然而,API期望类似JSON的:

{
  "username": "uname",
  "password": "pword",
  "version": 1
}
同样的问题也适用于所有其他99个类:这些类还需要在序列化JSON中输入值为1的字段
version


有些解决方案需要低级字符串操作或添加大量样板代码,但GSON处理此问题的通用方法是什么?

首先,让GSON序列化(或反序列化)一堆不同类型的对象具有相同类型的自适应避免注册大量适配器或更改类声明的最佳方法是利用
TypeAdapterFactory

它本身并不绑定到任何
类型
,而是决定当Gson碰到某个要序列化(或反序列化)的对象时,每个类型返回哪个
类型适配器
。使用
typeadapterfactory
将代码从注册大量
TypeAdapter
s中解放出来

其次当然,为了避免创建许多
TypeAdapter
s,解决方案是尽可能创建一个通用类型的
TypeAdapter

从泛型
TypeAdapter
开始,在疑问句中可能是这样的:

@RequiredArgsConstructor
private class GenericTypeAdapter<T> extends TypeAdapter<T> {

    // typeToken is needed when deserializing
    private final TypeToken<T> typeToken;
    private final Gson gson = new GsonBuilder().setPrettyPrinting().create();

    @Override
    public void write(JsonWriter out, T value) throws IOException {
        // Altering could be done with some low level string manipulation
        // but JsonObject makes altering object more safe.
        // Feel free to comment for better way to instantiate it,
        // this is just for an example.
        JsonObject jsonObject = gson.fromJson(gson.toJson(value)
                            ,JsonElement.class).getAsJsonObject();
        // alter jsonObject in any way needed,
        // here is only added version information
        jsonObject.addProperty("version", 1);
        out.jsonValue(gson.toJson(jsonObject));
    }

    @Override
    public T read(JsonReader in) throws IOException {
        // maybe needless to mention but mention still:
        // here it is possible to init object in a way 
        // that provided JSON solely does not make possible
        return gson.fromJson(in, typeToken.getType());
    }
}
使用方法将简单地是:

Gson gson = new GsonBuilder()
    .registerTypeAdapterFactory(new GenericTypeAdapterFactory())
    .setPrettyPrinting()
    .create()
注意:我最初准备了这个答案,但后来似乎是基于Kotlin(?)的,所以我觉得最好创建一个更通用的Java问答

Gson gson = new GsonBuilder()
    .registerTypeAdapterFactory(new GenericTypeAdapterFactory())
    .setPrettyPrinting()
    .create()