gpt4 book ai didi

java - Gson:如何更改序列化中的特定字段键

转载 作者:行者123 更新时间:2023-12-01 08:52:14 27 4
gpt4 key购买 nike

我正在使用 Gson 进行序列化,并且我正在努力动态更改字段名称。这是我的类(class):

public class Response<T> 
{

private String status;
private String message;
private T data;

public Response(T data)
{
this.setData(data);
}

public String getStatus() {
return status;
}

public void setStatus(String status) {
this.status = status;
}

public String getMessage() {
return message;
}

public void setMessage(String message) {
this.message = message;
}

public T getData() {
return data;
}

public void setData(T data) {
this.data = data;
}

}

我必须根据资源动态更改字段名称。有什么办法可以改变这个吗?

最佳答案

使用 map 可能不是最佳选择,因为您的 Response 类可能具有特殊的 Gson 注释,一旦您的响应对象转换为 map ,这些注释将被忽略。

假设有以下简单的响应类:

final class Response<T> {

@Expose(serialize = true)
final String status = "STATUS";

@Expose(serialize = true)
final String message = "MESSAGE";

@Expose(serialize = true)
final T data;

@Expose(serialize = false, deserialize = false)
final String whatever = "WHATEVER";

Response(final T data) {
this.data = data;
}

}

为了简单起见,此响应没有使用其他 Gson 注释。特别使用动态字段重命名:

final Gson gson = new GsonBuilder()
.excludeFieldsWithoutExposeAnnotation()
// ... any Gson configuration here ...
.create();
final Response<List<String>> response = new Response<>(ImmutableList.of("foo", "bar"));
final JsonElement jsonTree = gson.toJsonTree(response, stringListResponseTypeToken.getType());
final JsonObject responseJson = jsonTree.getAsJsonObject();
final JsonElement dataPropertyJson = responseJson.get("data");
responseJson.remove("data");
responseJson.add(response.getClass().getSimpleName(), dataPropertyJson);
gson.toJson(responseJson, System.out);

请注意,这里的主要技巧是创建中间 JSON 树并替换动态属性名称。不幸的是,这个解决方案需要一个中间 JSON 树。另一个更“Gson-ish”的解决方案是创建一个特殊的类型适配器,以免每次需要时都重新映射响应对象。

final Gson gson = new GsonBuilder()
.excludeFieldsWithoutExposeAnnotation()
// ... any Gson configuration here ...
.registerTypeAdapterFactory(getDynamicPropertyResponseTypeAdapterFactory())
.create();
final Response<List<String>> response = new Response<>(ImmutableList.of("foo", "bar"));
gson.toJson(response, stringListResponseTypeToken.getType(), System.out);

其中类型适配器工厂和类型适配器的实现如下:

final class DynamicPropertyResponseTypeAdapterFactory
implements TypeAdapterFactory {

private static final TypeAdapterFactory dynamicPropertyResponseTypeAdapterFactory = new DynamicPropertyResponseTypeAdapterFactory();

private DynamicPropertyResponseTypeAdapterFactory() {
}

static TypeAdapterFactory getDynamicPropertyResponseTypeAdapterFactory() {
return dynamicPropertyResponseTypeAdapterFactory;
}

@Override
public <T> TypeAdapter<T> create(final Gson gson, final TypeToken<T> typeToken) {
if ( Response.class.isAssignableFrom(typeToken.getRawType()) ) {
@SuppressWarnings("unchecked")
final TypeAdapter<Response<Object>> delegateTypeAdapter = (TypeAdapter<Response<Object>>) gson.getDelegateAdapter(this, typeToken);
@SuppressWarnings("unchecked")
final TypeAdapter<T> castTypeAdapter = (TypeAdapter<T>) getDynamicPropertyResponseJsonTypeAdapter(delegateTypeAdapter, gson);
return castTypeAdapter;
}
return null;
}

}

请注意,如果处理的类是 Response,此类型适配器工厂会选择下游类型适配器以避免无限递归,否则返回 null 以让 Gson 使用自己的适配器(反)序列化策略。

final class DynamicPropertyResponseJsonTypeAdapter<T>
extends TypeAdapter<Response<T>> {

private final TypeAdapter<Response<T>> delegateTypeAdapter;
private final Gson gson;

private DynamicPropertyResponseJsonTypeAdapter(final TypeAdapter<Response<T>> delegateTypeAdapter, final Gson gson) {
this.delegateTypeAdapter = delegateTypeAdapter;
this.gson = gson;
}

static <T> TypeAdapter<Response<T>> getDynamicPropertyResponseJsonTypeAdapter(final TypeAdapter<Response<T>> delegateTypeAdapter, final Gson gson) {
return new DynamicPropertyResponseJsonTypeAdapter<>(delegateTypeAdapter, gson);
}

@Override
@SuppressWarnings("resource")
public void write(final JsonWriter out, final Response<T> response)
throws IOException {
if ( response == null ) {
out.nullValue();
return;
}
final JsonElement jsonTree = delegateTypeAdapter.toJsonTree(response);
final JsonObject responseJson = jsonTree.getAsJsonObject();
final JsonElement dataPropertyJson = responseJson.get("data");
responseJson.remove("data");
responseJson.add(response.getClass().getSimpleName(), dataPropertyJson);
gson.toJson(responseJson, out);
}

@Override
public Response<T> read(final JsonReader in) {
throw new UnsupportedOperationException();
}

}

上面使用了同样的不太便宜的技巧,但现在它作为 Gson 实例的一部分工作。对于这两种情况,输出如下:

{"status":"STATUS","message":"MESSAGE","Response":["foo","bar"]}

您可能需要考虑的另一个选项是:

  • Response 类抽象化,并让子类通过 @SerializedName 定义自己的 data 字段名称(如果名称应该是这样的话)进行硬编码。
  • 创建您的实现 ReflectiveTypeAdapterFactory(请参阅 Gson 源代码)并使字段名称动态化,而无需创建中间 JSON 树。

关于java - Gson:如何更改序列化中的特定字段键,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42315035/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com