Gson doesnt have direct support for serializing @AutoValue classes or for Optional<> fields, but com.ryanharter.auto.value adds @AutoValue and net.dongliu:gson-java8-datatype adds Optional<> and other java8 types.
However, they dont work together AFAICT.
Test code:
public class TestOptionalWithAutoValue {
private static final Gson gson = new GsonBuilder().serializeNulls()
// doesnt matter which order these are registered in
.registerTypeAdapterFactory(new GsonJava8TypeAdapterFactory())
.registerTypeAdapterFactory(AutoValueGsonTypeAdapterFactory.create())
.create();
@Test
public void testAutoValueOptionalEmpty() {
AvoTestClass subject = AvoTestClass.create(Optional.empty());
String json = gson.toJson(subject, AvoTestClass.class);
System.out.printf("Json produced = %s%n", json);
AvoTestClass back = gson.fromJson(json, new TypeToken<AvoTestClass>() {}.getType());
assertThat(back).isEqualTo(subject);
}
@Test
public void testAutoValueOptionalFull() {
AvoTestClass subject = AvoTestClass.create(Optional.of("ok"));
String json = gson.toJson(subject, AvoTestClass.class);
System.out.printf("Json produced = '%s'%n", json);
AvoTestClass back = gson.fromJson(json, new TypeToken<AvoTestClass>() {}.getType());
assertThat(back).isEqualTo(subject);
}
}
@AutoValue
public abstract class AvoTestClass {
abstract Optional<String> sval();
public static AvoTestClass create(Optional<String> sval) {
return new AutoValue_AvoTestClass(sval);
}
public static TypeAdapter<AvoTestClass> typeAdapter(Gson gson) {
return new AutoValue_AvoTestClass.GsonTypeAdapter(gson);
}
}
@GsonTypeAdapterFactory
public abstract class AutoValueGsonTypeAdapterFactory implements TypeAdapterFactory {
public static TypeAdapterFactory create() {
return new AutoValueGson_AutoValueGsonTypeAdapterFactory();
}
}
gradle dependencies:
annotationProcessor "com.google.auto.value:auto-value:1.7.4"
annotationProcessor("com.ryanharter.auto.value:auto-value-gson-extension:1.3.1")
implementation("com.ryanharter.auto.value:auto-value-gson-runtime:1.3.1")
annotationProcessor("com.ryanharter.auto.value:auto-value-gson-factory:1.3.1")
implementation 'net.dongliu:gson-java8-datatype:1.1.0'
Fails with:
Json produced = {"sval":null}
...
java.lang.NullPointerException: Null sval
...
net.dongliu.gson.OptionalAdapter is called on serialization, but not deserialization.
Im wondering if theres a workaround, or if the answer is that Gson needs to have direct support for Optional<> ?
Glad to see you've updated your question by adding much more information and even by adding a test! :) That really makes it clear!
I'm not sure, but the generated type adapter has no mention for the default value for
sval:I have no idea if there is a way to configure the default values in AutoValue or other generators you mentioned, but it looks like a bug.
If there is no any way to work around it (say, library development abandoned; it takes too much time to wait for a fix; whatever), you can always implement it yourself, however with some runtime cost (basically this how Gson works under the hood for data bag objects). The idea is delegating the job to the built-in
RuntimeTypeAdapterFactoryso that it could deal with a concrete class, not an abstract one, and set all fields according to the registered type adapters (so that the Java 8 types are supported as well). The cost here is reflection, thus that adapter may work slower than generated type adapters. Another thing is that if a JSON property does not even encounter in the JSON object, the corresponding field will remainnull. This requires another post-deserialization type adapter.This solution is reflection-based heavily, but it's just a work-around if the generators cannot do the job (again, not sure if they can be configured so that there are no such issues).