Down to 22 failing tests.
Consolidated all of the different code paths that we use to construct instances. We now have an ObjectConstructor class that knows what type it constructs; this means that we don't need to ever do reflection to lookup a constructor at construction time. Cleaned up some buggy type adapters, particularly around handling of null. Removed dead code for object graph navigation. Moved some classes into 'internal' so they are visible to the 'bind' subpackage. Turned some TypeAdapterFactory/TypeAdapter pairs inside out so that the TypeAdapter is now the inner class. This is necessary so that the factories can take parameters. Added an API to request the 'next' type adapter for a type. This allows type adapters to compose other type adapters. We're using this in two places: - where the user has excluded a type from serialization but not deserialization, we need to use the "default" deserialization but interpose null on serialization. We create a type adapter that delegates for one and returns null for the other. - similarly when a DOM type serializer is registered but no deserializer, or vice versa. This is the biggest change to the MiniGson core. For backwards compatibility, return null for the empty string. Simplify JsonSerializationContext/JsonDeserializationContext to simply call through to GSON. SerializeDefault is currently unsupported. More useful error messages when calling getAsBoolean on a JsonNull. Remove currently unused MemoryRefStack. We might need this back again, though wiring it back in will be much more difficult because we don't interject ourselves between the users' various type adapters.
This commit is contained in:
parent
cdd5d80b85
commit
25c6ae177b
@ -1,40 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2011 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.google.gson;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Captures all the common/shared logic between the old, ({@link MapTypeAdapter}, and
|
||||
* the new, {@link MapAsArrayTypeAdapter}, map type adapters.
|
||||
*
|
||||
* @author Joel Leitch
|
||||
*/
|
||||
abstract class BaseMapTypeAdapter
|
||||
implements JsonSerializer<Map<?, ?>>, JsonDeserializer<Map<?, ?>> {
|
||||
|
||||
protected static JsonElement serialize(JsonSerializationContext context,
|
||||
Object src, Type srcType) {
|
||||
return context.serialize(src, srcType, false, false);
|
||||
}
|
||||
|
||||
protected static Map<Object, Object> constructMapType(
|
||||
Type mapType, JsonDeserializationContext context) {
|
||||
return context.construct(mapType);
|
||||
}
|
||||
}
|
@ -16,30 +16,19 @@
|
||||
|
||||
package com.google.gson;
|
||||
|
||||
import com.google.gson.internal.$Gson$Types;
|
||||
import com.google.gson.internal.ParameterizedTypeHandlerMap;
|
||||
import java.lang.reflect.Type;
|
||||
import java.sql.Time;
|
||||
import java.sql.Timestamp;
|
||||
import java.text.DateFormat;
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.BitSet;
|
||||
import java.util.Calendar;
|
||||
import java.util.Collection;
|
||||
import java.util.Date;
|
||||
import java.util.GregorianCalendar;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Queue;
|
||||
import java.util.Set;
|
||||
import java.util.SortedSet;
|
||||
import java.util.TimeZone;
|
||||
import java.util.TreeSet;
|
||||
|
||||
/**
|
||||
* List of all the default type adapters ({@link JsonSerializer}s, {@link JsonDeserializer}s,
|
||||
@ -61,7 +50,6 @@ final class DefaultTypeAdapters {
|
||||
@SuppressWarnings("unchecked")
|
||||
private static final EnumTypeAdapter ENUM_TYPE_ADAPTER = new EnumTypeAdapter();
|
||||
private static final BitSetTypeAdapter BIT_SET_ADAPTER = new BitSetTypeAdapter();
|
||||
private static final MapTypeAdapter MAP_TYPE_ADAPTER = new MapTypeAdapter();
|
||||
|
||||
private static final CharacterTypeAdapter CHARACTER_TYPE_ADAPTER = new CharacterTypeAdapter();
|
||||
private static final NumberTypeAdapter NUMBER_TYPE_ADAPTER = new NumberTypeAdapter();
|
||||
@ -107,7 +95,6 @@ final class DefaultTypeAdapters {
|
||||
ParameterizedTypeHandlerMap<JsonSerializer<?>> map =
|
||||
new ParameterizedTypeHandlerMap<JsonSerializer<?>>();
|
||||
map.registerForTypeHierarchy(Enum.class, ENUM_TYPE_ADAPTER, true);
|
||||
map.registerForTypeHierarchy(Map.class, MAP_TYPE_ADAPTER, true);
|
||||
map.makeUnmodifiable();
|
||||
return map;
|
||||
}
|
||||
@ -135,35 +122,14 @@ final class DefaultTypeAdapters {
|
||||
ParameterizedTypeHandlerMap<JsonDeserializer<?>> map =
|
||||
new ParameterizedTypeHandlerMap<JsonDeserializer<?>>();
|
||||
map.registerForTypeHierarchy(Enum.class, wrapDeserializer(ENUM_TYPE_ADAPTER), true);
|
||||
map.registerForTypeHierarchy(Map.class, wrapDeserializer(MAP_TYPE_ADAPTER), true);
|
||||
map.makeUnmodifiable();
|
||||
return map;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private static ParameterizedTypeHandlerMap<InstanceCreator<?>> createDefaultInstanceCreators() {
|
||||
ParameterizedTypeHandlerMap<InstanceCreator<?>> map =
|
||||
new ParameterizedTypeHandlerMap<InstanceCreator<?>>();
|
||||
DefaultConstructorAllocator allocator = new DefaultConstructorAllocator(50);
|
||||
|
||||
// Map Instance Creators
|
||||
map.registerForTypeHierarchy(Map.class,
|
||||
new DefaultConstructorCreator<Map>(LinkedHashMap.class, allocator), true);
|
||||
|
||||
// Add Collection type instance creators
|
||||
DefaultConstructorCreator<List> listCreator =
|
||||
new DefaultConstructorCreator<List>(ArrayList.class, allocator);
|
||||
DefaultConstructorCreator<Queue> queueCreator =
|
||||
new DefaultConstructorCreator<Queue>(LinkedList.class, allocator);
|
||||
DefaultConstructorCreator<Set> setCreator =
|
||||
new DefaultConstructorCreator<Set>(HashSet.class, allocator);
|
||||
DefaultConstructorCreator<SortedSet> sortedSetCreator =
|
||||
new DefaultConstructorCreator<SortedSet>(TreeSet.class, allocator);
|
||||
map.registerForTypeHierarchy(Collection.class, listCreator, true);
|
||||
map.registerForTypeHierarchy(Queue.class, queueCreator, true);
|
||||
map.registerForTypeHierarchy(Set.class, setCreator, true);
|
||||
map.registerForTypeHierarchy(SortedSet.class, sortedSetCreator, true);
|
||||
|
||||
ParameterizedTypeHandlerMap<InstanceCreator<?>> map
|
||||
= new ParameterizedTypeHandlerMap<InstanceCreator<?>>();
|
||||
map.makeUnmodifiable();
|
||||
return map;
|
||||
}
|
||||
@ -566,33 +532,4 @@ final class DefaultTypeAdapters {
|
||||
return CharacterTypeAdapter.class.getSimpleName();
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private static final class DefaultConstructorCreator<T> implements InstanceCreator<T> {
|
||||
private final Class<? extends T> defaultInstance;
|
||||
private final DefaultConstructorAllocator allocator;
|
||||
|
||||
public DefaultConstructorCreator(Class<? extends T> defaultInstance,
|
||||
DefaultConstructorAllocator allocator) {
|
||||
this.defaultInstance = defaultInstance;
|
||||
this.allocator = allocator;
|
||||
}
|
||||
|
||||
public T createInstance(Type type) {
|
||||
Class<?> rawType = $Gson$Types.getRawType(type);
|
||||
try {
|
||||
T specificInstance = (T) allocator.newInstance(rawType);
|
||||
return (specificInstance == null)
|
||||
? allocator.newInstance(defaultInstance)
|
||||
: specificInstance;
|
||||
} catch (Exception e) {
|
||||
throw new JsonIOException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return DefaultConstructorCreator.class.getSimpleName();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,118 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2008 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.google.gson;
|
||||
|
||||
import com.google.gson.internal.$Gson$Preconditions;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* A simple implementation of the {@link JsonElementVisitor} that simply delegates the method
|
||||
* invocation onto a {@code delegate} instance of the {@link JsonElementVisitor}. This object
|
||||
* can be used to build a chain of visitors such that each Visitor instance can perform some
|
||||
* operation on the {@link JsonElement} and then pass on the input to the delegate. This kind
|
||||
* of pattern is sometimes referred as a "Chain of Responsibility".
|
||||
*
|
||||
* <p>The following is an example use case:
|
||||
*
|
||||
* <pre>
|
||||
* class JsonEscapingVisitor extends DelegatingJsonElementVisitor {
|
||||
* public JsonEscapingVisitor(JsonElementVisitor) {
|
||||
* super(visitor);
|
||||
* }
|
||||
*
|
||||
* public void visitPrimitive(JsonPrimitive primitive) {
|
||||
* JsonPrimitive escapedPrimitive = escapePrimitiveObject(primitive);
|
||||
* super.visitPrimitive(escapedPrimitive);
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* JsonElementVisitor visitor = new JsonEscapingVisitor(new FormattingVisitor());
|
||||
* </pre></p>
|
||||
*
|
||||
* @author Joel Leitch
|
||||
*/
|
||||
final class DelegatingJsonElementVisitor implements JsonElementVisitor {
|
||||
private final JsonElementVisitor delegate;
|
||||
|
||||
protected DelegatingJsonElementVisitor(JsonElementVisitor delegate) {
|
||||
this.delegate = $Gson$Preconditions.checkNotNull(delegate);
|
||||
}
|
||||
|
||||
public void endArray(JsonArray array) throws IOException {
|
||||
delegate.endArray(array);
|
||||
}
|
||||
|
||||
public void endObject(JsonObject object) throws IOException {
|
||||
delegate.endObject(object);
|
||||
}
|
||||
|
||||
public void startArray(JsonArray array) throws IOException {
|
||||
delegate.startArray(array);
|
||||
}
|
||||
|
||||
public void startObject(JsonObject object) throws IOException {
|
||||
delegate.startObject(object);
|
||||
}
|
||||
|
||||
public void visitArrayMember(JsonArray parent, JsonPrimitive member,
|
||||
boolean isFirst) throws IOException {
|
||||
delegate.visitArrayMember(parent, member, isFirst);
|
||||
}
|
||||
|
||||
public void visitArrayMember(JsonArray parent, JsonArray member,
|
||||
boolean isFirst) throws IOException {
|
||||
delegate.visitArrayMember(parent, member, isFirst);
|
||||
}
|
||||
|
||||
public void visitArrayMember(JsonArray parent, JsonObject member,
|
||||
boolean isFirst) throws IOException {
|
||||
delegate.visitArrayMember(parent, member, isFirst);
|
||||
}
|
||||
|
||||
public void visitObjectMember(JsonObject parent, String memberName, JsonPrimitive member,
|
||||
boolean isFirst) throws IOException {
|
||||
delegate.visitObjectMember(parent, memberName, member, isFirst);
|
||||
}
|
||||
|
||||
public void visitObjectMember(JsonObject parent, String memberName, JsonArray member,
|
||||
boolean isFirst) throws IOException {
|
||||
delegate.visitObjectMember(parent, memberName, member, isFirst);
|
||||
}
|
||||
|
||||
public void visitObjectMember(JsonObject parent, String memberName, JsonObject member,
|
||||
boolean isFirst) throws IOException {
|
||||
delegate.visitObjectMember(parent, memberName, member, isFirst);
|
||||
}
|
||||
|
||||
public void visitNullObjectMember(JsonObject parent, String memberName,
|
||||
boolean isFirst) throws IOException {
|
||||
delegate.visitNullObjectMember(parent, memberName, isFirst);
|
||||
}
|
||||
|
||||
public void visitPrimitive(JsonPrimitive primitive) throws IOException {
|
||||
delegate.visitPrimitive(primitive);
|
||||
}
|
||||
|
||||
public void visitNull() throws IOException {
|
||||
delegate.visitNull();
|
||||
}
|
||||
|
||||
public void visitNullArrayMember(JsonArray parent, boolean isFirst) throws IOException {
|
||||
delegate.visitNullArrayMember(parent, isFirst);
|
||||
}
|
||||
}
|
@ -19,6 +19,7 @@ package com.google.gson;
|
||||
import com.google.gson.internal.$Gson$Preconditions;
|
||||
import com.google.gson.internal.$Gson$Types;
|
||||
|
||||
import com.google.gson.internal.Pair;
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Type;
|
||||
|
@ -16,15 +16,19 @@
|
||||
|
||||
package com.google.gson;
|
||||
|
||||
import com.google.gson.internal.ConstructorConstructor;
|
||||
import com.google.gson.internal.ParameterizedTypeHandlerMap;
|
||||
import com.google.gson.internal.Primitives;
|
||||
import com.google.gson.internal.Streams;
|
||||
import com.google.gson.internal.bind.ArrayTypeAdapter;
|
||||
import com.google.gson.internal.bind.BigDecimalTypeAdapter;
|
||||
import com.google.gson.internal.bind.BigIntegerTypeAdapter;
|
||||
import com.google.gson.internal.bind.CollectionTypeAdapter;
|
||||
import com.google.gson.internal.bind.GsonCompatibleMapTypeAdapter;
|
||||
import com.google.gson.internal.bind.CollectionTypeAdapterFactory;
|
||||
import com.google.gson.internal.bind.ExcludedTypeAdapterFactory;
|
||||
import com.google.gson.internal.bind.MapTypeAdapterFactory;
|
||||
import com.google.gson.internal.bind.MiniGson;
|
||||
import com.google.gson.internal.bind.ObjectTypeAdapter;
|
||||
import com.google.gson.internal.bind.ReflectiveTypeAdapter;
|
||||
import com.google.gson.internal.bind.ReflectiveTypeAdapterFactory;
|
||||
import com.google.gson.internal.bind.TypeAdapter;
|
||||
import com.google.gson.internal.bind.TypeAdapters;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
@ -32,7 +36,7 @@ import com.google.gson.stream.JsonReader;
|
||||
import com.google.gson.stream.JsonToken;
|
||||
import com.google.gson.stream.JsonWriter;
|
||||
import com.google.gson.stream.MalformedJsonException;
|
||||
|
||||
import java.io.EOFException;
|
||||
import java.io.IOException;
|
||||
import java.io.Reader;
|
||||
import java.io.StringReader;
|
||||
@ -113,7 +117,7 @@ public final class Gson {
|
||||
private final ExclusionStrategy deserializationExclusionStrategy;
|
||||
private final ExclusionStrategy serializationExclusionStrategy;
|
||||
private final FieldNamingStrategy2 fieldNamingPolicy;
|
||||
private final MappedObjectConstructor objectConstructor;
|
||||
private final ConstructorConstructor constructorConstructor;
|
||||
|
||||
/** Map containing Type or Class objects as keys */
|
||||
private final ParameterizedTypeHandlerMap<JsonSerializer<?>> serializers;
|
||||
@ -164,7 +168,7 @@ public final class Gson {
|
||||
*/
|
||||
public Gson() {
|
||||
this(DEFAULT_EXCLUSION_STRATEGY, DEFAULT_EXCLUSION_STRATEGY, DEFAULT_NAMING_POLICY,
|
||||
new MappedObjectConstructor(DefaultTypeAdapters.getDefaultInstanceCreators()),
|
||||
DefaultTypeAdapters.getDefaultInstanceCreators(),
|
||||
false, DefaultTypeAdapters.getAllDefaultSerializers(),
|
||||
DefaultTypeAdapters.getAllDefaultDeserializers(), DEFAULT_JSON_NON_EXECUTABLE, true, false,
|
||||
false, LongSerializationPolicy.DEFAULT);
|
||||
@ -173,7 +177,7 @@ public final class Gson {
|
||||
Gson(final ExclusionStrategy deserializationExclusionStrategy,
|
||||
final ExclusionStrategy serializationExclusionStrategy,
|
||||
final FieldNamingStrategy2 fieldNamingPolicy,
|
||||
final MappedObjectConstructor objectConstructor, boolean serializeNulls,
|
||||
final ParameterizedTypeHandlerMap<InstanceCreator<?>> instanceCreators, boolean serializeNulls,
|
||||
final ParameterizedTypeHandlerMap<JsonSerializer<?>> serializers,
|
||||
final ParameterizedTypeHandlerMap<JsonDeserializer<?>> deserializers,
|
||||
boolean generateNonExecutableGson, boolean htmlSafe, boolean prettyPrinting,
|
||||
@ -181,7 +185,7 @@ public final class Gson {
|
||||
this.deserializationExclusionStrategy = deserializationExclusionStrategy;
|
||||
this.serializationExclusionStrategy = serializationExclusionStrategy;
|
||||
this.fieldNamingPolicy = fieldNamingPolicy;
|
||||
this.objectConstructor = objectConstructor;
|
||||
this.constructorConstructor = new ConstructorConstructor(instanceCreators);
|
||||
this.serializeNulls = serializeNulls;
|
||||
this.serializers = serializers;
|
||||
this.deserializers = deserializers;
|
||||
@ -196,33 +200,24 @@ public final class Gson {
|
||||
serializeNulls
|
||||
serializers
|
||||
*/
|
||||
TypeAdapter.Factory reflectiveTypeAdapterFactory =
|
||||
new ReflectiveTypeAdapter.FactoryImpl() {
|
||||
TypeAdapter.Factory reflectiveTypeAdapterFactory
|
||||
= new ReflectiveTypeAdapterFactory(constructorConstructor) {
|
||||
@Override
|
||||
public String getFieldName(Class<?> declaringClazz, Field f, Type declaredType) {
|
||||
return fieldNamingPolicy.translateName(new FieldAttributes(declaringClazz, f, declaredType));
|
||||
}
|
||||
@Override
|
||||
public boolean serializeField(Class<?> declaringClazz, Field f, Type declaredType) {
|
||||
return !Gson.this.serializationExclusionStrategy.shouldSkipField(
|
||||
new FieldAttributes(declaringClazz, f, declaredType));
|
||||
ExclusionStrategy strategy = Gson.this.serializationExclusionStrategy;
|
||||
return !strategy.shouldSkipClass(f.getType())
|
||||
&& !strategy.shouldSkipField(new FieldAttributes(declaringClazz, f, declaredType));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean deserializeField(Class<?> declaringClazz, Field f, Type declaredType) {
|
||||
return !Gson.this.deserializationExclusionStrategy.shouldSkipField(
|
||||
new FieldAttributes(declaringClazz, f, declaredType));
|
||||
}
|
||||
};
|
||||
|
||||
TypeAdapter.Factory excludedTypeFactory = new TypeAdapter.Factory() {
|
||||
public <T> TypeAdapter<T> create(MiniGson context, TypeToken<T> type) {
|
||||
Class<?> rawType = type.getRawType();
|
||||
if (serializationExclusionStrategy.shouldSkipClass(rawType)
|
||||
|| deserializationExclusionStrategy.shouldSkipClass(rawType)) {
|
||||
return TypeAdapters.EXCLUDED_TYPE_ADAPTER;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
ExclusionStrategy strategy = Gson.this.deserializationExclusionStrategy;
|
||||
return !strategy.shouldSkipClass(f.getType())
|
||||
&& !strategy.shouldSkipField(new FieldAttributes(declaringClazz, f, declaredType));
|
||||
}
|
||||
};
|
||||
|
||||
@ -238,6 +233,8 @@ public final class Gson {
|
||||
doubleAdapter(serializeSpecialFloatingPointValues)))
|
||||
.factory(TypeAdapters.newFactory(float.class, Float.class,
|
||||
floatAdapter(serializeSpecialFloatingPointValues)))
|
||||
.factory(new ExcludedTypeAdapterFactory(
|
||||
serializationExclusionStrategy, deserializationExclusionStrategy))
|
||||
.factory(TypeAdapters.STRING_FACTORY)
|
||||
.factory(TypeAdapters.STRING_BUILDER_FACTORY)
|
||||
.factory(TypeAdapters.STRING_BUFFER_FACTORY)
|
||||
@ -248,11 +245,12 @@ public final class Gson {
|
||||
.factory(TypeAdapters.INET_ADDRESS_FACTORY)
|
||||
.typeAdapter(BigDecimal.class, new BigDecimalTypeAdapter())
|
||||
.typeAdapter(BigInteger.class, new BigIntegerTypeAdapter())
|
||||
.factory(excludedTypeFactory)
|
||||
.factory(GsonCompatibleMapTypeAdapter.FACTORY)
|
||||
.factory(CollectionTypeAdapter.FACTORY)
|
||||
.factory(new MapTypeAdapterFactory(constructorConstructor))
|
||||
.factory(new CollectionTypeAdapterFactory(constructorConstructor))
|
||||
.factory(ObjectTypeAdapter.FACTORY)
|
||||
.factory(new GsonToMiniGsonTypeAdapter(serializers, deserializers, serializeNulls))
|
||||
.factory(new GsonToMiniGsonTypeAdapterFactory(serializers, deserializers,
|
||||
new JsonDeserializationContext(this), new JsonSerializationContext(this), serializeNulls
|
||||
))
|
||||
.factory(ArrayTypeAdapter.FACTORY)
|
||||
.factory(reflectiveTypeAdapterFactory);
|
||||
|
||||
@ -265,9 +263,17 @@ public final class Gson {
|
||||
}
|
||||
return new TypeAdapter<Number>() {
|
||||
@Override public Double read(JsonReader reader) throws IOException {
|
||||
if (reader.peek() == JsonToken.NULL) {
|
||||
reader.nextNull(); // TODO: does this belong here?
|
||||
return null;
|
||||
}
|
||||
return reader.nextDouble();
|
||||
}
|
||||
@Override public void write(JsonWriter writer, Number value) throws IOException {
|
||||
if (value == null) {
|
||||
writer.nullValue(); // TODO: better policy here?
|
||||
return;
|
||||
}
|
||||
double doubleValue = value.doubleValue();
|
||||
checkValidFloatingPoint(doubleValue);
|
||||
writer.value(value);
|
||||
@ -281,9 +287,17 @@ public final class Gson {
|
||||
}
|
||||
return new TypeAdapter<Number>() {
|
||||
@Override public Float read(JsonReader reader) throws IOException {
|
||||
if (reader.peek() == JsonToken.NULL) {
|
||||
reader.nextNull(); // TODO: does this belong here?
|
||||
return null;
|
||||
}
|
||||
return (float) reader.nextDouble();
|
||||
}
|
||||
@Override public void write(JsonWriter writer, Number value) throws IOException {
|
||||
if (value == null) {
|
||||
writer.nullValue(); // TODO: better policy here?
|
||||
return;
|
||||
}
|
||||
float floatValue = value.floatValue();
|
||||
checkValidFloatingPoint(floatValue);
|
||||
writer.value(value);
|
||||
@ -305,9 +319,17 @@ public final class Gson {
|
||||
}
|
||||
return new TypeAdapter<Number>() {
|
||||
@Override public Number read(JsonReader reader) throws IOException {
|
||||
if (reader.peek() == JsonToken.NULL) {
|
||||
reader.nextNull(); // TODO: does this belong here?
|
||||
return null;
|
||||
}
|
||||
return reader.nextLong();
|
||||
}
|
||||
@Override public void write(JsonWriter writer, Number value) throws IOException {
|
||||
if (value == null) {
|
||||
writer.nullValue(); // TODO: better policy here?
|
||||
return;
|
||||
}
|
||||
writer.value(value.toString());
|
||||
}
|
||||
};
|
||||
@ -640,11 +662,23 @@ public final class Gson {
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> T fromJson(JsonReader reader, Type typeOfT) throws JsonIOException, JsonSyntaxException {
|
||||
boolean isEmpty = true;
|
||||
boolean oldLenient = reader.isLenient();
|
||||
reader.setLenient(true);
|
||||
try {
|
||||
reader.peek();
|
||||
isEmpty = false;
|
||||
TypeAdapter<T> typeAdapter = (TypeAdapter<T>) miniGson.getAdapter(TypeToken.get(typeOfT));
|
||||
return typeAdapter.read(reader);
|
||||
} catch (EOFException e) {
|
||||
/*
|
||||
* For compatibility with JSON 1.5 and earlier, we return null for empty
|
||||
* documents instead of throwing.
|
||||
*/
|
||||
if (isEmpty) {
|
||||
return null;
|
||||
}
|
||||
throw new JsonSyntaxException(e);
|
||||
} catch (IOException e) {
|
||||
// TODO(inder): Figure out whether it is indeed right to rethrow this as JsonSyntaxException
|
||||
throw new JsonSyntaxException(e);
|
||||
@ -710,8 +744,9 @@ public final class Gson {
|
||||
// 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(",instanceCreators:").append(constructorConstructor)
|
||||
.append("}");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -18,6 +18,8 @@ package com.google.gson;
|
||||
|
||||
import com.google.gson.DefaultTypeAdapters.DefaultDateTypeAdapter;
|
||||
import com.google.gson.internal.$Gson$Preconditions;
|
||||
import com.google.gson.internal.ParameterizedTypeHandlerMap;
|
||||
import com.google.gson.internal.Primitives;
|
||||
import java.lang.reflect.Type;
|
||||
import java.sql.Timestamp;
|
||||
import java.text.DateFormat;
|
||||
@ -678,6 +680,7 @@ public final class GsonBuilder {
|
||||
addTypeAdaptersForDate(datePattern, dateStyle, timeStyle, customSerializers,
|
||||
customDeserializers);
|
||||
|
||||
customSerializers.registerIfAbsent(DefaultTypeAdapters.getDefaultSerializers());
|
||||
customDeserializers.registerIfAbsent(DefaultTypeAdapters.getDefaultDeserializers());
|
||||
|
||||
ParameterizedTypeHandlerMap<InstanceCreator<?>> customInstanceCreators =
|
||||
@ -688,11 +691,9 @@ public final class GsonBuilder {
|
||||
customDeserializers.makeUnmodifiable();
|
||||
instanceCreators.makeUnmodifiable();
|
||||
|
||||
MappedObjectConstructor objConstructor = new MappedObjectConstructor(customInstanceCreators);
|
||||
|
||||
return new Gson(new DisjunctionExclusionStrategy(deserializationStrategies),
|
||||
new DisjunctionExclusionStrategy(serializationStrategies),
|
||||
fieldNamingPolicy, objConstructor, serializeNulls,
|
||||
fieldNamingPolicy, instanceCreators, serializeNulls,
|
||||
customSerializers, customDeserializers, generateNonExecutableJson, escapeHtmlChars,
|
||||
prettyPrinting, serializeSpecialFloatingPointValues, longSerializationPolicy);
|
||||
}
|
||||
|
@ -1,106 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2011 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.google.gson;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Type;
|
||||
|
||||
import com.google.gson.internal.Streams;
|
||||
import com.google.gson.internal.bind.MiniGson;
|
||||
import com.google.gson.internal.bind.TypeAdapter;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
import com.google.gson.stream.JsonReader;
|
||||
import com.google.gson.stream.JsonWriter;
|
||||
|
||||
final class GsonToMiniGsonTypeAdapter implements TypeAdapter.Factory {
|
||||
private final ParameterizedTypeHandlerMap<JsonSerializer<?>> serializers;
|
||||
private final ParameterizedTypeHandlerMap<JsonDeserializer<?>> deserializers;
|
||||
private final boolean serializeNulls;
|
||||
|
||||
GsonToMiniGsonTypeAdapter(ParameterizedTypeHandlerMap<JsonSerializer<?>> serializers,
|
||||
ParameterizedTypeHandlerMap<JsonDeserializer<?>> deserializers, boolean serializeNulls) {
|
||||
this.serializers = serializers;
|
||||
this.deserializers = deserializers;
|
||||
this.serializeNulls = serializeNulls;
|
||||
}
|
||||
|
||||
public <T> TypeAdapter<T> create(final MiniGson miniGson, TypeToken<T> type) {
|
||||
final Type typeOfT = type.getType();
|
||||
final JsonSerializer serializer = serializers.getHandlerFor(typeOfT, false);
|
||||
final JsonDeserializer deserializer = deserializers.getHandlerFor(typeOfT, false);
|
||||
if (serializer == null && deserializer == null) {
|
||||
return null;
|
||||
}
|
||||
return new TypeAdapter() {
|
||||
@Override
|
||||
public Object read(JsonReader reader) throws IOException {
|
||||
if (deserializer == null) {
|
||||
// TODO: handle if deserializer is null
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
JsonElement value = Streams.parse(reader);
|
||||
if (value.isJsonNull()) {
|
||||
return null;
|
||||
}
|
||||
return deserializer.deserialize(value, typeOfT, createDeserializationContext(miniGson));
|
||||
}
|
||||
@Override
|
||||
public void write(JsonWriter writer, Object value) throws IOException {
|
||||
if (serializer == null) {
|
||||
// TODO: handle if serializer is null
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
if (value == null) {
|
||||
writer.nullValue();
|
||||
return;
|
||||
}
|
||||
JsonElement element = serializer.serialize(value, typeOfT, createSerializationContext(miniGson));
|
||||
Streams.write(element, serializeNulls, writer);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public JsonSerializationContext createSerializationContext(final MiniGson miniGson) {
|
||||
return new JsonSerializationContext() {
|
||||
@Override
|
||||
JsonElement serialize(Object src, Type typeOfSrc, boolean preserveType, boolean defaultOnly) {
|
||||
TypeToken typeToken = TypeToken.get(typeOfSrc);
|
||||
return miniGson.getAdapter(typeToken).toJsonElement(src);
|
||||
}
|
||||
};
|
||||
}
|
||||
public JsonDeserializationContext createDeserializationContext(final MiniGson miniGson) {
|
||||
return new JsonDeserializationContext() {
|
||||
@Override
|
||||
public <T> T deserialize(JsonElement json, Type typeOfT) throws JsonParseException {
|
||||
TypeToken typeToken = TypeToken.get(typeOfT);
|
||||
return (T) miniGson.getAdapter(typeToken).fromJsonElement(json);
|
||||
}
|
||||
|
||||
@Override public <T> T construct(Type type) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override public Object constructArray(Type type, int length) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override public <T> T deserializeDefault(JsonElement json, Type typeOfT) throws JsonParseException {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
@ -0,0 +1,99 @@
|
||||
/*
|
||||
* Copyright (C) 2011 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.google.gson;
|
||||
|
||||
import com.google.gson.internal.ParameterizedTypeHandlerMap;
|
||||
import com.google.gson.internal.Streams;
|
||||
import com.google.gson.internal.bind.MiniGson;
|
||||
import com.google.gson.internal.bind.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.Type;
|
||||
|
||||
final class GsonToMiniGsonTypeAdapterFactory implements TypeAdapter.Factory {
|
||||
private final ParameterizedTypeHandlerMap<JsonSerializer<?>> serializers;
|
||||
private final ParameterizedTypeHandlerMap<JsonDeserializer<?>> deserializers;
|
||||
private final JsonDeserializationContext deserializationContext;
|
||||
private final JsonSerializationContext serializationContext;
|
||||
private final boolean serializeNulls;
|
||||
|
||||
GsonToMiniGsonTypeAdapterFactory(ParameterizedTypeHandlerMap<JsonSerializer<?>> serializers,
|
||||
ParameterizedTypeHandlerMap<JsonDeserializer<?>> deserializers,
|
||||
JsonDeserializationContext deserializationContext,
|
||||
JsonSerializationContext serializationContext, boolean serializeNulls) {
|
||||
this.serializers = serializers;
|
||||
this.deserializers = deserializers;
|
||||
this.serializeNulls = serializeNulls;
|
||||
this.deserializationContext = deserializationContext;
|
||||
this.serializationContext = serializationContext;
|
||||
}
|
||||
|
||||
public <T> TypeAdapter<T> create(final MiniGson context, final TypeToken<T> typeToken) {
|
||||
final Type type = typeToken.getType();
|
||||
|
||||
@SuppressWarnings("unchecked") // guaranteed to match typeOfT
|
||||
final JsonSerializer<T> serializer
|
||||
= (JsonSerializer<T>) serializers.getHandlerFor(type, false);
|
||||
@SuppressWarnings("unchecked") // guaranteed to match typeOfT
|
||||
final JsonDeserializer<T> deserializer
|
||||
= (JsonDeserializer<T>) deserializers.getHandlerFor(type, false);
|
||||
|
||||
if (serializer == null && deserializer == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return new TypeAdapter<T>() {
|
||||
/**
|
||||
* The delegate is lazily created because it may not be needed, and
|
||||
* creating it may fail.
|
||||
*/
|
||||
private TypeAdapter<T> delegate;
|
||||
|
||||
@Override public T read(JsonReader reader) throws IOException {
|
||||
if (deserializer == null) {
|
||||
return delegate().read(reader);
|
||||
}
|
||||
JsonElement value = Streams.parse(reader);
|
||||
if (value.isJsonNull()) {
|
||||
return null;
|
||||
}
|
||||
return deserializer.deserialize(value, type, deserializationContext);
|
||||
}
|
||||
|
||||
@Override public void write(JsonWriter writer, T value) throws IOException {
|
||||
if (serializer == null) {
|
||||
delegate().write(writer, value);
|
||||
return;
|
||||
}
|
||||
if (value == null) {
|
||||
writer.nullValue();
|
||||
return;
|
||||
}
|
||||
JsonElement element = serializer.serialize(value, type, serializationContext);
|
||||
Streams.write(element, serializeNulls, writer);
|
||||
}
|
||||
|
||||
private TypeAdapter<T> delegate() {
|
||||
TypeAdapter<T> d = delegate;
|
||||
return d != null
|
||||
? d
|
||||
: (delegate = context.getNextAdapter(GsonToMiniGsonTypeAdapterFactory.this, typeToken));
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
@ -1,111 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2008 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.google.gson;
|
||||
|
||||
import com.google.gson.internal.$Gson$Types;
|
||||
|
||||
import java.lang.reflect.Array;
|
||||
import java.lang.reflect.Type;
|
||||
|
||||
/**
|
||||
* A visitor that populates fields of an object with data from its equivalent
|
||||
* JSON representation
|
||||
*
|
||||
* @author Inderjeet Singh
|
||||
* @author Joel Leitch
|
||||
*/
|
||||
final class JsonArrayDeserializationVisitor<T> extends JsonDeserializationVisitor<T> {
|
||||
|
||||
JsonArrayDeserializationVisitor(JsonArray jsonArray, Type arrayType,
|
||||
ObjectNavigator objectNavigator, FieldNamingStrategy2 fieldNamingPolicy,
|
||||
ObjectConstructor objectConstructor,
|
||||
ParameterizedTypeHandlerMap<JsonDeserializer<?>> deserializers,
|
||||
JsonDeserializationContext context) {
|
||||
super(jsonArray, arrayType, objectNavigator, fieldNamingPolicy, objectConstructor, deserializers, context);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
protected T constructTarget() {
|
||||
if (!json.isJsonArray()) {
|
||||
throw new JsonParseException("Expecting array found: " + json);
|
||||
}
|
||||
JsonArray jsonArray = json.getAsJsonArray();
|
||||
if ($Gson$Types.isArray(targetType)) {
|
||||
// We know that we are getting back an array of the required type, so
|
||||
// this typecasting is safe.
|
||||
return (T) objectConstructor.constructArray($Gson$Types.getArrayComponentType(targetType),
|
||||
jsonArray.size());
|
||||
}
|
||||
// is a collection
|
||||
return (T) objectConstructor.construct($Gson$Types.getRawType(targetType));
|
||||
}
|
||||
|
||||
public void visitArray(Object array, Type arrayType) {
|
||||
if (!json.isJsonArray()) {
|
||||
throw new JsonParseException("Expecting array found: " + json);
|
||||
}
|
||||
JsonArray jsonArray = json.getAsJsonArray();
|
||||
for (int i = 0; i < jsonArray.size(); i++) {
|
||||
JsonElement jsonChild = jsonArray.get(i);
|
||||
Object child;
|
||||
|
||||
if (jsonChild == null || jsonChild.isJsonNull()) {
|
||||
child = null;
|
||||
} else if (jsonChild instanceof JsonObject) {
|
||||
child = visitChildAsObject($Gson$Types.getArrayComponentType(arrayType), jsonChild);
|
||||
} else if (jsonChild instanceof JsonArray) {
|
||||
child = visitChildAsArray($Gson$Types.getArrayComponentType(arrayType),
|
||||
jsonChild.getAsJsonArray());
|
||||
} else if (jsonChild instanceof JsonPrimitive) {
|
||||
child = visitChildAsObject($Gson$Types.getArrayComponentType(arrayType),
|
||||
jsonChild.getAsJsonPrimitive());
|
||||
} else {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
Array.set(array, i, child);
|
||||
}
|
||||
}
|
||||
|
||||
// We should not implement any other method from Visitor interface since
|
||||
// all other methods should be invoked on JsonObjectDeserializationVisitor
|
||||
// instead.
|
||||
|
||||
public void startVisitingObject(Object node) {
|
||||
throw new JsonParseException("Expecting array but found object: " + node);
|
||||
}
|
||||
|
||||
public void visitArrayField(FieldAttributes f, Type typeOfF, Object obj) {
|
||||
throw new JsonParseException("Expecting array but found array field " + f.getName() + ": "
|
||||
+ obj);
|
||||
}
|
||||
|
||||
public void visitObjectField(FieldAttributes f, Type typeOfF, Object obj) {
|
||||
throw new JsonParseException("Expecting array but found object field " + f.getName() + ": "
|
||||
+ obj);
|
||||
}
|
||||
|
||||
public boolean visitFieldUsingCustomHandler(FieldAttributes f, Type actualTypeOfField, Object parent) {
|
||||
throw new JsonParseException("Expecting array but found field " + f.getName() + ": "
|
||||
+ parent);
|
||||
}
|
||||
|
||||
public void visitPrimitive(Object primitive) {
|
||||
throw new JsonParseException(
|
||||
"Type information is unavailable, and the target is not a primitive: " + json);
|
||||
}
|
||||
}
|
@ -27,23 +27,10 @@ import java.lang.reflect.Type;
|
||||
* @author Joel Leitch
|
||||
*/
|
||||
public class JsonDeserializationContext {
|
||||
private final ObjectNavigator objectNavigator;
|
||||
private final FieldNamingStrategy2 fieldNamingPolicy;
|
||||
private final ParameterizedTypeHandlerMap<JsonDeserializer<?>> deserializers;
|
||||
private final MappedObjectConstructor objectConstructor;
|
||||
private final Gson gson;
|
||||
|
||||
JsonDeserializationContext(ObjectNavigator objectNavigator,
|
||||
FieldNamingStrategy2 fieldNamingPolicy,
|
||||
ParameterizedTypeHandlerMap<JsonDeserializer<?>> deserializers,
|
||||
MappedObjectConstructor objectConstructor) {
|
||||
this.objectNavigator = objectNavigator;
|
||||
this.fieldNamingPolicy = fieldNamingPolicy;
|
||||
this.deserializers = deserializers;
|
||||
this.objectConstructor = objectConstructor;
|
||||
}
|
||||
|
||||
JsonDeserializationContext() {
|
||||
this(null, null, null, null);
|
||||
JsonDeserializationContext(Gson gson) {
|
||||
this.gson = gson;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -51,41 +38,11 @@ public class JsonDeserializationContext {
|
||||
*/
|
||||
@SuppressWarnings("unchecked") @Deprecated
|
||||
public <T> T construct(Type type) {
|
||||
Object instance = objectConstructor.construct(type);
|
||||
return (T) instance;
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
public Object constructArray(Type type, int length) {
|
||||
return objectConstructor.constructArray(type, length);
|
||||
}
|
||||
|
||||
|
||||
private <T> T fromJsonArray(Type arrayType, JsonArray jsonArray,
|
||||
JsonDeserializationContext context, boolean systemOnly) throws JsonParseException {
|
||||
JsonArrayDeserializationVisitor<T> visitor = new JsonArrayDeserializationVisitor<T>(
|
||||
jsonArray, arrayType, objectNavigator, fieldNamingPolicy,
|
||||
objectConstructor, deserializers, context);
|
||||
objectNavigator.accept(new ObjectTypePair(null, arrayType, true, systemOnly), visitor);
|
||||
return visitor.getTarget();
|
||||
}
|
||||
|
||||
private <T> T fromJsonObject(Type typeOfT, JsonObject jsonObject,
|
||||
JsonDeserializationContext context, boolean systemOnly) throws JsonParseException {
|
||||
JsonObjectDeserializationVisitor<T> visitor = new JsonObjectDeserializationVisitor<T>(
|
||||
jsonObject, typeOfT, objectNavigator, fieldNamingPolicy,
|
||||
objectConstructor, deserializers, context);
|
||||
objectNavigator.accept(new ObjectTypePair(null, typeOfT, true, systemOnly), visitor);
|
||||
return visitor.getTarget();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private <T> T fromJsonPrimitive(Type typeOfT, JsonPrimitive json,
|
||||
JsonDeserializationContext context, boolean systemOnly) throws JsonParseException {
|
||||
JsonObjectDeserializationVisitor<T> visitor = new JsonObjectDeserializationVisitor<T>(
|
||||
json, typeOfT, objectNavigator, fieldNamingPolicy, objectConstructor, deserializers, context);
|
||||
objectNavigator.accept(new ObjectTypePair(json.getAsObject(), typeOfT, true, systemOnly), visitor);
|
||||
Object target = visitor.getTarget();
|
||||
return (T) target;
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -102,37 +59,11 @@ public class JsonDeserializationContext {
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> T deserialize(JsonElement json, Type typeOfT) throws JsonParseException {
|
||||
if (json == null || json.isJsonNull()) {
|
||||
return null;
|
||||
} else if (json.isJsonArray()) {
|
||||
Object array = fromJsonArray(typeOfT, json.getAsJsonArray(), this, false);
|
||||
return (T) array;
|
||||
} else if (json.isJsonObject()) {
|
||||
Object object = fromJsonObject(typeOfT, json.getAsJsonObject(), this, false);
|
||||
return (T) object;
|
||||
} else if (json.isJsonPrimitive()) {
|
||||
Object primitive = fromJsonPrimitive(typeOfT, json.getAsJsonPrimitive(), this, false);
|
||||
return (T) primitive;
|
||||
} else {
|
||||
throw new JsonParseException("Failed parsing JSON source: " + json + " to Json");
|
||||
}
|
||||
return gson.fromJson(json, typeOfT);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> T deserializeDefault(JsonElement json, Type typeOfT) throws JsonParseException {
|
||||
if (json == null || json.isJsonNull()) {
|
||||
return null;
|
||||
} else if (json.isJsonArray()) {
|
||||
Object array = fromJsonArray(typeOfT, json.getAsJsonArray(), this, true);
|
||||
return (T) array;
|
||||
} else if (json.isJsonObject()) {
|
||||
Object object = fromJsonObject(typeOfT, json.getAsJsonObject(), this, true);
|
||||
return (T) object;
|
||||
} else if (json.isJsonPrimitive()) {
|
||||
Object primitive = fromJsonPrimitive(typeOfT, json.getAsJsonPrimitive(), this, true);
|
||||
return (T) primitive;
|
||||
} else {
|
||||
throw new JsonParseException("Failed parsing JSON source: " + json + " to Json");
|
||||
}
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
@ -1,115 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2008 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.google.gson;
|
||||
|
||||
import com.google.gson.internal.$Gson$Preconditions;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
|
||||
/**
|
||||
* Abstract data value container for the {@link ObjectNavigator.Visitor}
|
||||
* implementations. This class exposes the {@link #getTarget()} method
|
||||
* which returns the class that was visited by this object.
|
||||
*
|
||||
* @author Inderjeet Singh
|
||||
* @author Joel Leitch
|
||||
*/
|
||||
abstract class JsonDeserializationVisitor<T> implements ObjectNavigator.Visitor {
|
||||
|
||||
protected final ObjectNavigator objectNavigator;
|
||||
protected final FieldNamingStrategy2 fieldNamingPolicy;
|
||||
protected final ObjectConstructor objectConstructor;
|
||||
protected final ParameterizedTypeHandlerMap<JsonDeserializer<?>> deserializers;
|
||||
protected T target;
|
||||
protected final JsonElement json;
|
||||
protected final Type targetType;
|
||||
protected final JsonDeserializationContext context;
|
||||
protected boolean constructed;
|
||||
|
||||
JsonDeserializationVisitor(JsonElement json, Type targetType,
|
||||
ObjectNavigator objectNavigator, FieldNamingStrategy2 fieldNamingPolicy,
|
||||
ObjectConstructor objectConstructor,
|
||||
ParameterizedTypeHandlerMap<JsonDeserializer<?>> deserializers,
|
||||
JsonDeserializationContext context) {
|
||||
this.targetType = targetType;
|
||||
this.objectNavigator = objectNavigator;
|
||||
this.fieldNamingPolicy = fieldNamingPolicy;
|
||||
this.objectConstructor = objectConstructor;
|
||||
this.deserializers = deserializers;
|
||||
this.json = $Gson$Preconditions.checkNotNull(json);
|
||||
this.context = context;
|
||||
this.constructed = false;
|
||||
}
|
||||
|
||||
public T getTarget() {
|
||||
if (!constructed) {
|
||||
target = constructTarget();
|
||||
constructed = true;
|
||||
}
|
||||
return target;
|
||||
}
|
||||
|
||||
protected abstract T constructTarget();
|
||||
|
||||
public void start(ObjectTypePair node) {
|
||||
}
|
||||
|
||||
public void end(ObjectTypePair node) {
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public final boolean visitUsingCustomHandler(ObjectTypePair objTypePair) {
|
||||
Pair<JsonDeserializer<?>, ObjectTypePair> pair = objTypePair.getMatchingHandler(deserializers);
|
||||
if (pair == null) {
|
||||
return false;
|
||||
}
|
||||
Object value = invokeCustomDeserializer(json, pair);
|
||||
target = (T) value;
|
||||
constructed = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
protected Object invokeCustomDeserializer(JsonElement element,
|
||||
Pair<JsonDeserializer<?>, ObjectTypePair> pair) {
|
||||
if (element == null || element.isJsonNull()) {
|
||||
return null;
|
||||
}
|
||||
Type objType = pair.second.type;
|
||||
return (pair.first).deserialize(element, objType, context);
|
||||
}
|
||||
|
||||
final Object visitChildAsObject(Type childType, JsonElement jsonChild) {
|
||||
JsonDeserializationVisitor<?> childVisitor =
|
||||
new JsonObjectDeserializationVisitor<Object>(jsonChild, childType,
|
||||
objectNavigator, fieldNamingPolicy, objectConstructor, deserializers, context);
|
||||
return visitChild(childType, childVisitor);
|
||||
}
|
||||
|
||||
final Object visitChildAsArray(Type childType, JsonArray jsonChild) {
|
||||
JsonDeserializationVisitor<?> childVisitor =
|
||||
new JsonArrayDeserializationVisitor<Object>(jsonChild.getAsJsonArray(), childType,
|
||||
objectNavigator, fieldNamingPolicy, objectConstructor, deserializers, context);
|
||||
return visitChild(childType, childVisitor);
|
||||
}
|
||||
|
||||
private Object visitChild(Type type, JsonDeserializationVisitor<?> childVisitor) {
|
||||
objectNavigator.accept(new ObjectTypePair(null, type, false, false), childVisitor);
|
||||
// the underlying object may have changed during the construction phase
|
||||
// This happens primarily because of custom deserializers
|
||||
return childVisitor.getTarget();
|
||||
}
|
||||
}
|
@ -143,7 +143,7 @@ public abstract class JsonElement {
|
||||
* more than a single element.
|
||||
*/
|
||||
public boolean getAsBoolean() {
|
||||
throw new UnsupportedOperationException();
|
||||
throw new UnsupportedOperationException(getClass().getSimpleName());
|
||||
}
|
||||
|
||||
/**
|
||||
@ -156,7 +156,7 @@ public abstract class JsonElement {
|
||||
* more than a single element.
|
||||
*/
|
||||
Boolean getAsBooleanWrapper() {
|
||||
throw new UnsupportedOperationException();
|
||||
throw new UnsupportedOperationException(getClass().getSimpleName());
|
||||
}
|
||||
|
||||
/**
|
||||
@ -169,7 +169,7 @@ public abstract class JsonElement {
|
||||
* more than a single element.
|
||||
*/
|
||||
public Number getAsNumber() {
|
||||
throw new UnsupportedOperationException();
|
||||
throw new UnsupportedOperationException(getClass().getSimpleName());
|
||||
}
|
||||
|
||||
/**
|
||||
@ -182,7 +182,7 @@ public abstract class JsonElement {
|
||||
* more than a single element.
|
||||
*/
|
||||
public String getAsString() {
|
||||
throw new UnsupportedOperationException();
|
||||
throw new UnsupportedOperationException(getClass().getSimpleName());
|
||||
}
|
||||
|
||||
/**
|
||||
@ -195,7 +195,7 @@ public abstract class JsonElement {
|
||||
* more than a single element.
|
||||
*/
|
||||
public double getAsDouble() {
|
||||
throw new UnsupportedOperationException();
|
||||
throw new UnsupportedOperationException(getClass().getSimpleName());
|
||||
}
|
||||
|
||||
/**
|
||||
@ -208,7 +208,7 @@ public abstract class JsonElement {
|
||||
* more than a single element.
|
||||
*/
|
||||
public float getAsFloat() {
|
||||
throw new UnsupportedOperationException();
|
||||
throw new UnsupportedOperationException(getClass().getSimpleName());
|
||||
}
|
||||
|
||||
/**
|
||||
@ -221,7 +221,7 @@ public abstract class JsonElement {
|
||||
* more than a single element.
|
||||
*/
|
||||
public long getAsLong() {
|
||||
throw new UnsupportedOperationException();
|
||||
throw new UnsupportedOperationException(getClass().getSimpleName());
|
||||
}
|
||||
|
||||
/**
|
||||
@ -234,7 +234,7 @@ public abstract class JsonElement {
|
||||
* more than a single element.
|
||||
*/
|
||||
public int getAsInt() {
|
||||
throw new UnsupportedOperationException();
|
||||
throw new UnsupportedOperationException(getClass().getSimpleName());
|
||||
}
|
||||
|
||||
/**
|
||||
@ -248,7 +248,7 @@ public abstract class JsonElement {
|
||||
* @since 1.3
|
||||
*/
|
||||
public byte getAsByte() {
|
||||
throw new UnsupportedOperationException();
|
||||
throw new UnsupportedOperationException(getClass().getSimpleName());
|
||||
}
|
||||
|
||||
/**
|
||||
@ -262,7 +262,7 @@ public abstract class JsonElement {
|
||||
* @since 1.3
|
||||
*/
|
||||
public char getAsCharacter() {
|
||||
throw new UnsupportedOperationException();
|
||||
throw new UnsupportedOperationException(getClass().getSimpleName());
|
||||
}
|
||||
|
||||
/**
|
||||
@ -276,7 +276,7 @@ public abstract class JsonElement {
|
||||
* @since 1.2
|
||||
*/
|
||||
public BigDecimal getAsBigDecimal() {
|
||||
throw new UnsupportedOperationException();
|
||||
throw new UnsupportedOperationException(getClass().getSimpleName());
|
||||
}
|
||||
|
||||
/**
|
||||
@ -290,7 +290,7 @@ public abstract class JsonElement {
|
||||
* @since 1.2
|
||||
*/
|
||||
public BigInteger getAsBigInteger() {
|
||||
throw new UnsupportedOperationException();
|
||||
throw new UnsupportedOperationException(getClass().getSimpleName());
|
||||
}
|
||||
|
||||
/**
|
||||
@ -303,7 +303,7 @@ public abstract class JsonElement {
|
||||
* more than a single element.
|
||||
*/
|
||||
public short getAsShort() {
|
||||
throw new UnsupportedOperationException();
|
||||
throw new UnsupportedOperationException(getClass().getSimpleName());
|
||||
}
|
||||
|
||||
/**
|
||||
@ -316,7 +316,7 @@ public abstract class JsonElement {
|
||||
* more than a single element.
|
||||
*/
|
||||
Object getAsObject() {
|
||||
throw new UnsupportedOperationException();
|
||||
throw new UnsupportedOperationException(getClass().getSimpleName());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1,136 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2008 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.google.gson;
|
||||
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
|
||||
/**
|
||||
* A visitor that populates fields of an object with data from its equivalent
|
||||
* JSON representation
|
||||
*
|
||||
* @author Inderjeet Singh
|
||||
* @author Joel Leitch
|
||||
*/
|
||||
final class JsonObjectDeserializationVisitor<T> extends JsonDeserializationVisitor<T> {
|
||||
|
||||
JsonObjectDeserializationVisitor(JsonElement json, Type type,
|
||||
ObjectNavigator objectNavigator, FieldNamingStrategy2 fieldNamingPolicy,
|
||||
ObjectConstructor objectConstructor,
|
||||
ParameterizedTypeHandlerMap<JsonDeserializer<?>> deserializers,
|
||||
JsonDeserializationContext context) {
|
||||
super(json, type, objectNavigator, fieldNamingPolicy, objectConstructor, deserializers, context);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
protected T constructTarget() {
|
||||
return (T) objectConstructor.construct(targetType);
|
||||
}
|
||||
|
||||
public void startVisitingObject(Object node) {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
public void visitArray(Object array, Type componentType) {
|
||||
// should not be called since this case should invoke JsonArrayDeserializationVisitor
|
||||
throw new JsonParseException("Expecting object but found array: " + array);
|
||||
}
|
||||
|
||||
public void visitObjectField(FieldAttributes f, Type typeOfF, Object obj) {
|
||||
try {
|
||||
if (!json.isJsonObject()) {
|
||||
throw new JsonParseException("Expecting object found: " + json);
|
||||
}
|
||||
JsonObject jsonObject = json.getAsJsonObject();
|
||||
String fName = getFieldName(f);
|
||||
JsonElement jsonChild = jsonObject.get(fName);
|
||||
if (jsonChild != null) {
|
||||
Object child = visitChildAsObject(typeOfF, jsonChild);
|
||||
f.set(obj, child);
|
||||
} else {
|
||||
f.set(obj, null);
|
||||
}
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public void visitArrayField(FieldAttributes f, Type typeOfF, Object obj) {
|
||||
try {
|
||||
if (!json.isJsonObject()) {
|
||||
throw new JsonParseException("Expecting object found: " + json);
|
||||
}
|
||||
JsonObject jsonObject = json.getAsJsonObject();
|
||||
String fName = getFieldName(f);
|
||||
JsonArray jsonChild = (JsonArray) jsonObject.get(fName);
|
||||
if (jsonChild != null) {
|
||||
Object array = visitChildAsArray(typeOfF, jsonChild);
|
||||
f.set(obj, array);
|
||||
} else {
|
||||
f.set(obj, null);
|
||||
}
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private String getFieldName(FieldAttributes f) {
|
||||
return fieldNamingPolicy.translateName(f);
|
||||
}
|
||||
|
||||
public boolean visitFieldUsingCustomHandler(FieldAttributes f, Type declaredTypeOfField, Object parent) {
|
||||
try {
|
||||
String fName = getFieldName(f);
|
||||
if (!json.isJsonObject()) {
|
||||
throw new JsonParseException("Expecting object found: " + json);
|
||||
}
|
||||
JsonElement child = json.getAsJsonObject().get(fName);
|
||||
boolean isPrimitive = Primitives.isPrimitive(declaredTypeOfField);
|
||||
if (child == null) { // Child will be null if the field wasn't present in Json
|
||||
return true;
|
||||
} else if (child.isJsonNull()) {
|
||||
if (!isPrimitive) {
|
||||
f.set(parent, null);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
ObjectTypePair objTypePair = new ObjectTypePair(null, declaredTypeOfField, false, false);
|
||||
Pair<JsonDeserializer<?>, ObjectTypePair> pair = objTypePair.getMatchingHandler(deserializers);
|
||||
if (pair == null) {
|
||||
return false;
|
||||
}
|
||||
Object value = invokeCustomDeserializer(child, pair);
|
||||
if (value != null || !isPrimitive) {
|
||||
f.set(parent, value);
|
||||
}
|
||||
return true;
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new RuntimeException();
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public void visitPrimitive(Object primitive) {
|
||||
if (!json.isJsonPrimitive()) {
|
||||
throw new JsonParseException(
|
||||
"Type information is unavailable, and the target object is not a primitive: " + json);
|
||||
}
|
||||
JsonPrimitive prim = json.getAsJsonPrimitive();
|
||||
target = (T) prim.getAsObject();
|
||||
}
|
||||
}
|
@ -27,24 +27,10 @@ import java.lang.reflect.Type;
|
||||
*/
|
||||
public class JsonSerializationContext {
|
||||
|
||||
private final ObjectNavigator objectNavigator;
|
||||
private final FieldNamingStrategy2 fieldNamingPolicy;
|
||||
private final ParameterizedTypeHandlerMap<JsonSerializer<?>> serializers;
|
||||
private final boolean serializeNulls;
|
||||
private final MemoryRefStack ancestors;
|
||||
private final Gson gson;
|
||||
|
||||
JsonSerializationContext(ObjectNavigator objectNavigator,
|
||||
FieldNamingStrategy2 fieldNamingPolicy, boolean serializeNulls,
|
||||
ParameterizedTypeHandlerMap<JsonSerializer<?>> serializers) {
|
||||
this.objectNavigator = objectNavigator;
|
||||
this.fieldNamingPolicy = fieldNamingPolicy;
|
||||
this.serializeNulls = serializeNulls;
|
||||
this.serializers = serializers;
|
||||
this.ancestors = new MemoryRefStack();
|
||||
}
|
||||
|
||||
JsonSerializationContext() {
|
||||
this(null, null, false, null);
|
||||
JsonSerializationContext(Gson gson) {
|
||||
this.gson = gson;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -54,10 +40,7 @@ public class JsonSerializationContext {
|
||||
* @return a tree of {@link JsonElement}s corresponding to the serialized form of {@code src}.
|
||||
*/
|
||||
public JsonElement serialize(Object src) {
|
||||
if (src == null) {
|
||||
return JsonNull.INSTANCE;
|
||||
}
|
||||
return serialize(src, src.getClass(), false, false);
|
||||
return gson.toJsonTree(src);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -71,21 +54,10 @@ public class JsonSerializationContext {
|
||||
* @return a tree of {@link JsonElement}s corresponding to the serialized form of {@code src}.
|
||||
*/
|
||||
public JsonElement serialize(Object src, Type typeOfSrc) {
|
||||
return serialize(src, typeOfSrc, true, false);
|
||||
return gson.toJsonTree(src, typeOfSrc);
|
||||
}
|
||||
|
||||
public JsonElement serializeDefault(Object src, Type typeOfSrc) {
|
||||
return serialize(src, typeOfSrc, true, true);
|
||||
}
|
||||
|
||||
JsonElement serialize(Object src, Type typeOfSrc, boolean preserveType, boolean defaultOnly) {
|
||||
if (src == null) {
|
||||
return JsonNull.INSTANCE;
|
||||
}
|
||||
JsonSerializationVisitor visitor = new JsonSerializationVisitor(
|
||||
objectNavigator, fieldNamingPolicy, serializeNulls, serializers, this, ancestors);
|
||||
ObjectTypePair objTypePair = new ObjectTypePair(src, typeOfSrc, preserveType, defaultOnly);
|
||||
objectNavigator.accept(objTypePair, visitor);
|
||||
return visitor.getJsonElement();
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
@ -1,236 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2008 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.google.gson;
|
||||
|
||||
import com.google.gson.internal.$Gson$Types;
|
||||
import com.google.gson.internal.$Gson$Preconditions;
|
||||
|
||||
import java.lang.reflect.Array;
|
||||
import java.lang.reflect.Type;
|
||||
|
||||
/**
|
||||
* A visitor that adds JSON elements corresponding to each field of an object
|
||||
*
|
||||
* @author Inderjeet Singh
|
||||
* @author Joel Leitch
|
||||
*/
|
||||
final class JsonSerializationVisitor implements ObjectNavigator.Visitor {
|
||||
|
||||
private final ObjectNavigator objectNavigator;
|
||||
private final FieldNamingStrategy2 fieldNamingPolicy;
|
||||
private final ParameterizedTypeHandlerMap<JsonSerializer<?>> serializers;
|
||||
private final boolean serializeNulls;
|
||||
private final JsonSerializationContext context;
|
||||
private final MemoryRefStack ancestors;
|
||||
private JsonElement root;
|
||||
|
||||
JsonSerializationVisitor(ObjectNavigator objectNavigator, FieldNamingStrategy2 fieldNamingPolicy,
|
||||
boolean serializeNulls, ParameterizedTypeHandlerMap<JsonSerializer<?>> serializers,
|
||||
JsonSerializationContext context, MemoryRefStack ancestors) {
|
||||
this.objectNavigator = objectNavigator;
|
||||
this.fieldNamingPolicy = fieldNamingPolicy;
|
||||
this.serializeNulls = serializeNulls;
|
||||
this.serializers = serializers;
|
||||
this.context = context;
|
||||
this.ancestors = ancestors;
|
||||
}
|
||||
|
||||
public Object getTarget() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public void start(ObjectTypePair node) {
|
||||
if (node == null || node.isSystemOnly()) {
|
||||
return;
|
||||
}
|
||||
if (ancestors.contains(node)) {
|
||||
throw new CircularReferenceException(node);
|
||||
}
|
||||
ancestors.push(node);
|
||||
}
|
||||
|
||||
public void end(ObjectTypePair node) {
|
||||
if (node != null && !node.isSystemOnly()) {
|
||||
ancestors.pop();
|
||||
}
|
||||
}
|
||||
|
||||
public void startVisitingObject(Object node) {
|
||||
assignToRoot(new JsonObject());
|
||||
}
|
||||
|
||||
public void visitArray(Object array, Type arrayType) {
|
||||
assignToRoot(new JsonArray());
|
||||
int length = Array.getLength(array);
|
||||
Type componentType = $Gson$Types.getArrayComponentType(arrayType);
|
||||
for (int i = 0; i < length; ++i) {
|
||||
Object child = Array.get(array, i);
|
||||
// we should not get more specific component type yet since it is possible
|
||||
// that a custom serializer is registered for the componentType
|
||||
addAsArrayElement(new ObjectTypePair(child, componentType, false, false));
|
||||
}
|
||||
}
|
||||
|
||||
public void visitArrayField(FieldAttributes f, Type typeOfF, Object obj) {
|
||||
try {
|
||||
if (isFieldNull(f, obj)) {
|
||||
if (serializeNulls) {
|
||||
addChildAsElement(f, JsonNull.INSTANCE);
|
||||
}
|
||||
} else {
|
||||
Object array = getFieldValue(f, obj);
|
||||
addAsChildOfObject(f, new ObjectTypePair(array, typeOfF, false, false));
|
||||
}
|
||||
} catch (CircularReferenceException e) {
|
||||
throw e.createDetailedException(f);
|
||||
}
|
||||
}
|
||||
|
||||
public void visitObjectField(FieldAttributes f, Type typeOfF, Object obj) {
|
||||
try {
|
||||
if (isFieldNull(f, obj)) {
|
||||
if (serializeNulls) {
|
||||
addChildAsElement(f, JsonNull.INSTANCE);
|
||||
}
|
||||
} else {
|
||||
Object fieldValue = getFieldValue(f, obj);
|
||||
// we should not get more specific component type yet since it is
|
||||
// possible that a custom
|
||||
// serializer is registered for the componentType
|
||||
addAsChildOfObject(f, new ObjectTypePair(fieldValue, typeOfF, false, false));
|
||||
}
|
||||
} catch (CircularReferenceException e) {
|
||||
throw e.createDetailedException(f);
|
||||
}
|
||||
}
|
||||
|
||||
public void visitPrimitive(Object obj) {
|
||||
JsonElement json = obj == null ? JsonNull.INSTANCE : new JsonPrimitive(obj);
|
||||
assignToRoot(json);
|
||||
}
|
||||
|
||||
private void addAsChildOfObject(FieldAttributes f, ObjectTypePair fieldValuePair) {
|
||||
JsonElement childElement = getJsonElementForChild(fieldValuePair);
|
||||
addChildAsElement(f, childElement);
|
||||
}
|
||||
|
||||
private void addChildAsElement(FieldAttributes f, JsonElement childElement) {
|
||||
root.getAsJsonObject().add(fieldNamingPolicy.translateName(f), childElement);
|
||||
}
|
||||
|
||||
private void addAsArrayElement(ObjectTypePair elementTypePair) {
|
||||
if (elementTypePair.getObject() == null) {
|
||||
root.getAsJsonArray().add(JsonNull.INSTANCE);
|
||||
} else {
|
||||
JsonElement childElement = getJsonElementForChild(elementTypePair);
|
||||
root.getAsJsonArray().add(childElement);
|
||||
}
|
||||
}
|
||||
|
||||
private JsonElement getJsonElementForChild(ObjectTypePair fieldValueTypePair) {
|
||||
JsonSerializationVisitor childVisitor = new JsonSerializationVisitor(
|
||||
objectNavigator, fieldNamingPolicy, serializeNulls, serializers, context, ancestors);
|
||||
objectNavigator.accept(fieldValueTypePair, childVisitor);
|
||||
return childVisitor.getJsonElement();
|
||||
}
|
||||
|
||||
public boolean visitUsingCustomHandler(ObjectTypePair objTypePair) {
|
||||
try {
|
||||
Object obj = objTypePair.getObject();
|
||||
if (obj == null) {
|
||||
if (serializeNulls) {
|
||||
assignToRoot(JsonNull.INSTANCE);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
JsonElement element = findAndInvokeCustomSerializer(objTypePair);
|
||||
if (element != null) {
|
||||
assignToRoot(element);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
} catch (CircularReferenceException e) {
|
||||
throw e.createDetailedException(null);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* objTypePair.getObject() must not be null
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
private JsonElement findAndInvokeCustomSerializer(ObjectTypePair objTypePair) {
|
||||
Pair<JsonSerializer<?>,ObjectTypePair> pair = objTypePair.getMatchingHandler(serializers);
|
||||
if (pair == null) {
|
||||
return null;
|
||||
}
|
||||
JsonSerializer serializer = pair.first;
|
||||
objTypePair = pair.second;
|
||||
start(objTypePair);
|
||||
try {
|
||||
JsonElement element =
|
||||
serializer.serialize(objTypePair.getObject(), objTypePair.getType(), context);
|
||||
return element == null ? JsonNull.INSTANCE : element;
|
||||
} finally {
|
||||
end(objTypePair);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean visitFieldUsingCustomHandler(
|
||||
FieldAttributes f, Type declaredTypeOfField, Object parent) {
|
||||
try {
|
||||
$Gson$Preconditions.checkState(root.isJsonObject());
|
||||
Object obj = f.get(parent);
|
||||
if (obj == null) {
|
||||
if (serializeNulls) {
|
||||
addChildAsElement(f, JsonNull.INSTANCE);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
ObjectTypePair objTypePair = new ObjectTypePair(obj, declaredTypeOfField, false, false);
|
||||
JsonElement child = findAndInvokeCustomSerializer(objTypePair);
|
||||
if (child != null) {
|
||||
addChildAsElement(f, child);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new RuntimeException();
|
||||
} catch (CircularReferenceException e) {
|
||||
throw e.createDetailedException(f);
|
||||
}
|
||||
}
|
||||
|
||||
private void assignToRoot(JsonElement newRoot) {
|
||||
root = $Gson$Preconditions.checkNotNull(newRoot);
|
||||
}
|
||||
|
||||
private boolean isFieldNull(FieldAttributes f, Object obj) {
|
||||
return getFieldValue(f, obj) == null;
|
||||
}
|
||||
|
||||
private Object getFieldValue(FieldAttributes f, Object obj) {
|
||||
try {
|
||||
return f.get(obj);
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public JsonElement getJsonElement() {
|
||||
return root;
|
||||
}
|
||||
}
|
@ -1,111 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2008 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.google.gson;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* A navigator to navigate a tree of JsonElement nodes in Depth-first order
|
||||
*
|
||||
* @author Inderjeet Singh
|
||||
*/
|
||||
final class JsonTreeNavigator {
|
||||
private final JsonElementVisitor visitor;
|
||||
private final boolean visitNulls;
|
||||
|
||||
JsonTreeNavigator(JsonElementVisitor visitor, boolean visitNulls) {
|
||||
this.visitor = visitor;
|
||||
this.visitNulls = visitNulls;
|
||||
}
|
||||
|
||||
public void navigate(JsonElement element) throws IOException {
|
||||
if (element.isJsonNull()) {
|
||||
visitor.visitNull();
|
||||
} else if (element.isJsonArray()) {
|
||||
JsonArray array = element.getAsJsonArray();
|
||||
visitor.startArray(array);
|
||||
boolean isFirst = true;
|
||||
for (JsonElement child : array) {
|
||||
visitChild(array, child, isFirst);
|
||||
if (isFirst) {
|
||||
isFirst = false;
|
||||
}
|
||||
}
|
||||
visitor.endArray(array);
|
||||
} else if (element.isJsonObject()) {
|
||||
JsonObject object = element.getAsJsonObject();
|
||||
visitor.startObject(object);
|
||||
boolean isFirst = true;
|
||||
for (Map.Entry<String, JsonElement> member : object.entrySet()) {
|
||||
boolean visited = visitChild(object, member.getKey(), member.getValue(), isFirst);
|
||||
if (visited && isFirst) {
|
||||
isFirst = false;
|
||||
}
|
||||
}
|
||||
visitor.endObject(object);
|
||||
} else { // must be JsonPrimitive
|
||||
visitor.visitPrimitive(element.getAsJsonPrimitive());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the child was visited, false if it was skipped.
|
||||
*/
|
||||
private boolean visitChild(JsonObject parent, String childName, JsonElement child,
|
||||
boolean isFirst) throws IOException {
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.isJsonNull()) {
|
||||
visitor.visitNullArrayMember(parent, isFirst);
|
||||
navigate(child);
|
||||
} else if (child.isJsonArray()) {
|
||||
JsonArray childAsArray = child.getAsJsonArray();
|
||||
visitor.visitArrayMember(parent, childAsArray, isFirst);
|
||||
navigate(childAsArray);
|
||||
} else if (child.isJsonObject()) {
|
||||
JsonObject childAsObject = child.getAsJsonObject();
|
||||
visitor.visitArrayMember(parent, childAsObject, isFirst);
|
||||
navigate(childAsObject);
|
||||
} else { // is a JsonPrimitive
|
||||
visitor.visitArrayMember(parent, child.getAsJsonPrimitive(), isFirst);
|
||||
}
|
||||
}
|
||||
}
|
@ -16,10 +16,7 @@
|
||||
|
||||
package com.google.gson;
|
||||
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
@ -90,79 +87,16 @@ import java.util.Map;
|
||||
* object.
|
||||
*/
|
||||
final class MapAsArrayTypeAdapter
|
||||
extends BaseMapTypeAdapter
|
||||
implements JsonSerializer<Map<?, ?>>, JsonDeserializer<Map<?, ?>> {
|
||||
|
||||
public Map<?, ?> deserialize(JsonElement json, Type typeOfT,
|
||||
JsonDeserializationContext context) throws JsonParseException {
|
||||
Map<Object, Object> result = constructMapType(typeOfT, context);
|
||||
Type[] keyAndValueType = typeToTypeArguments(typeOfT);
|
||||
if (json.isJsonArray()) {
|
||||
JsonArray array = json.getAsJsonArray();
|
||||
for (int i = 0; i < array.size(); i++) {
|
||||
JsonArray entryArray = array.get(i).getAsJsonArray();
|
||||
Object k = context.deserialize(entryArray.get(0), keyAndValueType[0]);
|
||||
Object v = context.deserialize(entryArray.get(1), keyAndValueType[1]);
|
||||
result.put(k, v);
|
||||
}
|
||||
checkSize(array, array.size(), result, result.size());
|
||||
} else {
|
||||
JsonObject object = json.getAsJsonObject();
|
||||
for (Map.Entry<String, JsonElement> entry : object.entrySet()) {
|
||||
Object k = context.deserialize(new JsonPrimitive(entry.getKey()), keyAndValueType[0]);
|
||||
Object v = context.deserialize(entry.getValue(), keyAndValueType[1]);
|
||||
result.put(k, v);
|
||||
}
|
||||
checkSize(object, object.entrySet().size(), result, result.size());
|
||||
}
|
||||
return result;
|
||||
// TODO
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
public JsonElement serialize(Map<?, ?> src, Type typeOfSrc, JsonSerializationContext context) {
|
||||
Type[] keyAndValueType = typeToTypeArguments(typeOfSrc);
|
||||
boolean serializeAsArray = false;
|
||||
List<JsonElement> keysAndValues = new ArrayList<JsonElement>();
|
||||
for (Map.Entry<?, ?> entry : src.entrySet()) {
|
||||
JsonElement key = serialize(context, entry.getKey(), keyAndValueType[0]);
|
||||
serializeAsArray |= key.isJsonObject() || key.isJsonArray();
|
||||
keysAndValues.add(key);
|
||||
keysAndValues.add(serialize(context, entry.getValue(), keyAndValueType[1]));
|
||||
}
|
||||
|
||||
if (serializeAsArray) {
|
||||
JsonArray result = new JsonArray();
|
||||
for (int i = 0; i < keysAndValues.size(); i+=2) {
|
||||
JsonArray entryArray = new JsonArray();
|
||||
entryArray.add(keysAndValues.get(i));
|
||||
entryArray.add(keysAndValues.get(i + 1));
|
||||
result.add(entryArray);
|
||||
}
|
||||
return result;
|
||||
} else {
|
||||
JsonObject result = new JsonObject();
|
||||
for (int i = 0; i < keysAndValues.size(); i+=2) {
|
||||
result.add(keysAndValues.get(i).getAsString(), keysAndValues.get(i + 1));
|
||||
}
|
||||
checkSize(src, src.size(), result, result.entrySet().size());
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
private Type[] typeToTypeArguments(Type typeOfT) {
|
||||
if (typeOfT instanceof ParameterizedType) {
|
||||
Type[] typeArguments = ((ParameterizedType) typeOfT).getActualTypeArguments();
|
||||
if (typeArguments.length != 2) {
|
||||
throw new IllegalArgumentException("MapAsArrayTypeAdapter cannot handle " + typeOfT);
|
||||
}
|
||||
return typeArguments;
|
||||
}
|
||||
return new Type[] { Object.class, Object.class };
|
||||
}
|
||||
|
||||
private void checkSize(Object input, int inputSize, Object output, int outputSize) {
|
||||
if (inputSize != outputSize) {
|
||||
throw new JsonSyntaxException("Input size " + inputSize + " != output size " + outputSize
|
||||
+ " for input " + input + " and output " + output);
|
||||
}
|
||||
// TODO
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
|
@ -1,78 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2011 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.google.gson;
|
||||
|
||||
import com.google.gson.internal.$Gson$Types;
|
||||
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Default serialization and deserialization of a map type. This implementation really only works
|
||||
* well with simple primitive types as the map key. If the key is not a simple primitive then the
|
||||
* object is {@code toString}ed and that value is used as its key.
|
||||
*
|
||||
* @author Joel Leitch
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
final class MapTypeAdapter extends BaseMapTypeAdapter {
|
||||
|
||||
public JsonElement serialize(Map src, Type typeOfSrc, JsonSerializationContext context) {
|
||||
JsonObject map = new JsonObject();
|
||||
Type childGenericType = null;
|
||||
if (typeOfSrc instanceof ParameterizedType) {
|
||||
Class<?> rawTypeOfSrc = $Gson$Types.getRawType(typeOfSrc);
|
||||
childGenericType = $Gson$Types.getMapKeyAndValueTypes(typeOfSrc, rawTypeOfSrc)[1];
|
||||
}
|
||||
|
||||
for (Map.Entry entry : (Set<Map.Entry>) src.entrySet()) {
|
||||
Object value = entry.getValue();
|
||||
|
||||
JsonElement valueElement;
|
||||
if (value == null) {
|
||||
valueElement = JsonNull.INSTANCE;
|
||||
} else {
|
||||
Type childType = (childGenericType == null)
|
||||
? value.getClass() : childGenericType;
|
||||
valueElement = serialize(context, value, childType);
|
||||
}
|
||||
map.add(String.valueOf(entry.getKey()), valueElement);
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
public Map deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
|
||||
throws JsonParseException {
|
||||
// Use ObjectConstructor to create instance instead of hard-coding a specific type.
|
||||
// This handles cases where users are using their own subclass of Map.
|
||||
Map<Object, Object> map = constructMapType(typeOfT, context);
|
||||
Type[] keyAndValueTypes = $Gson$Types.getMapKeyAndValueTypes(typeOfT, $Gson$Types.getRawType(typeOfT));
|
||||
for (Map.Entry<String, JsonElement> entry : json.getAsJsonObject().entrySet()) {
|
||||
Object key = context.deserialize(new JsonPrimitive(entry.getKey()), keyAndValueTypes[0]);
|
||||
Object value = context.deserialize(entry.getValue(), keyAndValueTypes[1]);
|
||||
map.put(key, value);
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return MapTypeAdapter.class.getSimpleName();
|
||||
}
|
||||
}
|
@ -1,78 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2008 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.google.gson;
|
||||
|
||||
import com.google.gson.internal.$Gson$Types;
|
||||
|
||||
import com.google.gson.internal.UnsafeAllocator;
|
||||
import java.lang.reflect.Array;
|
||||
import java.lang.reflect.Type;
|
||||
|
||||
/**
|
||||
* This class contains a mapping of all the application specific
|
||||
* {@link InstanceCreator} instances. Registering an {@link InstanceCreator}
|
||||
* with this class will override the default object creation that is defined
|
||||
* by the ObjectConstructor that this class is wrapping. Using this class
|
||||
* with the JSON framework provides the application with "pluggable" modules
|
||||
* to customize framework to suit the application's needs.
|
||||
*
|
||||
* @author Joel Leitch
|
||||
*/
|
||||
final class MappedObjectConstructor implements ObjectConstructor {
|
||||
private static final UnsafeAllocator unsafeAllocator = UnsafeAllocator.create();
|
||||
private static final DefaultConstructorAllocator defaultConstructorAllocator =
|
||||
new DefaultConstructorAllocator(500);
|
||||
|
||||
private final ParameterizedTypeHandlerMap<InstanceCreator<?>> instanceCreatorMap;
|
||||
|
||||
public MappedObjectConstructor(
|
||||
ParameterizedTypeHandlerMap<InstanceCreator<?>> instanceCreators) {
|
||||
instanceCreatorMap = instanceCreators;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> T construct(Type typeOfT) {
|
||||
InstanceCreator<T> creator = (InstanceCreator<T>) instanceCreatorMap.getHandlerFor(typeOfT, false);
|
||||
if (creator != null) {
|
||||
return creator.createInstance(typeOfT);
|
||||
}
|
||||
return (T) constructWithAllocators(typeOfT);
|
||||
}
|
||||
|
||||
public Object constructArray(Type type, int length) {
|
||||
return Array.newInstance($Gson$Types.getRawType(type), length);
|
||||
}
|
||||
|
||||
@SuppressWarnings({"unchecked", "cast"})
|
||||
private <T> T constructWithAllocators(Type typeOfT) {
|
||||
try {
|
||||
Class<T> clazz = (Class<T>) $Gson$Types.getRawType(typeOfT);
|
||||
T obj = defaultConstructorAllocator.newInstance(clazz);
|
||||
return (obj == null)
|
||||
? unsafeAllocator.newInstance(clazz)
|
||||
: obj;
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(("Unable to invoke no-args constructor for " + typeOfT + ". "
|
||||
+ "Register an InstanceCreator with Gson for this type may fix this problem."), e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return instanceCreatorMap.toString();
|
||||
}
|
||||
}
|
@ -1,88 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2008 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.google.gson;
|
||||
|
||||
import com.google.gson.internal.$Gson$Preconditions;
|
||||
|
||||
import java.util.Stack;
|
||||
|
||||
/**
|
||||
* A stack data structure that only does a memory reference comparison
|
||||
* when looking for a particular item in the stack. This stack does
|
||||
* not allow {@code null} values to be added.
|
||||
*
|
||||
* @author Joel Leitch
|
||||
*/
|
||||
final class MemoryRefStack {
|
||||
private final Stack<ObjectTypePair> stack = new Stack<ObjectTypePair>();
|
||||
|
||||
/**
|
||||
* Adds a new element to the top of the stack.
|
||||
*
|
||||
* @param obj the object to add to the stack
|
||||
* @return the object that was added
|
||||
*/
|
||||
public ObjectTypePair push(ObjectTypePair obj) {
|
||||
$Gson$Preconditions.checkNotNull(obj);
|
||||
return stack.push(obj);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the top element from the stack.
|
||||
*
|
||||
* @return the element being removed from the stack
|
||||
* @throws java.util.EmptyStackException thrown if the stack is empty
|
||||
*/
|
||||
public ObjectTypePair pop() {
|
||||
return stack.pop();
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
return stack.isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the item from the top of the stack, but does not remove it.
|
||||
*
|
||||
* @return the item from the top of the stack
|
||||
* @throws java.util.EmptyStackException thrown if the stack is empty
|
||||
*/
|
||||
public ObjectTypePair peek() {
|
||||
return stack.peek();
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs a memory reference check to see it the {@code obj} exists in
|
||||
* the stack.
|
||||
*
|
||||
* @param obj the object to search for in the stack
|
||||
* @return true if this object is already in the stack otherwise false
|
||||
*/
|
||||
public boolean contains(ObjectTypePair obj) {
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (ObjectTypePair stackObject : stack) {
|
||||
if (stackObject.getObject() == obj.getObject()
|
||||
&& stackObject.type.equals(obj.type) ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
@ -1,36 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2008 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.google.gson;
|
||||
|
||||
/**
|
||||
* This acts as a "Null Object" pattern for the {@link ExclusionStrategy}.
|
||||
* Passing an instance of this class into the {@link ObjectNavigator} will
|
||||
* make the {@link ObjectNavigator} parse/visit every field of the object
|
||||
* being navigated.
|
||||
*
|
||||
* @author Joel Leitch
|
||||
*/
|
||||
final class NullExclusionStrategy implements ExclusionStrategy {
|
||||
|
||||
public boolean shouldSkipField(FieldAttributes f) {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean shouldSkipClass(Class<?> clazz) {
|
||||
return false;
|
||||
}
|
||||
}
|
@ -1,134 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2008 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.google.gson;
|
||||
|
||||
import com.google.gson.internal.$Gson$Types;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
|
||||
/**
|
||||
* Provides ability to apply a visitor to an object and all of its fields
|
||||
* recursively.
|
||||
*
|
||||
* @author Inderjeet Singh
|
||||
* @author Joel Leitch
|
||||
*/
|
||||
final class ObjectNavigator {
|
||||
|
||||
public interface Visitor {
|
||||
public void start(ObjectTypePair node);
|
||||
|
||||
public void end(ObjectTypePair node);
|
||||
|
||||
/**
|
||||
* This is called before the object navigator starts visiting the current
|
||||
* object
|
||||
*/
|
||||
void startVisitingObject(Object node);
|
||||
|
||||
/**
|
||||
* This is called to visit the current object if it is an array
|
||||
*/
|
||||
void visitArray(Object array, Type componentType);
|
||||
|
||||
/**
|
||||
* This is called to visit an object field of the current object
|
||||
*/
|
||||
void visitObjectField(FieldAttributes f, Type typeOfF, Object obj);
|
||||
|
||||
/**
|
||||
* This is called to visit an array field of the current object
|
||||
*/
|
||||
void visitArrayField(FieldAttributes f, Type typeOfF, Object obj);
|
||||
|
||||
/**
|
||||
* This is called to visit an object using a custom handler
|
||||
*
|
||||
* @return true if a custom handler exists, false otherwise
|
||||
*/
|
||||
public boolean visitUsingCustomHandler(ObjectTypePair objTypePair);
|
||||
|
||||
/**
|
||||
* This is called to visit a field of the current object using a custom
|
||||
* handler
|
||||
*/
|
||||
public boolean visitFieldUsingCustomHandler(FieldAttributes f, Type actualTypeOfField,
|
||||
Object parent);
|
||||
|
||||
void visitPrimitive(Object primitive);
|
||||
|
||||
/**
|
||||
* Retrieve the current target
|
||||
*/
|
||||
Object getTarget();
|
||||
}
|
||||
|
||||
private final ExclusionStrategy exclusionStrategy;
|
||||
private final ReflectingFieldNavigator reflectingFieldNavigator;
|
||||
|
||||
/**
|
||||
* @param strategy the concrete exclusion strategy object to be used to filter out fields of an
|
||||
* object.
|
||||
*/
|
||||
ObjectNavigator(ExclusionStrategy strategy) {
|
||||
this.exclusionStrategy = strategy == null ? new NullExclusionStrategy() : strategy;
|
||||
this.reflectingFieldNavigator = new ReflectingFieldNavigator(exclusionStrategy);
|
||||
}
|
||||
|
||||
/**
|
||||
* Navigate all the fields of the specified object. If a field is null, it
|
||||
* does not get visited.
|
||||
* @param objTypePair The object,type (fully genericized) being navigated
|
||||
*/
|
||||
public void accept(ObjectTypePair objTypePair, Visitor visitor) {
|
||||
if (exclusionStrategy.shouldSkipClass($Gson$Types.getRawType(objTypePair.type))) {
|
||||
return;
|
||||
}
|
||||
boolean visitedWithCustomHandler = visitor.visitUsingCustomHandler(objTypePair);
|
||||
if (!visitedWithCustomHandler) {
|
||||
objTypePair = objTypePair.toMoreSpecificType();
|
||||
Object obj = objTypePair.getObject();
|
||||
Object objectToVisit = (obj == null) ? visitor.getTarget() : obj;
|
||||
if (objectToVisit == null) {
|
||||
return;
|
||||
}
|
||||
objTypePair.setObject(objectToVisit);
|
||||
visitor.start(objTypePair);
|
||||
try {
|
||||
if ($Gson$Types.isArray(objTypePair.getMoreSpecificType())) {
|
||||
visitor.visitArray(objectToVisit, objTypePair.type);
|
||||
} else if (objTypePair.type == Object.class && isPrimitiveOrString(objectToVisit)) {
|
||||
// TODO(Joel): this is only used for deserialization of "primitives"
|
||||
// we should rethink this!!!
|
||||
visitor.visitPrimitive(objectToVisit);
|
||||
visitor.getTarget();
|
||||
} else {
|
||||
visitor.startVisitingObject(objectToVisit);
|
||||
reflectingFieldNavigator.visitFieldsReflectively(objTypePair, visitor);
|
||||
}
|
||||
} finally {
|
||||
visitor.end(objTypePair);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isPrimitiveOrString(Object objectToVisit) {
|
||||
Class<?> realClazz = objectToVisit.getClass();
|
||||
return realClazz == Object.class || realClazz == String.class
|
||||
|| Primitives.unwrap(realClazz).isPrimitive();
|
||||
}
|
||||
}
|
@ -1,150 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2009 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.google.gson;
|
||||
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
|
||||
/**
|
||||
* A holder class for an object and its type
|
||||
*
|
||||
* @author Inderjeet Singh
|
||||
*/
|
||||
final class ObjectTypePair {
|
||||
private Object obj;
|
||||
final Type type;
|
||||
private final boolean preserveType;
|
||||
private final boolean systemOnly;
|
||||
|
||||
ObjectTypePair(Object obj, Type type, boolean preserveType, boolean systemOnly) {
|
||||
this.obj = obj;
|
||||
this.type = type;
|
||||
this.preserveType = preserveType;
|
||||
this.systemOnly = systemOnly;
|
||||
}
|
||||
|
||||
Object getObject() {
|
||||
return obj;
|
||||
}
|
||||
|
||||
void setObject(Object obj) {
|
||||
this.obj = obj;
|
||||
}
|
||||
|
||||
Type getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("preserveType: %b, type: %s, obj: %s", preserveType, type, obj);
|
||||
}
|
||||
|
||||
<HANDLER> Pair<HANDLER, ObjectTypePair> getMatchingHandler(
|
||||
ParameterizedTypeHandlerMap<HANDLER> handlers) {
|
||||
HANDLER handler = null;
|
||||
if (!preserveType && obj != null) {
|
||||
// First try looking up the handler for the actual type
|
||||
ObjectTypePair moreSpecificType = toMoreSpecificType();
|
||||
handler = handlers.getHandlerFor(moreSpecificType.type, systemOnly);
|
||||
if (handler != null) {
|
||||
return new Pair<HANDLER, ObjectTypePair>(handler, moreSpecificType);
|
||||
}
|
||||
}
|
||||
// Try the specified type
|
||||
handler = handlers.getHandlerFor(type, systemOnly);
|
||||
return handler == null ? null : new Pair<HANDLER, ObjectTypePair>(handler, this);
|
||||
}
|
||||
|
||||
ObjectTypePair toMoreSpecificType() {
|
||||
if (preserveType || obj == null) {
|
||||
return this;
|
||||
}
|
||||
Type actualType = getActualTypeIfMoreSpecific(type, obj.getClass());
|
||||
if (actualType == type) {
|
||||
return this;
|
||||
}
|
||||
return new ObjectTypePair(obj, actualType, true, systemOnly);
|
||||
}
|
||||
|
||||
Type getMoreSpecificType() {
|
||||
if (preserveType || obj == null) {
|
||||
return type;
|
||||
}
|
||||
return getActualTypeIfMoreSpecific(type, obj.getClass());
|
||||
}
|
||||
|
||||
// This takes care of situations where the field was declared as an Object, but the
|
||||
// actual value contains something more specific. See Issue 54.
|
||||
// TODO (inder): This solution will not work if the field is of a generic type, but
|
||||
// the actual object is of a raw type (which is a sub-class of the generic type).
|
||||
static Type getActualTypeIfMoreSpecific(Type type, Class<?> actualClass) {
|
||||
if (type instanceof Class<?>) {
|
||||
Class<?> typeAsClass = (Class<?>) type;
|
||||
if (typeAsClass.isAssignableFrom(actualClass)) {
|
||||
type = actualClass;
|
||||
}
|
||||
if (type == Object.class) {
|
||||
type = actualClass;
|
||||
}
|
||||
}
|
||||
return type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
// Not using type.hashCode() since I am not sure if the subclasses of type reimplement
|
||||
// hashCode() to be equal for equal types
|
||||
return ((obj == null) ? 31 : obj.hashCode());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
if (getClass() != obj.getClass()) {
|
||||
return false;
|
||||
}
|
||||
ObjectTypePair other = (ObjectTypePair) obj;
|
||||
if (this.obj == null) {
|
||||
if (other.obj != null) {
|
||||
return false;
|
||||
}
|
||||
} else if (this.obj != other.obj) { // Checking for reference equality
|
||||
return false;
|
||||
}
|
||||
if (type == null) {
|
||||
if (other.type != null) {
|
||||
return false;
|
||||
}
|
||||
} else if (!type.equals(other.type)) {
|
||||
return false;
|
||||
}
|
||||
return preserveType == other.preserveType && systemOnly == other.systemOnly;
|
||||
}
|
||||
|
||||
public boolean isPreserveType() {
|
||||
return preserveType;
|
||||
}
|
||||
|
||||
public boolean isSystemOnly() {
|
||||
return systemOnly;
|
||||
}
|
||||
}
|
@ -1,121 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2011 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.google.gson;
|
||||
|
||||
import java.lang.reflect.AccessibleObject;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Type;
|
||||
import java.lang.reflect.TypeVariable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.google.gson.ObjectNavigator.Visitor;
|
||||
import com.google.gson.internal.$Gson$Preconditions;
|
||||
import com.google.gson.internal.$Gson$Types;
|
||||
|
||||
/**
|
||||
* Visits each of the fields of the specified class using reflection
|
||||
*
|
||||
* @author Inderjeet Singh
|
||||
* @author Joel Leitch
|
||||
* @author Jesse Wilson
|
||||
*/
|
||||
final class ReflectingFieldNavigator {
|
||||
|
||||
private static final Cache<Type, List<FieldAttributes>> fieldsCache =
|
||||
new LruCache<Type, List<FieldAttributes>>(500);
|
||||
|
||||
private final ExclusionStrategy exclusionStrategy;
|
||||
|
||||
/**
|
||||
* @param exclusionStrategy the concrete strategy object to be used to filter out fields of an
|
||||
* object.
|
||||
*/
|
||||
ReflectingFieldNavigator(ExclusionStrategy exclusionStrategy) {
|
||||
this.exclusionStrategy = $Gson$Preconditions.checkNotNull(exclusionStrategy);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param objTypePair The object,type (fully genericized) being navigated
|
||||
* @param visitor the visitor to visit each field with
|
||||
*/
|
||||
void visitFieldsReflectively(ObjectTypePair objTypePair, Visitor visitor) {
|
||||
Type moreSpecificType = objTypePair.getMoreSpecificType();
|
||||
Object obj = objTypePair.getObject();
|
||||
for (FieldAttributes fieldAttributes : getAllFields(moreSpecificType, objTypePair.getType())) {
|
||||
if (exclusionStrategy.shouldSkipField(fieldAttributes)
|
||||
|| exclusionStrategy.shouldSkipClass(fieldAttributes.getDeclaredClass())) {
|
||||
continue; // skip
|
||||
}
|
||||
Type resolvedTypeOfField = getMoreSpecificType(fieldAttributes.getResolvedType(), obj, fieldAttributes);
|
||||
boolean visitedWithCustomHandler =
|
||||
visitor.visitFieldUsingCustomHandler(fieldAttributes, resolvedTypeOfField, obj);
|
||||
if (!visitedWithCustomHandler) {
|
||||
if ($Gson$Types.isArray(resolvedTypeOfField)) {
|
||||
visitor.visitArrayField(fieldAttributes, resolvedTypeOfField, obj);
|
||||
} else {
|
||||
visitor.visitObjectField(fieldAttributes, resolvedTypeOfField, obj);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private static Type getMoreSpecificType(Type type, Object obj, FieldAttributes fieldAttributes) {
|
||||
try {
|
||||
if (obj != null && (Object.class == type || type instanceof TypeVariable)) {
|
||||
Object fieldValue = fieldAttributes.get(obj);
|
||||
if (fieldValue != null) {
|
||||
type = fieldValue.getClass();
|
||||
}
|
||||
}
|
||||
} catch (IllegalAccessException e) {
|
||||
}
|
||||
return type;
|
||||
}
|
||||
|
||||
private List<FieldAttributes> getAllFields(Type type, Type declaredType) {
|
||||
List<FieldAttributes> fields = fieldsCache.getElement(type);
|
||||
if (fields == null) {
|
||||
fields = new ArrayList<FieldAttributes>();
|
||||
for (Class<?> curr : getInheritanceHierarchy(type)) {
|
||||
Field[] currentClazzFields = curr.getDeclaredFields();
|
||||
AccessibleObject.setAccessible(currentClazzFields, true);
|
||||
Field[] classFields = currentClazzFields;
|
||||
for (Field f : classFields) {
|
||||
fields.add(new FieldAttributes(curr, f, declaredType));
|
||||
}
|
||||
}
|
||||
fieldsCache.addElement(type, fields);
|
||||
}
|
||||
return fields;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of classes corresponding to the inheritance of specified type
|
||||
*/
|
||||
private List<Class<?>> getInheritanceHierarchy(Type type) {
|
||||
List<Class<?>> classes = new ArrayList<Class<?>>();
|
||||
Class<?> topLevelClass = $Gson$Types.getRawType(type);
|
||||
for (Class<?> curr = topLevelClass; curr != null && !curr.equals(Object.class); curr =
|
||||
curr.getSuperclass()) {
|
||||
if (!curr.isSynthetic()) {
|
||||
classes.add(curr);
|
||||
}
|
||||
}
|
||||
return classes;
|
||||
}
|
||||
}
|
@ -0,0 +1,173 @@
|
||||
/*
|
||||
* Copyright (C) 2011 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.google.gson.internal;
|
||||
|
||||
import com.google.gson.InstanceCreator;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.LinkedList;
|
||||
import java.util.Map;
|
||||
import java.util.Queue;
|
||||
import java.util.Set;
|
||||
import java.util.SortedSet;
|
||||
import java.util.TreeSet;
|
||||
|
||||
/**
|
||||
* Returns a function that can construct an instance of a requested type.
|
||||
*/
|
||||
public final class ConstructorConstructor {
|
||||
private final ParameterizedTypeHandlerMap<InstanceCreator<?>> instanceCreators;
|
||||
|
||||
public ConstructorConstructor(ParameterizedTypeHandlerMap<InstanceCreator<?>> instanceCreators) {
|
||||
this.instanceCreators = instanceCreators;
|
||||
}
|
||||
|
||||
public ConstructorConstructor() {
|
||||
this(new ParameterizedTypeHandlerMap<InstanceCreator<?>>());
|
||||
}
|
||||
|
||||
public <T> ObjectConstructor<T> getConstructor(TypeToken<T> typeToken) {
|
||||
final Type type = typeToken.getType();
|
||||
final Class<? super T> rawType = typeToken.getRawType();
|
||||
|
||||
// first try an instance creator
|
||||
|
||||
@SuppressWarnings("unchecked") // types must agree
|
||||
final InstanceCreator<T> creator
|
||||
= (InstanceCreator<T>) instanceCreators.getHandlerFor(type, false);
|
||||
if (creator != null) {
|
||||
return new ObjectConstructor<T>() {
|
||||
@Override public T construct() {
|
||||
return creator.createInstance(type);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
ObjectConstructor<T> defaultConstructor = newDefaultConstructor(rawType);
|
||||
if (defaultConstructor != null) {
|
||||
return defaultConstructor;
|
||||
}
|
||||
|
||||
ObjectConstructor<T> defaultImplementation = newDefaultImplementationConstructor(rawType);
|
||||
if (defaultImplementation != null) {
|
||||
return defaultImplementation;
|
||||
}
|
||||
|
||||
// finally try unsafe
|
||||
return newUnsafeAllocator(type, rawType);
|
||||
}
|
||||
|
||||
private <T> ObjectConstructor<T> newDefaultConstructor(Class<? super T> rawType) {
|
||||
try {
|
||||
final Constructor<? super T> constructor = rawType.getDeclaredConstructor();
|
||||
if (!constructor.isAccessible()) {
|
||||
constructor.setAccessible(true);
|
||||
}
|
||||
return new ObjectConstructor<T>() {
|
||||
@SuppressWarnings("unchecked") // T is the same raw type as is requested
|
||||
@Override public T construct() {
|
||||
try {
|
||||
Object[] args = null;
|
||||
return (T) constructor.newInstance(args);
|
||||
} catch (InstantiationException e) {
|
||||
// TODO: JsonParseException ?
|
||||
throw new RuntimeException(e);
|
||||
} catch (InvocationTargetException e) {
|
||||
// TODO: don't wrap if cause is unchecked!
|
||||
// TODO: JsonParseException ?
|
||||
throw new RuntimeException(e.getTargetException());
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
};
|
||||
} catch (NoSuchMethodException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructors for common interface types like Map and List and their
|
||||
* subytpes.
|
||||
*/
|
||||
@SuppressWarnings("unchecked") // use runtime checks to guarantee that 'T' is what it is
|
||||
private <T> ObjectConstructor<T> newDefaultImplementationConstructor(Class<? super T> rawType) {
|
||||
if (Collection.class.isAssignableFrom(rawType)) {
|
||||
if (SortedSet.class.isAssignableFrom(rawType)) {
|
||||
return new ObjectConstructor<T>() {
|
||||
@Override public T construct() {
|
||||
return (T) new TreeSet<Object>();
|
||||
}
|
||||
};
|
||||
} else if (Set.class.isAssignableFrom(rawType)) {
|
||||
return new ObjectConstructor<T>() {
|
||||
@Override public T construct() {
|
||||
return (T) new LinkedHashSet<Object>();
|
||||
}
|
||||
};
|
||||
} else if (Queue.class.isAssignableFrom(rawType)) {
|
||||
return new ObjectConstructor<T>() {
|
||||
@Override public T construct() {
|
||||
return (T) new LinkedList<Object>();
|
||||
}
|
||||
};
|
||||
} else {
|
||||
return new ObjectConstructor<T>() {
|
||||
@Override public T construct() {
|
||||
return (T) new ArrayList<Object>();
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
if (Map.class.isAssignableFrom(rawType)) {
|
||||
return new ObjectConstructor<T>() {
|
||||
@Override public T construct() {
|
||||
return (T) new LinkedHashMap<Object, Object>();
|
||||
}
|
||||
};
|
||||
// TODO: SortedMap ?
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private <T> ObjectConstructor<T> newUnsafeAllocator(
|
||||
final Type type, final Class<? super T> rawType) {
|
||||
return new ObjectConstructor<T>() {
|
||||
private final UnsafeAllocator unsafeAllocator = UnsafeAllocator.create();
|
||||
@Override public T construct() {
|
||||
try {
|
||||
return (T) unsafeAllocator.newInstance(rawType);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(("Unable to invoke no-args constructor for " + type + ". "
|
||||
+ "Register an InstanceCreator with Gson for this type may fix this problem."), e);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override public String toString() {
|
||||
return instanceCreators.toString();
|
||||
}
|
||||
}
|
@ -14,9 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.google.gson;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
package com.google.gson.internal;
|
||||
|
||||
/**
|
||||
* Defines a generic object construction factory. The purpose of this class
|
||||
@ -26,22 +24,10 @@ import java.lang.reflect.Type;
|
||||
* @author Inderjeet Singh
|
||||
* @author Joel Leitch
|
||||
*/
|
||||
interface ObjectConstructor {
|
||||
public interface ObjectConstructor<T> {
|
||||
|
||||
/**
|
||||
* Creates a new instance of the given type.
|
||||
*
|
||||
* @param typeOfT the class type that should be instantiated
|
||||
* @return a default instance of the provided class.
|
||||
* Returns a new instance.
|
||||
*/
|
||||
public <T> T construct(Type typeOfT);
|
||||
|
||||
/**
|
||||
* Constructs an array type of the provided length.
|
||||
*
|
||||
* @param typeOfArrayElements type of objects in the array
|
||||
* @param length size of the array
|
||||
* @return new array of size length
|
||||
*/
|
||||
public Object constructArray(Type typeOfArrayElements, int length);
|
||||
public T construct();
|
||||
}
|
@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.google.gson;
|
||||
package com.google.gson.internal;
|
||||
|
||||
/**
|
||||
* A simple object that holds onto a pair of object references, first and second.
|
||||
@ -25,7 +25,7 @@ package com.google.gson;
|
||||
* @param <FIRST>
|
||||
* @param <SECOND>
|
||||
*/
|
||||
final class Pair<FIRST, SECOND> {
|
||||
public final class Pair<FIRST, SECOND> {
|
||||
public final FIRST first;
|
||||
public final SECOND second;
|
||||
|
@ -14,9 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.google.gson;
|
||||
|
||||
import com.google.gson.internal.$Gson$Types;
|
||||
package com.google.gson.internal;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.ArrayList;
|
||||
@ -35,7 +33,7 @@ import java.util.logging.Logger;
|
||||
*
|
||||
* @param <T> The handler that will be looked up by type
|
||||
*/
|
||||
final class ParameterizedTypeHandlerMap<T> {
|
||||
public final class ParameterizedTypeHandlerMap<T> {
|
||||
private static final Logger logger =
|
||||
Logger.getLogger(ParameterizedTypeHandlerMap.class.getName());
|
||||
/**
|
||||
@ -222,7 +220,7 @@ final class ParameterizedTypeHandlerMap<T> {
|
||||
ParameterizedTypeHandlerMap<T> copy = new ParameterizedTypeHandlerMap<T>();
|
||||
// Instead of individually registering entries in the map, make an efficient copy
|
||||
// of the list and map
|
||||
|
||||
|
||||
// TODO (inder): Performance optimization. We can probably just share the
|
||||
// systemMap and systemTypeHierarchyList instead of making copies
|
||||
copy.systemMap.putAll(systemMap);
|
@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.google.gson;
|
||||
package com.google.gson.internal;
|
||||
|
||||
|
||||
import com.google.gson.internal.$Gson$Preconditions;
|
||||
@ -29,7 +29,7 @@ import java.util.Map;
|
||||
*
|
||||
* @author Kevin Bourrillion
|
||||
*/
|
||||
final class Primitives {
|
||||
public final class Primitives {
|
||||
private Primitives() {}
|
||||
|
||||
/** A map from primitive types to their corresponding wrapper types. */
|
@ -28,7 +28,7 @@ import java.math.BigDecimal;
|
||||
*
|
||||
* @author Joel Leitch
|
||||
*/
|
||||
public class BigDecimalTypeAdapter extends TypeAdapter<BigDecimal> {
|
||||
public final class BigDecimalTypeAdapter extends TypeAdapter<BigDecimal> {
|
||||
|
||||
@Override
|
||||
public BigDecimal read(JsonReader reader) throws IOException {
|
||||
|
@ -28,7 +28,7 @@ import java.math.BigInteger;
|
||||
*
|
||||
* @author Joel Leitch
|
||||
*/
|
||||
public class BigIntegerTypeAdapter extends TypeAdapter<BigInteger> {
|
||||
public final class BigIntegerTypeAdapter extends TypeAdapter<BigInteger> {
|
||||
|
||||
@Override
|
||||
public BigInteger read(JsonReader reader) throws IOException {
|
||||
|
@ -1,121 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2011 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.google.gson.internal.bind;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Queue;
|
||||
import java.util.Set;
|
||||
import java.util.SortedSet;
|
||||
import java.util.TreeSet;
|
||||
|
||||
import com.google.gson.internal.$Gson$Types;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
import com.google.gson.stream.JsonReader;
|
||||
import com.google.gson.stream.JsonToken;
|
||||
import com.google.gson.stream.JsonWriter;
|
||||
|
||||
/**
|
||||
* Adapt a homogeneous collection of objects.
|
||||
*/
|
||||
public final class CollectionTypeAdapter<E> extends TypeAdapter<Collection<E>> {
|
||||
public static final Factory FACTORY = new Factory() {
|
||||
public <T> TypeAdapter<T> create(MiniGson context, TypeToken<T> typeToken) {
|
||||
Type type = typeToken.getType();
|
||||
|
||||
Class<? super T> rawType = typeToken.getRawType();
|
||||
if (!Collection.class.isAssignableFrom(rawType)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Type elementType = $Gson$Types.getCollectionElementType(type, rawType);
|
||||
TypeAdapter<?> elementTypeAdapter = context.getAdapter(TypeToken.get(elementType));
|
||||
|
||||
Class<?> constructorType;
|
||||
|
||||
if (rawType == List.class || rawType == Collection.class) {
|
||||
constructorType = ArrayList.class;
|
||||
} else if (rawType == Set.class) {
|
||||
constructorType = LinkedHashSet.class;
|
||||
} else if (rawType == Queue.class) {
|
||||
constructorType = LinkedList.class;
|
||||
} else if (rawType == SortedSet.class) {
|
||||
constructorType = TreeSet.class;
|
||||
} else {
|
||||
constructorType = rawType;
|
||||
}
|
||||
|
||||
Constructor<?> constructor = null;
|
||||
try {
|
||||
constructor = constructorType.getConstructor();
|
||||
} catch (NoSuchMethodException ignored) {
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked") // create() doesn't define a type parameter
|
||||
TypeAdapter<T> result = new CollectionTypeAdapter(context, elementType, elementTypeAdapter, constructor);
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
private final TypeAdapter<E> elementTypeAdapter;
|
||||
private final Constructor<? extends Collection<E>> constructor;
|
||||
|
||||
public CollectionTypeAdapter(MiniGson context, Type elementType, TypeAdapter<E> elementTypeAdapter,
|
||||
Constructor<? extends Collection<E>> constructor) {
|
||||
this.elementTypeAdapter =
|
||||
new TypeAdapterRuntimeTypeWrapper<E>(context, elementTypeAdapter, elementType);
|
||||
this.constructor = constructor;
|
||||
}
|
||||
|
||||
public Collection<E> read(JsonReader reader) throws IOException {
|
||||
if (reader.peek() == JsonToken.NULL) {
|
||||
reader.nextNull(); // TODO: does this belong here?
|
||||
return null;
|
||||
}
|
||||
|
||||
if (constructor == null) {
|
||||
throw new UnsupportedOperationException("TODO: use unsafeAllocator.newInstance");
|
||||
}
|
||||
Collection<E> collection = Reflection.newInstance(constructor);
|
||||
reader.beginArray();
|
||||
while (reader.hasNext()) {
|
||||
E instance = elementTypeAdapter.read(reader);
|
||||
collection.add(instance);
|
||||
}
|
||||
reader.endArray();
|
||||
return collection;
|
||||
}
|
||||
|
||||
public void write(JsonWriter writer, Collection<E> collection) throws IOException {
|
||||
if (collection == null) {
|
||||
writer.nullValue(); // TODO: better policy here?
|
||||
return;
|
||||
}
|
||||
|
||||
writer.beginArray();
|
||||
for (E element : collection) {
|
||||
elementTypeAdapter.write(writer, element);
|
||||
}
|
||||
writer.endArray();
|
||||
}
|
||||
}
|
@ -0,0 +1,98 @@
|
||||
/*
|
||||
* Copyright (C) 2011 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.google.gson.internal.bind;
|
||||
|
||||
import com.google.gson.internal.$Gson$Types;
|
||||
import com.google.gson.internal.ConstructorConstructor;
|
||||
import com.google.gson.internal.ObjectConstructor;
|
||||
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.lang.reflect.Type;
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* Adapt a homogeneous collection of objects.
|
||||
*/
|
||||
public final class CollectionTypeAdapterFactory implements TypeAdapter.Factory {
|
||||
private final ConstructorConstructor constructorConstructor;
|
||||
|
||||
public CollectionTypeAdapterFactory(ConstructorConstructor constructorConstructor) {
|
||||
this.constructorConstructor = constructorConstructor;
|
||||
}
|
||||
|
||||
public <T> TypeAdapter<T> create(MiniGson context, TypeToken<T> typeToken) {
|
||||
Type type = typeToken.getType();
|
||||
|
||||
Class<? super T> rawType = typeToken.getRawType();
|
||||
if (!Collection.class.isAssignableFrom(rawType)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Type elementType = $Gson$Types.getCollectionElementType(type, rawType);
|
||||
TypeAdapter<?> elementTypeAdapter = context.getAdapter(TypeToken.get(elementType));
|
||||
ObjectConstructor<T> constructor = constructorConstructor.getConstructor(typeToken);
|
||||
|
||||
@SuppressWarnings("unchecked") // create() doesn't define a type parameter
|
||||
TypeAdapter<T> result = new Adapter(context, elementType, elementTypeAdapter, constructor);
|
||||
return result;
|
||||
}
|
||||
|
||||
private final class Adapter<E> extends TypeAdapter<Collection<E>> {
|
||||
private final TypeAdapter<E> elementTypeAdapter;
|
||||
private final ObjectConstructor<? extends Collection<E>> constructor;
|
||||
|
||||
public Adapter(MiniGson context, Type elementType,
|
||||
TypeAdapter<E> elementTypeAdapter,
|
||||
ObjectConstructor<? extends Collection<E>> constructor) {
|
||||
this.elementTypeAdapter =
|
||||
new TypeAdapterRuntimeTypeWrapper<E>(context, elementTypeAdapter, elementType);
|
||||
this.constructor = constructor;
|
||||
}
|
||||
|
||||
public Collection<E> read(JsonReader reader) throws IOException {
|
||||
if (reader.peek() == JsonToken.NULL) {
|
||||
reader.nextNull(); // TODO: does this belong here?
|
||||
return null;
|
||||
}
|
||||
|
||||
Collection<E> collection = constructor.construct();
|
||||
reader.beginArray();
|
||||
while (reader.hasNext()) {
|
||||
E instance = elementTypeAdapter.read(reader);
|
||||
collection.add(instance);
|
||||
}
|
||||
reader.endArray();
|
||||
return collection;
|
||||
}
|
||||
|
||||
public void write(JsonWriter writer, Collection<E> collection) throws IOException {
|
||||
if (collection == null) {
|
||||
writer.nullValue(); // TODO: better policy here?
|
||||
return;
|
||||
}
|
||||
|
||||
writer.beginArray();
|
||||
for (E element : collection) {
|
||||
elementTypeAdapter.write(writer, element);
|
||||
}
|
||||
writer.endArray();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,79 @@
|
||||
/*
|
||||
* Copyright (C) 2011 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.google.gson.internal.bind;
|
||||
|
||||
import com.google.gson.ExclusionStrategy;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
import com.google.gson.stream.JsonReader;
|
||||
import com.google.gson.stream.JsonWriter;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* This type adapter skips values using an exclusion strategy. It may delegate
|
||||
* to another type adapter if only one direction is excluded.
|
||||
*/
|
||||
public final class ExcludedTypeAdapterFactory implements TypeAdapter.Factory {
|
||||
private final ExclusionStrategy serializationExclusionStrategy;
|
||||
private final ExclusionStrategy deserializationExclusionStrategy;
|
||||
|
||||
public ExcludedTypeAdapterFactory(ExclusionStrategy serializationExclusionStrategy,
|
||||
ExclusionStrategy deserializationExclusionStrategy) {
|
||||
this.serializationExclusionStrategy = serializationExclusionStrategy;
|
||||
this.deserializationExclusionStrategy = deserializationExclusionStrategy;
|
||||
}
|
||||
|
||||
public <T> TypeAdapter<T> create(final MiniGson context, final TypeToken<T> type) {
|
||||
Class<?> rawType = type.getRawType();
|
||||
final boolean skipSerialize = serializationExclusionStrategy.shouldSkipClass(rawType);
|
||||
final boolean skipDeserialize = deserializationExclusionStrategy.shouldSkipClass(rawType);
|
||||
|
||||
if (!skipSerialize && !skipDeserialize) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return new TypeAdapter<T>() {
|
||||
/**
|
||||
* The delegate is lazily created because it may not be needed, and
|
||||
* creating it may fail.
|
||||
*/
|
||||
private TypeAdapter<T> delegate;
|
||||
|
||||
@Override public T read(JsonReader reader) throws IOException {
|
||||
if (skipDeserialize) {
|
||||
reader.skipValue();
|
||||
return null;
|
||||
}
|
||||
return delegate().read(reader);
|
||||
}
|
||||
|
||||
@Override public void write(JsonWriter writer, T value) throws IOException {
|
||||
if (skipSerialize) {
|
||||
writer.nullValue();
|
||||
return;
|
||||
}
|
||||
delegate().write(writer, value);
|
||||
}
|
||||
|
||||
private TypeAdapter<T> delegate() {
|
||||
TypeAdapter<T> d = delegate;
|
||||
return d != null
|
||||
? d
|
||||
: (delegate = context.getNextAdapter(ExcludedTypeAdapterFactory.this, type));
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
@ -1,105 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2011 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.google.gson.internal.bind;
|
||||
|
||||
import com.google.gson.internal.$Gson$Types;
|
||||
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.lang.reflect.Constructor;
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Adapt a map whose keys are any type.
|
||||
*/
|
||||
public final class GsonCompatibleMapTypeAdapter<V> extends TypeAdapter<Map<?, V>> {
|
||||
public static final Factory FACTORY = new Factory() {
|
||||
public <T> TypeAdapter<T> create(MiniGson context, TypeToken<T> typeToken) {
|
||||
Type type = typeToken.getType();
|
||||
|
||||
Class<? super T> rawType = typeToken.getRawType();
|
||||
if (!Map.class.isAssignableFrom(rawType)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Type childGenericType = Object.class;
|
||||
if (type instanceof ParameterizedType) {
|
||||
Class<?> rawTypeOfSrc = $Gson$Types.getRawType(type);
|
||||
childGenericType = $Gson$Types.getMapKeyAndValueTypes(type, rawTypeOfSrc)[1];
|
||||
}
|
||||
TypeAdapter valueAdapter = context.getAdapter(TypeToken.get(childGenericType));
|
||||
|
||||
Constructor<?> constructor;
|
||||
try {
|
||||
Class<?> constructorType = (rawType == Map.class) ? LinkedHashMap.class : rawType;
|
||||
constructor = constructorType.getConstructor();
|
||||
} catch (NoSuchMethodException e) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked") // we don't define a type parameter for the key or value types
|
||||
TypeAdapter<T> result = new GsonCompatibleMapTypeAdapter(valueAdapter, constructor);
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
private final TypeAdapter<V> valueTypeAdapter;
|
||||
private final Constructor<? extends Map<String, V>> constructor;
|
||||
|
||||
public GsonCompatibleMapTypeAdapter(TypeAdapter<V> valueTypeAdapter,
|
||||
Constructor<? extends Map<String, V>> constructor) {
|
||||
this.valueTypeAdapter = valueTypeAdapter;
|
||||
this.constructor = constructor;
|
||||
}
|
||||
|
||||
public Map<?, V> read(JsonReader reader) throws IOException {
|
||||
if (reader.peek() == JsonToken.NULL) {
|
||||
reader.nextNull(); // TODO: does this belong here?
|
||||
return null;
|
||||
}
|
||||
|
||||
Map<String, V> map = Reflection.newInstance(constructor);
|
||||
reader.beginObject();
|
||||
while (reader.hasNext()) {
|
||||
String key = reader.nextName();
|
||||
V value = valueTypeAdapter.read(reader);
|
||||
map.put(key, value); // TODO: convert to the map's key type?
|
||||
}
|
||||
reader.endObject();
|
||||
return map;
|
||||
}
|
||||
|
||||
public void write(JsonWriter writer, Map<?, V> map) throws IOException {
|
||||
if (map == null) {
|
||||
writer.nullValue(); // TODO: better policy here?
|
||||
return;
|
||||
}
|
||||
|
||||
writer.beginObject();
|
||||
for (Map.Entry<?, V> entry : map.entrySet()) {
|
||||
String key = String.valueOf(entry.getKey());
|
||||
writer.name(key);
|
||||
valueTypeAdapter.write(writer, entry.getValue());
|
||||
}
|
||||
writer.endObject();
|
||||
}
|
||||
}
|
@ -0,0 +1,101 @@
|
||||
/*
|
||||
* Copyright (C) 2011 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.google.gson.internal.bind;
|
||||
|
||||
import com.google.gson.internal.$Gson$Types;
|
||||
import com.google.gson.internal.ConstructorConstructor;
|
||||
import com.google.gson.internal.ObjectConstructor;
|
||||
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.lang.reflect.Type;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Adapt a map whose keys are any type.
|
||||
*/
|
||||
public final class MapTypeAdapterFactory implements TypeAdapter.Factory {
|
||||
private final ConstructorConstructor constructorConstructor;
|
||||
|
||||
public MapTypeAdapterFactory(ConstructorConstructor constructorConstructor) {
|
||||
this.constructorConstructor = constructorConstructor;
|
||||
}
|
||||
|
||||
public <T> TypeAdapter<T> create(MiniGson context, TypeToken<T> typeToken) {
|
||||
Type type = typeToken.getType();
|
||||
|
||||
Class<? super T> rawType = typeToken.getRawType();
|
||||
if (!Map.class.isAssignableFrom(rawType)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Class<?> rawTypeOfSrc = $Gson$Types.getRawType(type);
|
||||
Type childGenericType = $Gson$Types.getMapKeyAndValueTypes(type, rawTypeOfSrc)[1];
|
||||
TypeAdapter valueAdapter = context.getAdapter(TypeToken.get(childGenericType));
|
||||
ObjectConstructor<T> constructor = constructorConstructor.getConstructor(typeToken);
|
||||
|
||||
@SuppressWarnings("unchecked") // we don't define a type parameter for the key or value types
|
||||
TypeAdapter<T> result = new Adapter(valueAdapter, constructor);
|
||||
return result;
|
||||
}
|
||||
|
||||
private final class Adapter<V> extends TypeAdapter<Map<?, V>> {
|
||||
private final TypeAdapter<V> valueTypeAdapter;
|
||||
private final ObjectConstructor<? extends Map<String, V>> constructor;
|
||||
|
||||
public Adapter(TypeAdapter<V> valueTypeAdapter,
|
||||
ObjectConstructor<? extends Map<String, V>> constructor) {
|
||||
this.valueTypeAdapter = valueTypeAdapter;
|
||||
this.constructor = constructor;
|
||||
}
|
||||
|
||||
public Map<?, V> read(JsonReader reader) throws IOException {
|
||||
if (reader.peek() == JsonToken.NULL) {
|
||||
reader.nextNull(); // TODO: does this belong here?
|
||||
return null;
|
||||
}
|
||||
|
||||
Map<String, V> map = constructor.construct();
|
||||
|
||||
reader.beginObject();
|
||||
while (reader.hasNext()) {
|
||||
String key = reader.nextName();
|
||||
V value = valueTypeAdapter.read(reader);
|
||||
map.put(key, value); // TODO: convert to the map's key type?
|
||||
}
|
||||
reader.endObject();
|
||||
return map;
|
||||
}
|
||||
|
||||
public void write(JsonWriter writer, Map<?, V> map) throws IOException {
|
||||
if (map == null) {
|
||||
writer.nullValue(); // TODO: better policy here?
|
||||
return;
|
||||
}
|
||||
|
||||
writer.beginObject();
|
||||
for (Map.Entry<?, V> entry : map.entrySet()) {
|
||||
String key = String.valueOf(entry.getKey());
|
||||
writer.name(key);
|
||||
valueTypeAdapter.write(writer, entry.getValue());
|
||||
}
|
||||
writer.endObject();
|
||||
}
|
||||
}
|
||||
}
|
@ -16,6 +16,10 @@
|
||||
|
||||
package com.google.gson.internal.bind;
|
||||
|
||||
import com.google.gson.internal.ConstructorConstructor;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
import com.google.gson.stream.JsonReader;
|
||||
import com.google.gson.stream.JsonWriter;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
@ -23,10 +27,6 @@ import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
import com.google.gson.stream.JsonReader;
|
||||
import com.google.gson.stream.JsonWriter;
|
||||
|
||||
/**
|
||||
* A basic binding between JSON and Java objects.
|
||||
*/
|
||||
@ -48,6 +48,7 @@ public final class MiniGson {
|
||||
private final List<TypeAdapter.Factory> factories;
|
||||
|
||||
private MiniGson(Builder builder) {
|
||||
ConstructorConstructor constructorConstructor = new ConstructorConstructor();
|
||||
List<TypeAdapter.Factory> factories = new ArrayList<TypeAdapter.Factory>();
|
||||
if (builder.addDefaultFactories) {
|
||||
factories.add(TypeAdapters.BOOLEAN_FACTORY);
|
||||
@ -59,11 +60,11 @@ public final class MiniGson {
|
||||
}
|
||||
factories.addAll(builder.factories);
|
||||
if (builder.addDefaultFactories) {
|
||||
factories.add(CollectionTypeAdapter.FACTORY);
|
||||
factories.add(StringToValueMapTypeAdapter.FACTORY);
|
||||
factories.add(new CollectionTypeAdapterFactory(constructorConstructor));
|
||||
factories.add(new StringToValueMapTypeAdapterFactory(constructorConstructor));
|
||||
factories.add(ArrayTypeAdapter.FACTORY);
|
||||
factories.add(ObjectTypeAdapter.FACTORY);
|
||||
factories.add(ReflectiveTypeAdapter.FACTORY);
|
||||
factories.add(new ReflectiveTypeAdapterFactory(constructorConstructor));
|
||||
}
|
||||
this.factories = Collections.unmodifiableList(factories);
|
||||
}
|
||||
@ -100,6 +101,33 @@ public final class MiniGson {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a type adapter for {@code} type that isn't {@code skipPast}. This
|
||||
* can be used for type adapters to compose other, simpler type adapters.
|
||||
*
|
||||
* @throws IllegalArgumentException if this GSON cannot serialize and
|
||||
* deserialize {@code type}.
|
||||
*/
|
||||
public <T> TypeAdapter<T> getNextAdapter(TypeAdapter.Factory skipPast, TypeToken<T> type) {
|
||||
boolean skipPastFound = false;
|
||||
|
||||
for (TypeAdapter.Factory factory : factories) {
|
||||
if (!skipPastFound) {
|
||||
if (factory == skipPast) {
|
||||
skipPastFound = true;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
TypeAdapter<T> candidate = factory.create(this, type);
|
||||
if (candidate != null) {
|
||||
return candidate;
|
||||
}
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException("This MiniGSON cannot serialize " + type);
|
||||
}
|
||||
|
||||
static class FutureTypeAdapter<T> extends TypeAdapter<T> {
|
||||
private TypeAdapter<T> delegate;
|
||||
|
||||
|
@ -15,8 +15,6 @@
|
||||
*/
|
||||
package com.google.gson.internal.bind;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Type;
|
||||
import java.lang.reflect.TypeVariable;
|
||||
|
||||
@ -27,29 +25,8 @@ final class Reflection {
|
||||
public static Type getRuntimeTypeIfMoreSpecific(Type type, Object value) {
|
||||
if (value != null
|
||||
&& (type == Object.class || type instanceof TypeVariable || type instanceof Class<?>)) {
|
||||
type = (Class<?>) value.getClass();
|
||||
type = value.getClass();
|
||||
}
|
||||
return type;
|
||||
}
|
||||
|
||||
// TODO: this should use Joel's unsafe constructor stuff
|
||||
public static <T> T newInstance(Constructor<T> constructor) {
|
||||
if (!constructor.isAccessible()) {
|
||||
constructor.setAccessible(true);
|
||||
}
|
||||
try {
|
||||
Object[] args = null;
|
||||
return constructor.newInstance(args);
|
||||
} catch (InstantiationException e) {
|
||||
// TODO: JsonParseException ?
|
||||
throw new RuntimeException(e);
|
||||
} catch (InvocationTargetException e) {
|
||||
// TODO: don't wrap if cause is unchecked!
|
||||
// TODO: JsonParseException ?
|
||||
throw new RuntimeException(e.getTargetException());
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,213 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2011 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.google.gson.internal.bind;
|
||||
|
||||
import com.google.gson.JsonSyntaxException;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.AccessibleObject;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Type;
|
||||
import java.lang.reflect.TypeVariable;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import com.google.gson.internal.$Gson$Types;
|
||||
import com.google.gson.internal.UnsafeAllocator;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
import com.google.gson.stream.JsonReader;
|
||||
import com.google.gson.stream.JsonToken;
|
||||
import com.google.gson.stream.JsonWriter;
|
||||
|
||||
/**
|
||||
* Adapts the fields of an object to the properties of a JSON object.
|
||||
*/
|
||||
public final class ReflectiveTypeAdapter<T> extends TypeAdapter<T> {
|
||||
public static final Factory FACTORY = new FactoryImpl();
|
||||
|
||||
private static final UnsafeAllocator unsafeAllocator = UnsafeAllocator.create();
|
||||
private final Class<? super T> rawType;
|
||||
private final Constructor<? super T> constructor;
|
||||
private final Map<String, BoundField> map;
|
||||
private final BoundField[] boundFields;
|
||||
|
||||
ReflectiveTypeAdapter(Class<? super T> rawType, Constructor<? super T> constructor, Map<String, BoundField> map) {
|
||||
this.rawType = rawType;
|
||||
this.constructor = constructor;
|
||||
this.map = map;
|
||||
this.boundFields = map.values().toArray(new BoundField[map.size()]);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked") // the '? super T' is a raw T (the only kind we can construct)
|
||||
public T read(JsonReader reader) throws IOException {
|
||||
if (reader.peek() == JsonToken.NULL) {
|
||||
reader.nextNull(); // TODO: does this belong here?
|
||||
return null;
|
||||
}
|
||||
|
||||
T instance;
|
||||
if (constructor != null) {
|
||||
instance = (T) Reflection.newInstance(constructor);
|
||||
} else {
|
||||
try {
|
||||
instance = (T) unsafeAllocator.newInstance(rawType);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(("Unable to invoke no-args constructor for " + rawType.getName()
|
||||
+ ". Register an InstanceCreator with Gson for this type may fix this problem."), e);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: null out the other fields?
|
||||
|
||||
try {
|
||||
reader.beginObject();
|
||||
while (reader.hasNext()) {
|
||||
String name = reader.nextName();
|
||||
BoundField field = map.get(name);
|
||||
if (field == null || !field.deserialized) {
|
||||
// TODO: define a better policy
|
||||
reader.skipValue();
|
||||
} else {
|
||||
field.read(reader, instance);
|
||||
}
|
||||
}
|
||||
} catch (IllegalStateException e) {
|
||||
throw new JsonSyntaxException(e);
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new AssertionError();
|
||||
}
|
||||
reader.endObject();
|
||||
return instance;
|
||||
}
|
||||
|
||||
public void write(JsonWriter writer, T value) throws IOException {
|
||||
if (value == null) {
|
||||
writer.nullValue(); // TODO: better policy here?
|
||||
return;
|
||||
}
|
||||
|
||||
writer.beginObject();
|
||||
try {
|
||||
for (BoundField boundField : boundFields) {
|
||||
if (boundField.serialized) {
|
||||
writer.name(boundField.name);
|
||||
boundField.write(writer, value);
|
||||
}
|
||||
}
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new AssertionError();
|
||||
}
|
||||
writer.endObject();
|
||||
}
|
||||
|
||||
static BoundField createBoundField(
|
||||
final MiniGson context, final Field field, final String name,
|
||||
final TypeToken<?> fieldType, boolean serialize, boolean deserialize) {
|
||||
// special casing primitives here saves ~5% on Android...
|
||||
return new BoundField(name, serialize, deserialize) {
|
||||
final TypeAdapter<?> typeAdapter = context.getAdapter(fieldType);
|
||||
@SuppressWarnings("unchecked") // the type adapter and field type always agree
|
||||
@Override void write(JsonWriter writer, Object value)
|
||||
throws IOException, IllegalAccessException {
|
||||
Object fieldValue = field.get(value);
|
||||
TypeAdapter t =
|
||||
new TypeAdapterRuntimeTypeWrapper(context, this.typeAdapter, fieldType.getType());
|
||||
t.write(writer, fieldValue);
|
||||
}
|
||||
@Override void read(JsonReader reader, Object value)
|
||||
throws IOException, IllegalAccessException {
|
||||
Object fieldValue = typeAdapter.read(reader);
|
||||
field.set(value, fieldValue);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static class FactoryImpl implements Factory {
|
||||
public boolean serializeField(Class<?> declaringClazz, Field f, Type declaredType) {
|
||||
return !f.isSynthetic();
|
||||
}
|
||||
public boolean deserializeField(Class<?> declaringClazz, Field f, Type declaredType) {
|
||||
return !f.isSynthetic();
|
||||
}
|
||||
|
||||
public String getFieldName(Class<?> declaringClazz, Field f, Type declaredType) {
|
||||
return f.getName();
|
||||
}
|
||||
|
||||
public <T> TypeAdapter<T> create(MiniGson context, TypeToken<T> type) {
|
||||
Class<? super T> raw = type.getRawType();
|
||||
|
||||
if (!Object.class.isAssignableFrom(raw)) {
|
||||
return null; // it's a primitive!
|
||||
}
|
||||
|
||||
Constructor<? super T> constructor = null;
|
||||
try {
|
||||
constructor = raw.getDeclaredConstructor();
|
||||
} catch (NoSuchMethodException ignored) {
|
||||
}
|
||||
|
||||
return new ReflectiveTypeAdapter<T>(raw, constructor, getBoundFields(context, type, raw));
|
||||
}
|
||||
|
||||
private Map<String, BoundField> getBoundFields(
|
||||
MiniGson context, TypeToken<?> type, Class<?> raw) {
|
||||
Map<String, BoundField> result = new LinkedHashMap<String, BoundField>();
|
||||
if (raw.isInterface()) {
|
||||
return result;
|
||||
}
|
||||
|
||||
Type declaredType = type.getType();
|
||||
while (raw != Object.class) {
|
||||
Field[] fields = raw.getDeclaredFields();
|
||||
AccessibleObject.setAccessible(fields, true);
|
||||
for (Field field : fields) {
|
||||
boolean serialize = serializeField(raw, field, declaredType);
|
||||
boolean deserialize = deserializeField(raw, field, declaredType);
|
||||
if (serialize || deserialize) {
|
||||
Type fieldType = $Gson$Types.resolve(type.getType(), raw, field.getGenericType());
|
||||
BoundField boundField = createBoundField(context, field, getFieldName(raw, field, declaredType),
|
||||
TypeToken.get(fieldType), serialize, deserialize);
|
||||
BoundField previous = result.put(boundField.name, boundField);
|
||||
if (previous != null) {
|
||||
throw new IllegalArgumentException(declaredType
|
||||
+ " declares multiple JSON fields named " + previous.name);
|
||||
}
|
||||
}
|
||||
}
|
||||
type = TypeToken.get($Gson$Types.resolve(type.getType(), raw, raw.getGenericSuperclass()));
|
||||
raw = type.getRawType();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
static abstract class BoundField {
|
||||
final String name;
|
||||
final boolean serialized;
|
||||
final boolean deserialized;
|
||||
|
||||
protected BoundField(String name, boolean serialized, boolean deserialized) {
|
||||
this.name = name;
|
||||
this.serialized = serialized;
|
||||
this.deserialized = deserialized;
|
||||
}
|
||||
|
||||
abstract void write(JsonWriter writer, Object value) throws IOException, IllegalAccessException;
|
||||
abstract void read(JsonReader reader, Object value) throws IOException, IllegalAccessException;
|
||||
}
|
||||
}
|
@ -0,0 +1,219 @@
|
||||
/*
|
||||
* Copyright (C) 2011 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.google.gson.internal.bind;
|
||||
|
||||
import com.google.gson.JsonSyntaxException;
|
||||
import com.google.gson.internal.$Gson$Types;
|
||||
import com.google.gson.internal.ObjectConstructor;
|
||||
import com.google.gson.internal.Primitives;
|
||||
import com.google.gson.internal.ConstructorConstructor;
|
||||
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.lang.reflect.AccessibleObject;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Type adapter that reflects over the fields and methods of a class.
|
||||
*/
|
||||
public class ReflectiveTypeAdapterFactory implements TypeAdapter.Factory {
|
||||
private final ConstructorConstructor constructorConstructor;
|
||||
|
||||
public ReflectiveTypeAdapterFactory(ConstructorConstructor constructorConstructor) {
|
||||
this.constructorConstructor = constructorConstructor;
|
||||
}
|
||||
|
||||
protected boolean serializeField(Class<?> declaringClazz, Field f, Type declaredType) {
|
||||
return !f.isSynthetic();
|
||||
}
|
||||
|
||||
protected boolean deserializeField(Class<?> declaringClazz, Field f, Type declaredType) {
|
||||
return !f.isSynthetic();
|
||||
}
|
||||
|
||||
protected String getFieldName(Class<?> declaringClazz, Field f, Type declaredType) {
|
||||
return f.getName();
|
||||
}
|
||||
|
||||
public <T> TypeAdapter<T> create(MiniGson context, final TypeToken<T> type) {
|
||||
Class<? super T> raw = type.getRawType();
|
||||
|
||||
if (!Object.class.isAssignableFrom(raw)) {
|
||||
return null; // it's a primitive!
|
||||
}
|
||||
|
||||
ObjectConstructor<T> constructor = constructorConstructor.getConstructor(type);
|
||||
|
||||
return new Adapter<T>(context, constructor, type,
|
||||
getBoundFields(context, type, raw));
|
||||
}
|
||||
|
||||
private ReflectiveTypeAdapterFactory.BoundField createBoundField(
|
||||
final MiniGson context, final Field field, final String name,
|
||||
final TypeToken<?> fieldType, boolean serialize, boolean deserialize) {
|
||||
final boolean isPrimitive = Primitives.isPrimitive(fieldType.getRawType());
|
||||
|
||||
// special casing primitives here saves ~5% on Android...
|
||||
return new ReflectiveTypeAdapterFactory.BoundField(name, serialize, deserialize) {
|
||||
final TypeAdapter<?> typeAdapter = context.getAdapter(fieldType);
|
||||
@SuppressWarnings("unchecked") // the type adapter and field type always agree
|
||||
@Override void write(JsonWriter writer, Object value)
|
||||
throws IOException, IllegalAccessException {
|
||||
Object fieldValue = field.get(value);
|
||||
TypeAdapter t =
|
||||
new TypeAdapterRuntimeTypeWrapper(context, this.typeAdapter, fieldType.getType());
|
||||
t.write(writer, fieldValue);
|
||||
}
|
||||
@Override void read(JsonReader reader, Object value)
|
||||
throws IOException, IllegalAccessException {
|
||||
Object fieldValue = typeAdapter.read(reader);
|
||||
if (fieldValue != null || !isPrimitive) {
|
||||
field.set(value, fieldValue);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private Map<String, BoundField> getBoundFields(
|
||||
MiniGson context, TypeToken<?> type, Class<?> raw) {
|
||||
Map<String, BoundField> result = new LinkedHashMap<String, BoundField>();
|
||||
if (raw.isInterface()) {
|
||||
return result;
|
||||
}
|
||||
|
||||
Type declaredType = type.getType();
|
||||
while (raw != Object.class) {
|
||||
Field[] fields = raw.getDeclaredFields();
|
||||
AccessibleObject.setAccessible(fields, true);
|
||||
for (Field field : fields) {
|
||||
boolean serialize = serializeField(raw, field, declaredType);
|
||||
boolean deserialize = deserializeField(raw, field, declaredType);
|
||||
if (!serialize && !deserialize) {
|
||||
continue;
|
||||
}
|
||||
Type fieldType = $Gson$Types.resolve(type.getType(), raw, field.getGenericType());
|
||||
BoundField boundField = createBoundField(context, field, getFieldName(raw, field, declaredType),
|
||||
TypeToken.get(fieldType), serialize, deserialize);
|
||||
BoundField previous = result.put(boundField.name, boundField);
|
||||
if (previous != null) {
|
||||
throw new IllegalArgumentException(declaredType
|
||||
+ " declares multiple JSON fields named " + previous.name);
|
||||
}
|
||||
}
|
||||
type = TypeToken.get($Gson$Types.resolve(type.getType(), raw, raw.getGenericSuperclass()));
|
||||
raw = type.getRawType();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static abstract class BoundField {
|
||||
final String name;
|
||||
final boolean serialized;
|
||||
final boolean deserialized;
|
||||
|
||||
protected BoundField(String name, boolean serialized, boolean deserialized) {
|
||||
this.name = name;
|
||||
this.serialized = serialized;
|
||||
this.deserialized = deserialized;
|
||||
}
|
||||
|
||||
abstract void write(JsonWriter writer, Object value) throws IOException, IllegalAccessException;
|
||||
abstract void read(JsonReader reader, Object value) throws IOException, IllegalAccessException;
|
||||
}
|
||||
|
||||
public final class Adapter<T> extends TypeAdapter<T> {
|
||||
private final MiniGson context;
|
||||
private final ObjectConstructor<T> constructor;
|
||||
private final TypeToken<T> type;
|
||||
private final Map<String, BoundField> boundFields;
|
||||
|
||||
private Adapter(MiniGson context, ObjectConstructor<T> constructor,
|
||||
TypeToken<T> type, Map<String, BoundField> boundFields) {
|
||||
this.context = context;
|
||||
this.constructor = constructor;
|
||||
this.type = type;
|
||||
this.boundFields = boundFields;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked") // the '? super T' is a raw T (the only kind we can construct)
|
||||
public T read(JsonReader reader) throws IOException {
|
||||
if (reader.peek() == JsonToken.NULL) {
|
||||
reader.nextNull(); // TODO: does this belong here?
|
||||
return null;
|
||||
}
|
||||
|
||||
T instance = constructor.construct();
|
||||
|
||||
// TODO: null out the other fields?
|
||||
|
||||
try {
|
||||
reader.beginObject();
|
||||
while (reader.hasNext()) {
|
||||
String name = reader.nextName();
|
||||
BoundField field = boundFields.get(name);
|
||||
if (field == null || !field.deserialized) {
|
||||
// TODO: define a better policy
|
||||
reader.skipValue();
|
||||
} else {
|
||||
field.read(reader, instance);
|
||||
}
|
||||
}
|
||||
} catch (IllegalStateException e) {
|
||||
throw new JsonSyntaxException(e);
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new AssertionError();
|
||||
}
|
||||
reader.endObject();
|
||||
return instance;
|
||||
}
|
||||
|
||||
public void write(JsonWriter writer, T value) throws IOException {
|
||||
if (value == null) {
|
||||
writer.nullValue(); // TODO: better policy here?
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: GSON includes subclass fields during serialization
|
||||
if (false) {
|
||||
Class<?> runtimeType = value.getClass();
|
||||
if (runtimeType != type.getRawType()) {
|
||||
TypeAdapter<?> adapter = context.getAdapter(runtimeType);
|
||||
((TypeAdapter) adapter).write(writer, value);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
writer.beginObject();
|
||||
try {
|
||||
for (BoundField boundField : boundFields.values()) {
|
||||
if (boundField.serialized) {
|
||||
writer.name(boundField.name);
|
||||
boundField.write(writer, value);
|
||||
}
|
||||
}
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new AssertionError();
|
||||
}
|
||||
writer.endObject();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,106 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2011 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.google.gson.internal.bind;
|
||||
|
||||
import com.google.gson.internal.$Gson$Types;
|
||||
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.lang.reflect.Constructor;
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Adapt a map whose keys are strings.
|
||||
*/
|
||||
public final class StringToValueMapTypeAdapter<V> extends TypeAdapter<Map<String, V>> {
|
||||
public static final Factory FACTORY = new Factory() {
|
||||
public <T> TypeAdapter<T> create(MiniGson context, TypeToken<T> typeToken) {
|
||||
Type type = typeToken.getType();
|
||||
if (!(type instanceof ParameterizedType)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Class<? super T> rawType = typeToken.getRawType();
|
||||
if (!Map.class.isAssignableFrom(rawType)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Type[] keyAndValueTypes = $Gson$Types.getMapKeyAndValueTypes(type, rawType);
|
||||
if (keyAndValueTypes[0] != String.class) {
|
||||
return null;
|
||||
}
|
||||
TypeAdapter<?> valueAdapter = context.getAdapter(TypeToken.get(keyAndValueTypes[1]));
|
||||
|
||||
Constructor<?> constructor;
|
||||
try {
|
||||
Class<?> constructorType = (rawType == Map.class) ? LinkedHashMap.class : rawType;
|
||||
constructor = constructorType.getConstructor();
|
||||
} catch (NoSuchMethodException e) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked") // we don't define a type parameter for the key or value types
|
||||
TypeAdapter<T> result = new StringToValueMapTypeAdapter(valueAdapter, constructor);
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
private final TypeAdapter<V> valueTypeAdapter;
|
||||
private final Constructor<? extends Map<String, V>> constructor;
|
||||
|
||||
public StringToValueMapTypeAdapter(TypeAdapter<V> valueTypeAdapter,
|
||||
Constructor<? extends Map<String, V>> constructor) {
|
||||
this.valueTypeAdapter = valueTypeAdapter;
|
||||
this.constructor = constructor;
|
||||
}
|
||||
|
||||
public Map<String, V> read(JsonReader reader) throws IOException {
|
||||
if (reader.peek() == JsonToken.NULL) {
|
||||
reader.nextNull(); // TODO: does this belong here?
|
||||
return null;
|
||||
}
|
||||
|
||||
Map<String, V> map = Reflection.newInstance(constructor);
|
||||
reader.beginObject();
|
||||
while (reader.hasNext()) {
|
||||
String key = reader.nextName();
|
||||
V value = valueTypeAdapter.read(reader);
|
||||
map.put(key, value);
|
||||
}
|
||||
reader.endObject();
|
||||
return map;
|
||||
}
|
||||
|
||||
public void write(JsonWriter writer, Map<String, V> map) throws IOException {
|
||||
if (map == null) {
|
||||
writer.nullValue(); // TODO: better policy here?
|
||||
return;
|
||||
}
|
||||
|
||||
writer.beginObject();
|
||||
for (Map.Entry<String, V> entry : map.entrySet()) {
|
||||
writer.name(entry.getKey());
|
||||
valueTypeAdapter.write(writer, entry.getValue());
|
||||
}
|
||||
writer.endObject();
|
||||
}
|
||||
}
|
@ -0,0 +1,106 @@
|
||||
/*
|
||||
* Copyright (C) 2011 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.google.gson.internal.bind;
|
||||
|
||||
import com.google.gson.internal.$Gson$Types;
|
||||
import com.google.gson.internal.ConstructorConstructor;
|
||||
import com.google.gson.internal.ObjectConstructor;
|
||||
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.lang.reflect.ParameterizedType;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Adapt a map whose keys are strings.
|
||||
*/
|
||||
public final class StringToValueMapTypeAdapterFactory implements TypeAdapter.Factory {
|
||||
private final ConstructorConstructor constructorConstructor;
|
||||
|
||||
public StringToValueMapTypeAdapterFactory(ConstructorConstructor constructorConstructor) {
|
||||
this.constructorConstructor = constructorConstructor;
|
||||
}
|
||||
|
||||
public <T> TypeAdapter<T> create(MiniGson context, TypeToken<T> typeToken) {
|
||||
Type type = typeToken.getType();
|
||||
if (!(type instanceof ParameterizedType)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Class<? super T> rawType = typeToken.getRawType();
|
||||
if (!Map.class.isAssignableFrom(rawType)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Type[] keyAndValueTypes = $Gson$Types.getMapKeyAndValueTypes(type, rawType);
|
||||
if (keyAndValueTypes[0] != String.class) {
|
||||
return null;
|
||||
}
|
||||
TypeAdapter<?> valueAdapter = context.getAdapter(TypeToken.get(keyAndValueTypes[1]));
|
||||
|
||||
ObjectConstructor<?> constructor = constructorConstructor.getConstructor(typeToken);
|
||||
|
||||
@SuppressWarnings("unchecked") // we don't define a type parameter for the key or value types
|
||||
TypeAdapter<T> result = new Adapter(valueAdapter, constructor);
|
||||
return result;
|
||||
}
|
||||
|
||||
private final class Adapter<V> extends TypeAdapter<Map<String, V>> {
|
||||
private final TypeAdapter<V> valueTypeAdapter;
|
||||
private final ObjectConstructor<? extends Map<String, V>> constructor;
|
||||
|
||||
public Adapter(TypeAdapter<V> valueTypeAdapter,
|
||||
ObjectConstructor<? extends Map<String, V>> constructor) {
|
||||
this.valueTypeAdapter = valueTypeAdapter;
|
||||
this.constructor = constructor;
|
||||
}
|
||||
|
||||
public Map<String, V> read(JsonReader reader) throws IOException {
|
||||
if (reader.peek() == JsonToken.NULL) {
|
||||
reader.nextNull(); // TODO: does this belong here?
|
||||
return null;
|
||||
}
|
||||
|
||||
Map<String, V> map = constructor.construct();
|
||||
reader.beginObject();
|
||||
while (reader.hasNext()) {
|
||||
String key = reader.nextName();
|
||||
V value = valueTypeAdapter.read(reader);
|
||||
map.put(key, value);
|
||||
}
|
||||
reader.endObject();
|
||||
return map;
|
||||
}
|
||||
|
||||
public void write(JsonWriter writer, Map<String, V> map) throws IOException {
|
||||
if (map == null) {
|
||||
writer.nullValue(); // TODO: better policy here?
|
||||
return;
|
||||
}
|
||||
|
||||
writer.beginObject();
|
||||
for (Map.Entry<String, V> entry : map.entrySet()) {
|
||||
writer.name(entry.getKey());
|
||||
valueTypeAdapter.write(writer, entry.getValue());
|
||||
}
|
||||
writer.endObject();
|
||||
}
|
||||
}
|
||||
}
|
@ -15,12 +15,11 @@
|
||||
*/
|
||||
package com.google.gson.internal.bind;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Type;
|
||||
|
||||
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.Type;
|
||||
|
||||
final class TypeAdapterRuntimeTypeWrapper<T> extends TypeAdapter<T> {
|
||||
|
||||
@ -52,10 +51,10 @@ final class TypeAdapterRuntimeTypeWrapper<T> extends TypeAdapter<T> {
|
||||
Type runtimeType = Reflection.getRuntimeTypeIfMoreSpecific(type, value);
|
||||
if (runtimeType != type) {
|
||||
TypeAdapter runtimeTypeAdapter = context.getAdapter(TypeToken.get(runtimeType));
|
||||
if (!(runtimeTypeAdapter instanceof ReflectiveTypeAdapter)) {
|
||||
if (!(runtimeTypeAdapter instanceof ReflectiveTypeAdapterFactory.Adapter)) {
|
||||
// The user registered a type adapter for the runtime type, so we will use that
|
||||
chosen = runtimeTypeAdapter;
|
||||
} else if (!(delegate instanceof ReflectiveTypeAdapter)) {
|
||||
} else if (!(delegate instanceof ReflectiveTypeAdapterFactory.Adapter)) {
|
||||
// The user registered a type adapter for Base class, so we prefer it over the
|
||||
// reflective type adapter for the runtime type
|
||||
chosen = delegate;
|
||||
|
@ -167,10 +167,15 @@ public final class TypeAdapters {
|
||||
|
||||
public static final TypeAdapter<String> STRING = new TypeAdapter<String>() {
|
||||
public String read(JsonReader reader) throws IOException {
|
||||
if (reader.peek() == JsonToken.NULL) {
|
||||
JsonToken peek = reader.peek();
|
||||
if (peek == JsonToken.NULL) {
|
||||
reader.nextNull(); // TODO: does this belong here?
|
||||
return null;
|
||||
}
|
||||
/* coerce booleans to strings for backwards compatibility */
|
||||
if (peek == JsonToken.BOOLEAN) {
|
||||
return Boolean.toString(reader.nextBoolean());
|
||||
}
|
||||
return reader.nextString();
|
||||
}
|
||||
public void write(JsonWriter writer, String value) throws IOException {
|
||||
@ -314,16 +319,6 @@ public final class TypeAdapters {
|
||||
|
||||
public static final TypeAdapter.Factory LOCALE_FACTORY = newFactory(Locale.class, LOCALE);
|
||||
|
||||
public static final TypeAdapter EXCLUDED_TYPE_ADAPTER = new TypeAdapter<Object>() {
|
||||
@Override public Object read(JsonReader reader) throws IOException {
|
||||
reader.skipValue();
|
||||
return null;
|
||||
}
|
||||
@Override public void write(JsonWriter writer, Object value) throws IOException {
|
||||
writer.nullValue();
|
||||
}
|
||||
};
|
||||
|
||||
public static <T> TypeAdapter.Factory newFactory(
|
||||
final TypeToken<T> type, final TypeAdapter<T> typeAdapter) {
|
||||
return new TypeAdapter.Factory() {
|
||||
|
@ -1,60 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2011 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.google.gson;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedList;
|
||||
|
||||
/**
|
||||
* Unit tests for the default constructor allocator class.
|
||||
*
|
||||
* @author Joel Leitch
|
||||
*/
|
||||
public class DefaultConstructorAllocatorTest extends TestCase {
|
||||
private DefaultConstructorAllocator allocator;
|
||||
|
||||
@Override
|
||||
protected void setUp() throws Exception {
|
||||
super.setUp();
|
||||
allocator = new DefaultConstructorAllocator();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public void testObjectConstructor() throws Exception {
|
||||
ArrayList<Object> arrayList = allocator.newInstance(ArrayList.class);
|
||||
assertTrue(arrayList.isEmpty());
|
||||
assertTrue(allocator.isInCache(ArrayList.class));
|
||||
|
||||
LinkedList<Object> linkedList = allocator.newInstance(LinkedList.class);
|
||||
assertTrue(linkedList.isEmpty());
|
||||
assertTrue(allocator.isInCache(LinkedList.class));
|
||||
}
|
||||
|
||||
public void testMissingDefaultConstructor() throws Exception {
|
||||
assertNull(allocator.newInstance(NoDefaultConstructor.class));
|
||||
assertTrue(allocator.isInCache(NoDefaultConstructor.class));
|
||||
}
|
||||
|
||||
private static class NoDefaultConstructor {
|
||||
@SuppressWarnings("unused")
|
||||
public NoDefaultConstructor(int i) {
|
||||
// do nothing
|
||||
}
|
||||
}
|
||||
}
|
@ -17,12 +17,10 @@
|
||||
package com.google.gson;
|
||||
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import junit.framework.TestCase;
|
||||
|
||||
/**
|
||||
* Unit test for the default JSON map serialization object located in the
|
||||
@ -31,17 +29,11 @@ import java.util.Map;
|
||||
* @author Joel Leitch
|
||||
*/
|
||||
public class DefaultMapJsonSerializerTest extends TestCase {
|
||||
private JsonSerializer<Map<?, ?>> mapSerializer;
|
||||
|
||||
@Override
|
||||
protected void setUp() throws Exception {
|
||||
super.setUp();
|
||||
mapSerializer = new MapTypeAdapter();
|
||||
}
|
||||
private Gson gson = new Gson();
|
||||
|
||||
public void testEmptyMapNoTypeSerialization() {
|
||||
Map<String, String> emptyMap = new HashMap<String, String>();
|
||||
JsonElement element = mapSerializer.serialize(emptyMap, emptyMap.getClass(), null);
|
||||
JsonElement element = gson.toJsonTree(emptyMap, emptyMap.getClass());
|
||||
assertTrue(element instanceof JsonObject);
|
||||
JsonObject emptyMapJsonObject = (JsonObject) element;
|
||||
assertTrue(emptyMapJsonObject.entrySet().isEmpty());
|
||||
@ -50,13 +42,13 @@ public class DefaultMapJsonSerializerTest extends TestCase {
|
||||
public void testEmptyMapSerialization() {
|
||||
Type mapType = new TypeToken<Map<String, String>>() { }.getType();
|
||||
Map<String, String> emptyMap = new HashMap<String, String>();
|
||||
JsonElement element = mapSerializer.serialize(emptyMap, mapType, null);
|
||||
JsonElement element = gson.toJsonTree(emptyMap, mapType);
|
||||
|
||||
assertTrue(element instanceof JsonObject);
|
||||
JsonObject emptyMapJsonObject = (JsonObject) element;
|
||||
assertTrue(emptyMapJsonObject.entrySet().isEmpty());
|
||||
}
|
||||
|
||||
|
||||
public void testNonEmptyMapSerialization() {
|
||||
Type mapType = new TypeToken<Map<String, String>>() { }.getType();
|
||||
Map<String, String> myMap = new HashMap<String, String>();
|
||||
|
@ -16,13 +16,11 @@
|
||||
|
||||
package com.google.gson;
|
||||
|
||||
import com.google.gson.common.TestTypes.ClassWithNoFields;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.LinkedList;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import com.google.gson.common.TestTypes.ClassWithNoFields;
|
||||
|
||||
/**
|
||||
* Functional tests for Gson that depend on some internal package-protected elements of
|
||||
* com.google.gson package and hence must be placed in the same package. We should make every
|
||||
@ -39,7 +37,7 @@ public class FunctionWithInternalDependenciesTest extends TestCase {
|
||||
strategies.add(new ModifierBasedExclusionStrategy(Modifier.TRANSIENT, Modifier.STATIC));
|
||||
ExclusionStrategy exclusionStrategy = new DisjunctionExclusionStrategy(strategies);
|
||||
Gson gson = new Gson(exclusionStrategy, exclusionStrategy, Gson.DEFAULT_NAMING_POLICY,
|
||||
new MappedObjectConstructor(DefaultTypeAdapters.getDefaultInstanceCreators()),
|
||||
DefaultTypeAdapters.getDefaultInstanceCreators(),
|
||||
false, DefaultTypeAdapters.getDefaultSerializers(),
|
||||
DefaultTypeAdapters.getDefaultDeserializers(), Gson.DEFAULT_JSON_NON_EXECUTABLE, true,
|
||||
false, false, LongSerializationPolicy.DEFAULT);
|
||||
|
@ -1,88 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2011 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.google.gson;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
|
||||
/**
|
||||
* Unit tests for the {@link MappedObjectConstructor} class.
|
||||
*
|
||||
* @author Joel Leitch
|
||||
*/
|
||||
public class MappedObjectConstructorTest extends TestCase {
|
||||
private ParameterizedTypeHandlerMap<InstanceCreator<?>> creatorMap;
|
||||
private MappedObjectConstructor constructor;
|
||||
|
||||
@Override
|
||||
protected void setUp() throws Exception {
|
||||
super.setUp();
|
||||
creatorMap = new ParameterizedTypeHandlerMap<InstanceCreator<?>>();
|
||||
constructor = new MappedObjectConstructor(creatorMap);
|
||||
}
|
||||
|
||||
public void testInstanceCreatorTakesTopPrecedence() throws Exception {
|
||||
creatorMap.register(ObjectWithDefaultConstructor.class, new MyInstanceCreator(), false);
|
||||
ObjectWithDefaultConstructor obj =
|
||||
constructor.construct(ObjectWithDefaultConstructor.class);
|
||||
assertEquals("instanceCreator", obj.stringValue);
|
||||
assertEquals(10, obj.intValue);
|
||||
}
|
||||
|
||||
public void testNoInstanceCreatorInvokesDefaultConstructor() throws Exception {
|
||||
ObjectWithDefaultConstructor expected = new ObjectWithDefaultConstructor();
|
||||
ObjectWithDefaultConstructor obj =
|
||||
constructor.construct(ObjectWithDefaultConstructor.class);
|
||||
assertEquals(expected.stringValue, obj.stringValue);
|
||||
assertEquals(expected.intValue, obj.intValue);
|
||||
}
|
||||
|
||||
public void testNoDefaultConstructor() throws Exception {
|
||||
ObjectNoDefaultConstructor obj = constructor.construct(ObjectNoDefaultConstructor.class);
|
||||
assertNull(obj.stringValue);
|
||||
assertEquals(0, obj.intValue);
|
||||
}
|
||||
|
||||
private static class MyInstanceCreator
|
||||
implements InstanceCreator<ObjectWithDefaultConstructor> {
|
||||
public ObjectWithDefaultConstructor createInstance(Type type) {
|
||||
return new ObjectWithDefaultConstructor("instanceCreator", 10);
|
||||
}
|
||||
}
|
||||
|
||||
private static class ObjectWithDefaultConstructor {
|
||||
public final String stringValue;
|
||||
public final int intValue;
|
||||
|
||||
private ObjectWithDefaultConstructor() {
|
||||
this("default", 5);
|
||||
}
|
||||
|
||||
public ObjectWithDefaultConstructor(String stringValue, int intValue) {
|
||||
this.stringValue = stringValue;
|
||||
this.intValue = intValue;
|
||||
}
|
||||
}
|
||||
|
||||
private static class ObjectNoDefaultConstructor extends ObjectWithDefaultConstructor {
|
||||
@SuppressWarnings("unused")
|
||||
public ObjectNoDefaultConstructor(String stringValue, int intValue) {
|
||||
super(stringValue, intValue);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,84 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2008 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.google.gson;
|
||||
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import java.util.EmptyStackException;
|
||||
|
||||
/**
|
||||
* Unit tests for the {@link MemoryRefStack} class.
|
||||
*
|
||||
* @author Joel Leitch
|
||||
*/
|
||||
public class MemoryRefStackTest extends TestCase {
|
||||
private MemoryRefStack stack;
|
||||
|
||||
@Override
|
||||
protected void setUp() throws Exception {
|
||||
super.setUp();
|
||||
stack = new MemoryRefStack();
|
||||
}
|
||||
|
||||
public void testPeekEmptyStack() throws Exception {
|
||||
try {
|
||||
stack.peek();
|
||||
} catch (EmptyStackException expected) { }
|
||||
}
|
||||
|
||||
public void testPushPeekAndPop() throws Exception {
|
||||
ObjectTypePair obj = new ObjectTypePair(this, getClass(), true, false);
|
||||
|
||||
assertEquals(obj, stack.push(obj));
|
||||
assertEquals(obj, stack.peek());
|
||||
assertEquals(obj, stack.pop());
|
||||
}
|
||||
|
||||
public void testPopTooMany() throws Exception {
|
||||
ObjectTypePair obj = new ObjectTypePair(this, getClass(), true, false);
|
||||
stack.push(obj);
|
||||
assertEquals(obj, stack.pop());
|
||||
|
||||
try {
|
||||
stack.pop();
|
||||
} catch (EmptyStackException expected) { }
|
||||
}
|
||||
|
||||
public void testContains() throws Exception {
|
||||
MockObject objA = new MockObject();
|
||||
MockObject objB = new MockObject();
|
||||
assertEquals(objA, objB);
|
||||
stack.push(new ObjectTypePair(objA, MockObject.class, true, false));
|
||||
assertTrue(stack.contains(new ObjectTypePair(objA, MockObject.class, true, false)));
|
||||
assertFalse(stack.contains(new ObjectTypePair(objB, MockObject.class, true, false)));
|
||||
}
|
||||
|
||||
private static class MockObject {
|
||||
private final int value = 1;
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
return obj instanceof MockObject && value == ((MockObject) obj).value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
}
|
@ -73,7 +73,7 @@ public final class MixedStreamTest extends TestCase {
|
||||
assertEquals(RED_MIATA, gson.fromJson(jsonReader, Car.class));
|
||||
jsonReader.endArray();
|
||||
}
|
||||
|
||||
|
||||
public void testReaderDoesNotMutateState() throws IOException {
|
||||
Gson gson = new Gson();
|
||||
JsonReader jsonReader = new JsonReader(new StringReader(CARS_JSON));
|
||||
@ -114,7 +114,7 @@ public final class MixedStreamTest extends TestCase {
|
||||
try {
|
||||
gson.fromJson(jsonReader, String.class);
|
||||
fail();
|
||||
} catch (IllegalArgumentException expected) {
|
||||
} catch (IllegalStateException expected) {
|
||||
}
|
||||
}
|
||||
|
||||
@ -152,7 +152,7 @@ public final class MixedStreamTest extends TestCase {
|
||||
} catch (IllegalStateException expected) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void testWriteNulls() {
|
||||
Gson gson = new Gson();
|
||||
try {
|
||||
@ -165,7 +165,7 @@ public final class MixedStreamTest extends TestCase {
|
||||
gson.toJson(null, new JsonWriter(stringWriter));
|
||||
assertEquals("", stringWriter.toString());
|
||||
}
|
||||
|
||||
|
||||
public void testReadNulls() {
|
||||
Gson gson = new Gson();
|
||||
try {
|
||||
@ -176,7 +176,7 @@ public final class MixedStreamTest extends TestCase {
|
||||
try {
|
||||
gson.fromJson(new JsonReader(new StringReader("true")), null);
|
||||
fail();
|
||||
} catch (IllegalArgumentException expected) {
|
||||
} catch (NullPointerException expected) {
|
||||
}
|
||||
}
|
||||
|
||||
@ -195,7 +195,7 @@ public final class MixedStreamTest extends TestCase {
|
||||
assertEquals("[\"<\",\">\",\"&\",\"=\",\"'\"]",
|
||||
writer.toString());
|
||||
}
|
||||
|
||||
|
||||
public void testWriteLenient() {
|
||||
List<Double> doubles = Arrays.asList(Double.NaN, Double.NEGATIVE_INFINITY,
|
||||
Double.POSITIVE_INFINITY, -0.0d, 0.5d, 0.0d);
|
||||
|
@ -1,43 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2008 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.google.gson;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
/**
|
||||
* Unit test for the {@link NullExclusionStrategy} class.
|
||||
*
|
||||
* @author Joel Leitch
|
||||
*/
|
||||
public class NullExclusionStrategyTest extends TestCase {
|
||||
private NullExclusionStrategy strategy;
|
||||
|
||||
@Override
|
||||
protected void setUp() throws Exception {
|
||||
super.setUp();
|
||||
strategy = new NullExclusionStrategy();
|
||||
}
|
||||
|
||||
public void testNeverSkipsClass() throws Exception {
|
||||
assertFalse(strategy.shouldSkipClass(String.class));
|
||||
}
|
||||
|
||||
public void testNeverSkipsField() throws Exception {
|
||||
assertFalse(strategy.shouldSkipField(
|
||||
new FieldAttributes(String.class, String.class.getFields()[0], String.class)));
|
||||
}
|
||||
}
|
@ -18,6 +18,7 @@ package com.google.gson;
|
||||
|
||||
import com.google.gson.internal.$Gson$Types;
|
||||
|
||||
import com.google.gson.internal.Primitives;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
|
@ -16,6 +16,7 @@
|
||||
|
||||
package com.google.gson;
|
||||
|
||||
import com.google.gson.internal.Primitives;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
|
@ -53,7 +53,7 @@ public class ExclusionStrategyFunctionalTest extends TestCase {
|
||||
assertFalse(json.contains("\"annotatedField\""));
|
||||
assertTrue(json.contains("\"longField\""));
|
||||
}
|
||||
|
||||
|
||||
public void testExclusionStrategyDeserialization() throws Exception {
|
||||
Gson gson = createGson(new MyExclusionStrategy(String.class), false);
|
||||
JsonObject json = new JsonObject();
|
||||
@ -68,13 +68,13 @@ public class ExclusionStrategyFunctionalTest extends TestCase {
|
||||
assertEquals(src.annotatedField, target.annotatedField);
|
||||
assertEquals(src.stringField, target.stringField);
|
||||
}
|
||||
|
||||
|
||||
public void testExclusionStrategyWithMode() throws Exception {
|
||||
SampleObjectForTest testObj = new SampleObjectForTest(
|
||||
src.annotatedField + 5, src.stringField + "blah,blah",
|
||||
src.longField + 655L);
|
||||
|
||||
Gson gson = createGson(new MyExclusionStrategy(String.class), false);
|
||||
Gson gson = createGson(new MyExclusionStrategy(String.class), false);
|
||||
JsonObject json = gson.toJsonTree(testObj).getAsJsonObject();
|
||||
assertEquals(testObj.annotatedField, json.get("annotatedField").getAsInt());
|
||||
assertEquals(testObj.stringField, json.get("stringField").getAsString());
|
||||
@ -99,7 +99,7 @@ public class ExclusionStrategyFunctionalTest extends TestCase {
|
||||
.serializeNulls()
|
||||
.create();
|
||||
}
|
||||
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ElementType.FIELD})
|
||||
private static @interface Foo {
|
||||
@ -115,7 +115,7 @@ public class ExclusionStrategyFunctionalTest extends TestCase {
|
||||
public SampleObjectForTest() {
|
||||
this(5, "someDefaultValue", 12345L);
|
||||
}
|
||||
|
||||
|
||||
public SampleObjectForTest(int annotatedField, String stringField, long longField) {
|
||||
this.annotatedField = annotatedField;
|
||||
this.stringField = stringField;
|
||||
|
@ -16,17 +16,15 @@
|
||||
|
||||
package com.google.gson.functional;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import com.google.gson.JsonSyntaxException;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import junit.framework.TestCase;
|
||||
|
||||
public class MapAsArrayTypeAdapterTest extends TestCase {
|
||||
|
||||
@ -82,7 +80,7 @@ public class MapAsArrayTypeAdapterTest extends TestCase {
|
||||
} catch (JsonSyntaxException expected) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void testMultipleEnableComplexKeyRegistrationHasNoEffect() throws Exception {
|
||||
Type type = new TypeToken<Map<Point, String>>() {}.getType();
|
||||
Gson gson = new GsonBuilder()
|
||||
|
@ -14,10 +14,11 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.google.gson;
|
||||
package com.google.gson.internal;
|
||||
|
||||
import com.google.gson.common.TestTypes.Base;
|
||||
import com.google.gson.common.TestTypes.Sub;
|
||||
import com.google.gson.internal.ParameterizedTypeHandlerMap;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
@ -26,7 +27,7 @@ import java.lang.reflect.Type;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Unit tests for the {@link ParameterizedTypeHandlerMap} class.
|
||||
* Unit tests for the {@link com.google.gson.internal.ParameterizedTypeHandlerMap} class.
|
||||
*
|
||||
* @author Joel Leitch
|
||||
*/
|
Loading…
Reference in New Issue
Block a user