Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ TypeAdapter<?> getTypeAdapter(ConstructorConstructor constructorConstructor, Gso
Object instance = constructorConstructor.get(TypeToken.get(annotation.value())).construct();

TypeAdapter<?> typeAdapter;
boolean nullSafe = annotation.nullSafe();
if (instance instanceof TypeAdapter) {
typeAdapter = (TypeAdapter<?>) instance;
} else if (instance instanceof TypeAdapterFactory) {
Expand All @@ -66,15 +67,16 @@ TypeAdapter<?> getTypeAdapter(ConstructorConstructor constructorConstructor, Gso
JsonDeserializer<?> deserializer = instance instanceof JsonDeserializer
? (JsonDeserializer) instance
: null;
typeAdapter = new TreeTypeAdapter(serializer, deserializer, gson, type, null);
typeAdapter = new TreeTypeAdapter(serializer, deserializer, gson, type, null, nullSafe);
nullSafe = false;
} else {
throw new IllegalArgumentException("Invalid attempt to bind an instance of "
+ instance.getClass().getName() + " as a @JsonAdapter for " + type.toString()
+ ". @JsonAdapter value must be a TypeAdapter, TypeAdapterFactory,"
+ " JsonSerializer or JsonDeserializer.");
}

if (typeAdapter != null && annotation.nullSafe()) {
if (typeAdapter != null && nullSafe) {
typeAdapter = typeAdapter.nullSafe();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,25 +45,32 @@ public final class TreeTypeAdapter<T> extends TypeAdapter<T> {
private final TypeToken<T> typeToken;
private final TypeAdapterFactory skipPast;
private final GsonContextImpl context = new GsonContextImpl();
private final boolean nullSafe;

/** The delegate is lazily created because it may not be needed, and creating it may fail. */
private TypeAdapter<T> delegate;

public TreeTypeAdapter(JsonSerializer<T> serializer, JsonDeserializer<T> deserializer,
Gson gson, TypeToken<T> typeToken, TypeAdapterFactory skipPast) {
Gson gson, TypeToken<T> typeToken, TypeAdapterFactory skipPast, boolean nullSafe) {
this.serializer = serializer;
this.deserializer = deserializer;
this.gson = gson;
this.typeToken = typeToken;
this.skipPast = skipPast;
this.nullSafe = nullSafe;
}

public TreeTypeAdapter(JsonSerializer<T> serializer, JsonDeserializer<T> deserializer,
Gson gson, TypeToken<T> typeToken, TypeAdapterFactory skipPast) {
this(serializer, deserializer, gson, typeToken, skipPast, true);
}

@Override public T read(JsonReader in) throws IOException {
if (deserializer == null) {
return delegate().read(in);
}
JsonElement value = Streams.parse(in);
if (value.isJsonNull()) {
if (nullSafe && value.isJsonNull()) {
return null;
}
return deserializer.deserialize(value, typeToken.getType(), context);
Expand All @@ -74,7 +81,7 @@ public TreeTypeAdapter(JsonSerializer<T> serializer, JsonDeserializer<T> deseria
delegate().write(out, value);
return;
}
if (value == null) {
if (nullSafe && value == null) {
out.nullValue();
return;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -161,4 +161,22 @@ private static final class BaseIntegerAdapter implements JsonSerializer<Base<Int
return new JsonPrimitive("BaseIntegerAdapter");
}
}

public void testJsonAdapterNullSafe() {
Gson gson = new Gson();
String json = gson.toJson(new Computer3(null, null));
assertEquals("{\"user1\":\"UserSerializerDeserializer\"}", json);
Computer3 computer3 = gson.fromJson("{\"user1\":null, \"user2\":null}", Computer3.class);
assertEquals("UserSerializerDeserializer", computer3.user1.name);
assertNull(computer3.user2);
}

private static final class Computer3 {
@JsonAdapter(value = UserSerializerDeserializer.class, nullSafe = false) final User user1;
@JsonAdapter(value = UserSerializerDeserializer.class) final User user2;
Computer3(User user1, User user2) {
this.user1 = user1;
this.user2 = user2;
}
}
}