我有一个具有以下属性的对象。
private final String messageBundle;
private final List<String> messageParams;
private final String actionBundle;
private final Map<String, String> data;
private final Optional<Pair<Integer,TimeUnit>> ttl;
private final Optional<Integer> badgeNumber;
private final Optional<String> collapseKey;
该对象位于库中,我宁愿不为了序列化目的而修改它,并且希望避免创建另一个 DTO 的成本。
如何序列化/反序列化可选属性? Optional 没有默认构造函数(apache commons Pair 也没有),但我无法使用 InstanceCreator,并且并不真正了解如何创建一个 TypeAdapter 来简单地将序列化委托给底层的Optional内容。
经过几个小时的搜索和编码 - 这是我的版本:
public class OptionalTypeAdapter<E> extends TypeAdapter<Optional<E>> {
public static final TypeAdapterFactory FACTORY = new TypeAdapterFactory() {
@Override
public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {
Class<T> rawType = (Class<T>) type.getRawType();
if (rawType != Optional.class) {
return null;
}
final ParameterizedType parameterizedType = (ParameterizedType) type.getType();
final Type actualType = parameterizedType.getActualTypeArguments()[0];
final TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(actualType));
return new OptionalTypeAdapter(adapter);
}
};
private final TypeAdapter<E> adapter;
public OptionalTypeAdapter(TypeAdapter<E> adapter) {
this.adapter = adapter;
}
@Override
public void write(JsonWriter out, Optional<E> value) throws IOException {
if(value.isPresent()){
adapter.write(out, value.get());
} else {
out.nullValue();
}
}
@Override
public Optional<E> read(JsonReader in) throws IOException {
final JsonToken peek = in.peek();
if(peek != JsonToken.NULL){
return Optional.ofNullable(adapter.read(in));
}
in.nextNull();
return Optional.empty();
}
}
您可以像这样简单地使用
GsonBuilder
注册它:
instance.registerTypeAdapterFactory(OptionalTypeAdapter.FACTORY)
请注意,如果 json 中不存在字段,Gson 不会为您的类字段设置值。所以你需要在你的实体中设置默认值
Optional.empty()
。
Ilya 的解决方案忽略了类型参数,因此它在一般情况下无法真正工作。我的解决方案相当复杂,因为需要区分
null
和 Optional.absent()
- 否则你可以将封装作为列表剥离。
public class GsonOptionalDeserializer<T>
implements JsonSerializer<Optional<T>>, JsonDeserializer<Optional<T>> {
@Override
public Optional<T> deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
throws JsonParseException {
final JsonArray asJsonArray = json.getAsJsonArray();
final JsonElement jsonElement = asJsonArray.get(0);
final T value = context.deserialize(jsonElement, ((ParameterizedType) typeOfT).getActualTypeArguments()[0]);
return Optional.fromNullable(value);
}
@Override
public JsonElement serialize(Optional<T> src, Type typeOfSrc, JsonSerializationContext context) {
final JsonElement element = context.serialize(src.orNull());
final JsonArray result = new JsonArray();
result.add(element);
return result;
}
}
作为maaartinus解决方案的补充,没有封装列表的版本,其中
Optional.absent
简单地序列化为null
:
public class GsonOptionalDeserializer<T> implements JsonSerializer<Optional<T>>, JsonDeserializer<Optional<T>> {
@Override
public Optional<T> deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
throws JsonParseException {
final T value = context.deserialize(json, ((ParameterizedType) typeOfT).getActualTypeArguments()[0]);
return Optional.fromNullable(value);
}
@Override
public JsonElement serialize(Optional<T> src, Type typeOfSrc, JsonSerializationContext context) {
return context.serialize(src.orNull());
}
}
我将添加到Anton Onikiychuk的答案
@Override
public Optional<E> read(JsonReader in) throws IOException {
JsonToken peek = in.peek();
if (peek == JsonToken.NULL) {
in.nextNull(); // consuming JSON null
return Optional.empty();
}
return Optional.ofNullable(adapter.read(in));
}
在尝试为 java.util.Optional 等可选类型创建自定义 Gson TypeAdapter 时,我遇到了类似的挑战。尽管进行了广泛的搜索并审查了现有的答案,但我找不到精确解决此问题的解决方案。
但是,经过彻底的实验,我成功创建了一个适合您的场景的自定义 TypeAdapter:
/**
* TypeAdapter to manage nullable fields with Optional approach
*/
public static class OptionalTypeAdapter<E> implements JsonSerializer<Optional<E>>, JsonDeserializer<Optional<E>> {
@Override
public JsonElement serialize(Optional<E> src, Type typeOfSrc, JsonSerializationContext context) {
if (src.isPresent()) {
return context.serialize(src.get());
} else {
return JsonNull.INSTANCE;
}
}
@Override
public Optional<E> deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
throws JsonParseException {
if (json.isJsonNull()) {
return Optional.empty();
} else {
E value = context.deserialize(json, ((ParameterizedType) typeOfT).getActualTypeArguments()[0]);
return Optional.ofNullable(value);
}
}
}
这个自定义的OptionalTypeAdapter应该允许Gson在序列化和反序列化中适当地处理可选类型。
现在可以通过以下代码实例化 Gson 对象来处理 JSON:
new GsonBuilder()
.registerTypeAdapter(Optional.class, new OptionalTypeAdapter<>())
.create();