Forbid custom serializers for primitive types (so we can avoid boxing in the reflective and array adapters)

This commit is contained in:
Jesse Wilson 2011-09-09 06:26:21 +00:00
parent fede584b98
commit e756608568
5 changed files with 88 additions and 139 deletions

View File

@ -31,3 +31,9 @@ com.google.gson.functional.PrimitiveTest.testDeserializingBigIntegerAsLong
GSON 1.x uses arbitrary precision for primitive type conversion (so -122.08e-2132 != 0) GSON 1.x uses arbitrary precision for primitive type conversion (so -122.08e-2132 != 0)
GSON 2.x uses double precision (so -122.08e-2132 == 0) GSON 2.x uses double precision (so -122.08e-2132 == 0)
com.google.gson.functional.PrimitiveTest.testDeserializingBigDecimalAsLongFails com.google.gson.functional.PrimitiveTest.testDeserializingBigDecimalAsLongFails
GSON 1.x supports type adapters for primitive types
GSON 2.x doesn't
com.google.gson.functional.CustomTypeAdaptersTest.testCustomSerializerForLong
com.google.gson.functional.CustomTypeAdaptersTest.testCustomDeserializerForLong

View File

@ -18,7 +18,6 @@ package com.google.gson;
import com.google.gson.DefaultTypeAdapters.DefaultDateTypeAdapter; import com.google.gson.DefaultTypeAdapters.DefaultDateTypeAdapter;
import com.google.gson.internal.$Gson$Preconditions; import com.google.gson.internal.$Gson$Preconditions;
import java.lang.reflect.Type; import java.lang.reflect.Type;
import java.sql.Timestamp; import java.sql.Timestamp;
import java.text.DateFormat; import java.text.DateFormat;
@ -495,6 +494,10 @@ public final class GsonBuilder {
private GsonBuilder registerTypeAdapter(Type type, Object typeAdapter, boolean isSystem) { private GsonBuilder registerTypeAdapter(Type type, Object typeAdapter, boolean isSystem) {
$Gson$Preconditions.checkArgument(typeAdapter instanceof JsonSerializer<?> $Gson$Preconditions.checkArgument(typeAdapter instanceof JsonSerializer<?>
|| typeAdapter instanceof JsonDeserializer<?> || typeAdapter instanceof InstanceCreator<?>); || typeAdapter instanceof JsonDeserializer<?> || typeAdapter instanceof InstanceCreator<?>);
if (Primitives.isPrimitive(type) || Primitives.isWrapperType(type)) {
throw new IllegalArgumentException(
"Cannot register type adapters for " + type);
}
if (typeAdapter instanceof InstanceCreator<?>) { if (typeAdapter instanceof InstanceCreator<?>) {
registerInstanceCreator(type, (InstanceCreator<?>) typeAdapter, isSystem); registerInstanceCreator(type, (InstanceCreator<?>) typeAdapter, isSystem);
} }

View File

@ -17,13 +17,12 @@
package com.google.gson; package com.google.gson;
import com.google.gson.internal.$Gson$Preconditions;
import java.lang.reflect.Type; import java.lang.reflect.Type;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import com.google.gson.internal.$Gson$Preconditions;
/** /**
* Contains static utility methods pertaining to primitive types and their * Contains static utility methods pertaining to primitive types and their
* corresponding wrapper types. * corresponding wrapper types.
@ -78,7 +77,7 @@ final class Primitives {
* *
* @see Class#isPrimitive * @see Class#isPrimitive
*/ */
public static boolean isWrapperType(Class<?> type) { public static boolean isWrapperType(Type type) {
return WRAPPER_TO_PRIMITIVE_TYPE.containsKey( return WRAPPER_TO_PRIMITIVE_TYPE.containsKey(
$Gson$Preconditions.checkNotNull(type)); $Gson$Preconditions.checkNotNull(type));
} }

View File

@ -173,34 +173,6 @@ public class CustomDeserializerTest extends TestCase {
assertNull(target.base); 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() { public void testCustomDeserializerReturnsNullForArrayElements() {
Gson gson = new GsonBuilder() Gson gson = new GsonBuilder()
.registerTypeAdapter(Base.class, new JsonDeserializer<Base>() { .registerTypeAdapter(Base.class, new JsonDeserializer<Base>() {

View File

@ -203,59 +203,28 @@ public class CustomTypeAdaptersTest extends TestCase {
} }
} }
public void testCustomSerializerForLong() { public void testCustomSerializerForbiddenForPrimitives() {
final ClassWithBooleanField customSerializerInvoked = new ClassWithBooleanField(); try {
customSerializerInvoked.value = false; new GsonBuilder().registerTypeAdapter(long.class, new JsonSerializer<Long>() {
Gson gson = new GsonBuilder().registerTypeAdapter(Long.class, new JsonSerializer<Long>() { public JsonElement serialize(Long s, Type t, JsonSerializationContext c) {
public JsonElement serialize(Long src, Type typeOfSrc, JsonSerializationContext context) { throw new AssertionError();
customSerializerInvoked.value = true; }
return new JsonPrimitive(src); });
fail();
} catch (IllegalArgumentException expected) {
} }
}).serializeNulls().create();
ClassWithWrapperLongField src = new ClassWithWrapperLongField();
String json = gson.toJson(src);
assertTrue(json.contains("\"value\":null"));
assertFalse(customSerializerInvoked.value);
customSerializerInvoked.value = false;
src.value = 10L;
json = gson.toJson(src);
assertTrue(json.contains("\"value\":10"));
assertTrue(customSerializerInvoked.value);
} }
public void testCustomDeserializerForLong() { public void testCustomDeserializerForbiddenForPrimitives() {
final ClassWithBooleanField customDeserializerInvoked = new ClassWithBooleanField(); try {
customDeserializerInvoked.value = false; new GsonBuilder().registerTypeAdapter(long.class, new JsonDeserializer<Long>() {
Gson gson = new GsonBuilder().registerTypeAdapter(Long.class, new JsonDeserializer<Long>() { public Long deserialize(JsonElement json, Type t, JsonDeserializationContext c) {
public Long deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throw new AssertionError();
throws JsonParseException {
customDeserializerInvoked.value = true;
if (json == null || json.isJsonNull()) {
return null;
} }
Number number = json.getAsJsonPrimitive().getAsNumber(); });
return number == null ? null : number.longValue(); fail();
} catch (Exception expected) {
} }
}).create();
String json = "{'value':null}";
ClassWithWrapperLongField target = gson.fromJson(json, ClassWithWrapperLongField.class);
assertNull(target.value);
assertFalse(customDeserializerInvoked.value);
customDeserializerInvoked.value = false;
json = "{'value':10}";
target = gson.fromJson(json, ClassWithWrapperLongField.class);
assertEquals(10L, target.value.longValue());
assertTrue(customDeserializerInvoked.value);
}
private static class ClassWithWrapperLongField {
Long value;
}
private static class ClassWithBooleanField {
Boolean value;
} }
public void testCustomByteArraySerializer() { public void testCustomByteArraySerializer() {