diff --git a/gson/src/main/java/com/google/gson/DefaultTypeAdapters.java b/gson/src/main/java/com/google/gson/DefaultTypeAdapters.java index 51e6aaea..20302d53 100644 --- a/gson/src/main/java/com/google/gson/DefaultTypeAdapters.java +++ b/gson/src/main/java/com/google/gson/DefaultTypeAdapters.java @@ -454,8 +454,8 @@ final class DefaultTypeAdapters { if (value == null) { valueElement = JsonNull.createJsonNull(); } else { - Type childType = (childGenericType == null) ? - childType = value.getClass() : childGenericType; + Type childType = (childGenericType == null) + ? value.getClass() : childGenericType; valueElement = context.serialize(value, childType); } map.add(String.valueOf(entry.getKey()), valueElement); diff --git a/gson/src/main/java/com/google/gson/Gson.java b/gson/src/main/java/com/google/gson/Gson.java index 60cf66f6..6520ec09 100644 --- a/gson/src/main/java/com/google/gson/Gson.java +++ b/gson/src/main/java/com/google/gson/Gson.java @@ -26,7 +26,6 @@ import java.lang.reflect.Type; import java.util.LinkedList; import java.util.List; import java.util.Map; -import java.util.logging.Logger; /** * This is the main class for using Gson. Gson is typically used by first constructing a @@ -76,6 +75,7 @@ public final class Gson { // constructor instead. At the minimum, mark those methods private. private static final String NULL_STRING = "null"; + // Default instances of plug-ins static final ModifierBasedExclusionStrategy DEFAULT_MODIFIER_BASED_EXCLUSION_STRATEGY = new ModifierBasedExclusionStrategy(true, new int[] { Modifier.TRANSIENT, Modifier.STATIC }); @@ -83,8 +83,6 @@ public final class Gson { static final FieldNamingStrategy DEFAULT_NAMING_POLICY = new SerializedNameAnnotationInterceptingNamingPolicy(new JavaFieldNamingPolicy()); - static final Logger logger = Logger.getLogger(Gson.class.getName()); - private final ExclusionStrategy strategy; private final FieldNamingStrategy fieldNamingPolicy; private final MappedObjectConstructor objectConstructor; @@ -402,15 +400,16 @@ public final class Gson { @Override public String toString() { - StringBuilder sb = new StringBuilder("{"); - sb.append("serializeNulls:").append(serializeNulls); - sb.append(",serializers:").append(serializers); - sb.append(",deserializers:").append(deserializers); - // using the name instanceCreator instead of ObjectConstructor since the users of Gson are - // more familiar with the concept of Instance Creators. Moreover, the objectConstructor is - // just a utility class around instance creators, and its toString() only displays them. - sb.append(",instanceCreators:").append(objectConstructor); - sb.append("}"); - return sb.toString(); + StringBuilder sb = new StringBuilder("{") + .append("serializeNulls:").append(serializeNulls) + .append(",serializers:").append(serializers) + .append(",deserializers:").append(deserializers) + + // using the name instanceCreator instead of ObjectConstructor since the users of Gson are + // more familiar with the concept of Instance Creators. Moreover, the objectConstructor is + // just a utility class around instance creators, and its toString() only displays them. + .append(",instanceCreators:").append(objectConstructor) + .append("}"); + return sb.toString(); } } diff --git a/gson/src/main/java/com/google/gson/GsonBuilder.java b/gson/src/main/java/com/google/gson/GsonBuilder.java index a075c4f7..a3297569 100644 --- a/gson/src/main/java/com/google/gson/GsonBuilder.java +++ b/gson/src/main/java/com/google/gson/GsonBuilder.java @@ -436,8 +436,8 @@ public final class GsonBuilder { dateTypeAdapter = new DefaultDateTypeAdapter(dateStyle, timeStyle); } if (dateTypeAdapter != null - && !serializers.hasAnyHandlerFor(Date.class) - && !deserializers.hasAnyHandlerFor(Date.class)) { + && !serializers.hasSpecificHandlerFor(Date.class) + && !deserializers.hasSpecificHandlerFor(Date.class)) { serializers.register(Date.class, dateTypeAdapter); deserializers.register(Date.class, dateTypeAdapter); } diff --git a/gson/src/main/java/com/google/gson/JsonArray.java b/gson/src/main/java/com/google/gson/JsonArray.java index 111f5e8d..db3788a3 100644 --- a/gson/src/main/java/com/google/gson/JsonArray.java +++ b/gson/src/main/java/com/google/gson/JsonArray.java @@ -16,6 +16,7 @@ package com.google.gson; +import java.io.IOException; import java.math.BigDecimal; import java.math.BigInteger; import java.util.Collections; @@ -291,7 +292,7 @@ public final class JsonArray extends JsonElement implements Iterable implements ObjectNavigator.Visitor { - protected static Logger logger = Logger.getLogger(JsonDeserializationVisitor.class.getName()); - protected final ObjectNavigatorFactory factory; protected final ObjectConstructor objectConstructor; protected final ParameterizedTypeHandlerMap> deserializers; diff --git a/gson/src/main/java/com/google/gson/JsonElement.java b/gson/src/main/java/com/google/gson/JsonElement.java index c0cb84dd..ac144a66 100644 --- a/gson/src/main/java/com/google/gson/JsonElement.java +++ b/gson/src/main/java/com/google/gson/JsonElement.java @@ -16,6 +16,7 @@ package com.google.gson; +import java.io.IOException; import java.math.BigDecimal; import java.math.BigInteger; @@ -311,10 +312,14 @@ public abstract class JsonElement { */ @Override public String toString() { - StringBuilder sb = new StringBuilder(); - toString(sb); - return sb.toString(); + try { + StringBuilder sb = new StringBuilder(); + toString(sb); + return sb.toString(); + } catch (IOException e) { + throw new RuntimeException(e); + } } - protected abstract void toString(StringBuilder sb); + protected abstract void toString(Appendable sb) throws IOException; } diff --git a/gson/src/main/java/com/google/gson/JsonEscapingVisitor.java b/gson/src/main/java/com/google/gson/JsonEscapingVisitor.java index f2209ee2..e8443643 100644 --- a/gson/src/main/java/com/google/gson/JsonEscapingVisitor.java +++ b/gson/src/main/java/com/google/gson/JsonEscapingVisitor.java @@ -61,10 +61,7 @@ class JsonEscapingVisitor extends DelegatingJsonElementVisitor { private JsonPrimitive escapeJsonPrimitive(JsonPrimitive member) { if (member.isString()) { String memberValue = member.getAsString(); - String escapedValue = escaper.escapeJsonString(memberValue); - if (!escapedValue.equals(memberValue)) { - member.setValue(escapedValue); - } + member.setValue(escaper.escapeJsonString(memberValue)); } return member; } diff --git a/gson/src/main/java/com/google/gson/JsonNull.java b/gson/src/main/java/com/google/gson/JsonNull.java index 014fd4b5..d5db280d 100755 --- a/gson/src/main/java/com/google/gson/JsonNull.java +++ b/gson/src/main/java/com/google/gson/JsonNull.java @@ -16,6 +16,8 @@ package com.google.gson; +import java.io.IOException; + /** * A class representing a Json {@code null} value. * @@ -34,7 +36,7 @@ public final class JsonNull extends JsonElement { } @Override - protected void toString(StringBuilder sb) { + protected void toString(Appendable sb) throws IOException { sb.append("null"); } diff --git a/gson/src/main/java/com/google/gson/JsonObject.java b/gson/src/main/java/com/google/gson/JsonObject.java index cda6d45e..dd5280a9 100644 --- a/gson/src/main/java/com/google/gson/JsonObject.java +++ b/gson/src/main/java/com/google/gson/JsonObject.java @@ -16,6 +16,7 @@ package com.google.gson; +import java.io.IOException; import java.util.LinkedHashMap; import java.util.Map; import java.util.Set; @@ -189,7 +190,7 @@ public final class JsonObject extends JsonElement { } @Override - protected void toString(StringBuilder sb) { + protected void toString(Appendable sb) throws IOException { sb.append('{'); boolean first = true; for (Map.Entry entry : members.entrySet()) { diff --git a/gson/src/main/java/com/google/gson/JsonPrimitive.java b/gson/src/main/java/com/google/gson/JsonPrimitive.java index a18ca799..31535b8e 100644 --- a/gson/src/main/java/com/google/gson/JsonPrimitive.java +++ b/gson/src/main/java/com/google/gson/JsonPrimitive.java @@ -16,6 +16,7 @@ package com.google.gson; +import java.io.IOException; import java.math.BigDecimal; import java.math.BigInteger; @@ -305,16 +306,13 @@ public final class JsonPrimitive extends JsonElement { } @Override - protected void toString(StringBuilder sb) { - if (value != null) { - if (value instanceof String) { - sb.append('"'); - sb.append(value); - sb.append('"'); - - } else { - sb.append(value); - } + protected void toString(Appendable sb) throws IOException { + if (value instanceof String) { + sb.append('"'); + sb.append((String) value); + sb.append('"'); + } else { + sb.append(value.toString()); } } diff --git a/gson/src/main/java/com/google/gson/JsonSerializationVisitor.java b/gson/src/main/java/com/google/gson/JsonSerializationVisitor.java index 0dfebcac..26e839ba 100644 --- a/gson/src/main/java/com/google/gson/JsonSerializationVisitor.java +++ b/gson/src/main/java/com/google/gson/JsonSerializationVisitor.java @@ -103,17 +103,13 @@ final class JsonSerializationVisitor implements ObjectNavigator.Visitor { private void addAsArrayElement(Type elementType, Object elementValue) { if (elementValue == null) { - addNullAsArrayElement(); + root.getAsJsonArray().add(JsonNull.createJsonNull()); } else { JsonElement childElement = getJsonElementForChild(elementType, elementValue); root.getAsJsonArray().add(childElement); } } - private void addNullAsArrayElement() { - root.getAsJsonArray().add(null); - } - private JsonElement getJsonElementForChild(Type fieldType, Object fieldValue) { ObjectNavigator on = factory.create(fieldValue, fieldType); JsonSerializationVisitor childVisitor = @@ -160,7 +156,7 @@ final class JsonSerializationVisitor implements ObjectNavigator.Visitor { } private void assignToRoot(JsonElement newRoot) { - Preconditions.checkArgument(root == null); + Preconditions.checkNotNull(newRoot); root = newRoot; } diff --git a/gson/src/main/java/com/google/gson/JsonTreeNavigator.java b/gson/src/main/java/com/google/gson/JsonTreeNavigator.java index 36d338bc..dfa23f51 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 == null || element.isJsonNull()) { + if (element.isJsonNull()) { visitor.visitNull(); } else if (element.isJsonArray()) { JsonArray array = element.getAsJsonArray(); @@ -68,25 +68,23 @@ final class JsonTreeNavigator { */ private boolean visitChild(JsonObject parent, String childName, JsonElement child, boolean isFirst) throws IOException { - if (child != null) { - if (child.isJsonNull()) { - if (visitNulls) { - visitor.visitNullObjectMember(parent, childName, isFirst); - navigate(child.getAsJsonNull()); - } else { // Null value is being skipped. - return false; - } - } else if (child.isJsonArray()) { - JsonArray childAsArray = child.getAsJsonArray(); - visitor.visitObjectMember(parent, childName, childAsArray, isFirst); - navigate(childAsArray); - } else if (child.isJsonObject()) { - JsonObject childAsObject = child.getAsJsonObject(); - visitor.visitObjectMember(parent, childName, childAsObject, isFirst); - navigate(childAsObject); - } else { // is a JsonPrimitive - visitor.visitObjectMember(parent, childName, child.getAsJsonPrimitive(), isFirst); + if (child.isJsonNull()) { + if (visitNulls) { + visitor.visitNullObjectMember(parent, childName, isFirst); + navigate(child.getAsJsonNull()); + } else { // Null value is being skipped. + return false; } + } else if (child.isJsonArray()) { + JsonArray childAsArray = child.getAsJsonArray(); + visitor.visitObjectMember(parent, childName, childAsArray, isFirst); + navigate(childAsArray); + } else if (child.isJsonObject()) { + JsonObject childAsObject = child.getAsJsonObject(); + visitor.visitObjectMember(parent, childName, childAsObject, isFirst); + navigate(childAsObject); + } else { // is a JsonPrimitive + visitor.visitObjectMember(parent, childName, child.getAsJsonPrimitive(), isFirst); } return true; } @@ -95,9 +93,9 @@ 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 == null || child.isJsonNull()) { + if (child.isJsonNull()) { visitor.visitNullArrayMember(parent, isFirst); - navigate(null); + navigate(child); } else if (child.isJsonArray()) { JsonArray childAsArray = child.getAsJsonArray(); visitor.visitArrayMember(parent, childAsArray, isFirst); diff --git a/gson/src/main/java/com/google/gson/MappedObjectConstructor.java b/gson/src/main/java/com/google/gson/MappedObjectConstructor.java index 5f82fbeb..9658639d 100644 --- a/gson/src/main/java/com/google/gson/MappedObjectConstructor.java +++ b/gson/src/main/java/com/google/gson/MappedObjectConstructor.java @@ -35,15 +35,15 @@ import java.util.logging.Logger; * @author Joel Leitch */ final class MappedObjectConstructor implements ObjectConstructor { - private final Logger log = Logger.getLogger(getClass().getName()); + private static final Logger log = Logger.getLogger(MappedObjectConstructor.class.getName()); private final ParameterizedTypeHandlerMap> instanceCreatorMap = - new ParameterizedTypeHandlerMap>(); + new ParameterizedTypeHandlerMap>(); @SuppressWarnings("unchecked") public T construct(Type typeOfT) { - if (instanceCreatorMap.hasAnyHandlerFor(typeOfT)) { - InstanceCreator creator = (InstanceCreator) instanceCreatorMap.getHandlerFor(typeOfT); + InstanceCreator creator = (InstanceCreator) instanceCreatorMap.getHandlerFor(typeOfT); + if (creator != null) { return creator.createInstance(typeOfT); } return (T) constructWithNoArgConstructor(typeOfT); diff --git a/gson/src/main/java/com/google/gson/ParameterizedTypeHandlerMap.java b/gson/src/main/java/com/google/gson/ParameterizedTypeHandlerMap.java index 32b7e12d..1eaf697c 100644 --- a/gson/src/main/java/com/google/gson/ParameterizedTypeHandlerMap.java +++ b/gson/src/main/java/com/google/gson/ParameterizedTypeHandlerMap.java @@ -16,40 +16,46 @@ package com.google.gson; -import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.util.Collection; import java.util.HashMap; import java.util.Map; import java.util.Set; import java.util.logging.Level; +import java.util.logging.Logger; /** - * A map that provides ability to associate handlers for a specific type or all of its sub-types - * + * A map that provides ability to associate handlers for a specific type or all + * of its sub-types + * * @author Inderjeet Singh * @author Joel Leitch - * - * @param The handler that will be looked up by type + * + * @param + * The handler that will be looked up by type */ final class ParameterizedTypeHandlerMap { - + private static final Logger logger = + Logger.getLogger(ParameterizedTypeHandlerMap.class.getName()); private final Map map = new HashMap(); private boolean modifiable = true; public synchronized void register(Type typeOfT, T value) { if (!modifiable) { - throw new IllegalStateException("Attempted to modify an unmodifiable map."); + throw new IllegalStateException( + "Attempted to modify an unmodifiable map."); } if (hasSpecificHandlerFor(typeOfT)) { - Gson.logger.log(Level.WARNING, "Overriding the existing type handler for " + typeOfT); + logger.log(Level.WARNING, + "Overriding the existing type handler for " + typeOfT); } map.put(typeOfT, value); } public synchronized void registerIfAbsent(ParameterizedTypeHandlerMap other) { if (!modifiable) { - throw new IllegalStateException("Attempted to modify an unmodifiable map."); + throw new IllegalStateException( + "Attempted to modify an unmodifiable map."); } for (Map.Entry entry : other.entrySet()) { if (!map.containsKey(entry.getKey())) { @@ -60,7 +66,8 @@ final class ParameterizedTypeHandlerMap { public synchronized void registerIfAbsent(Type typeOfT, T value) { if (!modifiable) { - throw new IllegalStateException("Attempted to modify an unmodifiable map."); + throw new IllegalStateException( + "Attempted to modify an unmodifiable map."); } if (!map.containsKey(typeOfT)) { register(typeOfT, value); @@ -72,18 +79,15 @@ final class ParameterizedTypeHandlerMap { } public synchronized T getHandlerFor(Type type) { - T handler = getRawHandlerFor(type); - Type rawType = type; - if (handler == null && type instanceof ParameterizedType) { - // a handler for a non-generic version may be registered, so use that - rawType = ((ParameterizedType)type).getRawType(); - handler = map.get(rawType); - } - - // Check for map or collection + T handler = map.get(type); if (handler == null) { - if (rawType instanceof Class) { - Class rawClass = (Class) rawType; + Class rawClass = TypeUtils.toRawClass(type); + if (rawClass != type) { + handler = getHandlerFor(rawClass); + } + + // Check for map or collection + if (handler == null) { if (Map.class.isAssignableFrom(rawClass)) { handler = map.get(Map.class); } else if (Collection.class.isAssignableFrom(rawClass)) { @@ -95,27 +99,6 @@ final class ParameterizedTypeHandlerMap { } return handler; } - - private synchronized T getRawHandlerFor(Type type) { - if (type instanceof Map) { - return map.get(Map.class); - } else if (type instanceof Collection) { - return map.get(Collection.class); - } else { - T handler = map.get(type); - if (handler == null) { - Class rawClass = TypeUtils.toRawClass(type); - if (rawClass != type) { - handler = getHandlerFor(rawClass); - } - } - return handler; - } - } - - public synchronized boolean hasAnyHandlerFor(Type type) { - return getHandlerFor(type) != null; - } public synchronized boolean hasSpecificHandlerFor(Type type) { return map.containsKey(type); @@ -132,7 +115,7 @@ final class ParameterizedTypeHandlerMap { public synchronized Set> entrySet() { return map.entrySet(); } - + @Override public String toString() { StringBuilder sb = new StringBuilder("{"); @@ -148,7 +131,7 @@ final class ParameterizedTypeHandlerMap { } return sb.toString(); } - + private String typeToString(Type type) { return TypeUtils.toRawClass(type).getSimpleName(); } diff --git a/gson/src/test/java/com/google/gson/ParameterizedTypeHandlerMapTest.java b/gson/src/test/java/com/google/gson/ParameterizedTypeHandlerMapTest.java index c0642db8..cd05b1c7 100644 --- a/gson/src/test/java/com/google/gson/ParameterizedTypeHandlerMapTest.java +++ b/gson/src/test/java/com/google/gson/ParameterizedTypeHandlerMapTest.java @@ -39,7 +39,7 @@ public class ParameterizedTypeHandlerMapTest extends TestCase { public void testNullMap() throws Exception { assertFalse(paramMap.hasSpecificHandlerFor(String.class)); - assertFalse(paramMap.hasAnyHandlerFor(String.class)); + assertNull(paramMap.getHandlerFor(String.class)); assertNull(paramMap.getHandlerFor(String.class)); } @@ -50,8 +50,8 @@ public class ParameterizedTypeHandlerMapTest extends TestCase { assertFalse(paramMap.hasSpecificHandlerFor(specificType)); assertTrue(paramMap.hasSpecificHandlerFor(List.class)); - assertTrue(paramMap.hasAnyHandlerFor(specificType)); - assertTrue(paramMap.hasAnyHandlerFor(List.class)); + assertNotNull(paramMap.getHandlerFor(specificType)); + assertNotNull(paramMap.getHandlerFor(List.class)); assertEquals(handler, paramMap.getHandlerFor(specificType)); } @@ -62,8 +62,8 @@ public class ParameterizedTypeHandlerMapTest extends TestCase { assertTrue(paramMap.hasSpecificHandlerFor(specificType)); assertFalse(paramMap.hasSpecificHandlerFor(List.class)); - assertTrue(paramMap.hasAnyHandlerFor(specificType)); - assertFalse(paramMap.hasAnyHandlerFor(List.class)); + assertNotNull(paramMap.getHandlerFor(specificType)); + assertNull(paramMap.getHandlerFor(List.class)); assertEquals(handler, paramMap.getHandlerFor(specificType)); } diff --git a/gson/src/test/java/com/google/gson/functional/ArrayTest.java b/gson/src/test/java/com/google/gson/functional/ArrayTest.java index 921673db..81feb7f4 100644 --- a/gson/src/test/java/com/google/gson/functional/ArrayTest.java +++ b/gson/src/test/java/com/google/gson/functional/ArrayTest.java @@ -13,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package com.google.gson.functional; import com.google.gson.Gson; @@ -82,6 +83,14 @@ public class ArrayTest extends TestCase { assertEquals(expected[i], target[i]); } } + + public void testNullsInArrayWithSerializeNullPropertySetSerialization() { + gson = new GsonBuilder().serializeNulls().create(); + String[] array = {"foo", null, "bar"}; + String expected = "[\"foo\",null,\"bar\"]"; + String json = gson.toJson(array); + assertEquals(expected, json); + } public void testArrayOfStringsSerialization() { String[] target = {"Hello", "World"};