Merge pull request #719 from google/jwilson_1021_runtime_type_mismatch
Fix type hierarchy adapters to do a runtime check.
This commit is contained in:
commit
fe101c10bc
@ -16,6 +16,22 @@
|
|||||||
|
|
||||||
package com.google.gson.internal.bind;
|
package com.google.gson.internal.bind;
|
||||||
|
|
||||||
|
import com.google.gson.Gson;
|
||||||
|
import com.google.gson.JsonArray;
|
||||||
|
import com.google.gson.JsonElement;
|
||||||
|
import com.google.gson.JsonIOException;
|
||||||
|
import com.google.gson.JsonNull;
|
||||||
|
import com.google.gson.JsonObject;
|
||||||
|
import com.google.gson.JsonPrimitive;
|
||||||
|
import com.google.gson.JsonSyntaxException;
|
||||||
|
import com.google.gson.TypeAdapter;
|
||||||
|
import com.google.gson.TypeAdapterFactory;
|
||||||
|
import com.google.gson.annotations.SerializedName;
|
||||||
|
import com.google.gson.internal.LazilyParsedNumber;
|
||||||
|
import com.google.gson.reflect.TypeToken;
|
||||||
|
import com.google.gson.stream.JsonReader;
|
||||||
|
import com.google.gson.stream.JsonToken;
|
||||||
|
import com.google.gson.stream.JsonWriter;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.math.BigInteger;
|
import java.math.BigInteger;
|
||||||
@ -34,23 +50,6 @@ import java.util.Map;
|
|||||||
import java.util.StringTokenizer;
|
import java.util.StringTokenizer;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
import com.google.gson.Gson;
|
|
||||||
import com.google.gson.JsonArray;
|
|
||||||
import com.google.gson.JsonElement;
|
|
||||||
import com.google.gson.JsonIOException;
|
|
||||||
import com.google.gson.JsonNull;
|
|
||||||
import com.google.gson.JsonObject;
|
|
||||||
import com.google.gson.JsonPrimitive;
|
|
||||||
import com.google.gson.JsonSyntaxException;
|
|
||||||
import com.google.gson.TypeAdapter;
|
|
||||||
import com.google.gson.TypeAdapterFactory;
|
|
||||||
import com.google.gson.annotations.SerializedName;
|
|
||||||
import com.google.gson.internal.LazilyParsedNumber;
|
|
||||||
import com.google.gson.reflect.TypeToken;
|
|
||||||
import com.google.gson.stream.JsonReader;
|
|
||||||
import com.google.gson.stream.JsonToken;
|
|
||||||
import com.google.gson.stream.JsonWriter;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Type adapters for basic types.
|
* Type adapters for basic types.
|
||||||
*/
|
*/
|
||||||
@ -818,12 +817,33 @@ public final class TypeAdapters {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public static <TT> TypeAdapterFactory newTypeHierarchyFactory(
|
/**
|
||||||
final Class<TT> clazz, final TypeAdapter<TT> typeAdapter) {
|
* Returns a factory for all subtypes of {@code typeAdapter}. We do a runtime check to confirm
|
||||||
|
* that the deserialized type matches the type requested.
|
||||||
|
*/
|
||||||
|
public static <T1> TypeAdapterFactory newTypeHierarchyFactory(
|
||||||
|
final Class<T1> clazz, final TypeAdapter<T1> typeAdapter) {
|
||||||
return new TypeAdapterFactory() {
|
return new TypeAdapterFactory() {
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> typeToken) {
|
public <T2> TypeAdapter<T2> create(Gson gson, TypeToken<T2> typeToken) {
|
||||||
return clazz.isAssignableFrom(typeToken.getRawType()) ? (TypeAdapter<T>) typeAdapter : null;
|
final Class<? super T2> requestedType = typeToken.getRawType();
|
||||||
|
if (!clazz.isAssignableFrom(requestedType)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return (TypeAdapter<T2>) new TypeAdapter<T1>() {
|
||||||
|
@Override public void write(JsonWriter out, T1 value) throws IOException {
|
||||||
|
typeAdapter.write(out, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public T1 read(JsonReader in) throws IOException {
|
||||||
|
T1 result = typeAdapter.read(in);
|
||||||
|
if (result != null && !requestedType.isInstance(result)) {
|
||||||
|
throw new JsonSyntaxException("Expected a " + requestedType.getName()
|
||||||
|
+ " but was " + result.getClass().getName());
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
@Override public String toString() {
|
@Override public String toString() {
|
||||||
return "Factory[typeHierarchy=" + clazz.getName() + ",adapter=" + typeAdapter + "]";
|
return "Factory[typeHierarchy=" + clazz.getName() + ",adapter=" + typeAdapter + "]";
|
||||||
|
@ -15,6 +15,21 @@
|
|||||||
*/
|
*/
|
||||||
package com.google.gson.functional;
|
package com.google.gson.functional;
|
||||||
|
|
||||||
|
import com.google.gson.Gson;
|
||||||
|
import com.google.gson.GsonBuilder;
|
||||||
|
import com.google.gson.JsonArray;
|
||||||
|
import com.google.gson.JsonDeserializationContext;
|
||||||
|
import com.google.gson.JsonDeserializer;
|
||||||
|
import com.google.gson.JsonElement;
|
||||||
|
import com.google.gson.JsonNull;
|
||||||
|
import com.google.gson.JsonObject;
|
||||||
|
import com.google.gson.JsonParseException;
|
||||||
|
import com.google.gson.JsonPrimitive;
|
||||||
|
import com.google.gson.JsonSyntaxException;
|
||||||
|
import com.google.gson.TypeAdapter;
|
||||||
|
import com.google.gson.reflect.TypeToken;
|
||||||
|
import com.google.gson.stream.JsonReader;
|
||||||
|
import com.google.gson.stream.JsonWriter;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.lang.reflect.Constructor;
|
import java.lang.reflect.Constructor;
|
||||||
import java.lang.reflect.Type;
|
import java.lang.reflect.Type;
|
||||||
@ -40,24 +55,8 @@ import java.util.Set;
|
|||||||
import java.util.TimeZone;
|
import java.util.TimeZone;
|
||||||
import java.util.TreeSet;
|
import java.util.TreeSet;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
import junit.framework.TestCase;
|
import junit.framework.TestCase;
|
||||||
|
|
||||||
import com.google.gson.Gson;
|
|
||||||
import com.google.gson.GsonBuilder;
|
|
||||||
import com.google.gson.JsonArray;
|
|
||||||
import com.google.gson.JsonDeserializationContext;
|
|
||||||
import com.google.gson.JsonDeserializer;
|
|
||||||
import com.google.gson.JsonElement;
|
|
||||||
import com.google.gson.JsonNull;
|
|
||||||
import com.google.gson.JsonObject;
|
|
||||||
import com.google.gson.JsonParseException;
|
|
||||||
import com.google.gson.JsonPrimitive;
|
|
||||||
import com.google.gson.TypeAdapter;
|
|
||||||
import com.google.gson.reflect.TypeToken;
|
|
||||||
import com.google.gson.stream.JsonReader;
|
|
||||||
import com.google.gson.stream.JsonWriter;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Functional test for Json serialization and deserialization for common classes for which default
|
* Functional test for Json serialization and deserialization for common classes for which default
|
||||||
* support is provided in Gson. The tests for Map types are available in {@link MapTest}.
|
* support is provided in Gson. The tests for Map types are available in {@link MapTest}.
|
||||||
@ -479,7 +478,8 @@ public class DefaultTypeAdaptersTest extends TestCase {
|
|||||||
Gson gson = new GsonBuilder()
|
Gson gson = new GsonBuilder()
|
||||||
.setDateFormat(pattern)
|
.setDateFormat(pattern)
|
||||||
.registerTypeAdapter(Date.class, new JsonDeserializer<Date>() {
|
.registerTypeAdapter(Date.class, new JsonDeserializer<Date>() {
|
||||||
public Date deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
|
public Date deserialize(JsonElement json, Type typeOfT,
|
||||||
|
JsonDeserializationContext context)
|
||||||
throws JsonParseException {
|
throws JsonParseException {
|
||||||
return new Date(1315806903103L);
|
return new Date(1315806903103L);
|
||||||
}
|
}
|
||||||
@ -618,6 +618,16 @@ public class DefaultTypeAdaptersTest extends TestCase {
|
|||||||
assertEquals(JsonNull.INSTANCE, gson.fromJson("null", JsonNull.class));
|
assertEquals(JsonNull.INSTANCE, gson.fromJson("null", JsonNull.class));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testJsonElementTypeMismatch() {
|
||||||
|
try {
|
||||||
|
gson.fromJson("\"abc\"", JsonObject.class);
|
||||||
|
fail();
|
||||||
|
} catch (JsonSyntaxException expected) {
|
||||||
|
assertEquals("Expected a com.google.gson.JsonObject but was com.google.gson.JsonPrimitive",
|
||||||
|
expected.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static class ClassWithBigDecimal {
|
private static class ClassWithBigDecimal {
|
||||||
BigDecimal value;
|
BigDecimal value;
|
||||||
ClassWithBigDecimal(String value) {
|
ClassWithBigDecimal(String value) {
|
||||||
|
Loading…
Reference in New Issue
Block a user