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.