diff --git a/gson/src/main/java/com/google/gson/JsonDeserializationVisitor.java b/gson/src/main/java/com/google/gson/JsonDeserializationVisitor.java index 23583c39..d977bd3a 100644 --- a/gson/src/main/java/com/google/gson/JsonDeserializationVisitor.java +++ b/gson/src/main/java/com/google/gson/JsonDeserializationVisitor.java @@ -69,7 +69,9 @@ abstract class JsonDeserializationVisitor implements ObjectNavigator.Visitor Type objType = objTypePair.getType(); JsonDeserializer deserializer = deserializers.getHandlerFor(objType); if (deserializer != null) { - target = (T) deserializer.deserialize(json, objType, context); + if (json != null && !json.isJsonNull()) { + target = (T) deserializer.deserialize(json, objType, context); + } return true; } return false; diff --git a/gson/src/main/java/com/google/gson/JsonObjectDeserializationVisitor.java b/gson/src/main/java/com/google/gson/JsonObjectDeserializationVisitor.java index 1df9da1b..9bfc65d8 100644 --- a/gson/src/main/java/com/google/gson/JsonObjectDeserializationVisitor.java +++ b/gson/src/main/java/com/google/gson/JsonObjectDeserializationVisitor.java @@ -112,8 +112,10 @@ final class JsonObjectDeserializationVisitor extends JsonDeserializationVisit @SuppressWarnings("unchecked") JsonDeserializer deserializer = deserializers.getHandlerFor(actualTypeOfField); if (deserializer != null) { - Object value = deserializer.deserialize(child, actualTypeOfField, context); - f.set(parent, value); + if (child != null && !child.isJsonNull()) { + Object value = deserializer.deserialize(child, actualTypeOfField, context); + f.set(parent, value); + } return true; } return false; diff --git a/gson/src/main/java/com/google/gson/JsonTreeNavigator.java b/gson/src/main/java/com/google/gson/JsonTreeNavigator.java index 992de504..7d6ad8d1 100644 --- a/gson/src/main/java/com/google/gson/JsonTreeNavigator.java +++ b/gson/src/main/java/com/google/gson/JsonTreeNavigator.java @@ -34,7 +34,7 @@ final class JsonTreeNavigator { } public void navigate(JsonElement element) throws IOException { - if (element.isJsonNull()) { + if (element == null || element.isJsonNull()) { visitor.visitNull(); } else if (element.isJsonArray()) { JsonArray array = element.getAsJsonArray(); @@ -68,7 +68,7 @@ final class JsonTreeNavigator { */ private boolean visitChild(JsonObject parent, String childName, JsonElement child, boolean isFirst) throws IOException { - if (child.isJsonNull()) { + if (child == null || child.isJsonNull()) { if (visitNulls) { visitor.visitNullObjectMember(parent, childName, isFirst); navigate(child.getAsJsonNull()); @@ -93,7 +93,7 @@ final class JsonTreeNavigator { * Returns true if the child was visited, false if it was skipped. */ private void visitChild(JsonArray parent, JsonElement child, boolean isFirst) throws IOException { - if (child.isJsonNull()) { + if (child == null || child.isJsonNull()) { visitor.visitNullArrayMember(parent, isFirst); navigate(child); } else if (child.isJsonArray()) { diff --git a/gson/src/test/java/com/google/gson/functional/CustomTypeAdaptersTest.java b/gson/src/test/java/com/google/gson/functional/CustomTypeAdaptersTest.java index 526a42c5..88dbc5a0 100644 --- a/gson/src/test/java/com/google/gson/functional/CustomTypeAdaptersTest.java +++ b/gson/src/test/java/com/google/gson/functional/CustomTypeAdaptersTest.java @@ -406,4 +406,72 @@ public class CustomTypeAdaptersTest extends TestCase { assertEquals("Jacob", foo.part1); assertEquals("Tomaw", foo.part2); } + + public void testEnsureCustomSerializerNotInvokedForNullValues() { + Gson gson = new GsonBuilder() + .registerTypeAdapter(DataHolder.class, new DataHolderSerializer()) + .create(); + DataHolderWrapper target = new DataHolderWrapper(new DataHolder("abc")); + String json = gson.toJson(target); + assertEquals("{\"wrappedData\":{\"myData\":\"abc\"}}", json); + } + + public void testEnsureCustomDeserializerNotInvokedForNullValues() { + Gson gson = new GsonBuilder() + .registerTypeAdapter(DataHolder.class, new DataHolderDeserializer()) + .create(); + String json = "{wrappedData:null}"; + DataHolderWrapper actual = gson.fromJson(json, DataHolderWrapper.class); + assertNull(actual.wrappedData); + } + + private static class DataHolder { + @SuppressWarnings("unused") + final String data; + + // For use by Gson + @SuppressWarnings("unused") + private DataHolder() { + this(""); + } + + public DataHolder(String data) { + this.data = data; + } + } + + private static class DataHolderWrapper { + final DataHolder wrappedData; + + // For use by Gson + @SuppressWarnings("unused") + private DataHolderWrapper() { + this(null); + } + + public DataHolderWrapper(DataHolder data) { + this.wrappedData = data; + } + } + + private static class DataHolderSerializer implements JsonSerializer { + public JsonElement serialize(DataHolder src, Type typeOfSrc, JsonSerializationContext context) { + JsonObject obj = new JsonObject(); + obj.addProperty("myData", src.data); + return obj; + } + } + + private static class DataHolderDeserializer implements JsonDeserializer { + public DataHolder deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) + throws JsonParseException { + JsonObject jsonObj = json.getAsJsonObject(); + JsonElement jsonElement = jsonObj.get("data"); + if (jsonElement == null || jsonElement.isJsonNull()) { + return new DataHolder(null); + } + return new DataHolder(jsonElement.getAsString()); + } + } + } diff --git a/gson/src/test/java/com/google/gson/functional/ObjectTest.java b/gson/src/test/java/com/google/gson/functional/ObjectTest.java index 86fe2c64..da5de99d 100644 --- a/gson/src/test/java/com/google/gson/functional/ObjectTest.java +++ b/gson/src/test/java/com/google/gson/functional/ObjectTest.java @@ -16,15 +16,10 @@ package com.google.gson.functional; -import java.lang.reflect.Type; -import java.util.ArrayList; -import java.util.Collection; - -import junit.framework.TestCase; - import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.InstanceCreator; +import com.google.gson.JsonObject; import com.google.gson.common.TestTypes.ArrayOfObjects; import com.google.gson.common.TestTypes.BagOfPrimitiveWrappers; import com.google.gson.common.TestTypes.BagOfPrimitives; @@ -35,6 +30,12 @@ import com.google.gson.common.TestTypes.ClassWithTransientFields; import com.google.gson.common.TestTypes.Nested; import com.google.gson.common.TestTypes.PrimitiveArray; +import junit.framework.TestCase; + +import java.lang.reflect.Type; +import java.util.ArrayList; +import java.util.Collection; + /** * Functional tests for Json serialization and deserialization of regular classes. * @@ -401,4 +402,11 @@ public class ObjectTest extends TestCase { String b = ""; String c = ""; } + + public void testJsonObjectSerialization() { + Gson gson = new GsonBuilder().serializeNulls().create(); + JsonObject obj = new JsonObject(); + String json = gson.toJson(obj); + assertEquals("{}", json); + } } diff --git a/gson/src/test/java/com/google/gson/functional/PrintFormattingTest.java b/gson/src/test/java/com/google/gson/functional/PrintFormattingTest.java index 7fded58f..757037b3 100644 --- a/gson/src/test/java/com/google/gson/functional/PrintFormattingTest.java +++ b/gson/src/test/java/com/google/gson/functional/PrintFormattingTest.java @@ -17,6 +17,8 @@ package com.google.gson.functional; import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonObject; import com.google.gson.common.TestTypes.BagOfPrimitives; import com.google.gson.common.TestTypes.ClassWithTransientFields; import com.google.gson.common.TestTypes.Nested; @@ -35,9 +37,16 @@ import java.util.List; */ public class PrintFormattingTest extends TestCase { + private Gson gson; + + @Override + protected void setUp() throws Exception { + super.setUp(); + gson = new Gson(); + } + @SuppressWarnings("unchecked") public void testCompactFormattingLeavesNoWhiteSpace() { - Gson gson = new Gson(); List list = new ArrayList(); list.add(new BagOfPrimitives()); list.add(new Nested()); @@ -48,6 +57,25 @@ public class PrintFormattingTest extends TestCase { assertContainsNoWhiteSpace(json); } + public void testJsonObjectWithNullValues() { + JsonObject obj = new JsonObject(); + obj.addProperty("field1", "value1"); + obj.addProperty("field2", (String) null); + String json = gson.toJson(obj); + assertTrue(json.contains("field1")); + assertFalse(json.contains("field2")); + } + + public void testJsonObjectWithNullValuesSerialized() { + gson = new GsonBuilder().serializeNulls().create(); + JsonObject obj = new JsonObject(); + obj.addProperty("field1", "value1"); + obj.addProperty("field2", (String) null); + String json = gson.toJson(obj); + assertTrue(json.contains("field1")); + assertTrue(json.contains("field2")); + } + private static void assertContainsNoWhiteSpace(String str) { for (char c : str.toCharArray()) { assertFalse(Character.isWhitespace(c));