How to serialize Optional classes with Gson?

后端 未结 5 2181
囚心锁ツ
囚心锁ツ 2020-12-15 05:47

I have an object with the following attributes.

private final String messageBundle;
private final List messageParams;
private final String acti         


        
相关标签:
5条回答
  • 2020-12-15 06:15

    After several hours of gooling and coding - there is my version:

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

    You can simple registered it with GsonBuilder like this:

    instance.registerTypeAdapterFactory(OptionalTypeAdapter.FACTORY)
    

    Please keep attention that Gson does not set values to your class field if field does not present in json. So you need to set default value Optional.empty() in your entity.

    0 讨论(0)
  • 2020-12-15 06:16

    I'll add to Anton Onikiychuk's answer

    @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));
    }
    
    0 讨论(0)
  • 2020-12-15 06:17

    Just as an addition to maaartinus solution, the version without the encapsulating list, where Optional.absent is simply serialized as 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());
        }
    }
    
    0 讨论(0)
  • 2020-12-15 06:22

    The solution by Ilya ignores type parameters, so it can't really work in the general case. My solution is rather complicated, because of the need to distinguish between null and Optional.absent() -- otherwise you could strip away the encapsulation as a list.

    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;
        }
    }
    
    0 讨论(0)
  • 2020-12-15 06:22

    you may want to try this gson module, which can deal with java8 optional types serialization/deserialization(and als java8 new date type).

    0 讨论(0)
提交回复
热议问题