24

次の属性を持つオブジェクトがあります。

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 を使用できず、基になる Optional コンテンツにシリアル化を委任するだけの TypeAdapter を作成する方法がよくわかりません。

4

4 に答える 4

21

数時間のグーリングとコーディングの後、私のバージョンがあります:

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()したがって、エンティティにデフォルト値を設定する必要があります。

于 2014-08-01T10:40:19.197 に答える
9

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;
    }
}
于 2012-08-28T17:33:39.527 に答える