Forbid custom serializers for primitive types (so we can avoid boxing in the reflective and array adapters)
This commit is contained in:
parent
fede584b98
commit
e756608568
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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));
|
||||||
}
|
}
|
||||||
|
|
|
@ -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>() {
|
||||||
|
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}).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() {
|
|
||||||
final ClassWithBooleanField customDeserializerInvoked = new ClassWithBooleanField();
|
|
||||||
customDeserializerInvoked.value = false;
|
|
||||||
Gson gson = new GsonBuilder().registerTypeAdapter(Long.class, new JsonDeserializer<Long>() {
|
|
||||||
public Long deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
|
|
||||||
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 (IllegalArgumentException 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 {
|
public void testCustomDeserializerForbiddenForPrimitives() {
|
||||||
Long value;
|
try {
|
||||||
}
|
new GsonBuilder().registerTypeAdapter(long.class, new JsonDeserializer<Long>() {
|
||||||
|
public Long deserialize(JsonElement json, Type t, JsonDeserializationContext c) {
|
||||||
private static class ClassWithBooleanField {
|
throw new AssertionError();
|
||||||
Boolean value;
|
}
|
||||||
|
});
|
||||||
|
fail();
|
||||||
|
} catch (Exception expected) {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testCustomByteArraySerializer() {
|
public void testCustomByteArraySerializer() {
|
||||||
|
|
Loading…
Reference in New Issue
Block a user