From 6035b204dcf958ef045a927fd6d14508960cedbd Mon Sep 17 00:00:00 2001
From: Brettflan
Date: Wed, 22 Jun 2011 18:40:56 -0500
Subject: [PATCH] updating built-in GSON to 1.7.1 release
---
...onymousAndLocalClassExclusionStrategy.java | 1 -
.../factions/gson/BaseMapTypeAdapter.java | 44 ++
src/org/mcteam/factions/gson/Cache.java | 16 +-
.../gson/CamelCaseSeparatorNamingPolicy.java | 6 +-
.../gson/DefaultConstructorAllocator.java | 91 +++
.../factions/gson/DefaultTypeAdapters.java | 513 ++++++++++-----
.../gson/DelegatingJsonElementVisitor.java | 21 +-
.../gson/DisjunctionExclusionStrategy.java | 7 +-
src/org/mcteam/factions/gson/Escaper.java | 16 +-
.../factions/gson/ExclusionStrategy.java | 14 +
...ationDeserializationExclusionStrategy.java | 5 +-
...otationSerializationExclusionStrategy.java | 4 +-
.../mcteam/factions/gson/FieldAttributes.java | 44 +-
.../factions/gson/FieldNamingStrategy2.java | 1 -
.../gson/FieldNamingStrategy2Adapter.java | 16 +-
.../factions/gson/GenericArrayTypeImpl.java | 70 ---
src/org/mcteam/factions/gson/Gson.java | 84 +--
src/org/mcteam/factions/gson/GsonBuilder.java | 232 +++++--
.../gson/InnerClassExclusionStrategy.java | 2 +-
src/org/mcteam/factions/gson/JsonArray.java | 10 +
.../gson/JsonArrayDeserializationVisitor.java | 33 +-
.../JsonDeserializationContextDefault.java | 27 +-
.../gson/JsonDeserializationVisitor.java | 27 +-
.../JsonDeserializerExceptionWrapper.java | 11 +-
.../factions/gson/JsonFieldNameValidator.java | 56 --
src/org/mcteam/factions/gson/JsonNull.java | 2 +-
src/org/mcteam/factions/gson/JsonObject.java | 16 +-
.../JsonObjectDeserializationVisitor.java | 23 +-
src/org/mcteam/factions/gson/JsonParser.java | 7 +-
.../mcteam/factions/gson/JsonPrimitive.java | 27 +-
.../gson/JsonSerializationContextDefault.java | 24 +-
.../gson/JsonSerializationVisitor.java | 44 +-
.../factions/gson/JsonStreamParser.java | 1 -
src/org/mcteam/factions/gson/LruCache.java | 21 +-
.../factions/gson/MapAsArrayTypeAdapter.java | 16 +-
.../mcteam/factions/gson/MapTypeAdapter.java | 78 +++
.../gson/MappedObjectConstructor.java | 71 +--
.../mcteam/factions/gson/MemoryRefStack.java | 5 +-
.../gson/ModifyFirstLetterNamingPolicy.java | 11 +-
.../factions/gson/NullExclusionStrategy.java | 1 -
.../mcteam/factions/gson/ObjectNavigator.java | 74 +--
.../factions/gson/ObjectNavigatorFactory.java | 61 --
.../mcteam/factions/gson/ObjectTypePair.java | 16 +-
src/org/mcteam/factions/gson/Pair.java | 7 +-
.../gson/ParameterizedTypeHandlerMap.java | 35 +-
.../factions/gson/ParameterizedTypeImpl.java | 91 ---
src/org/mcteam/factions/gson/Primitives.java | 37 +-
.../gson/RecursiveFieldNamingPolicy.java | 1 -
.../gson/ReflectingFieldNavigator.java | 106 ++++
...ameAnnotationInterceptingNamingPolicy.java | 22 +-
src/org/mcteam/factions/gson/Streams.java | 7 +-
.../gson/SyntheticFieldExclusionStrategy.java | 2 +-
src/org/mcteam/factions/gson/TypeAdapter.java | 35 --
src/org/mcteam/factions/gson/TypeInfo.java | 76 ---
.../mcteam/factions/gson/TypeInfoArray.java | 69 --
.../factions/gson/TypeInfoCollection.java | 46 --
.../mcteam/factions/gson/TypeInfoFactory.java | 175 ------
src/org/mcteam/factions/gson/TypeInfoMap.java | 58 --
src/org/mcteam/factions/gson/TypeUtils.java | 95 ---
.../mcteam/factions/gson/UnsafeAllocator.java | 104 ++++
.../gson/VersionExclusionStrategy.java | 5 +-
.../$Gson$Preconditions.java} | 17 +-
.../factions/gson/internal/$Gson$Types.java | 589 ++++++++++++++++++
.../factions/gson/internal/package-info.java | 7 +
.../mcteam/factions/gson/package-info.java | 6 +-
.../factions/gson/reflect/TypeToken.java | 227 +++----
.../factions/gson/stream/JsonReader.java | 3 +-
67 files changed, 2044 insertions(+), 1625 deletions(-)
create mode 100644 src/org/mcteam/factions/gson/BaseMapTypeAdapter.java
create mode 100644 src/org/mcteam/factions/gson/DefaultConstructorAllocator.java
delete mode 100644 src/org/mcteam/factions/gson/GenericArrayTypeImpl.java
delete mode 100644 src/org/mcteam/factions/gson/JsonFieldNameValidator.java
create mode 100644 src/org/mcteam/factions/gson/MapTypeAdapter.java
delete mode 100644 src/org/mcteam/factions/gson/ObjectNavigatorFactory.java
delete mode 100644 src/org/mcteam/factions/gson/ParameterizedTypeImpl.java
create mode 100644 src/org/mcteam/factions/gson/ReflectingFieldNavigator.java
delete mode 100644 src/org/mcteam/factions/gson/TypeAdapter.java
delete mode 100644 src/org/mcteam/factions/gson/TypeInfo.java
delete mode 100644 src/org/mcteam/factions/gson/TypeInfoArray.java
delete mode 100644 src/org/mcteam/factions/gson/TypeInfoCollection.java
delete mode 100644 src/org/mcteam/factions/gson/TypeInfoFactory.java
delete mode 100644 src/org/mcteam/factions/gson/TypeInfoMap.java
delete mode 100644 src/org/mcteam/factions/gson/TypeUtils.java
create mode 100644 src/org/mcteam/factions/gson/UnsafeAllocator.java
rename src/org/mcteam/factions/gson/{Preconditions.java => internal/$Gson$Preconditions.java} (77%)
create mode 100644 src/org/mcteam/factions/gson/internal/$Gson$Types.java
create mode 100644 src/org/mcteam/factions/gson/internal/package-info.java
diff --git a/src/org/mcteam/factions/gson/AnonymousAndLocalClassExclusionStrategy.java b/src/org/mcteam/factions/gson/AnonymousAndLocalClassExclusionStrategy.java
index 2d4cd23a..77817e52 100644
--- a/src/org/mcteam/factions/gson/AnonymousAndLocalClassExclusionStrategy.java
+++ b/src/org/mcteam/factions/gson/AnonymousAndLocalClassExclusionStrategy.java
@@ -16,7 +16,6 @@
package org.mcteam.factions.gson;
-
/**
* Strategy for excluding anonymous and local classes.
*
diff --git a/src/org/mcteam/factions/gson/BaseMapTypeAdapter.java b/src/org/mcteam/factions/gson/BaseMapTypeAdapter.java
new file mode 100644
index 00000000..bf0480fc
--- /dev/null
+++ b/src/org/mcteam/factions/gson/BaseMapTypeAdapter.java
@@ -0,0 +1,44 @@
+/*
+ * 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 org.mcteam.factions.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
*
* @author Inderjeet Singh
* @author Joel Leitch
*/
public final class GsonBuilder {
+ private static final MapAsArrayTypeAdapter COMPLEX_KEY_MAP_TYPE_ADAPTER =
+ new MapAsArrayTypeAdapter();
private static final InnerClassExclusionStrategy innerClassExclusionStrategy =
new InnerClassExclusionStrategy();
- private static final ExposeAnnotationSerializationExclusionStrategy
- exposeAnnotationSerializationExclusionStrategy =
- new ExposeAnnotationSerializationExclusionStrategy();
private static final ExposeAnnotationDeserializationExclusionStrategy
- exposeAnnotationDeserializationExclusionStrategy =
+ exposeAnnotationDeserializationExclusionStrategy =
new ExposeAnnotationDeserializationExclusionStrategy();
+ private static final ExposeAnnotationSerializationExclusionStrategy
+ exposeAnnotationSerializationExclusionStrategy =
+ new ExposeAnnotationSerializationExclusionStrategy();
- private final Collection exclusionStrategies =
+ private final Set serializeExclusionStrategies =
+ new HashSet();
+ private final Set deserializeExclusionStrategies =
new HashSet();
private double ignoreVersionsAfter;
@@ -91,8 +106,10 @@ public final class GsonBuilder {
*/
public GsonBuilder() {
// add default exclusion strategies
- exclusionStrategies.add(Gson.DEFAULT_ANON_LOCAL_CLASS_EXCLUSION_STRATEGY);
- exclusionStrategies.add(Gson.DEFAULT_SYNTHETIC_FIELD_EXCLUSION_STRATEGY);
+ deserializeExclusionStrategies.add(Gson.DEFAULT_ANON_LOCAL_CLASS_EXCLUSION_STRATEGY);
+ deserializeExclusionStrategies.add(Gson.DEFAULT_SYNTHETIC_FIELD_EXCLUSION_STRATEGY);
+ serializeExclusionStrategies.add(Gson.DEFAULT_ANON_LOCAL_CLASS_EXCLUSION_STRATEGY);
+ serializeExclusionStrategies.add(Gson.DEFAULT_SYNTHETIC_FIELD_EXCLUSION_STRATEGY);
// setup default values
ignoreVersionsAfter = VersionConstants.IGNORE_VERSIONS;
@@ -178,6 +195,87 @@ public final class GsonBuilder {
return this;
}
+ /**
+ * Enabling this feature will only change the serialized form if the map key is
+ * a complex type (i.e. non-primitive) in its serialized JSON
+ * form. The default implementation of map serialization uses {@code toString()}
+ * on the key; however, when this is called then one of the following cases
+ * apply:
+ *
+ *
Maps as JSON objects
+ * For this case, assume that a type adapter is registered to serialize and
+ * deserialize some {@code Point} class, which contains an x and y coordinate,
+ * to/from the JSON Primitive string value {@code "(x,y)"}. The Java map would
+ * then be serialized as a {@link JsonObject}.
+ *
+ *
+ * For this case, assume that a type adapter was NOT registered for some
+ * {@code Point} class, but rather the default Gson serialization is applied.
+ * In this case, some {@code new Point(2,3)} would serialize as {@code
+ * {"x":2,"y":5}}.
+ *
+ *
Given the assumption above, a {@code Map} will be
+ * serialize as an array of arrays (can be viewed as an entry set of pairs).
+ *
+ *
Below is an example of serializing complex types as JSON arrays:
+ *
{@code
+ * Gson gson = new GsonBuilder()
+ * .enableComplexMapKeySerialization()
+ * .create();
+ *
+ * Map original = new LinkedHashMap();
+ * original.put(new Point(5, 6), "a");
+ * original.put(new Point(8, 8), "b");
+ * System.out.println(gson.toJson(original, type));
+ * }
+ *
+ * The JSON output would look as follows:
+ *
+ *
+ * @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern
+ * @since 1.7
+ */
+ public GsonBuilder enableComplexMapKeySerialization() {
+ registerTypeHierarchyAdapter(Map.class, COMPLEX_KEY_MAP_TYPE_ADAPTER);
+ return this;
+ }
+
/**
* Configures Gson to exclude inner classes during serialization.
*
@@ -250,12 +348,45 @@ public final class GsonBuilder {
* @since 1.4
*/
public GsonBuilder setExclusionStrategies(ExclusionStrategy... strategies) {
- for (ExclusionStrategy strategy : strategies) {
- exclusionStrategies.add(strategy);
- }
+ List strategyList = Arrays.asList(strategies);
+ serializeExclusionStrategies.addAll(strategyList);
+ deserializeExclusionStrategies.addAll(strategyList);
return this;
}
+ /**
+ * Configures Gson to apply the passed in exclusion strategy during serialization.
+ * If this method is invoked numerous times with different exclusion strategy objects
+ * then the exclusion strategies that were added will be applied as a disjunction rule.
+ * This means that if one of the added exclusion strategies suggests that a field (or
+ * class) should be skipped then that field (or object) is skipped during its
+ * serialization.
+ *
+ * @param strategy an exclusion strategy to apply during serialization.
+ * @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern
+ * @since 1.7
+ */
+ public GsonBuilder addSerializationExclusionStrategy(ExclusionStrategy strategy) {
+ serializeExclusionStrategies.add(strategy);
+ return this;
+ }
+
+ /**
+ * Configures Gson to apply the passed in exclusion strategy during deserialization.
+ * If this method is invoked numerous times with different exclusion strategy objects
+ * then the exclusion strategies that were added will be applied as a disjunction rule.
+ * This means that if one of the added exclusion strategies suggests that a field (or
+ * class) should be skipped then that field (or object) is skipped during its
+ * deserialization.
+ *
+ * @param strategy an exclusion strategy to apply during deserialization.
+ * @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern
+ * @since 1.7
+ */
+ public GsonBuilder addDeserializationExclusionStrategy(ExclusionStrategy strategy) {
+ deserializeExclusionStrategies.add(strategy);
+ return this;
+ }
/**
* Configures Gson to output Json that fits in a page for pretty printing. This option only
* affects Json serialization.
@@ -284,6 +415,9 @@ public final class GsonBuilder {
* call this method or {@link #setDateFormat(int)} multiple times, but only the last invocation
* will be used to decide the serialization format.
*
+ *
The date format will be used to serialize and deserialize {@link java.util.Date}, {@link
+ * java.sql.Timestamp} and {@link java.sql.Date}.
+ *
*
Note that this pattern must abide by the convention provided by {@code SimpleDateFormat}
* class. See the documentation in {@link java.text.SimpleDateFormat} for more information on
* valid date and time patterns.
@@ -354,8 +488,8 @@ public final class GsonBuilder {
* @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern
*/
public GsonBuilder registerTypeAdapter(Type type, Object typeAdapter) {
- Preconditions.checkArgument(typeAdapter instanceof JsonSerializer>
- || typeAdapter instanceof JsonDeserializer> || typeAdapter instanceof InstanceCreator>);
+ $Gson$Preconditions.checkArgument(typeAdapter instanceof JsonSerializer>
+ || typeAdapter instanceof JsonDeserializer> || typeAdapter instanceof InstanceCreator>);
if (typeAdapter instanceof InstanceCreator>) {
registerInstanceCreator(type, (InstanceCreator>) typeAdapter);
}
@@ -432,9 +566,9 @@ public final class GsonBuilder {
* @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern
* @since 1.7
*/
- GsonBuilder registerTypeHierarchyAdapter(Class> baseType, Object typeAdapter) {
- Preconditions.checkArgument(typeAdapter instanceof JsonSerializer>
- || typeAdapter instanceof JsonDeserializer> || typeAdapter instanceof InstanceCreator>);
+ public GsonBuilder registerTypeHierarchyAdapter(Class> baseType, Object typeAdapter) {
+ $Gson$Preconditions.checkArgument(typeAdapter instanceof JsonSerializer>
+ || typeAdapter instanceof JsonDeserializer> || typeAdapter instanceof InstanceCreator>);
if (typeAdapter instanceof InstanceCreator>) {
registerInstanceCreatorForTypeHierarchy(baseType, (InstanceCreator>) typeAdapter);
}
@@ -498,33 +632,34 @@ public final class GsonBuilder {
* @return an instance of Gson configured with the options currently set in this builder
*/
public Gson create() {
- List serializationStrategies =
- new LinkedList(exclusionStrategies);
List deserializationStrategies =
- new LinkedList(exclusionStrategies);
-
- serializationStrategies.add(modifierBasedExclusionStrategy);
+ new LinkedList(deserializeExclusionStrategies);
+ List serializationStrategies =
+ new LinkedList(serializeExclusionStrategies);
deserializationStrategies.add(modifierBasedExclusionStrategy);
+ serializationStrategies.add(modifierBasedExclusionStrategy);
if (!serializeInnerClasses) {
- serializationStrategies.add(innerClassExclusionStrategy);
deserializationStrategies.add(innerClassExclusionStrategy);
+ serializationStrategies.add(innerClassExclusionStrategy);
}
if (ignoreVersionsAfter != VersionConstants.IGNORE_VERSIONS) {
- serializationStrategies.add(new VersionExclusionStrategy(ignoreVersionsAfter));
- deserializationStrategies.add(new VersionExclusionStrategy(ignoreVersionsAfter));
+ VersionExclusionStrategy versionExclusionStrategy =
+ new VersionExclusionStrategy(ignoreVersionsAfter);
+ deserializationStrategies.add(versionExclusionStrategy);
+ serializationStrategies.add(versionExclusionStrategy);
}
if (excludeFieldsWithoutExposeAnnotation) {
- serializationStrategies.add(exposeAnnotationSerializationExclusionStrategy);
deserializationStrategies.add(exposeAnnotationDeserializationExclusionStrategy);
+ serializationStrategies.add(exposeAnnotationSerializationExclusionStrategy);
}
- ExclusionStrategy serializationExclusionStrategy =
- new DisjunctionExclusionStrategy(serializationStrategies);
- ExclusionStrategy deserializationExclusionStrategy =
- new DisjunctionExclusionStrategy(deserializationStrategies);
- ParameterizedTypeHandlerMap> customSerializers = serializers.copyOf();
- ParameterizedTypeHandlerMap> customDeserializers = deserializers.copyOf();
+ ParameterizedTypeHandlerMap> customSerializers =
+ DefaultTypeAdapters.DEFAULT_HIERARCHY_SERIALIZERS.copyOf();
+ customSerializers.register(serializers.copyOf());
+ ParameterizedTypeHandlerMap> customDeserializers =
+ DefaultTypeAdapters.DEFAULT_HIERARCHY_DESERIALIZERS.copyOf();
+ customDeserializers.register(deserializers.copyOf());
addTypeAdaptersForDate(datePattern, dateStyle, timeStyle, customSerializers,
customDeserializers);
@@ -543,9 +678,11 @@ public final class GsonBuilder {
MappedObjectConstructor objConstructor = new MappedObjectConstructor(customInstanceCreators);
- Gson gson = new Gson(serializationExclusionStrategy, deserializationExclusionStrategy,
- fieldNamingPolicy, objConstructor, serializeNulls, customSerializers,
- customDeserializers, generateNonExecutableJson, escapeHtmlChars, prettyPrinting);
+ Gson gson = new Gson(new DisjunctionExclusionStrategy(deserializationStrategies),
+ new DisjunctionExclusionStrategy(serializationStrategies),
+ fieldNamingPolicy, objConstructor, serializeNulls,
+ customSerializers, customDeserializers, generateNonExecutableJson, escapeHtmlChars,
+ prettyPrinting);
return gson;
}
@@ -560,12 +697,19 @@ public final class GsonBuilder {
}
if (dateTypeAdapter != null) {
- if (!serializers.hasSpecificHandlerFor(Date.class)) {
- serializers.register(Date.class, dateTypeAdapter);
- }
- if (!deserializers.hasSpecificHandlerFor(Date.class)) {
- deserializers.register(Date.class, dateTypeAdapter);
- }
+ registerIfAbsent(Date.class, serializers, dateTypeAdapter);
+ registerIfAbsent(Date.class, deserializers, dateTypeAdapter);
+ registerIfAbsent(Timestamp.class, serializers, dateTypeAdapter);
+ registerIfAbsent(Timestamp.class, deserializers, dateTypeAdapter);
+ registerIfAbsent(java.sql.Date.class, serializers, dateTypeAdapter);
+ registerIfAbsent(java.sql.Date.class, deserializers, dateTypeAdapter);
+ }
+ }
+
+ private static void registerIfAbsent(Class> type,
+ ParameterizedTypeHandlerMap adapters, T adapter) {
+ if (!adapters.hasSpecificHandlerFor(type)) {
+ adapters.register(type, adapter);
}
}
}
diff --git a/src/org/mcteam/factions/gson/InnerClassExclusionStrategy.java b/src/org/mcteam/factions/gson/InnerClassExclusionStrategy.java
index 0942f453..9be82909 100644
--- a/src/org/mcteam/factions/gson/InnerClassExclusionStrategy.java
+++ b/src/org/mcteam/factions/gson/InnerClassExclusionStrategy.java
@@ -23,7 +23,7 @@ import java.lang.reflect.Modifier;
*
* @author Joel Leitch
*/
-class InnerClassExclusionStrategy implements ExclusionStrategy {
+final class InnerClassExclusionStrategy implements ExclusionStrategy {
public boolean shouldSkipField(FieldAttributes f) {
return isInnerClass(f.getDeclaredClass());
diff --git a/src/org/mcteam/factions/gson/JsonArray.java b/src/org/mcteam/factions/gson/JsonArray.java
index e9f04e08..f6fa7e58 100644
--- a/src/org/mcteam/factions/gson/JsonArray.java
+++ b/src/org/mcteam/factions/gson/JsonArray.java
@@ -295,6 +295,16 @@ public final class JsonArray extends JsonElement implements Iterable extends JsonDeserializationVisitor {
JsonArrayDeserializationVisitor(JsonArray jsonArray, Type arrayType,
- ObjectNavigatorFactory factory, ObjectConstructor objectConstructor,
+ ObjectNavigator objectNavigator, FieldNamingStrategy2 fieldNamingPolicy,
+ ObjectConstructor objectConstructor,
ParameterizedTypeHandlerMap> deserializers,
JsonDeserializationContext context) {
- super(jsonArray, arrayType, factory, objectConstructor, deserializers, context);
+ super(jsonArray, arrayType, objectNavigator, fieldNamingPolicy, objectConstructor, deserializers, context);
}
@Override
@SuppressWarnings("unchecked")
protected T constructTarget() {
-
- TypeInfo typeInfo = new TypeInfo(targetType);
-
if (!json.isJsonArray()) {
- throw new JsonParseException("Expecting array found: " + json);
+ throw new JsonParseException("Expecting array found: " + json);
}
JsonArray jsonArray = json.getAsJsonArray();
- if (typeInfo.isArray()) {
- TypeInfoArray arrayTypeInfo = TypeInfoFactory.getTypeInfoForArray(targetType);
+ 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(arrayTypeInfo.getSecondLevelType(),
+ return (T) objectConstructor.constructArray($Gson$Types.getArrayComponentType(targetType),
jsonArray.size());
}
// is a collection
- return (T) objectConstructor.construct(typeInfo.getRawClass());
+ 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);
+ throw new JsonParseException("Expecting array found: " + json);
}
JsonArray jsonArray = json.getAsJsonArray();
- TypeInfoArray arrayTypeInfo = TypeInfoFactory.getTypeInfoForArray(arrayType);
for (int i = 0; i < jsonArray.size(); i++) {
JsonElement jsonChild = jsonArray.get(i);
Object child;
@@ -69,11 +67,12 @@ final class JsonArrayDeserializationVisitor extends JsonDeserializationVisito
if (jsonChild == null || jsonChild.isJsonNull()) {
child = null;
} else if (jsonChild instanceof JsonObject) {
- child = visitChildAsObject(arrayTypeInfo.getComponentRawType(), jsonChild);
+ child = visitChildAsObject($Gson$Types.getArrayComponentType(arrayType), jsonChild);
} else if (jsonChild instanceof JsonArray) {
- child = visitChildAsArray(arrayTypeInfo.getSecondLevelType(), jsonChild.getAsJsonArray());
+ child = visitChildAsArray($Gson$Types.getArrayComponentType(arrayType),
+ jsonChild.getAsJsonArray());
} else if (jsonChild instanceof JsonPrimitive) {
- child = visitChildAsObject(arrayTypeInfo.getComponentRawType(),
+ child = visitChildAsObject($Gson$Types.getArrayComponentType(arrayType),
jsonChild.getAsJsonPrimitive());
} else {
throw new IllegalStateException();
@@ -96,12 +95,12 @@ final class JsonArrayDeserializationVisitor extends JsonDeserializationVisito
}
public void visitObjectField(FieldAttributes f, Type typeOfF, Object obj) {
- throw new JsonParseException("Expecting array but found object field " + f.getName() + ": "
+ 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() + ": "
+ throw new JsonParseException("Expecting array but found field " + f.getName() + ": "
+ parent);
}
diff --git a/src/org/mcteam/factions/gson/JsonDeserializationContextDefault.java b/src/org/mcteam/factions/gson/JsonDeserializationContextDefault.java
index 206191c6..abc6d84a 100644
--- a/src/org/mcteam/factions/gson/JsonDeserializationContextDefault.java
+++ b/src/org/mcteam/factions/gson/JsonDeserializationContextDefault.java
@@ -25,14 +25,17 @@ import java.lang.reflect.Type;
*/
final class JsonDeserializationContextDefault implements JsonDeserializationContext {
- private final ObjectNavigatorFactory navigatorFactory;
+ private final ObjectNavigator objectNavigator;
+ private final FieldNamingStrategy2 fieldNamingPolicy;
private final ParameterizedTypeHandlerMap> deserializers;
private final MappedObjectConstructor objectConstructor;
- JsonDeserializationContextDefault(ObjectNavigatorFactory navigatorFactory,
+ JsonDeserializationContextDefault(ObjectNavigator objectNavigator,
+ FieldNamingStrategy2 fieldNamingPolicy,
ParameterizedTypeHandlerMap> deserializers,
MappedObjectConstructor objectConstructor) {
- this.navigatorFactory = navigatorFactory;
+ this.objectNavigator = objectNavigator;
+ this.fieldNamingPolicy = fieldNamingPolicy;
this.deserializers = deserializers;
this.objectConstructor = objectConstructor;
}
@@ -59,18 +62,18 @@ final class JsonDeserializationContextDefault implements JsonDeserializationCont
private T fromJsonArray(Type arrayType, JsonArray jsonArray,
JsonDeserializationContext context) throws JsonParseException {
JsonArrayDeserializationVisitor visitor = new JsonArrayDeserializationVisitor(
- jsonArray, arrayType, navigatorFactory, objectConstructor, deserializers, context);
- ObjectNavigator on = navigatorFactory.create(new ObjectTypePair(null, arrayType, true));
- on.accept(visitor);
+ jsonArray, arrayType, objectNavigator, fieldNamingPolicy,
+ objectConstructor, deserializers, context);
+ objectNavigator.accept(new ObjectTypePair(null, arrayType, true), visitor);
return visitor.getTarget();
}
private T fromJsonObject(Type typeOfT, JsonObject jsonObject,
JsonDeserializationContext context) throws JsonParseException {
JsonObjectDeserializationVisitor visitor = new JsonObjectDeserializationVisitor(
- jsonObject, typeOfT, navigatorFactory, objectConstructor, deserializers, context);
- ObjectNavigator on = navigatorFactory.create(new ObjectTypePair(null, typeOfT, true));
- on.accept(visitor);
+ jsonObject, typeOfT, objectNavigator, fieldNamingPolicy,
+ objectConstructor, deserializers, context);
+ objectNavigator.accept(new ObjectTypePair(null, typeOfT, true), visitor);
return visitor.getTarget();
}
@@ -78,10 +81,8 @@ final class JsonDeserializationContextDefault implements JsonDeserializationCont
private T fromJsonPrimitive(Type typeOfT, JsonPrimitive json,
JsonDeserializationContext context) throws JsonParseException {
JsonObjectDeserializationVisitor visitor = new JsonObjectDeserializationVisitor(
- json, typeOfT, navigatorFactory, objectConstructor, deserializers, context);
- ObjectNavigator on =
- navigatorFactory.create(new ObjectTypePair(json.getAsObject(), typeOfT, true));
- on.accept(visitor);
+ json, typeOfT, objectNavigator, fieldNamingPolicy, objectConstructor, deserializers, context);
+ objectNavigator.accept(new ObjectTypePair(json.getAsObject(), typeOfT, true), visitor);
Object target = visitor.getTarget();
return (T) target;
}
diff --git a/src/org/mcteam/factions/gson/JsonDeserializationVisitor.java b/src/org/mcteam/factions/gson/JsonDeserializationVisitor.java
index dcec329c..34b10b61 100644
--- a/src/org/mcteam/factions/gson/JsonDeserializationVisitor.java
+++ b/src/org/mcteam/factions/gson/JsonDeserializationVisitor.java
@@ -16,6 +16,8 @@
package org.mcteam.factions.gson;
+import org.mcteam.factions.gson.internal.$Gson$Preconditions;
+
import java.lang.reflect.Type;
/**
@@ -28,7 +30,8 @@ import java.lang.reflect.Type;
*/
abstract class JsonDeserializationVisitor implements ObjectNavigator.Visitor {
- protected final ObjectNavigatorFactory factory;
+ protected final ObjectNavigator objectNavigator;
+ protected final FieldNamingStrategy2 fieldNamingPolicy;
protected final ObjectConstructor objectConstructor;
protected final ParameterizedTypeHandlerMap> deserializers;
protected T target;
@@ -37,16 +40,17 @@ abstract class JsonDeserializationVisitor implements ObjectNavigator.Visitor
protected final JsonDeserializationContext context;
protected boolean constructed;
- public JsonDeserializationVisitor(JsonElement json, Type targetType,
- ObjectNavigatorFactory factory, ObjectConstructor objectConstructor,
+ JsonDeserializationVisitor(JsonElement json, Type targetType,
+ ObjectNavigator objectNavigator, FieldNamingStrategy2 fieldNamingPolicy,
+ ObjectConstructor objectConstructor,
ParameterizedTypeHandlerMap> deserializers,
JsonDeserializationContext context) {
- Preconditions.checkNotNull(json);
this.targetType = targetType;
- this.factory = factory;
+ this.objectNavigator = objectNavigator;
+ this.fieldNamingPolicy = fieldNamingPolicy;
this.objectConstructor = objectConstructor;
this.deserializers = deserializers;
- this.json = json;
+ this.json = $Gson$Preconditions.checkNotNull(json);
this.context = context;
this.constructed = false;
}
@@ -72,14 +76,14 @@ abstract class JsonDeserializationVisitor implements ObjectNavigator.Visitor
Pair, 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,
+ protected Object invokeCustomDeserializer(JsonElement element,
Pair, ObjectTypePair> pair) {
if (element == null || element.isJsonNull()) {
return null;
@@ -91,20 +95,19 @@ abstract class JsonDeserializationVisitor implements ObjectNavigator.Visitor
final Object visitChildAsObject(Type childType, JsonElement jsonChild) {
JsonDeserializationVisitor> childVisitor =
new JsonObjectDeserializationVisitor(jsonChild, childType,
- factory, objectConstructor, deserializers, context);
+ objectNavigator, fieldNamingPolicy, objectConstructor, deserializers, context);
return visitChild(childType, childVisitor);
}
final Object visitChildAsArray(Type childType, JsonArray jsonChild) {
JsonDeserializationVisitor> childVisitor =
new JsonArrayDeserializationVisitor(jsonChild.getAsJsonArray(), childType,
- factory, objectConstructor, deserializers, context);
+ objectNavigator, fieldNamingPolicy, objectConstructor, deserializers, context);
return visitChild(childType, childVisitor);
}
private Object visitChild(Type type, JsonDeserializationVisitor> childVisitor) {
- ObjectNavigator on = factory.create(new ObjectTypePair(null, type, false));
- on.accept(childVisitor);
+ objectNavigator.accept(new ObjectTypePair(null, type, false), childVisitor);
// the underlying object may have changed during the construction phase
// This happens primarily because of custom deserializers
return childVisitor.getTarget();
diff --git a/src/org/mcteam/factions/gson/JsonDeserializerExceptionWrapper.java b/src/org/mcteam/factions/gson/JsonDeserializerExceptionWrapper.java
index 9344c25a..524242f6 100644
--- a/src/org/mcteam/factions/gson/JsonDeserializerExceptionWrapper.java
+++ b/src/org/mcteam/factions/gson/JsonDeserializerExceptionWrapper.java
@@ -16,6 +16,8 @@
package org.mcteam.factions.gson;
+import org.mcteam.factions.gson.internal.$Gson$Preconditions;
+
import java.lang.reflect.Type;
/**
@@ -28,7 +30,7 @@ import java.lang.reflect.Type;
* @author Inderjeet Singh
* @author Joel Leitch
*/
-class JsonDeserializerExceptionWrapper implements JsonDeserializer {
+final class JsonDeserializerExceptionWrapper implements JsonDeserializer {
private final JsonDeserializer delegate;
@@ -40,8 +42,7 @@ class JsonDeserializerExceptionWrapper implements JsonDeserializer {
* @throws IllegalArgumentException if {@code delegate} is {@code null}.
*/
JsonDeserializerExceptionWrapper(JsonDeserializer delegate) {
- Preconditions.checkNotNull(delegate);
- this.delegate = delegate;
+ this.delegate = $Gson$Preconditions.checkNotNull(delegate);
}
public T deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
@@ -56,14 +57,14 @@ class JsonDeserializerExceptionWrapper implements JsonDeserializer {
StringBuilder errorMsg = new StringBuilder()
.append("The JsonDeserializer ")
.append(delegate)
- .append(" failed to deserialized json object ")
+ .append(" failed to deserialize json object ")
.append(json)
.append(" given the type ")
.append(typeOfT);
throw new JsonParseException(errorMsg.toString(), e);
}
}
-
+
@Override
public String toString() {
return delegate.toString();
diff --git a/src/org/mcteam/factions/gson/JsonFieldNameValidator.java b/src/org/mcteam/factions/gson/JsonFieldNameValidator.java
deleted file mode 100644
index ae54e6e1..00000000
--- a/src/org/mcteam/factions/gson/JsonFieldNameValidator.java
+++ /dev/null
@@ -1,56 +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 org.mcteam.factions.gson;
-
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-/**
- * This class can be used to check the validity of a JSON field name.
- *
- *
The primary use of this object is to ensure that any Java fields that use the
- * {@link org.mcteam.factions.gson.annotations.SerializedName} annotation is providing valid JSON
- * field names. This will make the code fail-fast rather than letting the invalid
- * field name propagate to the client and it fails to parse.
- *
- * @author Joel Leitch
- */
-class JsonFieldNameValidator {
- private static final String COMMON_PATTERN = "[a-zA-Z][a-zA-Z0-9\\ \\$_\\-]*$";
-
- private static final Pattern JSON_FIELD_NAME_PATTERN =
- Pattern.compile("(^" + COMMON_PATTERN + ")|(^[\\$_]" + COMMON_PATTERN + ")");
-
-
- /**
- * Performs validation on the JSON field name to ensure it is a valid field name.
- *
- * @param fieldName the name of the field to validate
- * @return {@code fieldName} if it is a valid JSON field name
- * @throws IllegalArgumentException if the field name is an invalid JSON field name
- */
- public String validate(String fieldName) {
- Preconditions.checkNotNull(fieldName);
- Preconditions.checkArgument(!"".equals(fieldName.trim()));
-
- Matcher matcher = JSON_FIELD_NAME_PATTERN.matcher(fieldName);
- if (!matcher.matches()) {
- throw new IllegalArgumentException(fieldName + " is not a valid JSON field name.");
- }
- return fieldName;
- }
-}
diff --git a/src/org/mcteam/factions/gson/JsonNull.java b/src/org/mcteam/factions/gson/JsonNull.java
index 67ca1cc6..65424d47 100644
--- a/src/org/mcteam/factions/gson/JsonNull.java
+++ b/src/org/mcteam/factions/gson/JsonNull.java
@@ -53,7 +53,7 @@ public final class JsonNull extends JsonElement {
*/
@Override
public boolean equals(Object other) {
- return other instanceof JsonNull;
+ return this == other || other instanceof JsonNull;
}
/**
diff --git a/src/org/mcteam/factions/gson/JsonObject.java b/src/org/mcteam/factions/gson/JsonObject.java
index a8ebf8f7..87d7582d 100644
--- a/src/org/mcteam/factions/gson/JsonObject.java
+++ b/src/org/mcteam/factions/gson/JsonObject.java
@@ -16,6 +16,8 @@
package org.mcteam.factions.gson;
+import org.mcteam.factions.gson.internal.$Gson$Preconditions;
+
import java.io.IOException;
import java.util.LinkedHashMap;
import java.util.Map;
@@ -52,11 +54,10 @@ public final class JsonObject extends JsonElement {
* @param value the member object.
*/
public void add(String property, JsonElement value) {
- Preconditions.checkNotNull(property);
if (value == null) {
value = JsonNull.createJsonNull();
}
- members.put(property, value);
+ members.put($Gson$Preconditions.checkNotNull(property), value);
}
/**
@@ -188,6 +189,17 @@ public final class JsonObject extends JsonElement {
return (JsonObject) members.get(memberName);
}
+ @Override
+ public boolean equals(Object o) {
+ return (o == this) || (o instanceof JsonObject
+ && ((JsonObject) o).members.equals(members));
+ }
+
+ @Override
+ public int hashCode() {
+ return members.hashCode();
+ }
+
@Override
protected void toString(Appendable sb, Escaper escaper) throws IOException {
sb.append('{');
diff --git a/src/org/mcteam/factions/gson/JsonObjectDeserializationVisitor.java b/src/org/mcteam/factions/gson/JsonObjectDeserializationVisitor.java
index 5c456388..56347bd8 100644
--- a/src/org/mcteam/factions/gson/JsonObjectDeserializationVisitor.java
+++ b/src/org/mcteam/factions/gson/JsonObjectDeserializationVisitor.java
@@ -16,6 +16,7 @@
package org.mcteam.factions.gson;
+
import java.lang.reflect.Type;
/**
@@ -28,10 +29,11 @@ import java.lang.reflect.Type;
final class JsonObjectDeserializationVisitor extends JsonDeserializationVisitor {
JsonObjectDeserializationVisitor(JsonElement json, Type type,
- ObjectNavigatorFactory factory, ObjectConstructor objectConstructor,
+ ObjectNavigator objectNavigator, FieldNamingStrategy2 fieldNamingPolicy,
+ ObjectConstructor objectConstructor,
ParameterizedTypeHandlerMap> deserializers,
JsonDeserializationContext context) {
- super(json, type, factory, objectConstructor, deserializers, context);
+ super(json, type, objectNavigator, fieldNamingPolicy, objectConstructor, deserializers, context);
}
@Override
@@ -52,7 +54,7 @@ final class JsonObjectDeserializationVisitor extends JsonDeserializationVisit
public void visitObjectField(FieldAttributes f, Type typeOfF, Object obj) {
try {
if (!json.isJsonObject()) {
- throw new JsonParseException("Expecting object found: " + json);
+ throw new JsonParseException("Expecting object found: " + json);
}
JsonObject jsonObject = json.getAsJsonObject();
String fName = getFieldName(f);
@@ -71,7 +73,7 @@ final class JsonObjectDeserializationVisitor extends JsonDeserializationVisit
public void visitArrayField(FieldAttributes f, Type typeOfF, Object obj) {
try {
if (!json.isJsonObject()) {
- throw new JsonParseException("Expecting object found: " + json);
+ throw new JsonParseException("Expecting object found: " + json);
}
JsonObject jsonObject = json.getAsJsonObject();
String fName = getFieldName(f);
@@ -88,22 +90,21 @@ final class JsonObjectDeserializationVisitor extends JsonDeserializationVisit
}
private String getFieldName(FieldAttributes f) {
- FieldNamingStrategy2 namingPolicy = factory.getFieldNamingPolicy();
- return namingPolicy.translateName(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);
+ throw new JsonParseException("Expecting object found: " + json);
}
JsonElement child = json.getAsJsonObject().get(fName);
- TypeInfo typeInfo = new TypeInfo(declaredTypeOfField);
+ 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 (!typeInfo.isPrimitive()) {
+ if (!isPrimitive) {
f.set(parent, null);
}
return true;
@@ -112,9 +113,9 @@ final class JsonObjectDeserializationVisitor extends JsonDeserializationVisit
Pair, ObjectTypePair> pair = objTypePair.getMatchingHandler(deserializers);
if (pair == null) {
return false;
- }
+ }
Object value = invokeCustomDeserializer(child, pair);
- if (value != null || !typeInfo.isPrimitive()) {
+ if (value != null || !isPrimitive) {
f.set(parent, value);
}
return true;
diff --git a/src/org/mcteam/factions/gson/JsonParser.java b/src/org/mcteam/factions/gson/JsonParser.java
index f0c02957..2447fa2a 100644
--- a/src/org/mcteam/factions/gson/JsonParser.java
+++ b/src/org/mcteam/factions/gson/JsonParser.java
@@ -15,15 +15,14 @@
*/
package org.mcteam.factions.gson;
+import org.mcteam.factions.gson.stream.JsonReader;
+import org.mcteam.factions.gson.stream.JsonToken;
+import org.mcteam.factions.gson.stream.MalformedJsonException;
import java.io.EOFException;
import java.io.IOException;
import java.io.Reader;
import java.io.StringReader;
-import org.mcteam.factions.gson.stream.JsonReader;
-import org.mcteam.factions.gson.stream.JsonToken;
-import org.mcteam.factions.gson.stream.MalformedJsonException;
-
/**
* A parser to parse Json into a parse tree of {@link JsonElement}s
*
diff --git a/src/org/mcteam/factions/gson/JsonPrimitive.java b/src/org/mcteam/factions/gson/JsonPrimitive.java
index 1b1864b0..d830ffb4 100644
--- a/src/org/mcteam/factions/gson/JsonPrimitive.java
+++ b/src/org/mcteam/factions/gson/JsonPrimitive.java
@@ -16,6 +16,8 @@
package org.mcteam.factions.gson;
+import org.mcteam.factions.gson.internal.$Gson$Preconditions;
+
import java.io.IOException;
import java.math.BigDecimal;
import java.math.BigInteger;
@@ -92,8 +94,8 @@ public final class JsonPrimitive extends JsonElement {
char c = ((Character) primitive).charValue();
this.value = String.valueOf(c);
} else {
- Preconditions.checkArgument(primitive instanceof Number
- || isPrimitiveOrString(primitive));
+ $Gson$Preconditions.checkArgument(primitive instanceof Number
+ || isPrimitiveOrString(primitive));
this.value = primitive;
}
}
@@ -111,7 +113,6 @@ public final class JsonPrimitive extends JsonElement {
* convenience method to get this element as a {@link Boolean}.
*
* @return get this element as a {@link Boolean}.
- * @throws ClassCastException if the value contained is not a valid boolean value.
*/
@Override
Boolean getAsBooleanWrapper() {
@@ -122,7 +123,6 @@ public final class JsonPrimitive extends JsonElement {
* convenience method to get this element as a boolean value.
*
* @return get this element as a primitive boolean value.
- * @throws ClassCastException if the value contained is not a valid boolean value.
*/
@Override
public boolean getAsBoolean() {
@@ -142,7 +142,7 @@ public final class JsonPrimitive extends JsonElement {
* convenience method to get this element as a Number.
*
* @return get this element as a Number.
- * @throws ClassCastException if the value contained is not a valid Number.
+ * @throws NumberFormatException if the value contained is not a valid Number.
*/
@Override
public Number getAsNumber() {
@@ -179,7 +179,6 @@ public final class JsonPrimitive extends JsonElement {
* convenience method to get this element as a String.
*
* @return get this element as a String.
- * @throws ClassCastException if the value contained is not a valid String.
*/
@Override
public String getAsString() {
@@ -196,7 +195,7 @@ public final class JsonPrimitive extends JsonElement {
* convenience method to get this element as a primitive double.
*
* @return get this element as a primitive double.
- * @throws ClassCastException if the value contained is not a valid double.
+ * @throws NumberFormatException if the value contained is not a valid double.
*/
@Override
public double getAsDouble() {
@@ -229,7 +228,7 @@ public final class JsonPrimitive extends JsonElement {
* convenience method to get this element as a float.
*
* @return get this element as a float.
- * @throws ClassCastException if the value contained is not a valid float.
+ * @throws NumberFormatException if the value contained is not a valid float.
*/
@Override
public float getAsFloat() {
@@ -240,7 +239,7 @@ public final class JsonPrimitive extends JsonElement {
* convenience method to get this element as a primitive long.
*
* @return get this element as a primitive long.
- * @throws ClassCastException if the value contained is not a valid long.
+ * @throws NumberFormatException if the value contained is not a valid long.
*/
@Override
public long getAsLong() {
@@ -251,7 +250,7 @@ public final class JsonPrimitive extends JsonElement {
* convenience method to get this element as a primitive short.
*
* @return get this element as a primitive short.
- * @throws ClassCastException if the value contained is not a valid short value.
+ * @throws NumberFormatException if the value contained is not a valid short value.
*/
@Override
public short getAsShort() {
@@ -262,7 +261,7 @@ public final class JsonPrimitive extends JsonElement {
* convenience method to get this element as a primitive integer.
*
* @return get this element as a primitive integer.
- * @throws ClassCastException if the value contained is not a valid integer.
+ * @throws NumberFormatException if the value contained is not a valid integer.
*/
@Override
public int getAsInt() {
@@ -356,7 +355,11 @@ public final class JsonPrimitive extends JsonElement {
return getAsNumber().longValue() == other.getAsNumber().longValue();
}
if (isFloatingPoint(this) && isFloatingPoint(other)) {
- return getAsNumber().doubleValue() == other.getAsNumber().doubleValue();
+ double a = getAsNumber().doubleValue();
+ // Java standard types other than double return true for two NaN. So, need
+ // special handling for double.
+ double b = other.getAsNumber().doubleValue();
+ return a == b || (Double.isNaN(a) && Double.isNaN(b));
}
return value.equals(other.value);
}
diff --git a/src/org/mcteam/factions/gson/JsonSerializationContextDefault.java b/src/org/mcteam/factions/gson/JsonSerializationContextDefault.java
index 736a8c51..14c3df00 100644
--- a/src/org/mcteam/factions/gson/JsonSerializationContextDefault.java
+++ b/src/org/mcteam/factions/gson/JsonSerializationContextDefault.java
@@ -16,6 +16,7 @@
package org.mcteam.factions.gson;
+
import java.lang.reflect.Type;
/**
@@ -25,14 +26,17 @@ import java.lang.reflect.Type;
*/
final class JsonSerializationContextDefault implements JsonSerializationContext {
- private final ObjectNavigatorFactory factory;
+ private final ObjectNavigator objectNavigator;
+ private final FieldNamingStrategy2 fieldNamingPolicy;
private final ParameterizedTypeHandlerMap> serializers;
private final boolean serializeNulls;
private final MemoryRefStack ancestors;
- JsonSerializationContextDefault(ObjectNavigatorFactory factory, boolean serializeNulls,
+ JsonSerializationContextDefault(ObjectNavigator objectNavigator,
+ FieldNamingStrategy2 fieldNamingPolicy, boolean serializeNulls,
ParameterizedTypeHandlerMap> serializers) {
- this.factory = factory;
+ this.objectNavigator = objectNavigator;
+ this.fieldNamingPolicy = fieldNamingPolicy;
this.serializeNulls = serializeNulls;
this.serializers = serializers;
this.ancestors = new MemoryRefStack();
@@ -42,18 +46,20 @@ final class JsonSerializationContextDefault implements JsonSerializationContext
if (src == null) {
return JsonNull.createJsonNull();
}
- return serialize(src, src.getClass(), true);
+ return serialize(src, src.getClass(), false);
}
public JsonElement serialize(Object src, Type typeOfSrc) {
return serialize(src, typeOfSrc, true);
}
- public JsonElement serialize(Object src, Type typeOfSrc, boolean preserveType) {
- ObjectNavigator on = factory.create(new ObjectTypePair(src, typeOfSrc, preserveType));
- JsonSerializationVisitor visitor =
- new JsonSerializationVisitor(factory, serializeNulls, serializers, this, ancestors);
- on.accept(visitor);
+ JsonElement serialize(Object src, Type typeOfSrc, boolean preserveType) {
+ if (src == null) {
+ return JsonNull.createJsonNull();
+ }
+ JsonSerializationVisitor visitor = new JsonSerializationVisitor(
+ objectNavigator, fieldNamingPolicy, serializeNulls, serializers, this, ancestors);
+ objectNavigator.accept(new ObjectTypePair(src, typeOfSrc, preserveType), visitor);
return visitor.getJsonElement();
}
}
diff --git a/src/org/mcteam/factions/gson/JsonSerializationVisitor.java b/src/org/mcteam/factions/gson/JsonSerializationVisitor.java
index ba0f2eb6..25af6b1e 100644
--- a/src/org/mcteam/factions/gson/JsonSerializationVisitor.java
+++ b/src/org/mcteam/factions/gson/JsonSerializationVisitor.java
@@ -16,6 +16,9 @@
package org.mcteam.factions.gson;
+import org.mcteam.factions.gson.internal.$Gson$Types;
+import org.mcteam.factions.gson.internal.$Gson$Preconditions;
+
import java.lang.reflect.Array;
import java.lang.reflect.Type;
@@ -27,17 +30,19 @@ import java.lang.reflect.Type;
*/
final class JsonSerializationVisitor implements ObjectNavigator.Visitor {
- private final ObjectNavigatorFactory factory;
+ private final ObjectNavigator objectNavigator;
+ private final FieldNamingStrategy2 fieldNamingPolicy;
private final ParameterizedTypeHandlerMap> serializers;
private final boolean serializeNulls;
private final JsonSerializationContext context;
private final MemoryRefStack ancestors;
private JsonElement root;
- JsonSerializationVisitor(ObjectNavigatorFactory factory, boolean serializeNulls,
- ParameterizedTypeHandlerMap> serializers, JsonSerializationContext context,
- MemoryRefStack ancestors) {
- this.factory = factory;
+ JsonSerializationVisitor(ObjectNavigator objectNavigator, FieldNamingStrategy2 fieldNamingPolicy,
+ boolean serializeNulls, ParameterizedTypeHandlerMap> serializers,
+ JsonSerializationContext context, MemoryRefStack ancestors) {
+ this.objectNavigator = objectNavigator;
+ this.fieldNamingPolicy = fieldNamingPolicy;
this.serializeNulls = serializeNulls;
this.serializers = serializers;
this.context = context;
@@ -71,15 +76,12 @@ final class JsonSerializationVisitor implements ObjectNavigator.Visitor {
public void visitArray(Object array, Type arrayType) {
assignToRoot(new JsonArray());
int length = Array.getLength(array);
- TypeInfoArray fieldTypeInfo = TypeInfoFactory.getTypeInfoForArray(arrayType);
- Type componentType = fieldTypeInfo.getSecondLevelType();
+ Type componentType = $Gson$Types.getArrayComponentType(arrayType);
for (int i = 0; i < length; ++i) {
Object child = Array.get(array, i);
- Type childType = componentType;
// 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, childType, false));
+ // that a custom serializer is registered for the componentType
+ addAsArrayElement(new ObjectTypePair(child, componentType, false));
}
}
@@ -127,8 +129,7 @@ final class JsonSerializationVisitor implements ObjectNavigator.Visitor {
}
private void addChildAsElement(FieldAttributes f, JsonElement childElement) {
- FieldNamingStrategy2 namingPolicy = factory.getFieldNamingPolicy();
- root.getAsJsonObject().add(namingPolicy.translateName(f), childElement);
+ root.getAsJsonObject().add(fieldNamingPolicy.translateName(f), childElement);
}
private void addAsArrayElement(ObjectTypePair elementTypePair) {
@@ -141,10 +142,9 @@ final class JsonSerializationVisitor implements ObjectNavigator.Visitor {
}
private JsonElement getJsonElementForChild(ObjectTypePair fieldValueTypePair) {
- ObjectNavigator on = factory.create(fieldValueTypePair);
- JsonSerializationVisitor childVisitor =
- new JsonSerializationVisitor(factory, serializeNulls, serializers, context, ancestors);
- on.accept(childVisitor);
+ JsonSerializationVisitor childVisitor = new JsonSerializationVisitor(
+ objectNavigator, fieldNamingPolicy, serializeNulls, serializers, context, ancestors);
+ objectNavigator.accept(fieldValueTypePair, childVisitor);
return childVisitor.getJsonElement();
}
@@ -171,7 +171,7 @@ final class JsonSerializationVisitor implements ObjectNavigator.Visitor {
/**
* objTypePair.getObject() must not be null
*/
- @SuppressWarnings({"unchecked", "rawtypes"})
+ @SuppressWarnings("unchecked")
private JsonElement findAndInvokeCustomSerializer(ObjectTypePair objTypePair) {
Pair,ObjectTypePair> pair = objTypePair.getMatchingHandler(serializers);
if (pair == null) {
@@ -189,9 +189,10 @@ final class JsonSerializationVisitor implements ObjectNavigator.Visitor {
}
}
- public boolean visitFieldUsingCustomHandler(FieldAttributes f, Type declaredTypeOfField, Object parent) {
+ public boolean visitFieldUsingCustomHandler(
+ FieldAttributes f, Type declaredTypeOfField, Object parent) {
try {
- Preconditions.checkState(root.isJsonObject());
+ $Gson$Preconditions.checkState(root.isJsonObject());
Object obj = f.get(parent);
if (obj == null) {
if (serializeNulls) {
@@ -214,8 +215,7 @@ final class JsonSerializationVisitor implements ObjectNavigator.Visitor {
}
private void assignToRoot(JsonElement newRoot) {
- Preconditions.checkNotNull(newRoot);
- root = newRoot;
+ root = $Gson$Preconditions.checkNotNull(newRoot);
}
private boolean isFieldNull(FieldAttributes f, Object obj) {
diff --git a/src/org/mcteam/factions/gson/JsonStreamParser.java b/src/org/mcteam/factions/gson/JsonStreamParser.java
index 84fd7e44..ac868936 100644
--- a/src/org/mcteam/factions/gson/JsonStreamParser.java
+++ b/src/org/mcteam/factions/gson/JsonStreamParser.java
@@ -26,7 +26,6 @@ import org.mcteam.factions.gson.stream.JsonReader;
import org.mcteam.factions.gson.stream.JsonToken;
import org.mcteam.factions.gson.stream.MalformedJsonException;
-
/**
* A streaming parser that allows reading of multiple {@link JsonElement}s from the specified reader
* asynchronously.
diff --git a/src/org/mcteam/factions/gson/LruCache.java b/src/org/mcteam/factions/gson/LruCache.java
index 4d6d2b0e..e9318a2f 100644
--- a/src/org/mcteam/factions/gson/LruCache.java
+++ b/src/org/mcteam/factions/gson/LruCache.java
@@ -16,6 +16,7 @@
package org.mcteam.factions.gson;
+
import java.util.LinkedHashMap;
import java.util.Map;
@@ -23,7 +24,7 @@ import java.util.Map;
* An implementation of the {@link Cache} interface that evict objects from the cache using an
* LRU (least recently used) algorithm. Object start getting evicted from the cache once the
* {@code maxCapacity} is reached.
- *
+ *
* @author Inderjeet Singh
* @author Joel Leitch
*/
@@ -32,33 +33,23 @@ final class LruCache extends LinkedHashMap implements Cache {
private final int maxCapacity;
- LruCache(int maxCapacity) {
+ public LruCache(int maxCapacity) {
super(maxCapacity, 0.7F, true);
this.maxCapacity = maxCapacity;
}
- public void addElement(K key, V value) {
+ public synchronized void addElement(K key, V value) {
put(key, value);
}
- @Override
- public void clear() {
- super.clear();
- }
-
- public V getElement(K key) {
+ public synchronized V getElement(K key) {
return get(key);
}
- public V removeElement(K key) {
+ public synchronized V removeElement(K key) {
return remove(key);
}
- @Override
- public int size() {
- return super.size();
- }
-
@Override
protected boolean removeEldestEntry(Map.Entry entry) {
return size() > maxCapacity;
diff --git a/src/org/mcteam/factions/gson/MapAsArrayTypeAdapter.java b/src/org/mcteam/factions/gson/MapAsArrayTypeAdapter.java
index 4fb91c97..98b308d8 100644
--- a/src/org/mcteam/factions/gson/MapAsArrayTypeAdapter.java
+++ b/src/org/mcteam/factions/gson/MapAsArrayTypeAdapter.java
@@ -19,7 +19,6 @@ package org.mcteam.factions.gson;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
-import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
@@ -45,9 +44,9 @@ import java.util.Map;
* But GSON is unable to deserialize this value because the JSON string name is
* just the {@link Object#toString() toString()} of the map key. Attempting to
* convert the above JSON to an object fails with a parse exception:
- *
com.bukkit.mcteam.gson.JsonParseException: Expecting object found: "(5,6)"
- * at com.bukkit.mcteam.gson.JsonObjectDeserializationVisitor.visitFieldUsingCustomHandler
- * at com.bukkit.mcteam.gson.ObjectNavigator.navigateClassFields
+ *
org.mcteam.factions.gson.JsonParseException: Expecting object found: "(5,6)"
+ * at org.mcteam.factions.gson.JsonObjectDeserializationVisitor.visitFieldUsingCustomHandler
+ * at org.mcteam.factions.gson.ObjectNavigator.navigateClassFields
* ...
*
*
Maps as JSON arrays
@@ -90,12 +89,13 @@ import java.util.Map;
* complex. A key is complex if its JSON-serialized form is an array or an
* object.
*/
-public final class MapAsArrayTypeAdapter
+final class MapAsArrayTypeAdapter
+ extends BaseMapTypeAdapter
implements JsonSerializer>, JsonDeserializer> {
public Map, ?> deserialize(JsonElement json, Type typeOfT,
JsonDeserializationContext context) throws JsonParseException {
- Map result = new LinkedHashMap();
+ Map result = constructMapType(typeOfT, context);
Type[] keyAndValueType = typeToTypeArguments(typeOfT);
if (json.isJsonArray()) {
JsonArray array = json.getAsJsonArray();
@@ -123,10 +123,10 @@ public final class MapAsArrayTypeAdapter
boolean serializeAsArray = false;
List keysAndValues = new ArrayList();
for (Map.Entry, ?> entry : src.entrySet()) {
- JsonElement key = context.serialize(entry.getKey(), keyAndValueType[0]);
+ JsonElement key = serialize(context, entry.getKey(), keyAndValueType[0]);
serializeAsArray |= key.isJsonObject() || key.isJsonArray();
keysAndValues.add(key);
- keysAndValues.add(context.serialize(entry.getValue(), keyAndValueType[1]));
+ keysAndValues.add(serialize(context, entry.getValue(), keyAndValueType[1]));
}
if (serializeAsArray) {
diff --git a/src/org/mcteam/factions/gson/MapTypeAdapter.java b/src/org/mcteam/factions/gson/MapTypeAdapter.java
new file mode 100644
index 00000000..d1d52399
--- /dev/null
+++ b/src/org/mcteam/factions/gson/MapTypeAdapter.java
@@ -0,0 +1,78 @@
+/*
+ * 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 org.mcteam.factions.gson;
+
+import org.mcteam.factions.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) src.entrySet()) {
+ Object value = entry.getValue();
+
+ JsonElement valueElement;
+ if (value == null) {
+ valueElement = JsonNull.createJsonNull();
+ } 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 map = constructMapType(typeOfT, context);
+ Type[] keyAndValueTypes = $Gson$Types.getMapKeyAndValueTypes(typeOfT, $Gson$Types.getRawType(typeOfT));
+ for (Map.Entry 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();
+ }
+}
\ No newline at end of file
diff --git a/src/org/mcteam/factions/gson/MappedObjectConstructor.java b/src/org/mcteam/factions/gson/MappedObjectConstructor.java
index 12296e33..81ac8019 100644
--- a/src/org/mcteam/factions/gson/MappedObjectConstructor.java
+++ b/src/org/mcteam/factions/gson/MappedObjectConstructor.java
@@ -16,13 +16,10 @@
package org.mcteam.factions.gson;
-import java.lang.reflect.AccessibleObject;
+import org.mcteam.factions.gson.internal.$Gson$Types;
+
import java.lang.reflect.Array;
-import java.lang.reflect.Constructor;
-import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Type;
-import java.util.logging.Level;
-import java.util.logging.Logger;
/**
* This class contains a mapping of all the application specific
@@ -35,10 +32,12 @@ import java.util.logging.Logger;
* @author Joel Leitch
*/
final class MappedObjectConstructor implements ObjectConstructor {
- private static final Logger log = Logger.getLogger(MappedObjectConstructor.class.getName());
+ private static final UnsafeAllocator unsafeAllocator = UnsafeAllocator.create();
+ private static final DefaultConstructorAllocator defaultConstructorAllocator =
+ new DefaultConstructorAllocator(500);
private final ParameterizedTypeHandlerMap> instanceCreatorMap;
-
+
public MappedObjectConstructor(
ParameterizedTypeHandlerMap> instanceCreators) {
instanceCreatorMap = instanceCreators;
@@ -50,61 +49,27 @@ final class MappedObjectConstructor implements ObjectConstructor {
if (creator != null) {
return creator.createInstance(typeOfT);
}
- return (T) constructWithNoArgConstructor(typeOfT);
+ return (T) constructWithAllocators(typeOfT);
}
public Object constructArray(Type type, int length) {
- return Array.newInstance(TypeUtils.toRawClass(type), length);
- }
-
- private T constructWithNoArgConstructor(Type typeOfT) {
- try {
- Constructor constructor = getNoArgsConstructor(typeOfT);
- if (constructor == null) {
- throw new RuntimeException(("No-args constructor for " + typeOfT + " does not exist. "
- + "Register an InstanceCreator with Gson for this type to fix this problem."));
- }
- return constructor.newInstance();
- } catch (InstantiationException 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);
- } catch (IllegalAccessException 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);
- } catch (InvocationTargetException 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);
- }
+ return Array.newInstance($Gson$Types.getRawType(type), length);
}
@SuppressWarnings({"unchecked", "cast"})
- private Constructor getNoArgsConstructor(Type typeOfT) {
- TypeInfo typeInfo = new TypeInfo(typeOfT);
- Class clazz = (Class) typeInfo.getRawClass();
- Constructor[] declaredConstructors = (Constructor[]) clazz.getDeclaredConstructors();
- AccessibleObject.setAccessible(declaredConstructors, true);
- for (Constructor constructor : declaredConstructors) {
- if (constructor.getParameterTypes().length == 0) {
- return constructor;
- }
+ private T constructWithAllocators(Type typeOfT) {
+ try {
+ Class clazz = (Class) $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);
}
- return null;
}
- /**
- * Use this methods to register an {@link InstanceCreator} for a new type.
- *
- * @param the type of class to be mapped with its "creator"
- * @param typeOfT the instance type that will be created
- * @param creator the {@link InstanceCreator} instance to register
- */
- void register(Type typeOfT, InstanceCreator extends T> creator) {
- if (instanceCreatorMap.hasSpecificHandlerFor(typeOfT)) {
- log.log(Level.WARNING, "Overriding the existing InstanceCreator for {0}", typeOfT);
- }
- instanceCreatorMap.register(typeOfT, creator);
- }
-
@Override
public String toString() {
return instanceCreatorMap.toString();
diff --git a/src/org/mcteam/factions/gson/MemoryRefStack.java b/src/org/mcteam/factions/gson/MemoryRefStack.java
index a79f1851..fa2292d1 100644
--- a/src/org/mcteam/factions/gson/MemoryRefStack.java
+++ b/src/org/mcteam/factions/gson/MemoryRefStack.java
@@ -16,6 +16,8 @@
package org.mcteam.factions.gson;
+import org.mcteam.factions.gson.internal.$Gson$Preconditions;
+
import java.util.Stack;
/**
@@ -35,8 +37,7 @@ final class MemoryRefStack {
* @return the object that was added
*/
public ObjectTypePair push(ObjectTypePair obj) {
- Preconditions.checkNotNull(obj);
-
+ $Gson$Preconditions.checkNotNull(obj);
return stack.push(obj);
}
diff --git a/src/org/mcteam/factions/gson/ModifyFirstLetterNamingPolicy.java b/src/org/mcteam/factions/gson/ModifyFirstLetterNamingPolicy.java
index 31652b48..d53982ae 100644
--- a/src/org/mcteam/factions/gson/ModifyFirstLetterNamingPolicy.java
+++ b/src/org/mcteam/factions/gson/ModifyFirstLetterNamingPolicy.java
@@ -16,6 +16,8 @@
package org.mcteam.factions.gson;
+import org.mcteam.factions.gson.internal.$Gson$Preconditions;
+
import java.lang.annotation.Annotation;
import java.lang.reflect.Type;
import java.util.Collection;
@@ -62,9 +64,8 @@ final class ModifyFirstLetterNamingPolicy extends RecursiveFieldNamingPolicy {
* @param modifier the type of modification that should be performed
* @throws IllegalArgumentException if {@code modifier} is null
*/
- public ModifyFirstLetterNamingPolicy(LetterModifier modifier) {
- Preconditions.checkNotNull(modifier);
- this.letterModifier = modifier;
+ ModifyFirstLetterNamingPolicy(LetterModifier modifier) {
+ this.letterModifier = $Gson$Preconditions.checkNotNull(modifier);
}
@Override
@@ -100,8 +101,8 @@ final class ModifyFirstLetterNamingPolicy extends RecursiveFieldNamingPolicy {
}
private String modifyString(char firstCharacter, String srcString, int indexOfSubstring) {
- return indexOfSubstring < srcString.length() ?
- firstCharacter + srcString.substring(indexOfSubstring)
+ return (indexOfSubstring < srcString.length())
+ ? firstCharacter + srcString.substring(indexOfSubstring)
: String.valueOf(firstCharacter);
}
}
diff --git a/src/org/mcteam/factions/gson/NullExclusionStrategy.java b/src/org/mcteam/factions/gson/NullExclusionStrategy.java
index eaea6261..8836ede3 100644
--- a/src/org/mcteam/factions/gson/NullExclusionStrategy.java
+++ b/src/org/mcteam/factions/gson/NullExclusionStrategy.java
@@ -16,7 +16,6 @@
package org.mcteam.factions.gson;
-
/**
* This acts as a "Null Object" pattern for the {@link ExclusionStrategy}.
* Passing an instance of this class into the {@link ObjectNavigator} will
diff --git a/src/org/mcteam/factions/gson/ObjectNavigator.java b/src/org/mcteam/factions/gson/ObjectNavigator.java
index 0a59ea64..2f442f6a 100644
--- a/src/org/mcteam/factions/gson/ObjectNavigator.java
+++ b/src/org/mcteam/factions/gson/ObjectNavigator.java
@@ -16,14 +16,14 @@
package org.mcteam.factions.gson;
-import java.lang.reflect.AccessibleObject;
-import java.lang.reflect.Field;
+import org.mcteam.factions.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
*/
@@ -57,7 +57,7 @@ final class ObjectNavigator {
/**
* 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);
@@ -69,38 +69,33 @@ final class ObjectNavigator {
public boolean visitFieldUsingCustomHandler(FieldAttributes f, Type actualTypeOfField,
Object parent);
+ void visitPrimitive(Object primitive);
+
/**
* Retrieve the current target
*/
Object getTarget();
-
- void visitPrimitive(Object primitive);
}
private final ExclusionStrategy exclusionStrategy;
- private final ObjectTypePair objTypePair;
+ private final ReflectingFieldNavigator reflectingFieldNavigator;
/**
- * @param objTypePair
- * The object,type (fully genericized) being navigated
- * @param exclusionStrategy
- * the concrete strategy object to be used to filter out fields of an
+ * @param strategy the concrete exclusion strategy object to be used to filter out fields of an
* object.
*/
- ObjectNavigator(ObjectTypePair objTypePair, ExclusionStrategy exclusionStrategy) {
- Preconditions.checkNotNull(exclusionStrategy);
-
- this.objTypePair = objTypePair;
- this.exclusionStrategy = exclusionStrategy;
+ 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(Visitor visitor) {
- TypeInfo objTypeInfo = new TypeInfo(objTypePair.type);
- if (exclusionStrategy.shouldSkipClass(objTypeInfo.getRawClass())) {
+ public void accept(ObjectTypePair objTypePair, Visitor visitor) {
+ if (exclusionStrategy.shouldSkipClass($Gson$Types.getRawType(objTypePair.type))) {
return;
}
boolean visitedWithCustomHandler = visitor.visitUsingCustomHandler(objTypePair);
@@ -113,24 +108,16 @@ final class ObjectNavigator {
objTypePair.setObject(objectToVisit);
visitor.start(objTypePair);
try {
- if (objTypeInfo.isArray()) {
+ if ($Gson$Types.isArray(objTypePair.type)) {
visitor.visitArray(objectToVisit, objTypePair.type);
- } else if (objTypeInfo.getActualType() == Object.class
- && isPrimitiveOrString(objectToVisit)) {
+ } 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);
- objectToVisit = visitor.getTarget();
+ visitor.getTarget();
} else {
visitor.startVisitingObject(objectToVisit);
- ObjectTypePair currObjTypePair = objTypePair.toMoreSpecificType();
- Class> topLevelClass = new TypeInfo(currObjTypePair.type).getRawClass();
- for (Class> curr = topLevelClass; curr != null && !curr.equals(Object.class); curr =
- curr.getSuperclass()) {
- if (!curr.isSynthetic()) {
- navigateClassFields(objectToVisit, curr, visitor);
- }
- }
+ reflectingFieldNavigator.visitFieldsReflectively(objTypePair, visitor);
}
} finally {
visitor.end(objTypePair);
@@ -138,32 +125,9 @@ final class ObjectNavigator {
}
}
- private boolean isPrimitiveOrString(Object objectToVisit) {
+ private static boolean isPrimitiveOrString(Object objectToVisit) {
Class> realClazz = objectToVisit.getClass();
return realClazz == Object.class || realClazz == String.class
|| Primitives.unwrap(realClazz).isPrimitive();
}
-
- private void navigateClassFields(Object obj, Class> clazz, Visitor visitor) {
- Field[] fields = clazz.getDeclaredFields();
- AccessibleObject.setAccessible(fields, true);
- for (Field f : fields) {
- FieldAttributes fieldAttributes = new FieldAttributes(clazz, f);
- if (exclusionStrategy.shouldSkipField(fieldAttributes)
- || exclusionStrategy.shouldSkipClass(fieldAttributes.getDeclaredClass())) {
- continue; // skip
- }
- TypeInfo fieldTypeInfo = TypeInfoFactory.getTypeInfoForField(f, objTypePair.type);
- Type declaredTypeOfField = fieldTypeInfo.getActualType();
- boolean visitedWithCustomHandler =
- visitor.visitFieldUsingCustomHandler(fieldAttributes, declaredTypeOfField, obj);
- if (!visitedWithCustomHandler) {
- if (fieldTypeInfo.isArray()) {
- visitor.visitArrayField(fieldAttributes, declaredTypeOfField, obj);
- } else {
- visitor.visitObjectField(fieldAttributes, declaredTypeOfField, obj);
- }
- }
- }
- }
}
diff --git a/src/org/mcteam/factions/gson/ObjectNavigatorFactory.java b/src/org/mcteam/factions/gson/ObjectNavigatorFactory.java
deleted file mode 100644
index 2d4b2be3..00000000
--- a/src/org/mcteam/factions/gson/ObjectNavigatorFactory.java
+++ /dev/null
@@ -1,61 +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 org.mcteam.factions.gson;
-
-/**
- * A factory class used to simplify {@link ObjectNavigator} creation.
- * This object holds on to a reference of the {@link ExclusionStrategy}
- * that you'd like to use with the {@link ObjectNavigator}.
- *
- * @author Joel Leitch
- */
-final class ObjectNavigatorFactory {
- private final ExclusionStrategy strategy;
- private final FieldNamingStrategy2 fieldNamingPolicy;
-
- /**
- * Creates a factory object that will be able to create new
- * {@link ObjectNavigator}s with the provided {@code strategy}
- *
- * @param strategy the exclusion strategy to use with every instance that
- * is created by this factory instance.
- * @param fieldNamingPolicy the naming policy that should be applied to field
- * names
- */
- public ObjectNavigatorFactory(ExclusionStrategy strategy, FieldNamingStrategy2 fieldNamingPolicy) {
- Preconditions.checkNotNull(fieldNamingPolicy);
- this.strategy = (strategy == null ? new NullExclusionStrategy() : strategy);
- this.fieldNamingPolicy = fieldNamingPolicy;
- }
-
- /**
- * Creates a new {@link ObjectNavigator} for this {@code srcObject},
- * {@code type} pair.
- *
- * @param objTypePair The object,type (fully genericized) being navigated
- * @return a new instance of a {@link ObjectNavigator} ready to navigate the
- * {@code srcObject} while taking into consideration the
- * {@code type}.
- */
- public ObjectNavigator create(ObjectTypePair objTypePair) {
- return new ObjectNavigator(objTypePair, strategy);
- }
-
- FieldNamingStrategy2 getFieldNamingPolicy() {
- return fieldNamingPolicy;
- }
-}
diff --git a/src/org/mcteam/factions/gson/ObjectTypePair.java b/src/org/mcteam/factions/gson/ObjectTypePair.java
index 811f1734..d38b8e8e 100644
--- a/src/org/mcteam/factions/gson/ObjectTypePair.java
+++ b/src/org/mcteam/factions/gson/ObjectTypePair.java
@@ -15,6 +15,7 @@
*/
package org.mcteam.factions.gson;
+
import java.lang.reflect.Type;
/**
@@ -55,7 +56,7 @@ final class ObjectTypePair {
HANDLER handler = null;
if (!preserveType && obj != null) {
// First try looking up the handler for the actual type
- ObjectTypePair moreSpecificType = toMoreSpecificType();
+ ObjectTypePair moreSpecificType = toMoreSpecificType();
handler = handlers.getHandlerFor(moreSpecificType.type);
if (handler != null) {
return new Pair(handler, moreSpecificType);
@@ -66,7 +67,7 @@ final class ObjectTypePair {
return handler == null ? null : new Pair(handler, this);
}
- ObjectTypePair toMoreSpecificType() {
+ ObjectTypePair toMoreSpecificType() {
if (preserveType || obj == null) {
return this;
}
@@ -77,9 +78,16 @@ final class ObjectTypePair {
return new ObjectTypePair(obj, actualType, preserveType);
}
+ 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
+ // 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>) {
@@ -89,7 +97,7 @@ final class ObjectTypePair {
}
if (type == Object.class) {
type = actualClass;
- }
+ }
}
return type;
}
diff --git a/src/org/mcteam/factions/gson/Pair.java b/src/org/mcteam/factions/gson/Pair.java
index d034a48c..cb3a5bed 100644
--- a/src/org/mcteam/factions/gson/Pair.java
+++ b/src/org/mcteam/factions/gson/Pair.java
@@ -26,11 +26,10 @@ package org.mcteam.factions.gson;
* @param
*/
final class Pair {
+ public final FIRST first;
+ public final SECOND second;
- final FIRST first;
- final SECOND second;
-
- Pair(FIRST first, SECOND second) {
+ public Pair(FIRST first, SECOND second) {
this.first = first;
this.second = second;
}
diff --git a/src/org/mcteam/factions/gson/ParameterizedTypeHandlerMap.java b/src/org/mcteam/factions/gson/ParameterizedTypeHandlerMap.java
index a631e9e6..6e83d6eb 100644
--- a/src/org/mcteam/factions/gson/ParameterizedTypeHandlerMap.java
+++ b/src/org/mcteam/factions/gson/ParameterizedTypeHandlerMap.java
@@ -16,6 +16,8 @@
package org.mcteam.factions.gson;
+import org.mcteam.factions.gson.internal.$Gson$Types;
+
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.HashMap;
@@ -27,10 +29,10 @@ import java.util.logging.Logger;
/**
* A map that provides ability to associate handlers for a specific type or all
* of its sub-types
- *
+ *
* @author Inderjeet Singh
* @author Joel Leitch
- *
+ *
* @param The handler that will be looked up by type
*/
final class ParameterizedTypeHandlerMap {
@@ -105,6 +107,21 @@ final class ParameterizedTypeHandlerMap {
}
}
+ public synchronized void register(ParameterizedTypeHandlerMap other) {
+ if (!modifiable) {
+ throw new IllegalStateException("Attempted to modify an unmodifiable map.");
+ }
+ for (Map.Entry entry : other.map.entrySet()) {
+ register(entry.getKey(), entry.getValue());
+ }
+ // Quite important to traverse the typeHierarchyList from stack bottom first since
+ // we want to register the handlers in the same order to preserve priority order
+ for (int i = other.typeHierarchyList.size()-1; i >= 0; --i) {
+ Pair, T> entry = other.typeHierarchyList.get(i);
+ registerForTypeHierarchy(entry);
+ }
+ }
+
public synchronized void registerIfAbsent(Type typeOfT, T value) {
if (!modifiable) {
throw new IllegalStateException("Attempted to modify an unmodifiable map.");
@@ -121,7 +138,7 @@ final class ParameterizedTypeHandlerMap {
public synchronized T getHandlerFor(Type type) {
T handler = map.get(type);
if (handler == null) {
- Class> rawClass = TypeUtils.toRawClass(type);
+ Class> rawClass = $Gson$Types.getRawType(type);
if (rawClass != type) {
handler = getHandlerFor(rawClass);
}
@@ -157,12 +174,10 @@ final class ParameterizedTypeHandlerMap {
public synchronized ParameterizedTypeHandlerMap copyOf() {
ParameterizedTypeHandlerMap copy = new ParameterizedTypeHandlerMap();
- for (Map.Entry entry : map.entrySet()) {
- copy.register(entry.getKey(), entry.getValue());
- }
- for (Pair, T> entry : typeHierarchyList) {
- copy.registerForTypeHierarchy(entry);
- }
+ // Instead of individually registering entries in the map, make an efficient copy
+ // of the list and map
+ copy.map.putAll(map);
+ copy.typeHierarchyList.addAll(typeHierarchyList);
return copy;
}
@@ -195,6 +210,6 @@ final class ParameterizedTypeHandlerMap {
}
private String typeToString(Type type) {
- return TypeUtils.toRawClass(type).getSimpleName();
+ return $Gson$Types.getRawType(type).getSimpleName();
}
}
diff --git a/src/org/mcteam/factions/gson/ParameterizedTypeImpl.java b/src/org/mcteam/factions/gson/ParameterizedTypeImpl.java
deleted file mode 100644
index 13e64ff6..00000000
--- a/src/org/mcteam/factions/gson/ParameterizedTypeImpl.java
+++ /dev/null
@@ -1,91 +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 org.mcteam.factions.gson;
-
-import java.lang.reflect.ParameterizedType;
-import java.lang.reflect.Type;
-import java.util.Arrays;
-
-/**
- * An immutable implementation of the {@link ParameterizedType} interface. This object allows
- * us to build a reflective {@link Type} objects on demand. This object is used to support
- * serialization and deserialization of classes with an {@code ParameterizedType} field where
- * as least one of the actual type parameters is a {@code TypeVariable}.
- *
- *
- *
- * @author Inderjeet Singh
- * @author Joel Leitch
- */
-final class ParameterizedTypeImpl implements ParameterizedType {
-
- private final Type rawType;
- private final Type[] actualTypeArguments;
- private final Type owner;
-
- public ParameterizedTypeImpl(Type rawType, Type[] actualTypeArguments, Type owner) {
- this.rawType = rawType;
- this.actualTypeArguments = actualTypeArguments;
- this.owner = owner;
- }
-
- public Type getRawType() {
- return rawType;
- }
-
- public Type[] getActualTypeArguments() {
- return actualTypeArguments;
- }
-
- public Type getOwnerType() {
- return owner;
- }
-
- @Override
- public boolean equals(Object o) {
- if (!(o instanceof ParameterizedType)) {
- return false;
- }
- // Check that information is equivalent
- ParameterizedType that = (ParameterizedType) o;
- if (this == that) {
- return true;
- }
- Type thatOwner = that.getOwnerType();
- Type thatRawType = that.getRawType();
-
- return (owner == null ? thatOwner == null : owner.equals(thatOwner))
- && (rawType == null ? thatRawType == null : rawType.equals(thatRawType))
- && Arrays.equals(actualTypeArguments, that.getActualTypeArguments());
- }
-
- @Override
- public int hashCode() {
- return Arrays.hashCode(actualTypeArguments)
- ^ (owner == null ? 0 : owner.hashCode())
- ^ (rawType == null ? 0 : rawType.hashCode());
- }
-}
diff --git a/src/org/mcteam/factions/gson/Primitives.java b/src/org/mcteam/factions/gson/Primitives.java
index dafdeeec..9629dbe1 100644
--- a/src/org/mcteam/factions/gson/Primitives.java
+++ b/src/org/mcteam/factions/gson/Primitives.java
@@ -16,10 +16,14 @@
package org.mcteam.factions.gson;
+
+import java.lang.reflect.Type;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
+import org.mcteam.factions.gson.internal.$Gson$Preconditions;
+
/**
* Contains static utility methods pertaining to primitive types and their
* corresponding wrapper types.
@@ -30,13 +34,13 @@ final class Primitives {
private Primitives() {}
/** A map from primitive types to their corresponding wrapper types. */
- public static final Map, Class>> PRIMITIVE_TO_WRAPPER_TYPE;
+ private static final Map, Class>> PRIMITIVE_TO_WRAPPER_TYPE;
/** A map from wrapper types to their corresponding primitive types. */
- public static final Map, Class>> WRAPPER_TO_PRIMITIVE_TYPE;
+ private static final Map, Class>> WRAPPER_TO_PRIMITIVE_TYPE;
// Sad that we can't use a BiMap. :(
-
+
static {
Map, Class>> primToWrap = new HashMap, Class>>(16);
Map, Class>> wrapToPrim = new HashMap, Class>>(16);
@@ -61,6 +65,13 @@ final class Primitives {
backward.put(value, key);
}
+ /**
+ * Returns true if this type is a primitive.
+ */
+ public static boolean isPrimitive(Type type) {
+ return PRIMITIVE_TO_WRAPPER_TYPE.containsKey(type);
+ }
+
/**
* Returns {@code true} if {@code type} is one of the nine
* primitive-wrapper types, such as {@link Integer}.
@@ -68,12 +79,8 @@ final class Primitives {
* @see Class#isPrimitive
*/
public static boolean isWrapperType(Class> type) {
- return WRAPPER_TO_PRIMITIVE_TYPE.containsKey(checkNotNull(type));
- }
-
- private static Class> checkNotNull(Class> type) {
- Preconditions.checkNotNull(type);
- return type;
+ return WRAPPER_TO_PRIMITIVE_TYPE.containsKey(
+ $Gson$Preconditions.checkNotNull(type));
}
/**
@@ -86,11 +93,10 @@ final class Primitives {
*
*/
public static Class wrap(Class type) {
- checkNotNull(type);
-
// cast is safe: long.class and Long.class are both of type Class
@SuppressWarnings("unchecked")
- Class wrapped = (Class) PRIMITIVE_TO_WRAPPER_TYPE.get(type);
+ Class wrapped = (Class) PRIMITIVE_TO_WRAPPER_TYPE.get(
+ $Gson$Preconditions.checkNotNull(type));
return (wrapped == null) ? type : wrapped;
}
@@ -104,11 +110,10 @@ final class Primitives {
*
*/
public static Class unwrap(Class type) {
- checkNotNull(type);
-
// cast is safe: long.class and Long.class are both of type Class
@SuppressWarnings("unchecked")
- Class unwrapped = (Class) WRAPPER_TO_PRIMITIVE_TYPE.get(type);
+ Class unwrapped = (Class) WRAPPER_TO_PRIMITIVE_TYPE.get(
+ $Gson$Preconditions.checkNotNull(type));
return (unwrapped == null) ? type : unwrapped;
- }
+ }
}
diff --git a/src/org/mcteam/factions/gson/RecursiveFieldNamingPolicy.java b/src/org/mcteam/factions/gson/RecursiveFieldNamingPolicy.java
index e7c05637..6d8a305b 100644
--- a/src/org/mcteam/factions/gson/RecursiveFieldNamingPolicy.java
+++ b/src/org/mcteam/factions/gson/RecursiveFieldNamingPolicy.java
@@ -30,7 +30,6 @@ import java.util.Collection;
abstract class RecursiveFieldNamingPolicy implements FieldNamingStrategy2 {
public final String translateName(FieldAttributes f) {
- Preconditions.checkNotNull(f);
return translateName(f.getName(), f.getDeclaredType(), f.getAnnotations());
}
diff --git a/src/org/mcteam/factions/gson/ReflectingFieldNavigator.java b/src/org/mcteam/factions/gson/ReflectingFieldNavigator.java
new file mode 100644
index 00000000..fb2fd8f4
--- /dev/null
+++ b/src/org/mcteam/factions/gson/ReflectingFieldNavigator.java
@@ -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 org.mcteam.factions.gson;
+
+import java.lang.reflect.AccessibleObject;
+import java.lang.reflect.Field;
+import java.lang.reflect.Type;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.mcteam.factions.gson.ObjectNavigator.Visitor;
+import org.mcteam.factions.gson.internal.$Gson$Preconditions;
+import org.mcteam.factions.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> fieldsCache =
+ new LruCache>(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 = fieldAttributes.getResolvedType();
+ 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);
+ }
+ }
+ }
+ }
+
+ private List getAllFields(Type type, Type declaredType) {
+ List fields = fieldsCache.getElement(type);
+ if (fields == null) {
+ fields = new ArrayList();
+ 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> getInheritanceHierarchy(Type type) {
+ List> classes = new ArrayList>();
+ 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;
+ }
+}
diff --git a/src/org/mcteam/factions/gson/SerializedNameAnnotationInterceptingNamingPolicy.java b/src/org/mcteam/factions/gson/SerializedNameAnnotationInterceptingNamingPolicy.java
index 42da8201..537c40e7 100644
--- a/src/org/mcteam/factions/gson/SerializedNameAnnotationInterceptingNamingPolicy.java
+++ b/src/org/mcteam/factions/gson/SerializedNameAnnotationInterceptingNamingPolicy.java
@@ -19,30 +19,30 @@ package org.mcteam.factions.gson;
import org.mcteam.factions.gson.annotations.SerializedName;
/**
- * A {@link FieldNamingStrategy2} that acts as a chain of responsibility. If the
- * {@link org.mcteam.factions.gson.annotations.SerializedName} annotation is applied to a field then this
- * strategy will translate the name to the {@code serializedName.value()}; otherwise it delegates
- * to the wrapped {@link FieldNamingStrategy2}.
+ * A {@link FieldNamingStrategy2} that acts as a chain of responsibility. If the
+ * {@link org.mcteam.factions.gson.annotations.SerializedName} annotation is applied to a
+ * field then this strategy will translate the name to the {@code
+ * serializedName.value()}; otherwise it delegates to the wrapped
+ * {@link FieldNamingStrategy2}.
*
- *
NOTE: this class performs JSON field name validation for any of the fields marked with
- * an {@code @SerializedName} annotation.
+ *
+ * NOTE: this class performs JSON field name validation for any of the fields
+ * marked with an {@code @SerializedName} annotation.
+ *
*
* @see SerializedName
*
* @author Joel Leitch
*/
final class SerializedNameAnnotationInterceptingNamingPolicy implements FieldNamingStrategy2 {
- private static final JsonFieldNameValidator fieldNameValidator = new JsonFieldNameValidator();
private final FieldNamingStrategy2 delegate;
- public SerializedNameAnnotationInterceptingNamingPolicy(FieldNamingStrategy2 delegate) {
+ SerializedNameAnnotationInterceptingNamingPolicy(FieldNamingStrategy2 delegate) {
this.delegate = delegate;
}
public String translateName(FieldAttributes f) {
- Preconditions.checkNotNull(f);
SerializedName serializedName = f.getAnnotation(SerializedName.class);
- return serializedName == null ? delegate.translateName(f)
- : fieldNameValidator.validate(serializedName.value());
+ return serializedName == null ? delegate.translateName(f) : serializedName.value();
}
}
diff --git a/src/org/mcteam/factions/gson/Streams.java b/src/org/mcteam/factions/gson/Streams.java
index a71feb4c..305c504e 100644
--- a/src/org/mcteam/factions/gson/Streams.java
+++ b/src/org/mcteam/factions/gson/Streams.java
@@ -16,15 +16,14 @@
package org.mcteam.factions.gson;
+import org.mcteam.factions.gson.stream.JsonReader;
+import org.mcteam.factions.gson.stream.JsonWriter;
+import org.mcteam.factions.gson.stream.MalformedJsonException;
import java.io.EOFException;
import java.io.IOException;
import java.io.Writer;
import java.util.Map;
-import org.mcteam.factions.gson.stream.JsonReader;
-import org.mcteam.factions.gson.stream.JsonWriter;
-import org.mcteam.factions.gson.stream.MalformedJsonException;
-
/**
* Reads and writes GSON parse trees over streams.
*/
diff --git a/src/org/mcteam/factions/gson/SyntheticFieldExclusionStrategy.java b/src/org/mcteam/factions/gson/SyntheticFieldExclusionStrategy.java
index a988d097..5824b04c 100644
--- a/src/org/mcteam/factions/gson/SyntheticFieldExclusionStrategy.java
+++ b/src/org/mcteam/factions/gson/SyntheticFieldExclusionStrategy.java
@@ -26,7 +26,7 @@ package org.mcteam.factions.gson;
*
* @since 1.4
*/
-class SyntheticFieldExclusionStrategy implements ExclusionStrategy {
+final class SyntheticFieldExclusionStrategy implements ExclusionStrategy {
private final boolean skipSyntheticFields;
SyntheticFieldExclusionStrategy(boolean skipSyntheticFields) {
diff --git a/src/org/mcteam/factions/gson/TypeAdapter.java b/src/org/mcteam/factions/gson/TypeAdapter.java
deleted file mode 100644
index b5813ee5..00000000
--- a/src/org/mcteam/factions/gson/TypeAdapter.java
+++ /dev/null
@@ -1,35 +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 org.mcteam.factions.gson;
-
-/**
- * This class is responsible for adapting/converting an particular "from"
- * instance to an instance of type "to".
- *
- * @author Joel Leitch
- */
-interface TypeAdapter {
-
- /**
- * Adapts an object instance "from" to and instance of type "to".
- *
- * @param from the object to adapt
- * @param to the Type/Class which this will convert to
- * @return the converted "from" instance to type "to"
- */
- public T adaptType(Object from, Class to);
-}
diff --git a/src/org/mcteam/factions/gson/TypeInfo.java b/src/org/mcteam/factions/gson/TypeInfo.java
deleted file mode 100644
index 88e4fa8d..00000000
--- a/src/org/mcteam/factions/gson/TypeInfo.java
+++ /dev/null
@@ -1,76 +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 org.mcteam.factions.gson;
-
-import java.lang.reflect.Type;
-import java.util.Collection;
-
-/**
- * Class that provides information relevant to different parts of a type.
- *
- * @author Inderjeet Singh
- * @author Joel Leitch
- */
-class TypeInfo {
- protected final Type actualType;
- protected final Class> rawClass;
-
- TypeInfo(Type actualType) {
- this.actualType = actualType;
- rawClass = TypeUtils.toRawClass(actualType);
- }
-
- public final Type getActualType() {
- return actualType;
- }
-
- /**
- * Returns the corresponding wrapper type of {@code type} if it is a primitive
- * type; otherwise returns {@code type} itself. Idempotent.
- *
- * TypeUtils.getActualTypeForFirstTypeVariable(fooType) will return Integer.class.
- */
- static Type getActualTypeForFirstTypeVariable(Type type) {
- if (type instanceof Class>) {
- return Object.class;
- } else if (type instanceof ParameterizedType) {
- return ((ParameterizedType)type).getActualTypeArguments()[0];
- } else if (type instanceof GenericArrayType) {
- return getActualTypeForFirstTypeVariable(((GenericArrayType)type).getGenericComponentType());
- } else {
- throw new IllegalArgumentException("Type \'" + type + "\' is not a Class, "
- + "ParameterizedType, or GenericArrayType. Can't extract class.");
- }
- }
-
- static boolean isArray(Type type) {
- if (type instanceof Class>) {
- return ((Class>)type).isArray();
- } else if (type instanceof GenericArrayType) {
- return true;
- } else {
- return false;
- }
- }
-
- /**
- * This method returns the actual raw class associated with the specified type.
- */
- static Class> toRawClass(Type type) {
- if (type instanceof Class>) {
- return (Class>) type;
- } else if (type instanceof ParameterizedType) {
- ParameterizedType actualType = (ParameterizedType)type;
- return toRawClass(actualType.getRawType());
- } else if (type instanceof GenericArrayType) {
- GenericArrayType actualType = (GenericArrayType) type;
- Class> rawClass = toRawClass(actualType.getGenericComponentType());
- return wrapWithArray(rawClass);
- } else if (type instanceof WildcardType) {
- WildcardType castedType = (WildcardType) type;
- return toRawClass(castedType.getUpperBounds()[0]);
- } else {
- throw new IllegalArgumentException("Type \'" + type + "\' is not a Class, "
- + "ParameterizedType, or GenericArrayType. Can't extract class.");
- }
- }
-
- static Class> wrapWithArray(Class> rawClass) {
- return Array.newInstance(rawClass, 0).getClass();
- }
-
- private TypeUtils() {
- // Class with just some static utility methods, should not be instantiated
- }
-}
diff --git a/src/org/mcteam/factions/gson/UnsafeAllocator.java b/src/org/mcteam/factions/gson/UnsafeAllocator.java
new file mode 100644
index 00000000..82cb29cc
--- /dev/null
+++ b/src/org/mcteam/factions/gson/UnsafeAllocator.java
@@ -0,0 +1,104 @@
+/*
+ * 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 org.mcteam.factions.gson;
+
+import java.io.ObjectInputStream;
+import java.io.ObjectStreamClass;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+
+/**
+ * Do sneaky things to allocate objects without invoking their constructors.
+ *
+ * @author Joel Leitch
+ * @author Jesse Wilson
+ */
+abstract class UnsafeAllocator {
+ public abstract T newInstance(Class c) throws Exception;
+
+ public static UnsafeAllocator create() {
+ // try JVM
+ // public class Unsafe {
+ // public Object allocateInstance(Class> type);
+ // }
+ try {
+ Class> unsafeClass = Class.forName("sun.misc.Unsafe");
+ Field f = unsafeClass.getDeclaredField("theUnsafe");
+ f.setAccessible(true);
+ final Object unsafe = f.get(null);
+ final Method allocateInstance = unsafeClass.getMethod("allocateInstance", Class.class);
+ return new UnsafeAllocator() {
+ @Override
+ @SuppressWarnings("unchecked")
+ public T newInstance(Class c) throws Exception {
+ return (T) allocateInstance.invoke(unsafe, c);
+ }
+ };
+ } catch (Exception ignored) {
+ }
+
+ // try dalvikvm, pre-gingerbread
+ // public class ObjectInputStream {
+ // private static native Object newInstance(
+ // Class> instantiationClass, Class> constructorClass);
+ // }
+ try {
+ final Method newInstance = ObjectInputStream.class
+ .getDeclaredMethod("newInstance", Class.class, Class.class);
+ newInstance.setAccessible(true);
+ return new UnsafeAllocator() {
+ @Override
+ @SuppressWarnings("unchecked")
+ public T newInstance(Class c) throws Exception {
+ return (T) newInstance.invoke(null, c, Object.class);
+ }
+ };
+ } catch (Exception ignored) {
+ }
+
+ // try dalvivkm, post-gingerbread
+ // public class ObjectStreamClass {
+ // private static native int getConstructorId(Class> c);
+ // private static native Object newInstance(Class> instantiationClass, int methodId);
+ // }
+ try {
+ Method getConstructorId = ObjectStreamClass.class
+ .getDeclaredMethod("getConstructorId", Class.class);
+ getConstructorId.setAccessible(true);
+ final int constructorId = (Integer) getConstructorId.invoke(null, Object.class);
+ final Method newInstance = ObjectStreamClass.class
+ .getDeclaredMethod("newInstance", Class.class, int.class);
+ newInstance.setAccessible(true);
+ return new UnsafeAllocator() {
+ @Override
+ @SuppressWarnings("unchecked")
+ public T newInstance(Class c) throws Exception {
+ return (T) newInstance.invoke(null, c, constructorId);
+ }
+ };
+ } catch (Exception ignored) {
+ }
+
+ // give up
+ return new UnsafeAllocator() {
+ @Override
+ public T newInstance(Class c) {
+ throw new UnsupportedOperationException("Cannot allocate " + c);
+ }
+ };
+ }
+}
diff --git a/src/org/mcteam/factions/gson/VersionExclusionStrategy.java b/src/org/mcteam/factions/gson/VersionExclusionStrategy.java
index 29c7bb9f..d55fc56c 100644
--- a/src/org/mcteam/factions/gson/VersionExclusionStrategy.java
+++ b/src/org/mcteam/factions/gson/VersionExclusionStrategy.java
@@ -18,6 +18,7 @@ package org.mcteam.factions.gson;
import org.mcteam.factions.gson.annotations.Since;
import org.mcteam.factions.gson.annotations.Until;
+import org.mcteam.factions.gson.internal.$Gson$Preconditions;
/**
* This strategy will exclude any files and/or class that are passed the
@@ -28,8 +29,8 @@ import org.mcteam.factions.gson.annotations.Until;
final class VersionExclusionStrategy implements ExclusionStrategy {
private final double version;
- public VersionExclusionStrategy(double version) {
- Preconditions.checkArgument(version >= 0.0D);
+ VersionExclusionStrategy(double version) {
+ $Gson$Preconditions.checkArgument(version >= 0.0D);
this.version = version;
}
diff --git a/src/org/mcteam/factions/gson/Preconditions.java b/src/org/mcteam/factions/gson/internal/$Gson$Preconditions.java
similarity index 77%
rename from src/org/mcteam/factions/gson/Preconditions.java
rename to src/org/mcteam/factions/gson/internal/$Gson$Preconditions.java
index 6561a1d0..c6fb2a26 100644
--- a/src/org/mcteam/factions/gson/Preconditions.java
+++ b/src/org/mcteam/factions/gson/internal/$Gson$Preconditions.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package org.mcteam.factions.gson;
+package org.mcteam.factions.gson.internal;
/**
* A simple utility class used to check method Preconditions.
@@ -29,20 +29,23 @@ package org.mcteam.factions.gson;
* @author Inderjeet Singh
* @author Joel Leitch
*/
-final class Preconditions {
- public static void checkNotNull(Object obj) {
- checkArgument(obj != null);
+public final class $Gson$Preconditions {
+ public static T checkNotNull(T obj) {
+ if (obj == null) {
+ throw new NullPointerException();
+ }
+ return obj;
}
public static void checkArgument(boolean condition) {
if (!condition) {
- throw new IllegalArgumentException("condition failed: " + condition);
+ throw new IllegalArgumentException();
}
}
-
+
public static void checkState(boolean condition) {
if (!condition) {
- throw new IllegalArgumentException("condition failed: " + condition);
+ throw new IllegalStateException();
}
}
}
diff --git a/src/org/mcteam/factions/gson/internal/$Gson$Types.java b/src/org/mcteam/factions/gson/internal/$Gson$Types.java
new file mode 100644
index 00000000..3adae2f4
--- /dev/null
+++ b/src/org/mcteam/factions/gson/internal/$Gson$Types.java
@@ -0,0 +1,589 @@
+/**
+ * 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 org.mcteam.factions.gson.internal;
+
+import static org.mcteam.factions.gson.internal.$Gson$Preconditions.checkArgument;
+import static org.mcteam.factions.gson.internal.$Gson$Preconditions.checkNotNull;
+import java.io.Serializable;
+import java.lang.reflect.Array;
+import java.lang.reflect.GenericArrayType;
+import java.lang.reflect.GenericDeclaration;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.lang.reflect.TypeVariable;
+import java.lang.reflect.WildcardType;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Map;
+import java.util.NoSuchElementException;
+import java.util.Properties;
+
+/**
+ * Static methods for working with types.
+ *
+ * @author Bob Lee
+ * @author Jesse Wilson
+ */
+public final class $Gson$Types {
+ static final Type[] EMPTY_TYPE_ARRAY = new Type[] {};
+
+ private $Gson$Types() {}
+
+ /**
+ * Returns a new parameterized type, applying {@code typeArguments} to
+ * {@code rawType} and enclosed by {@code ownerType}.
+ *
+ * @return a {@link java.io.Serializable serializable} parameterized type.
+ */
+ public static ParameterizedType newParameterizedTypeWithOwner(
+ Type ownerType, Type rawType, Type... typeArguments) {
+ return new ParameterizedTypeImpl(ownerType, rawType, typeArguments);
+ }
+
+ /**
+ * Returns an array type whose elements are all instances of
+ * {@code componentType}.
+ *
+ * @return a {@link java.io.Serializable serializable} generic array type.
+ */
+ public static GenericArrayType arrayOf(Type componentType) {
+ return new GenericArrayTypeImpl(componentType);
+ }
+
+ /**
+ * Returns a type that represents an unknown type that extends {@code bound}.
+ * For example, if {@code bound} is {@code CharSequence.class}, this returns
+ * {@code ? extends CharSequence}. If {@code bound} is {@code Object.class},
+ * this returns {@code ?}, which is shorthand for {@code ? extends Object}.
+ */
+ public static WildcardType subtypeOf(Type bound) {
+ return new WildcardTypeImpl(new Type[] { bound }, EMPTY_TYPE_ARRAY);
+ }
+
+ /**
+ * Returns a type that represents an unknown supertype of {@code bound}. For
+ * example, if {@code bound} is {@code String.class}, this returns {@code ?
+ * super String}.
+ */
+ public static WildcardType supertypeOf(Type bound) {
+ return new WildcardTypeImpl(new Type[] { Object.class }, new Type[] { bound });
+ }
+
+ /**
+ * Returns a type that is functionally equal but not necessarily equal
+ * according to {@link Object#equals(Object) Object.equals()}. The returned
+ * type is {@link java.io.Serializable}.
+ */
+ @SuppressWarnings("unchecked")
+ public static Type canonicalize(Type type) {
+ if (type instanceof Class) {
+ Class> c = (Class>) type;
+ return c.isArray() ? new GenericArrayTypeImpl(canonicalize(c.getComponentType())) : c;
+
+ } else if (type instanceof ParameterizedType) {
+ ParameterizedType p = (ParameterizedType) type;
+ return new ParameterizedTypeImpl(p.getOwnerType(),
+ p.getRawType(), p.getActualTypeArguments());
+
+ } else if (type instanceof GenericArrayType) {
+ GenericArrayType g = (GenericArrayType) type;
+ return new GenericArrayTypeImpl(g.getGenericComponentType());
+
+ } else if (type instanceof WildcardType) {
+ WildcardType w = (WildcardType) type;
+ return new WildcardTypeImpl(w.getUpperBounds(), w.getLowerBounds());
+
+ } else {
+ // type is either serializable as-is or unsupported
+ return type;
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ public static Class> getRawType(Type type) {
+ if (type instanceof Class>) {
+ // type is a normal class.
+ return (Class>) type;
+
+ } else if (type instanceof ParameterizedType) {
+ ParameterizedType parameterizedType = (ParameterizedType) type;
+
+ // I'm not exactly sure why getRawType() returns Type instead of Class.
+ // Neal isn't either but suspects some pathological case related
+ // to nested classes exists.
+ Type rawType = parameterizedType.getRawType();
+ checkArgument(rawType instanceof Class);
+ return (Class>) rawType;
+
+ } else if (type instanceof GenericArrayType) {
+ Type componentType = ((GenericArrayType)type).getGenericComponentType();
+ return Array.newInstance(getRawType(componentType), 0).getClass();
+
+ } else if (type instanceof TypeVariable) {
+ // we could use the variable's bounds, but that won't work if there are multiple.
+ // having a raw type that's more general than necessary is okay
+ return Object.class;
+
+ } else if (type instanceof WildcardType) {
+ return getRawType(((WildcardType) type).getUpperBounds()[0]);
+
+ } else {
+ String className = type == null ? "null" : type.getClass().getName();
+ throw new IllegalArgumentException("Expected a Class, ParameterizedType, or "
+ + "GenericArrayType, but <" + type + "> is of type " + className);
+ }
+ }
+
+ static boolean equal(Object a, Object b) {
+ return a == b || (a != null && a.equals(b));
+ }
+
+ /**
+ * Returns true if {@code a} and {@code b} are equal.
+ */
+ @SuppressWarnings("unchecked")
+ public static boolean equals(Type a, Type b) {
+ if (a == b) {
+ // also handles (a == null && b == null)
+ return true;
+
+ } else if (a instanceof Class) {
+ // Class already specifies equals().
+ return a.equals(b);
+
+ } else if (a instanceof ParameterizedType) {
+ if (!(b instanceof ParameterizedType)) {
+ return false;
+ }
+
+ // TODO: save a .clone() call
+ ParameterizedType pa = (ParameterizedType) a;
+ ParameterizedType pb = (ParameterizedType) b;
+ return equal(pa.getOwnerType(), pb.getOwnerType())
+ && pa.getRawType().equals(pb.getRawType())
+ && Arrays.equals(pa.getActualTypeArguments(), pb.getActualTypeArguments());
+
+ } else if (a instanceof GenericArrayType) {
+ if (!(b instanceof GenericArrayType)) {
+ return false;
+ }
+
+ GenericArrayType ga = (GenericArrayType) a;
+ GenericArrayType gb = (GenericArrayType) b;
+ return equals(ga.getGenericComponentType(), gb.getGenericComponentType());
+
+ } else if (a instanceof WildcardType) {
+ if (!(b instanceof WildcardType)) {
+ return false;
+ }
+
+ WildcardType wa = (WildcardType) a;
+ WildcardType wb = (WildcardType) b;
+ return Arrays.equals(wa.getUpperBounds(), wb.getUpperBounds())
+ && Arrays.equals(wa.getLowerBounds(), wb.getLowerBounds());
+
+ } else if (a instanceof TypeVariable) {
+ if (!(b instanceof TypeVariable)) {
+ return false;
+ }
+ TypeVariable> va = (TypeVariable>) a;
+ TypeVariable> vb = (TypeVariable>) b;
+ return va.getGenericDeclaration() == vb.getGenericDeclaration()
+ && va.getName().equals(vb.getName());
+
+ } else {
+ // This isn't a type we support. Could be a generic array type, wildcard type, etc.
+ return false;
+ }
+ }
+
+ private static int hashCodeOrZero(Object o) {
+ return o != null ? o.hashCode() : 0;
+ }
+
+ @SuppressWarnings("unchecked")
+ public static String typeToString(Type type) {
+ return type instanceof Class ? ((Class>) type).getName() : type.toString();
+ }
+
+ /**
+ * Returns the generic supertype for {@code supertype}. For example, given a class {@code
+ * IntegerSet}, the result for when supertype is {@code Set.class} is {@code Set} and the
+ * result when the supertype is {@code Collection.class} is {@code Collection}.
+ */
+ static Type getGenericSupertype(Type context, Class> rawType, Class> toResolve) {
+ if (toResolve == rawType) {
+ return context;
+ }
+
+ // we skip searching through interfaces if unknown is an interface
+ if (toResolve.isInterface()) {
+ Class>[] interfaces = rawType.getInterfaces();
+ for (int i = 0, length = interfaces.length; i < length; i++) {
+ if (interfaces[i] == toResolve) {
+ return rawType.getGenericInterfaces()[i];
+ } else if (toResolve.isAssignableFrom(interfaces[i])) {
+ return getGenericSupertype(rawType.getGenericInterfaces()[i], interfaces[i], toResolve);
+ }
+ }
+ }
+
+ // check our supertypes
+ if (!rawType.isInterface()) {
+ while (rawType != Object.class) {
+ Class> rawSupertype = rawType.getSuperclass();
+ if (rawSupertype == toResolve) {
+ return rawType.getGenericSuperclass();
+ } else if (toResolve.isAssignableFrom(rawSupertype)) {
+ return getGenericSupertype(rawType.getGenericSuperclass(), rawSupertype, toResolve);
+ }
+ rawType = rawSupertype;
+ }
+ }
+
+ // we can't resolve this further
+ return toResolve;
+ }
+
+ /**
+ * Returns the generic form of {@code supertype}. For example, if this is {@code
+ * ArrayList}, this returns {@code Iterable} given the input {@code
+ * Iterable.class}.
+ *
+ * @param supertype a superclass of, or interface implemented by, this.
+ */
+ static Type getSupertype(Type context, Class> contextRawType, Class> supertype) {
+ checkArgument(supertype.isAssignableFrom(contextRawType));
+ return resolve(context, contextRawType,
+ $Gson$Types.getGenericSupertype(context, contextRawType, supertype));
+ }
+
+ /**
+ * Returns true if this type is an array.
+ */
+ @SuppressWarnings("unchecked")
+ public static boolean isArray(Type type) {
+ return type instanceof GenericArrayType
+ || (type instanceof Class && ((Class>) type).isArray());
+ }
+
+ /**
+ * Returns the component type of this array type.
+ * @throws ClassCastException if this type is not an array.
+ */
+ public static Type getArrayComponentType(Type array) {
+ return array instanceof GenericArrayType
+ ? ((GenericArrayType) array).getGenericComponentType()
+ : ((Class>) array).getComponentType();
+ }
+
+ /**
+ * Returns the element type of this collection type.
+ * @throws IllegalArgumentException if this type is not a collection.
+ */
+ public static Type getCollectionElementType(Type context, Class> contextRawType) {
+ Type collectionType = getSupertype(context, contextRawType, Collection.class);
+ return ((ParameterizedType) collectionType).getActualTypeArguments()[0];
+ }
+
+ /**
+ * Returns a two element array containing this map's key and value types in
+ * positions 0 and 1 respectively.
+ */
+ public static Type[] getMapKeyAndValueTypes(Type context, Class> contextRawType) {
+ /*
+ * Work around a problem with the declaration of java.util.Properties. That
+ * class should extend Hashtable, but it's declared to
+ * extend Hashtable.
+ */
+ if (context == Properties.class) {
+ return new Type[] { String.class, String.class }; // TODO: test subclasses of Properties!
+ }
+
+ Type mapType = getSupertype(context, contextRawType, Map.class);
+ ParameterizedType mapParameterizedType = (ParameterizedType) mapType;
+ return mapParameterizedType.getActualTypeArguments();
+ }
+
+ @SuppressWarnings("unchecked")
+ public static Type resolve(Type context, Class> contextRawType, Type toResolve) {
+ // this implementation is made a little more complicated in an attempt to avoid object-creation
+ while (true) {
+ if (toResolve instanceof TypeVariable) {
+ TypeVariable> typeVariable = (TypeVariable>) toResolve;
+ toResolve = resolveTypeVariable(context, contextRawType, typeVariable);
+ if (toResolve == typeVariable) {
+ return toResolve;
+ }
+
+ } else if (toResolve instanceof Class && ((Class>) toResolve).isArray()) {
+ Class> original = (Class>) toResolve;
+ Type componentType = original.getComponentType();
+ Type newComponentType = resolve(context, contextRawType, componentType);
+ return componentType == newComponentType
+ ? original
+ : arrayOf(newComponentType);
+
+ } else if (toResolve instanceof GenericArrayType) {
+ GenericArrayType original = (GenericArrayType) toResolve;
+ Type componentType = original.getGenericComponentType();
+ Type newComponentType = resolve(context, contextRawType, componentType);
+ return componentType == newComponentType
+ ? original
+ : arrayOf(newComponentType);
+
+ } else if (toResolve instanceof ParameterizedType) {
+ ParameterizedType original = (ParameterizedType) toResolve;
+ Type ownerType = original.getOwnerType();
+ Type newOwnerType = resolve(context, contextRawType, ownerType);
+ boolean changed = newOwnerType != ownerType;
+
+ Type[] args = original.getActualTypeArguments();
+ for (int t = 0, length = args.length; t < length; t++) {
+ Type resolvedTypeArgument = resolve(context, contextRawType, args[t]);
+ if (resolvedTypeArgument != args[t]) {
+ if (!changed) {
+ args = args.clone();
+ changed = true;
+ }
+ args[t] = resolvedTypeArgument;
+ }
+ }
+
+ return changed
+ ? newParameterizedTypeWithOwner(newOwnerType, original.getRawType(), args)
+ : original;
+
+ } else if (toResolve instanceof WildcardType) {
+ WildcardType original = (WildcardType) toResolve;
+ Type[] originalLowerBound = original.getLowerBounds();
+ Type[] originalUpperBound = original.getUpperBounds();
+
+ if (originalLowerBound.length == 1) {
+ Type lowerBound = resolve(context, contextRawType, originalLowerBound[0]);
+ if (lowerBound != originalLowerBound[0]) {
+ return supertypeOf(lowerBound);
+ }
+ } else if (originalUpperBound.length == 1) {
+ Type upperBound = resolve(context, contextRawType, originalUpperBound[0]);
+ if (upperBound != originalUpperBound[0]) {
+ return subtypeOf(upperBound);
+ }
+ }
+ return original;
+
+ } else {
+ return toResolve;
+ }
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ static Type resolveTypeVariable(Type context, Class> contextRawType, TypeVariable unknown) {
+ Class> declaredByRaw = declaringClassOf(unknown);
+
+ // we can't reduce this further
+ if (declaredByRaw == null) {
+ return unknown;
+ }
+
+ Type declaredBy = getGenericSupertype(context, contextRawType, declaredByRaw);
+ if (declaredBy instanceof ParameterizedType) {
+ int index = indexOf(declaredByRaw.getTypeParameters(), unknown);
+ return ((ParameterizedType) declaredBy).getActualTypeArguments()[index];
+ }
+
+ return unknown;
+ }
+
+ private static int indexOf(Object[] array, Object toFind) {
+ for (int i = 0; i < array.length; i++) {
+ if (toFind.equals(array[i])) {
+ return i;
+ }
+ }
+ throw new NoSuchElementException();
+ }
+
+ /**
+ * Returns the declaring class of {@code typeVariable}, or {@code null} if it was not declared by
+ * a class.
+ */
+ @SuppressWarnings("unchecked")
+ private static Class> declaringClassOf(TypeVariable typeVariable) {
+ GenericDeclaration genericDeclaration = typeVariable.getGenericDeclaration();
+ return genericDeclaration instanceof Class
+ ? (Class>) genericDeclaration
+ : null;
+ }
+
+ private static void checkNotPrimitive(Type type) {
+ checkArgument(!(type instanceof Class>) || !((Class>) type).isPrimitive());
+ }
+
+ private static final class ParameterizedTypeImpl implements ParameterizedType, Serializable {
+ private final Type ownerType;
+ private final Type rawType;
+ private final Type[] typeArguments;
+
+ @SuppressWarnings("unchecked")
+ public ParameterizedTypeImpl(Type ownerType, Type rawType, Type... typeArguments) {
+ // require an owner type if the raw type needs it
+ if (rawType instanceof Class>) {
+ Class rawTypeAsClass = (Class) rawType;
+ checkArgument(ownerType != null || rawTypeAsClass.getEnclosingClass() == null);
+ checkArgument(ownerType == null || rawTypeAsClass.getEnclosingClass() != null);
+ }
+
+ this.ownerType = ownerType == null ? null : canonicalize(ownerType);
+ this.rawType = canonicalize(rawType);
+ this.typeArguments = typeArguments.clone();
+ for (int t = 0; t < this.typeArguments.length; t++) {
+ checkNotNull(this.typeArguments[t]);
+ checkNotPrimitive(this.typeArguments[t]);
+ this.typeArguments[t] = canonicalize(this.typeArguments[t]);
+ }
+ }
+
+ public Type[] getActualTypeArguments() {
+ return typeArguments.clone();
+ }
+
+ public Type getRawType() {
+ return rawType;
+ }
+
+ public Type getOwnerType() {
+ return ownerType;
+ }
+
+ @Override public boolean equals(Object other) {
+ return other instanceof ParameterizedType
+ && $Gson$Types.equals(this, (ParameterizedType) other);
+ }
+
+ @Override public int hashCode() {
+ return Arrays.hashCode(typeArguments)
+ ^ rawType.hashCode()
+ ^ hashCodeOrZero(ownerType);
+ }
+
+ @Override public String toString() {
+ StringBuilder stringBuilder = new StringBuilder(30 * (typeArguments.length + 1));
+ stringBuilder.append(typeToString(rawType));
+
+ if (typeArguments.length == 0) {
+ return stringBuilder.toString();
+ }
+
+ stringBuilder.append("<").append(typeToString(typeArguments[0]));
+ for (int i = 1; i < typeArguments.length; i++) {
+ stringBuilder.append(", ").append(typeToString(typeArguments[i]));
+ }
+ return stringBuilder.append(">").toString();
+ }
+
+ private static final long serialVersionUID = 0;
+ }
+
+ private static final class GenericArrayTypeImpl implements GenericArrayType, Serializable {
+ private final Type componentType;
+
+ public GenericArrayTypeImpl(Type componentType) {
+ this.componentType = canonicalize(componentType);
+ }
+
+ public Type getGenericComponentType() {
+ return componentType;
+ }
+
+ @Override public boolean equals(Object o) {
+ return o instanceof GenericArrayType
+ && $Gson$Types.equals(this, (GenericArrayType) o);
+ }
+
+ @Override public int hashCode() {
+ return componentType.hashCode();
+ }
+
+ @Override public String toString() {
+ return typeToString(componentType) + "[]";
+ }
+
+ private static final long serialVersionUID = 0;
+ }
+
+ /**
+ * The WildcardType interface supports multiple upper bounds and multiple
+ * lower bounds. We only support what the Java 6 language needs - at most one
+ * bound. If a lower bound is set, the upper bound must be Object.class.
+ */
+ private static final class WildcardTypeImpl implements WildcardType, Serializable {
+ private final Type upperBound;
+ private final Type lowerBound;
+
+ public WildcardTypeImpl(Type[] upperBounds, Type[] lowerBounds) {
+ checkArgument(lowerBounds.length <= 1);
+ checkArgument(upperBounds.length == 1);
+
+ if (lowerBounds.length == 1) {
+ checkNotNull(lowerBounds[0]);
+ checkNotPrimitive(lowerBounds[0]);
+ checkArgument(upperBounds[0] == Object.class);
+ this.lowerBound = canonicalize(lowerBounds[0]);
+ this.upperBound = Object.class;
+
+ } else {
+ checkNotNull(upperBounds[0]);
+ checkNotPrimitive(upperBounds[0]);
+ this.lowerBound = null;
+ this.upperBound = canonicalize(upperBounds[0]);
+ }
+ }
+
+ public Type[] getUpperBounds() {
+ return new Type[] { upperBound };
+ }
+
+ public Type[] getLowerBounds() {
+ return lowerBound != null ? new Type[] { lowerBound } : EMPTY_TYPE_ARRAY;
+ }
+
+ @Override public boolean equals(Object other) {
+ return other instanceof WildcardType
+ && $Gson$Types.equals(this, (WildcardType) other);
+ }
+
+ @Override public int hashCode() {
+ // this equals Arrays.hashCode(getLowerBounds()) ^ Arrays.hashCode(getUpperBounds());
+ return (lowerBound != null ? 31 + lowerBound.hashCode() : 1)
+ ^ (31 + upperBound.hashCode());
+ }
+
+ @Override public String toString() {
+ if (lowerBound != null) {
+ return "? super " + typeToString(lowerBound);
+ } else if (upperBound == Object.class) {
+ return "?";
+ } else {
+ return "? extends " + typeToString(upperBound);
+ }
+ }
+
+ private static final long serialVersionUID = 0;
+ }
+}
diff --git a/src/org/mcteam/factions/gson/internal/package-info.java b/src/org/mcteam/factions/gson/internal/package-info.java
new file mode 100644
index 00000000..28c0c6e8
--- /dev/null
+++ b/src/org/mcteam/factions/gson/internal/package-info.java
@@ -0,0 +1,7 @@
+/**
+ * Do NOT use any class in this package as they are meant for internal use in Gson.
+ * These classes will very likely change incompatibly in future versions. You have been warned.
+ *
+ * @author Inderjeet Singh, Joel Leitch, Jesse Wilson
+ */
+package org.mcteam.factions.gson.internal;
\ No newline at end of file
diff --git a/src/org/mcteam/factions/gson/package-info.java b/src/org/mcteam/factions/gson/package-info.java
index f187694f..7a0a1aba 100644
--- a/src/org/mcteam/factions/gson/package-info.java
+++ b/src/org/mcteam/factions/gson/package-info.java
@@ -1,9 +1,9 @@
/**
- * This package provides the {@link com.bukkit.mcteam.gson.Gson} class to convert Json to Java and
+ * This package provides the {@link org.mcteam.factions.gson.Gson} class to convert Json to Java and
* vice-versa.
*
- *
The primary class to use is {@link com.bukkit.mcteam.gson.Gson} which can be constructed with
- * {@code new Gson()} (using default settings) or by using {@link com.bukkit.mcteam.gson.GsonBuilder}
+ *
The primary class to use is {@link org.mcteam.factions.gson.Gson} which can be constructed with
+ * {@code new Gson()} (using default settings) or by using {@link org.mcteam.factions.gson.GsonBuilder}
* (to configure various options such as using versioning and so on).
*
* @author Inderjeet Singh, Joel Leitch
diff --git a/src/org/mcteam/factions/gson/reflect/TypeToken.java b/src/org/mcteam/factions/gson/reflect/TypeToken.java
index 310f8cab..2c0849fb 100644
--- a/src/org/mcteam/factions/gson/reflect/TypeToken.java
+++ b/src/org/mcteam/factions/gson/reflect/TypeToken.java
@@ -16,7 +16,8 @@
package org.mcteam.factions.gson.reflect;
-import java.lang.reflect.Array;
+import org.mcteam.factions.gson.internal.$Gson$Types;
+import org.mcteam.factions.gson.internal.$Gson$Preconditions;
import java.lang.reflect.GenericArrayType;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
@@ -25,135 +26,101 @@ import java.util.HashMap;
import java.util.Map;
/**
- * Represents a generic type {@code T}.
+ * Represents a generic type {@code T}. Java doesn't yet provide a way to
+ * represent generic types, so this class does. Forces clients to create a
+ * subclass of this class which enables retrieval the type information even at
+ * runtime.
+ *
+ *
For example, to create a type literal for {@code List}, you can
+ * create an empty anonymous inner class:
*
- * You can use this class to get the generic type for a class. For example,
- * to get the generic type for Collection<Foo>, you can use:
*
- * Type typeOfCollectionOfFoo = new TypeToken<Collection<Foo>>(){}.getType()
- *
- *
- *
Assumes {@code Type} implements {@code equals()} and {@code hashCode()}
- * as a value (as opposed to identity) comparison.
+ * {@code TypeToken> list = new TypeToken>() {};}
*
- * Also implements {@link #isAssignableFrom(Type)} to check type-safe
- * assignability.
+ *
This syntax cannot be used to create type literals that have wildcard
+ * parameters, such as {@code Class>} or {@code List extends CharSequence>}.
*
* @author Bob Lee
* @author Sven Mawson
+ * @author Jesse Wilson
*/
-public abstract class TypeToken {
+public class TypeToken {
final Class super T> rawType;
final Type type;
+ final int hashCode;
/**
- * Constructs a new type token. Derives represented class from type
+ * Constructs a new type literal. Derives represented class from type
* parameter.
*
*
Clients create an empty anonymous subclass. Doing so embeds the type
- * parameter in the anonymous class's type hierarchy so we can reconstitute
- * it at runtime despite erasure.
- *
- *
For example:
- *
- * {@literal TypeToken> t = new TypeToken>}(){}
- *
+ * parameter in the anonymous class's type hierarchy so we can reconstitute it
+ * at runtime despite erasure.
*/
@SuppressWarnings("unchecked")
protected TypeToken() {
this.type = getSuperclassTypeParameter(getClass());
- this.rawType = (Class super T>) getRawType(type);
+ this.rawType = (Class super T>) $Gson$Types.getRawType(type);
+ this.hashCode = type.hashCode();
}
/**
- * Unsafe. Constructs a type token manually.
+ * Unsafe. Constructs a type literal manually.
*/
- @SuppressWarnings({"unchecked"})
- private TypeToken(Type type) {
- this.rawType = (Class super T>) getRawType(nonNull(type, "type"));
- this.type = type;
+ @SuppressWarnings("unchecked")
+ TypeToken(Type type) {
+ this.type = $Gson$Types.canonicalize($Gson$Preconditions.checkNotNull(type));
+ this.rawType = (Class super T>) $Gson$Types.getRawType(this.type);
+ this.hashCode = this.type.hashCode();
}
- private static T nonNull(T o, String message) {
- if (o == null) {
- throw new NullPointerException(message);
- }
- return o;
- }
-
/**
- * Gets type from super class's type parameter.
+ * Returns the type from super class's type parameter in {@link $Gson$Types#canonicalize
+ * canonical form}.
*/
+ @SuppressWarnings("unchecked")
static Type getSuperclassTypeParameter(Class> subclass) {
Type superclass = subclass.getGenericSuperclass();
- if (superclass instanceof Class>) {
+ if (superclass instanceof Class) {
throw new RuntimeException("Missing type parameter.");
}
- return ((ParameterizedType) superclass).getActualTypeArguments()[0];
+ ParameterizedType parameterized = (ParameterizedType) superclass;
+ return $Gson$Types.canonicalize(parameterized.getActualTypeArguments()[0]);
}
/**
- * Gets type token from super class's type parameter.
+ * Returns the raw (non-generic) type for this type.
*/
- static TypeToken> fromSuperclassTypeParameter(Class> subclass) {
- return new SimpleTypeToken(subclass);
- }
-
- private static Class> getRawType(Type type) {
- if (type instanceof Class>) {
- // type is a normal class.
- return (Class>) type;
- } else if (type instanceof ParameterizedType) {
- ParameterizedType parameterizedType = (ParameterizedType) type;
-
- // I'm not exactly sure why getRawType() returns Type instead of Class.
- // Neal isn't either but suspects some pathological case related
- // to nested classes exists.
- Type rawType = parameterizedType.getRawType();
- if (rawType instanceof Class>) {
- return (Class>) rawType;
- }
- throw buildUnexpectedTypeError(rawType, Class.class);
- } else if (type instanceof GenericArrayType) {
- GenericArrayType genericArrayType = (GenericArrayType) type;
-
- // TODO(jleitch): This is not the most efficient way to handle generic
- // arrays, but is there another way to extract the array class in a
- // non-hacky way (i.e. using String value class names- "[L...")?
- Object rawArrayType = Array.newInstance(
- getRawType(genericArrayType.getGenericComponentType()), 0);
- return rawArrayType.getClass();
- } else {
- throw buildUnexpectedTypeError(
- type, ParameterizedType.class, GenericArrayType.class);
- }
- }
-
- /**
- * Gets the raw type.
- */
- public Class super T> getRawType() {
+ public final Class super T> getRawType() {
return rawType;
}
/**
* Gets underlying {@code Type} instance.
*/
- public Type getType() {
+ public final Type getType() {
return type;
}
/**
* Check if this type is assignable from the given class object.
+ *
+ * @deprecated this implementation may be inconsistent with javac for types
+ * with wildcards.
*/
+ @Deprecated
public boolean isAssignableFrom(Class> cls) {
return isAssignableFrom((Type) cls);
}
/**
* Check if this type is assignable from the given Type.
+ *
+ * @deprecated this implementation may be inconsistent with javac for types
+ * with wildcards.
*/
+ @Deprecated
public boolean isAssignableFrom(Type from) {
if (from == null) {
return false;
@@ -164,12 +131,12 @@ public abstract class TypeToken {
}
if (type instanceof Class>) {
- return rawType.isAssignableFrom(getRawType(from));
+ return rawType.isAssignableFrom($Gson$Types.getRawType(from));
} else if (type instanceof ParameterizedType) {
return isAssignableFrom(from, (ParameterizedType) type,
new HashMap());
} else if (type instanceof GenericArrayType) {
- return rawType.isAssignableFrom(getRawType(from))
+ return rawType.isAssignableFrom($Gson$Types.getRawType(from))
&& isAssignableFrom(from, (GenericArrayType) type);
} else {
throw buildUnexpectedTypeError(
@@ -179,7 +146,11 @@ public abstract class TypeToken {
/**
* Check if this type is assignable from the given type token.
+ *
+ * @deprecated this implementation may be inconsistent with javac for types
+ * with wildcards.
*/
+ @Deprecated
public boolean isAssignableFrom(TypeToken> token) {
return isAssignableFrom(token.getType());
}
@@ -225,7 +196,7 @@ public abstract class TypeToken {
}
// First figure out the class and any type information.
- Class> clazz = getRawType(from);
+ Class> clazz = $Gson$Types.getRawType(from);
ParameterizedType ptype = null;
if (from instanceof ParameterizedType) {
ptype = (ParameterizedType) from;
@@ -259,11 +230,7 @@ public abstract class TypeToken {
// Interfaces didn't work, try the superclass.
Type sType = clazz.getGenericSuperclass();
- if (isAssignableFrom(sType, to, new HashMap(typeVarMap))) {
- return true;
- }
-
- return false;
+ return isAssignableFrom(sType, to, new HashMap(typeVarMap));
}
/**
@@ -285,55 +252,6 @@ public abstract class TypeToken {
return false;
}
- /**
- * Checks if two types are the same or are equivalent under a variable mapping
- * given in the type map that was provided.
- */
- private static boolean matches(Type from, Type to,
- Map typeMap) {
- if (to.equals(from)) return true;
-
- if (from instanceof TypeVariable>) {
- return to.equals(typeMap.get(((TypeVariable>)from).getName()));
- }
-
- return false;
- }
-
- /**
- * Hashcode for this object.
- * @return hashcode for this object.
- */
- @Override public int hashCode() {
- return type.hashCode();
- }
-
- /**
- * Method to test equality.
- *
- * @return true if this object is logically equal to the specified object, false otherwise.
- */
- @Override public boolean equals(Object o) {
- if (o == this) {
- return true;
- }
- if (!(o instanceof TypeToken>)) {
- return false;
- }
- TypeToken> t = (TypeToken>) o;
- return type.equals(t.type);
- }
-
- /**
- * Returns a string representation of this object.
- * @return a string representation of this object.
- */
- @Override public String toString() {
- return type instanceof Class>
- ? ((Class>) type).getName()
- : type.toString();
- }
-
private static AssertionError buildUnexpectedTypeError(
Type token, Class>... expected) {
@@ -350,26 +268,41 @@ public abstract class TypeToken {
}
/**
- * Gets type token for the given {@code Type} instance.
+ * Checks if two types are the same or are equivalent under a variable mapping
+ * given in the type map that was provided.
+ */
+ @SuppressWarnings("unchecked")
+ private static boolean matches(Type from, Type to, Map typeMap) {
+ return to.equals(from)
+ || (from instanceof TypeVariable
+ && to.equals(typeMap.get(((TypeVariable>) from).getName())));
+
+ }
+
+ @Override public final int hashCode() {
+ return this.hashCode;
+ }
+
+ @Override public final boolean equals(Object o) {
+ return o instanceof TypeToken>
+ && $Gson$Types.equals(type, ((TypeToken>) o).type);
+ }
+
+ @Override public final String toString() {
+ return $Gson$Types.typeToString(type);
+ }
+
+ /**
+ * Gets type literal for the given {@code Type} instance.
*/
public static TypeToken> get(Type type) {
- return new SimpleTypeToken(type);
+ return new TypeToken(type);
}
/**
- * Gets type token for the given {@code Class} instance.
+ * Gets type literal for the given {@code Class} instance.
*/
public static TypeToken get(Class type) {
- return new SimpleTypeToken(type);
- }
-
- /**
- * Private static class to not create more anonymous classes than
- * necessary.
- */
- private static class SimpleTypeToken extends TypeToken {
- public SimpleTypeToken(Type type) {
- super(type);
- }
+ return new TypeToken(type);
}
}
diff --git a/src/org/mcteam/factions/gson/stream/JsonReader.java b/src/org/mcteam/factions/gson/stream/JsonReader.java
index 5f79cbea..4499a78a 100644
--- a/src/org/mcteam/factions/gson/stream/JsonReader.java
+++ b/src/org/mcteam/factions/gson/stream/JsonReader.java
@@ -1097,7 +1097,8 @@ public final class JsonReader implements Closeable {
token = JsonToken.NUMBER;
} catch (NumberFormatException ignored) {
// this must be an unquoted string
- throw syntaxError("invalid number or unquoted string");
+ checkLenient();
+ token = JsonToken.STRING;
}
}
}