Ensured that custom deserializer is invoked with actual type returned for field values.
Fixed a bug where a top-level object was constructed with default values even when the custom deserializer tried to set it to null.
This commit is contained in:
parent
338758a0d3
commit
bc1e5c5c99
@ -35,6 +35,7 @@ abstract class JsonDeserializationVisitor<T> implements ObjectNavigator.Visitor
|
||||
protected final JsonElement json;
|
||||
protected final Type targetType;
|
||||
protected final JsonDeserializationContext context;
|
||||
protected boolean constructed;
|
||||
|
||||
public JsonDeserializationVisitor(JsonElement json, Type targetType,
|
||||
ObjectNavigatorFactory factory, ObjectConstructor objectConstructor,
|
||||
@ -47,11 +48,13 @@ abstract class JsonDeserializationVisitor<T> implements ObjectNavigator.Visitor
|
||||
this.deserializers = deserializers;
|
||||
this.json = json;
|
||||
this.context = context;
|
||||
this.constructed = false;
|
||||
}
|
||||
|
||||
public T getTarget() {
|
||||
if (target == null) {
|
||||
if (!constructed) {
|
||||
target = constructTarget();
|
||||
constructed = true;
|
||||
}
|
||||
return target;
|
||||
}
|
||||
@ -70,14 +73,21 @@ abstract class JsonDeserializationVisitor<T> implements ObjectNavigator.Visitor
|
||||
if (pair == null) {
|
||||
return false;
|
||||
}
|
||||
if (!json.isJsonNull()) {
|
||||
JsonDeserializer deserializer = pair.getFirst();
|
||||
Type objType = pair.getSecond().getType();
|
||||
target = (T) deserializer.deserialize(json, objType, context);
|
||||
}
|
||||
Object value = invokeCustomDeserializer(json, pair);
|
||||
target = (T) value;
|
||||
constructed = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
protected Object invokeCustomDeserializer(JsonElement element,
|
||||
Pair<JsonDeserializer<?>, ObjectTypePair> pair) {
|
||||
if (element == null || element.isJsonNull()) {
|
||||
return null;
|
||||
}
|
||||
Type objType = pair.getSecond().getType();
|
||||
return (pair.getFirst()).deserialize(element, objType, context);
|
||||
}
|
||||
|
||||
final Object visitChildAsObject(Type childType, JsonElement jsonChild) {
|
||||
JsonDeserializationVisitor<?> childVisitor =
|
||||
new JsonObjectDeserializationVisitor<Object>(jsonChild, childType,
|
||||
|
@ -93,32 +93,32 @@ final class JsonObjectDeserializationVisitor<T> extends JsonDeserializationVisit
|
||||
return namingPolicy.translateName(f);
|
||||
}
|
||||
|
||||
public boolean visitFieldUsingCustomHandler(Field f, Type actualTypeOfField, Object parent) {
|
||||
public boolean visitFieldUsingCustomHandler(Field f, Type declaredTypeOfField, Object parent) {
|
||||
try {
|
||||
String fName = getFieldName(f);
|
||||
if (!json.isJsonObject()) {
|
||||
throw new JsonParseException("Expecting object found: " + json);
|
||||
}
|
||||
JsonElement child = json.getAsJsonObject().get(fName);
|
||||
if (child == null) {
|
||||
TypeInfo typeInfo = new TypeInfo(declaredTypeOfField);
|
||||
if (child == null) { // Child will be null if the field wasn't present in Json
|
||||
return true;
|
||||
} else if (child.isJsonNull()) {
|
||||
TypeInfo typeInfo = new TypeInfo(actualTypeOfField);
|
||||
if (!typeInfo.isPrimitive()) {
|
||||
f.set(parent, null);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@SuppressWarnings("unchecked")
|
||||
JsonDeserializer deserializer = deserializers.getHandlerFor(actualTypeOfField);
|
||||
if (deserializer != null) {
|
||||
if (!child.isJsonNull()) {
|
||||
Object value = deserializer.deserialize(child, actualTypeOfField, context);
|
||||
f.set(parent, value);
|
||||
}
|
||||
return true;
|
||||
ObjectTypePair objTypePair = new ObjectTypePair(null, declaredTypeOfField, false);
|
||||
Pair<JsonDeserializer<?>, ObjectTypePair> pair = objTypePair.getMatchingHandler(deserializers);
|
||||
if (pair == null) {
|
||||
return false;
|
||||
}
|
||||
Object value = invokeCustomDeserializer(child, pair);
|
||||
if (value != null || !typeInfo.isPrimitive()) {
|
||||
f.set(parent, value);
|
||||
}
|
||||
return false;
|
||||
return true;
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new RuntimeException();
|
||||
}
|
||||
|
@ -23,6 +23,8 @@ import com.google.gson.JsonDeserializer;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParseException;
|
||||
import com.google.gson.common.TestTypes.Base;
|
||||
import com.google.gson.common.TestTypes.ClassWithBaseField;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
@ -144,4 +146,90 @@ public class CustomDeserializerTest extends TestCase {
|
||||
@SuppressWarnings("unused")
|
||||
String field2;
|
||||
}
|
||||
|
||||
public void testCustomDeserializerReturnsNullForTopLevelObject() {
|
||||
Gson gson = new GsonBuilder()
|
||||
.registerTypeAdapter(Base.class, new JsonDeserializer<Base>() {
|
||||
public Base deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
|
||||
throws JsonParseException {
|
||||
return null;
|
||||
}
|
||||
}).create();
|
||||
String json = "{baseName:'Base',subName:'SubRevised'}";
|
||||
Base target = gson.fromJson(json, Base.class);
|
||||
assertNull(target);
|
||||
}
|
||||
|
||||
public void testCustomDeserializerReturnsNull() {
|
||||
Gson gson = new GsonBuilder()
|
||||
.registerTypeAdapter(Base.class, new JsonDeserializer<Base>() {
|
||||
public Base deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
|
||||
throws JsonParseException {
|
||||
return null;
|
||||
}
|
||||
}).create();
|
||||
String json = "{base:{baseName:'Base',subName:'SubRevised'}}";
|
||||
ClassWithBaseField target = gson.fromJson(json, ClassWithBaseField.class);
|
||||
assertNull(target.base);
|
||||
}
|
||||
|
||||
public void testCustomDeserializerReturnsNullForTopLevelPrimitives() {
|
||||
Gson gson = new GsonBuilder()
|
||||
.registerTypeAdapter(long.class, new JsonDeserializer<Long>() {
|
||||
public Long deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
|
||||
throws JsonParseException {
|
||||
return null;
|
||||
}
|
||||
}).create();
|
||||
String json = "10";
|
||||
assertNull(gson.fromJson(json, long.class));
|
||||
}
|
||||
|
||||
public void testCustomDeserializerReturnsNullForPrimitiveFields() {
|
||||
Gson gson = new GsonBuilder()
|
||||
.registerTypeAdapter(long.class, new JsonDeserializer<Long>() {
|
||||
public Long deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
|
||||
throws JsonParseException {
|
||||
return null;
|
||||
}
|
||||
}).create();
|
||||
String json = "{field:10}";
|
||||
ClassWithLong target = gson.fromJson(json, ClassWithLong.class);
|
||||
assertEquals(0, target.field);
|
||||
}
|
||||
private static class ClassWithLong {
|
||||
long field;
|
||||
}
|
||||
|
||||
public void testCustomDeserializerReturnsNullForArrayElements() {
|
||||
Gson gson = new GsonBuilder()
|
||||
.registerTypeAdapter(Base.class, new JsonDeserializer<Base>() {
|
||||
public Base deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
|
||||
throws JsonParseException {
|
||||
return null;
|
||||
}
|
||||
}).create();
|
||||
String json = "[{baseName:'Base'},{baseName:'Base'}]";
|
||||
Base[] target = gson.fromJson(json, Base[].class);
|
||||
assertNull(target[0]);
|
||||
assertNull(target[1]);
|
||||
}
|
||||
|
||||
public void testCustomDeserializerReturnsNullForArrayElementsForArrayField() {
|
||||
Gson gson = new GsonBuilder()
|
||||
.registerTypeAdapter(Base.class, new JsonDeserializer<Base>() {
|
||||
public Base deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
|
||||
throws JsonParseException {
|
||||
return null;
|
||||
}
|
||||
}).create();
|
||||
String json = "{bases:[{baseName:'Base'},{baseName:'Base'}]}";
|
||||
ClassWithBaseArray target = gson.fromJson(json, ClassWithBaseArray.class);
|
||||
assertNull(target.bases[0]);
|
||||
assertNull(target.bases[1]);
|
||||
}
|
||||
|
||||
private static class ClassWithBaseArray {
|
||||
Base[] bases;
|
||||
}
|
||||
}
|
||||
|
@ -200,7 +200,7 @@ public class NullObjectAndFieldTest extends TestCase {
|
||||
}).create();
|
||||
String json = "{value:'value1'}";
|
||||
ObjectWithField target = gson.fromJson(json, ObjectWithField.class);
|
||||
assertFalse("value1".equals(target.value));
|
||||
assertNull(target);
|
||||
}
|
||||
|
||||
private static class ObjectWithField {
|
||||
|
Loading…
Reference in New Issue
Block a user