Java 如何序列化可选<;T>;和Gson一起上课?

Java 如何序列化可选<;T>;和Gson一起上课?,java,json,serialization,gson,Java,Json,Serialization,Gson,我有一个具有以下属性的对象 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

我有一个具有以下属性的对象

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;
私有最终字符串messageBundle;
私有最终列表消息参数;
私有最终字符串actionBundle;
私人最终地图数据;
私人最终可选ttl;
私人最终可选证件号码;
私人最终可选collapseKey;
该对象位于库中,我不希望仅为了序列化目的而修改它,而是希望避免创建另一个DTO的成本


如何序列化/取消序列化可选属性?Optional没有默认构造函数(也没有apache commons对),但我不能使用InstanceCreator,也不知道如何创建一个TypeAdapter,将序列化简单地委托给底层可选内容。

Ilya的解决方案忽略了类型参数,因此在一般情况下它无法真正工作。我的解决方案相当复杂,因为需要区分
null
Optional.缺席()

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;
    }
}
公共类GsonOptionalDeserializer
实现JsonSerializer、JsonDeserializer{
@凌驾
公共可选反序列化(JsonElement json,类型typeOfT,JsonDeserializationContext)
抛出JsonParseException{
final JsonArray asJsonArray=json.getAsJsonArray();
final JsonElement JsonElement=asJsonArray.get(0);
最后一个T值=context.deserialize(jsonElement,((ParameteredType)typeOfT).getActualTypeArguments()[0]);
返回可选的.fromNullable(值);
}
@凌驾
公共JsonElement序列化(可选src、类型typeOfSrc、JsonSerializationContext){
最后一个JsonElement元素=context.serialize(src.orNull());
最终JsonArray结果=新JsonArray();
结果:添加(元素);
返回结果;
}
}

经过几个小时的谷歌搜索和编码,我的版本如下:

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();
    }

}

请注意,如果json中没有字段,Gson不会为类字段设置值。因此,您需要在实体中设置默认值
Optional.empty()

您可能需要尝试,它可以处理java8可选类型序列化/反序列化(以及als java8新日期类型)。

就像maaartinus解决方案的一个补充,没有封装列表的版本,其中,
可选。缺席
被简单地序列化为
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());
    }
}
公共类GsonOptionalDeserializer实现JsonSerializer、JsonDeserializer{
@凌驾
公共可选反序列化(JsonElement json,类型typeOfT,JsonDeserializationContext)
抛出JsonParseException{
final T value=context.deserialize(json,((ParameterizedType)typeOfT).getActualTypeArguments()[0]);
返回可选的.fromNullable(值);
}
@凌驾
公共JsonElement序列化(可选src、类型typeOfSrc、JsonSerializationContext){
返回context.serialize(src.orNull());
}
}
我将补充您的答案

@覆盖
公共可选读取(JsonReader in)引发IOException{
JsonToken peek=in.peek();
if(peek==JsonToken.NULL){
in.nextNull();//使用JSON null
返回可选的.empty();
}
返回可选的.ofNullable(adapter.read(in));
}

您是否需要为要序列化的每种类型的
可选
注册一个新的
GsonOptionalDeserializer
实例?@scompt.com不,就像这样。啊,我明白了。我最终实现了
TypeAdapterFactory
并做了一些类似于Javadocs中的的的事情。看起来在反序列化过程中,这仍然不能区分
可选。缺席()
null
,因为它在所有情况下都返回一个非null的
可选值
。@JackEdmonds确实是,它不能,因为它需要对
可选值进行不同的表示。缺席()
null
。您可以通过使用单个元素数组来解决它(因为
Optional
是一个最多一个元素的集合),但是oth,
Optional
只不过是分解的
@Nullable
,使用
@Nullable Optional
是完全错误的。Optional不应该用于属性或参数,只是返回类型。这比答案要好。JsonArray不是必需的。注意,这个答案是关于番石榴的。对于Java8选项,使用
Optional.ofNullable(value)
src.orElse(null)
read(…)
不使用
null
。它应该调用
skipValue()
nextNull()
@Marcono1234我解决了这个问题,并为列表提供了TypeAdapter,下面是我的完整代码:这是一个很好且重要的观点!不过,最好是将其添加为评论或建议作为编辑。我现在提出了一个解决这个问题的方法。
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());
    }
}
@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));
}