![](/img/trans.png)
[英]Gson: How to exclude specific fields from Serialization without annotations
[英]Gson: How to change specific fields key from serialization
我正在使用Gson进行序列化,并且正在努力地动态更改字段名称。 这是我的课:
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;
}
}
我必须根据资源动态更改字段名称。 有什么办法可以改变吗?
使用地图可能不是最佳选择,因为您的Response
类可能具有特殊的Gson批注,一旦您的响应对象转换为地图,这些批注将被忽略。
假设以下简单响应类:
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式”的解决方案是创建一种特殊类型的适配器,以免在需要时不重新映射响应对象。
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树。 如果您需要更改字段名称,则意味着您不需要类型安全,因此可以执行以下操作:
Map<String, Object> response = new LinkedHashMap<>();
response.put("message", message);
response.put("status", status);
response.put(dynamicFieldName, dynamicFieldValue);
String json = gson.toJson(response);
您仍然可以在此低级代码之上包装一个便捷库,以解决常见的用例。
在这种情况下为什么不使用HashMap?
private HashMap<String, String> data;
public HashMap<String, String> getData() {
return this.data;
}
public void setDataValue(String key, String value) {
data.put(key, value);
}
请注意,数据字段也可以是<String, Object>
或<Long, Object>
的HashMap,以保存子对象,从而接受所有Gson支持的结构。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.