Fix type hierarchy adapters to do a runtime check.
Otherwise if we have a type hierarchy adapter for Vehicle, and we attempt to decode a JSON string as a Car, we get the right exception if the JSON string is actually decoded as a Truck.
This commit is contained in:
parent
93605e7145
commit
7d1973e6c5
|
@ -16,6 +16,22 @@
|
|||
|
||||
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.math.BigDecimal;
|
||||
import java.math.BigInteger;
|
||||
|
@ -34,23 +50,6 @@ import java.util.Map;
|
|||
import java.util.StringTokenizer;
|
||||
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.
|
||||
*/
|
||||
|
@ -815,12 +814,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() {
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> typeToken) {
|
||||
return clazz.isAssignableFrom(typeToken.getRawType()) ? (TypeAdapter<T>) typeAdapter : null;
|
||||
public <T2> TypeAdapter<T2> create(Gson gson, TypeToken<T2> typeToken) {
|
||||
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() {
|
||||
return "Factory[typeHierarchy=" + clazz.getName() + ",adapter=" + typeAdapter + "]";
|
||||
|
|
|
@ -15,6 +15,21 @@
|
|||
*/
|
||||
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.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Type;
|
||||
|
@ -40,24 +55,8 @@ import java.util.Set;
|
|||
import java.util.TimeZone;
|
||||
import java.util.TreeSet;
|
||||
import java.util.UUID;
|
||||
|
||||
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
|
||||
* 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()
|
||||
.setDateFormat(pattern)
|
||||
.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 {
|
||||
return new Date(1315806903103L);
|
||||
}
|
||||
|
@ -618,6 +618,16 @@ public class DefaultTypeAdaptersTest extends TestCase {
|
|||
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 {
|
||||
BigDecimal value;
|
||||
ClassWithBigDecimal(String value) {
|
||||
|
|
Loading…
Reference in New Issue
Block a user