updating built-in GSON to 1.7.1 release

This commit is contained in:
Brettflan 2011-06-22 18:40:56 -05:00
parent ef2de46dd6
commit 6035b204dc
67 changed files with 2044 additions and 1625 deletions

View File

@ -16,7 +16,6 @@
package org.mcteam.factions.gson; package org.mcteam.factions.gson;
/** /**
* Strategy for excluding anonymous and local classes. * Strategy for excluding anonymous and local classes.
* *

View File

@ -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<Map<?, ?>>, JsonDeserializer<Map<?, ?>> {
protected static final JsonElement serialize(JsonSerializationContext context,
Object src, Type srcType) {
JsonSerializationContextDefault contextImpl = (JsonSerializationContextDefault) context;
return contextImpl.serialize(src, srcType, false);
}
@SuppressWarnings("unchecked")
protected static final Map<Object, Object> constructMapType(
Type mapType, JsonDeserializationContext context) {
JsonDeserializationContextDefault contextImpl = (JsonDeserializationContextDefault) context;
ObjectConstructor objectConstructor = contextImpl.getObjectConstructor();
return (Map<Object, Object>) objectConstructor.construct(mapType);
}
}

View File

@ -18,7 +18,7 @@ package org.mcteam.factions.gson;
/** /**
* Defines generic cache interface. * Defines generic cache interface.
* *
* @author Inderjeet Singh * @author Inderjeet Singh
* @author Joel Leitch * @author Joel Leitch
*/ */
@ -40,22 +40,12 @@ interface Cache<K, V> {
* @return the cached value for the given {@code key} * @return the cached value for the given {@code key}
*/ */
V getElement(K key); V getElement(K key);
/** /**
* Removes the value from the cache for the given key. * Removes the value from the cache for the given key.
* *
* @param key the key identifying the value to remove * @param key the key identifying the value to remove
* @return the value for the given {@code key} * @return the value for the given {@code key}
*/ */
V removeElement(K key); V removeElement(K key);
/**
* Removes everything from this cache.
*/
void clear();
/**
* @return the number of objects in this cache
*/
int size();
} }

View File

@ -16,6 +16,8 @@
package org.mcteam.factions.gson; package org.mcteam.factions.gson;
import org.mcteam.factions.gson.internal.$Gson$Preconditions;
import java.lang.annotation.Annotation; import java.lang.annotation.Annotation;
import java.lang.reflect.Type; import java.lang.reflect.Type;
import java.util.Collection; import java.util.Collection;
@ -51,8 +53,8 @@ final class CamelCaseSeparatorNamingPolicy extends RecursiveFieldNamingPolicy {
* is null or empty. * is null or empty.
*/ */
public CamelCaseSeparatorNamingPolicy(String separatorString) { public CamelCaseSeparatorNamingPolicy(String separatorString) {
Preconditions.checkNotNull(separatorString); $Gson$Preconditions.checkNotNull(separatorString);
Preconditions.checkArgument(!"".equals(separatorString)); $Gson$Preconditions.checkArgument(!"".equals(separatorString));
this.separatorString = separatorString; this.separatorString = separatorString;
} }

View File

@ -0,0 +1,91 @@
/*
* 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.Constructor;
/**
* Use the default constructor on the class to instantiate an object.
*
* @author Joel Leitch
*/
final class DefaultConstructorAllocator {
private static final Constructor<Null> NULL_CONSTRUCTOR = createNullConstructor();
private final Cache<Class<?>, Constructor<?>> constructorCache;
public DefaultConstructorAllocator() {
this(200);
}
public DefaultConstructorAllocator(int cacheSize) {
constructorCache = new LruCache<Class<?>, Constructor<?>>(cacheSize);
}
// for testing purpose
final boolean isInCache(Class<?> cacheKey) {
return constructorCache.getElement(cacheKey) != null;
}
private static final Constructor<Null> createNullConstructor() {
try {
return getNoArgsConstructor(Null.class);
} catch (Exception e) {
return null;
}
}
public <T> T newInstance(Class<T> c) throws Exception {
Constructor<T> constructor = findConstructor(c);
return (constructor != null) ? constructor.newInstance() : null;
}
@SuppressWarnings("unchecked")
private <T> Constructor<T> findConstructor(Class<T> c) {
Constructor<T> cachedElement = (Constructor<T>) constructorCache.getElement(c);
if (cachedElement != null) {
if (cachedElement == NULL_CONSTRUCTOR) {
return null;
} else {
return cachedElement;
}
}
Constructor<T> noArgsConstructor = getNoArgsConstructor(c);
if (noArgsConstructor != null) {
constructorCache.addElement(c, noArgsConstructor);
} else {
constructorCache.addElement(c, NULL_CONSTRUCTOR);
}
return noArgsConstructor;
}
private static <T> Constructor<T> getNoArgsConstructor(Class<T> c) {
try {
Constructor<T> declaredConstructor = c.getDeclaredConstructor();
declaredConstructor.setAccessible(true);
return declaredConstructor;
} catch (Exception e) {
return null;
}
}
// placeholder class for Null constructor
private static final class Null {
}
}

View File

@ -16,19 +16,23 @@
package org.mcteam.factions.gson; package org.mcteam.factions.gson;
import org.mcteam.factions.gson.internal.$Gson$Types;
import java.lang.reflect.ParameterizedType; import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type; import java.lang.reflect.Type;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.math.BigInteger; import java.math.BigInteger;
import java.net.InetAddress;
import java.net.MalformedURLException; import java.net.MalformedURLException;
import java.net.URI; import java.net.URI;
import java.net.URISyntaxException; import java.net.URISyntaxException;
import java.net.URL; import java.net.URL;
import java.net.UnknownHostException;
import java.sql.Time; import java.sql.Time;
import java.sql.Timestamp; import java.sql.Timestamp;
import java.text.DateFormat; import java.text.DateFormat;
import java.text.ParseException; import java.text.ParseException;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar; import java.util.Calendar;
import java.util.Collection; import java.util.Collection;
import java.util.Date; import java.util.Date;
@ -36,12 +40,14 @@ import java.util.GregorianCalendar;
import java.util.HashSet; import java.util.HashSet;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.Map; import java.util.Map;
import java.util.Properties; import java.util.Queue;
import java.util.Set; import java.util.Set;
import java.util.SortedSet; import java.util.SortedSet;
import java.util.StringTokenizer; import java.util.StringTokenizer;
import java.util.TimeZone;
import java.util.TreeSet; import java.util.TreeSet;
import java.util.UUID; import java.util.UUID;
@ -62,13 +68,15 @@ final class DefaultTypeAdapters {
private static final DefaultTimestampDeserializer TIMESTAMP_DESERIALIZER = private static final DefaultTimestampDeserializer TIMESTAMP_DESERIALIZER =
new DefaultTimestampDeserializer(); new DefaultTimestampDeserializer();
@SuppressWarnings("rawtypes") @SuppressWarnings("unchecked")
private static final EnumTypeAdapter ENUM_TYPE_ADAPTER = new EnumTypeAdapter(); private static final EnumTypeAdapter ENUM_TYPE_ADAPTER = new EnumTypeAdapter();
private static final UrlTypeAdapter URL_TYPE_ADAPTER = new UrlTypeAdapter(); private static final UrlTypeAdapter URL_TYPE_ADAPTER = new UrlTypeAdapter();
private static final UriTypeAdapter URI_TYPE_ADAPTER = new UriTypeAdapter(); private static final UriTypeAdapter URI_TYPE_ADAPTER = new UriTypeAdapter();
private static final UuidTypeAdapter UUUID_TYPE_ADAPTER = new UuidTypeAdapter(); private static final UuidTypeAdapter UUUID_TYPE_ADAPTER = new UuidTypeAdapter();
private static final LocaleTypeAdapter LOCALE_TYPE_ADAPTER = new LocaleTypeAdapter(); private static final LocaleTypeAdapter LOCALE_TYPE_ADAPTER = new LocaleTypeAdapter();
private static final CollectionTypeAdapter COLLECTION_TYPE_ADAPTER = new CollectionTypeAdapter(); private static final DefaultInetAddressAdapter INET_ADDRESS_ADAPTER =
new DefaultInetAddressAdapter();
private static final CollectionTypeAdapter COLLECTION_TYPE_ADAPTER = new CollectionTypeAdapter();
private static final MapTypeAdapter MAP_TYPE_ADAPTER = new MapTypeAdapter(); private static final MapTypeAdapter MAP_TYPE_ADAPTER = new MapTypeAdapter();
private static final BigDecimalTypeAdapter BIG_DECIMAL_TYPE_ADAPTER = new BigDecimalTypeAdapter(); private static final BigDecimalTypeAdapter BIG_DECIMAL_TYPE_ADAPTER = new BigDecimalTypeAdapter();
private static final BigIntegerTypeAdapter BIG_INTEGER_TYPE_ADAPTER = new BigIntegerTypeAdapter(); private static final BigIntegerTypeAdapter BIG_INTEGER_TYPE_ADAPTER = new BigIntegerTypeAdapter();
@ -83,20 +91,25 @@ final class DefaultTypeAdapters {
private static final NumberTypeAdapter NUMBER_TYPE_ADAPTER = new NumberTypeAdapter(); private static final NumberTypeAdapter NUMBER_TYPE_ADAPTER = new NumberTypeAdapter();
private static final ShortTypeAdapter SHORT_TYPE_ADAPTER = new ShortTypeAdapter(); private static final ShortTypeAdapter SHORT_TYPE_ADAPTER = new ShortTypeAdapter();
private static final StringTypeAdapter STRING_TYPE_ADAPTER = new StringTypeAdapter(); private static final StringTypeAdapter STRING_TYPE_ADAPTER = new StringTypeAdapter();
private static final StringBuilderTypeAdapter STRING_BUILDER_TYPE_ADAPTER =
new StringBuilderTypeAdapter();
private static final StringBufferTypeAdapter STRING_BUFFER_TYPE_ADAPTER =
new StringBufferTypeAdapter();
private static final PropertiesCreator PROPERTIES_CREATOR = new PropertiesCreator();
private static final TreeSetCreator TREE_SET_CREATOR = new TreeSetCreator();
private static final HashSetCreator HASH_SET_CREATOR = new HashSetCreator();
private static final GregorianCalendarTypeAdapter GREGORIAN_CALENDAR_TYPE_ADAPTER = private static final GregorianCalendarTypeAdapter GREGORIAN_CALENDAR_TYPE_ADAPTER =
new GregorianCalendarTypeAdapter(); new GregorianCalendarTypeAdapter();
// The constants DEFAULT_SERIALIZERS, DEFAULT_DESERIALIZERS, and DEFAULT_INSTANCE_CREATORS // The constants DEFAULT_SERIALIZERS, DEFAULT_DESERIALIZERS, and DEFAULT_INSTANCE_CREATORS
// must be defined after the constants for the type adapters. Otherwise, the type adapter // must be defined after the constants for the type adapters. Otherwise, the type adapter
// constants will appear as nulls. // constants will appear as nulls.
private static final ParameterizedTypeHandlerMap<JsonSerializer<?>> DEFAULT_SERIALIZERS = private static final ParameterizedTypeHandlerMap<JsonSerializer<?>> DEFAULT_SERIALIZERS =
createDefaultSerializers(); createDefaultSerializers();
static final ParameterizedTypeHandlerMap<JsonSerializer<?>> DEFAULT_HIERARCHY_SERIALIZERS =
createDefaultHierarchySerializers();
private static final ParameterizedTypeHandlerMap<JsonDeserializer<?>> DEFAULT_DESERIALIZERS = private static final ParameterizedTypeHandlerMap<JsonDeserializer<?>> DEFAULT_DESERIALIZERS =
createDefaultDeserializers(); createDefaultDeserializers();
static final ParameterizedTypeHandlerMap<JsonDeserializer<?>> DEFAULT_HIERARCHY_DESERIALIZERS =
createDefaultHierarchyDeserializers();
private static final ParameterizedTypeHandlerMap<InstanceCreator<?>> DEFAULT_INSTANCE_CREATORS = private static final ParameterizedTypeHandlerMap<InstanceCreator<?>> DEFAULT_INSTANCE_CREATORS =
createDefaultInstanceCreators(); createDefaultInstanceCreators();
@ -104,13 +117,10 @@ final class DefaultTypeAdapters {
ParameterizedTypeHandlerMap<JsonSerializer<?>> map = ParameterizedTypeHandlerMap<JsonSerializer<?>> map =
new ParameterizedTypeHandlerMap<JsonSerializer<?>>(); new ParameterizedTypeHandlerMap<JsonSerializer<?>>();
map.registerForTypeHierarchy(Enum.class, ENUM_TYPE_ADAPTER);
map.register(URL.class, URL_TYPE_ADAPTER); map.register(URL.class, URL_TYPE_ADAPTER);
map.register(URI.class, URI_TYPE_ADAPTER); map.register(URI.class, URI_TYPE_ADAPTER);
map.register(UUID.class, UUUID_TYPE_ADAPTER); map.register(UUID.class, UUUID_TYPE_ADAPTER);
map.register(Locale.class, LOCALE_TYPE_ADAPTER); map.register(Locale.class, LOCALE_TYPE_ADAPTER);
map.registerForTypeHierarchy(Collection.class, COLLECTION_TYPE_ADAPTER);
map.registerForTypeHierarchy(Map.class, MAP_TYPE_ADAPTER);
map.register(Date.class, DATE_TYPE_ADAPTER); map.register(Date.class, DATE_TYPE_ADAPTER);
map.register(java.sql.Date.class, JAVA_SQL_DATE_TYPE_ADAPTER); map.register(java.sql.Date.class, JAVA_SQL_DATE_TYPE_ADAPTER);
map.register(Timestamp.class, DATE_TYPE_ADAPTER); map.register(Timestamp.class, DATE_TYPE_ADAPTER);
@ -133,70 +143,106 @@ final class DefaultTypeAdapters {
map.register(Short.class, SHORT_TYPE_ADAPTER); map.register(Short.class, SHORT_TYPE_ADAPTER);
map.register(short.class, SHORT_TYPE_ADAPTER); map.register(short.class, SHORT_TYPE_ADAPTER);
map.register(String.class, STRING_TYPE_ADAPTER); map.register(String.class, STRING_TYPE_ADAPTER);
map.register(StringBuilder.class, STRING_BUILDER_TYPE_ADAPTER);
map.register(StringBuffer.class, STRING_BUFFER_TYPE_ADAPTER);
map.makeUnmodifiable(); map.makeUnmodifiable();
return map; return map;
} }
private static ParameterizedTypeHandlerMap<JsonSerializer<?>> createDefaultHierarchySerializers() {
ParameterizedTypeHandlerMap<JsonSerializer<?>> map =
new ParameterizedTypeHandlerMap<JsonSerializer<?>>();
map.registerForTypeHierarchy(Enum.class, ENUM_TYPE_ADAPTER);
map.registerForTypeHierarchy(InetAddress.class, INET_ADDRESS_ADAPTER);
map.registerForTypeHierarchy(Collection.class, COLLECTION_TYPE_ADAPTER);
map.registerForTypeHierarchy(Map.class, MAP_TYPE_ADAPTER);
map.makeUnmodifiable();
return map;
}
private static ParameterizedTypeHandlerMap<JsonDeserializer<?>> createDefaultDeserializers() { private static ParameterizedTypeHandlerMap<JsonDeserializer<?>> createDefaultDeserializers() {
ParameterizedTypeHandlerMap<JsonDeserializer<?>> map = ParameterizedTypeHandlerMap<JsonDeserializer<?>> map =
new ParameterizedTypeHandlerMap<JsonDeserializer<?>>(); new ParameterizedTypeHandlerMap<JsonDeserializer<?>>();
map.registerForTypeHierarchy(Enum.class, wrapDeserializer(ENUM_TYPE_ADAPTER));
map.register(URL.class, wrapDeserializer(URL_TYPE_ADAPTER)); map.register(URL.class, wrapDeserializer(URL_TYPE_ADAPTER));
map.register(URI.class, wrapDeserializer(URI_TYPE_ADAPTER)); map.register(URI.class, wrapDeserializer(URI_TYPE_ADAPTER));
map.register(UUID.class, wrapDeserializer(UUUID_TYPE_ADAPTER)); map.register(UUID.class, wrapDeserializer(UUUID_TYPE_ADAPTER));
map.register(Locale.class, wrapDeserializer(LOCALE_TYPE_ADAPTER)); map.register(Locale.class, wrapDeserializer(LOCALE_TYPE_ADAPTER));
map.registerForTypeHierarchy(Collection.class, wrapDeserializer(COLLECTION_TYPE_ADAPTER));
map.registerForTypeHierarchy(Map.class, wrapDeserializer(MAP_TYPE_ADAPTER));
map.register(Date.class, wrapDeserializer(DATE_TYPE_ADAPTER)); map.register(Date.class, wrapDeserializer(DATE_TYPE_ADAPTER));
map.register(java.sql.Date.class, wrapDeserializer(JAVA_SQL_DATE_TYPE_ADAPTER)); map.register(java.sql.Date.class, wrapDeserializer(JAVA_SQL_DATE_TYPE_ADAPTER));
map.register(Timestamp.class, wrapDeserializer(TIMESTAMP_DESERIALIZER)); map.register(Timestamp.class, wrapDeserializer(TIMESTAMP_DESERIALIZER));
map.register(Time.class, wrapDeserializer(TIME_TYPE_ADAPTER)); map.register(Time.class, wrapDeserializer(TIME_TYPE_ADAPTER));
map.register(Calendar.class, GREGORIAN_CALENDAR_TYPE_ADAPTER); map.register(Calendar.class, GREGORIAN_CALENDAR_TYPE_ADAPTER);
map.register(GregorianCalendar.class, GREGORIAN_CALENDAR_TYPE_ADAPTER); map.register(GregorianCalendar.class, GREGORIAN_CALENDAR_TYPE_ADAPTER);
map.register(BigDecimal.class, wrapDeserializer(BIG_DECIMAL_TYPE_ADAPTER)); map.register(BigDecimal.class, BIG_DECIMAL_TYPE_ADAPTER);
map.register(BigInteger.class, wrapDeserializer(BIG_INTEGER_TYPE_ADAPTER)); map.register(BigInteger.class, BIG_INTEGER_TYPE_ADAPTER);
// Add primitive deserializers // Add primitive deserializers
map.register(Boolean.class, wrapDeserializer(BOOLEAN_TYPE_ADAPTER)); map.register(Boolean.class, BOOLEAN_TYPE_ADAPTER);
map.register(boolean.class, wrapDeserializer(BOOLEAN_TYPE_ADAPTER)); map.register(boolean.class, BOOLEAN_TYPE_ADAPTER);
map.register(Byte.class, wrapDeserializer(BYTE_TYPE_ADAPTER)); map.register(Byte.class, BYTE_TYPE_ADAPTER);
map.register(byte.class, wrapDeserializer(BYTE_TYPE_ADAPTER)); map.register(byte.class, BYTE_TYPE_ADAPTER);
map.register(Character.class, wrapDeserializer(CHARACTER_TYPE_ADAPTER)); map.register(Character.class, wrapDeserializer(CHARACTER_TYPE_ADAPTER));
map.register(char.class, wrapDeserializer(CHARACTER_TYPE_ADAPTER)); map.register(char.class, wrapDeserializer(CHARACTER_TYPE_ADAPTER));
map.register(Double.class, wrapDeserializer(DOUBLE_TYPE_ADAPTER)); map.register(Double.class, DOUBLE_TYPE_ADAPTER);
map.register(double.class, wrapDeserializer(DOUBLE_TYPE_ADAPTER)); map.register(double.class, DOUBLE_TYPE_ADAPTER);
map.register(Float.class, wrapDeserializer(FLOAT_TYPE_ADAPTER)); map.register(Float.class, FLOAT_TYPE_ADAPTER);
map.register(float.class, wrapDeserializer(FLOAT_TYPE_ADAPTER)); map.register(float.class, FLOAT_TYPE_ADAPTER);
map.register(Integer.class, wrapDeserializer(INTEGER_TYPE_ADAPTER)); map.register(Integer.class, INTEGER_TYPE_ADAPTER);
map.register(int.class, wrapDeserializer(INTEGER_TYPE_ADAPTER)); map.register(int.class, INTEGER_TYPE_ADAPTER);
map.register(Long.class, wrapDeserializer(LONG_DESERIALIZER)); map.register(Long.class, LONG_DESERIALIZER);
map.register(long.class, wrapDeserializer(LONG_DESERIALIZER)); map.register(long.class, LONG_DESERIALIZER);
map.register(Number.class, wrapDeserializer(NUMBER_TYPE_ADAPTER)); map.register(Number.class, NUMBER_TYPE_ADAPTER);
map.register(Short.class, wrapDeserializer(SHORT_TYPE_ADAPTER)); map.register(Short.class, SHORT_TYPE_ADAPTER);
map.register(short.class, wrapDeserializer(SHORT_TYPE_ADAPTER)); map.register(short.class, SHORT_TYPE_ADAPTER);
map.register(String.class, wrapDeserializer(STRING_TYPE_ADAPTER)); map.register(String.class, wrapDeserializer(STRING_TYPE_ADAPTER));
map.register(StringBuilder.class, wrapDeserializer(STRING_BUILDER_TYPE_ADAPTER));
map.register(StringBuffer.class, wrapDeserializer(STRING_BUFFER_TYPE_ADAPTER));
map.makeUnmodifiable(); map.makeUnmodifiable();
return map; return map;
} }
private static ParameterizedTypeHandlerMap<JsonDeserializer<?>> createDefaultHierarchyDeserializers() {
ParameterizedTypeHandlerMap<JsonDeserializer<?>> map =
new ParameterizedTypeHandlerMap<JsonDeserializer<?>>();
map.registerForTypeHierarchy(Enum.class, wrapDeserializer(ENUM_TYPE_ADAPTER));
map.registerForTypeHierarchy(InetAddress.class, wrapDeserializer(INET_ADDRESS_ADAPTER));
map.registerForTypeHierarchy(Collection.class, wrapDeserializer(COLLECTION_TYPE_ADAPTER));
map.registerForTypeHierarchy(Map.class, wrapDeserializer(MAP_TYPE_ADAPTER));
map.makeUnmodifiable();
return map;
}
@SuppressWarnings("unchecked")
private static ParameterizedTypeHandlerMap<InstanceCreator<?>> createDefaultInstanceCreators() { private static ParameterizedTypeHandlerMap<InstanceCreator<?>> createDefaultInstanceCreators() {
ParameterizedTypeHandlerMap<InstanceCreator<?>> map = ParameterizedTypeHandlerMap<InstanceCreator<?>> map =
new ParameterizedTypeHandlerMap<InstanceCreator<?>>(); new ParameterizedTypeHandlerMap<InstanceCreator<?>>();
map.registerForTypeHierarchy(Map.class, MAP_TYPE_ADAPTER); DefaultConstructorAllocator allocator = new DefaultConstructorAllocator(50);
// Map Instance Creators
map.registerForTypeHierarchy(Map.class,
new DefaultConstructorCreator<Map>(LinkedHashMap.class, allocator));
// Add Collection type instance creators // Add Collection type instance creators
map.registerForTypeHierarchy(Collection.class, COLLECTION_TYPE_ADAPTER); DefaultConstructorCreator<List> listCreator =
new DefaultConstructorCreator<List>(ArrayList.class, allocator);
DefaultConstructorCreator<Queue> queueCreator =
new DefaultConstructorCreator<Queue>(LinkedList.class, allocator);
DefaultConstructorCreator<Set> setCreator =
new DefaultConstructorCreator<Set>(HashSet.class, allocator);
DefaultConstructorCreator<SortedSet> sortedSetCreator =
new DefaultConstructorCreator<SortedSet>(TreeSet.class, allocator);
map.registerForTypeHierarchy(Collection.class, listCreator);
map.registerForTypeHierarchy(Queue.class, queueCreator);
map.registerForTypeHierarchy(Set.class, setCreator);
map.registerForTypeHierarchy(SortedSet.class, sortedSetCreator);
map.registerForTypeHierarchy(Set.class, HASH_SET_CREATOR);
map.registerForTypeHierarchy(SortedSet.class, TREE_SET_CREATOR);
map.register(Properties.class, PROPERTIES_CREATOR);
map.makeUnmodifiable(); map.makeUnmodifiable();
return map; return map;
} }
@SuppressWarnings({"unchecked", "rawtypes"}) @SuppressWarnings("unchecked")
private static JsonDeserializer<?> wrapDeserializer(JsonDeserializer<?> deserializer) { private static JsonDeserializer<?> wrapDeserializer(JsonDeserializer<?> deserializer) {
return new JsonDeserializerExceptionWrapper(deserializer); return new JsonDeserializerExceptionWrapper(deserializer);
} }
@ -205,6 +251,20 @@ final class DefaultTypeAdapters {
return getDefaultSerializers(false, LongSerializationPolicy.DEFAULT); return getDefaultSerializers(false, LongSerializationPolicy.DEFAULT);
} }
static ParameterizedTypeHandlerMap<JsonSerializer<?>> getAllDefaultSerializers() {
ParameterizedTypeHandlerMap<JsonSerializer<?>> defaultSerializers =
getDefaultSerializers(false, LongSerializationPolicy.DEFAULT);
defaultSerializers.register(DEFAULT_HIERARCHY_SERIALIZERS);
return defaultSerializers;
}
static ParameterizedTypeHandlerMap<JsonDeserializer<?>> getAllDefaultDeserializers() {
ParameterizedTypeHandlerMap<JsonDeserializer<?>> defaultDeserializers =
getDefaultDeserializers().copyOf();
defaultDeserializers.register(DEFAULT_HIERARCHY_DESERIALIZERS);
return defaultDeserializers;
}
static ParameterizedTypeHandlerMap<JsonSerializer<?>> getDefaultSerializers( static ParameterizedTypeHandlerMap<JsonSerializer<?>> getDefaultSerializers(
boolean serializeSpecialFloatingPointValues, LongSerializationPolicy longSerializationPolicy) { boolean serializeSpecialFloatingPointValues, LongSerializationPolicy longSerializationPolicy) {
ParameterizedTypeHandlerMap<JsonSerializer<?>> serializers = ParameterizedTypeHandlerMap<JsonSerializer<?>> serializers =
@ -240,30 +300,45 @@ final class DefaultTypeAdapters {
return DEFAULT_INSTANCE_CREATORS; return DEFAULT_INSTANCE_CREATORS;
} }
static class DefaultDateTypeAdapter implements JsonSerializer<Date>, JsonDeserializer<Date> { /**
private final DateFormat format; * This type adapter supports three subclasses of date: Date, Timestamp, and
* java.sql.Date.
*/
static final class DefaultDateTypeAdapter implements JsonSerializer<Date>, JsonDeserializer<Date> {
private final DateFormat enUsFormat;
private final DateFormat localFormat;
private final DateFormat iso8601Format;
DefaultDateTypeAdapter() { DefaultDateTypeAdapter() {
this.format = DateFormat.getDateTimeInstance(); this(DateFormat.getDateTimeInstance(DateFormat.DEFAULT, DateFormat.DEFAULT, Locale.US),
DateFormat.getDateTimeInstance(DateFormat.DEFAULT, DateFormat.DEFAULT));
} }
DefaultDateTypeAdapter(final String datePattern) { DefaultDateTypeAdapter(String datePattern) {
this.format = new SimpleDateFormat(datePattern); this(new SimpleDateFormat(datePattern, Locale.US), new SimpleDateFormat(datePattern));
} }
DefaultDateTypeAdapter(final int style) { DefaultDateTypeAdapter(int style) {
this.format = DateFormat.getDateInstance(style); this(DateFormat.getDateInstance(style, Locale.US), DateFormat.getDateInstance(style));
} }
public DefaultDateTypeAdapter(final int dateStyle, final int timeStyle) { public DefaultDateTypeAdapter(int dateStyle, int timeStyle) {
this.format = DateFormat.getDateTimeInstance(dateStyle, timeStyle); this(DateFormat.getDateTimeInstance(dateStyle, timeStyle, Locale.US),
DateFormat.getDateTimeInstance(dateStyle, timeStyle));
}
DefaultDateTypeAdapter(DateFormat enUsFormat, DateFormat localFormat) {
this.enUsFormat = enUsFormat;
this.localFormat = localFormat;
this.iso8601Format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.US);
this.iso8601Format.setTimeZone(TimeZone.getTimeZone("UTC"));
} }
// These methods need to be synchronized since JDK DateFormat classes are not thread-safe // These methods need to be synchronized since JDK DateFormat classes are not thread-safe
// See issue 162 // See issue 162
public JsonElement serialize(Date src, Type typeOfSrc, JsonSerializationContext context) { public JsonElement serialize(Date src, Type typeOfSrc, JsonSerializationContext context) {
synchronized (format) { synchronized (localFormat) {
String dateFormatAsString = format.format(src); String dateFormatAsString = enUsFormat.format(src);
return new JsonPrimitive(dateFormatAsString); return new JsonPrimitive(dateFormatAsString);
} }
} }
@ -273,12 +348,33 @@ final class DefaultTypeAdapters {
if (!(json instanceof JsonPrimitive)) { if (!(json instanceof JsonPrimitive)) {
throw new JsonParseException("The date should be a string value"); throw new JsonParseException("The date should be a string value");
} }
try { Date date = deserializeToDate(json);
synchronized (format) { if (typeOfT == Date.class) {
return format.parse(json.getAsString()); return date;
} else if (typeOfT == Timestamp.class) {
return new Timestamp(date.getTime());
} else if (typeOfT == java.sql.Date.class) {
return new java.sql.Date(date.getTime());
} else {
throw new IllegalArgumentException(getClass() + " cannot deserialize to " + typeOfT);
}
}
private Date deserializeToDate(JsonElement json) {
synchronized (localFormat) {
try {
return localFormat.parse(json.getAsString());
} catch (ParseException ignored) {
}
try {
return enUsFormat.parse(json.getAsString());
} catch (ParseException ignored) {
}
try {
return iso8601Format.parse(json.getAsString());
} catch (ParseException e) {
throw new JsonSyntaxException(json.getAsString(), e);
} }
} catch (ParseException e) {
throw new JsonSyntaxException(e);
} }
} }
@ -286,12 +382,12 @@ final class DefaultTypeAdapters {
public String toString() { public String toString() {
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
sb.append(DefaultDateTypeAdapter.class.getSimpleName()); sb.append(DefaultDateTypeAdapter.class.getSimpleName());
sb.append('(').append(format.getClass().getSimpleName()).append(')'); sb.append('(').append(localFormat.getClass().getSimpleName()).append(')');
return sb.toString(); return sb.toString();
} }
} }
static class DefaultJavaSqlDateTypeAdapter implements JsonSerializer<java.sql.Date>, static final class DefaultJavaSqlDateTypeAdapter implements JsonSerializer<java.sql.Date>,
JsonDeserializer<java.sql.Date> { JsonDeserializer<java.sql.Date> {
private final DateFormat format; private final DateFormat format;
DefaultJavaSqlDateTypeAdapter() { DefaultJavaSqlDateTypeAdapter() {
@ -322,7 +418,7 @@ final class DefaultTypeAdapters {
} }
} }
static class DefaultTimestampDeserializer implements JsonDeserializer<Timestamp> { static final class DefaultTimestampDeserializer implements JsonDeserializer<Timestamp> {
public Timestamp deserialize(JsonElement json, Type typeOfT, public Timestamp deserialize(JsonElement json, Type typeOfT,
JsonDeserializationContext context) throws JsonParseException { JsonDeserializationContext context) throws JsonParseException {
Date date = context.deserialize(json, Date.class); Date date = context.deserialize(json, Date.class);
@ -330,7 +426,7 @@ final class DefaultTypeAdapters {
} }
} }
static class DefaultTimeTypeAdapter implements JsonSerializer<Time>, JsonDeserializer<Time> { static final class DefaultTimeTypeAdapter implements JsonSerializer<Time>, JsonDeserializer<Time> {
private final DateFormat format; private final DateFormat format;
DefaultTimeTypeAdapter() { DefaultTimeTypeAdapter() {
this.format = new SimpleDateFormat("hh:mm:ss a"); this.format = new SimpleDateFormat("hh:mm:ss a");
@ -357,7 +453,7 @@ final class DefaultTypeAdapters {
} }
} }
private static class GregorianCalendarTypeAdapter private static final class GregorianCalendarTypeAdapter
implements JsonSerializer<GregorianCalendar>, JsonDeserializer<GregorianCalendar> { implements JsonSerializer<GregorianCalendar>, JsonDeserializer<GregorianCalendar> {
private static final String YEAR = "year"; private static final String YEAR = "year";
@ -397,8 +493,26 @@ final class DefaultTypeAdapters {
} }
} }
static final class DefaultInetAddressAdapter
implements JsonDeserializer<InetAddress>, JsonSerializer<InetAddress> {
public InetAddress deserialize(JsonElement json, Type typeOfT,
JsonDeserializationContext context) throws JsonParseException {
try {
return InetAddress.getByName(json.getAsString());
} catch (UnknownHostException e) {
throw new JsonParseException(e);
}
}
public JsonElement serialize(InetAddress src, Type typeOfSrc,
JsonSerializationContext context) {
return new JsonPrimitive(src.getHostAddress());
}
}
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
private static class EnumTypeAdapter<T extends Enum<T>> private static final class EnumTypeAdapter<T extends Enum<T>>
implements JsonSerializer<T>, JsonDeserializer<T> { implements JsonSerializer<T>, JsonDeserializer<T> {
public JsonElement serialize(T src, Type typeOfSrc, JsonSerializationContext context) { public JsonElement serialize(T src, Type typeOfSrc, JsonSerializationContext context) {
return new JsonPrimitive(src.name()); return new JsonPrimitive(src.name());
@ -416,7 +530,7 @@ final class DefaultTypeAdapters {
} }
} }
private static class UrlTypeAdapter implements JsonSerializer<URL>, JsonDeserializer<URL> { private static final class UrlTypeAdapter implements JsonSerializer<URL>, JsonDeserializer<URL> {
public JsonElement serialize(URL src, Type typeOfSrc, JsonSerializationContext context) { public JsonElement serialize(URL src, Type typeOfSrc, JsonSerializationContext context) {
return new JsonPrimitive(src.toExternalForm()); return new JsonPrimitive(src.toExternalForm());
} }
@ -436,7 +550,7 @@ final class DefaultTypeAdapters {
} }
} }
private static class UriTypeAdapter implements JsonSerializer<URI>, JsonDeserializer<URI> { private static final class UriTypeAdapter implements JsonSerializer<URI>, JsonDeserializer<URI> {
public JsonElement serialize(URI src, Type typeOfSrc, JsonSerializationContext context) { public JsonElement serialize(URI src, Type typeOfSrc, JsonSerializationContext context) {
return new JsonPrimitive(src.toASCIIString()); return new JsonPrimitive(src.toASCIIString());
} }
@ -454,7 +568,7 @@ final class DefaultTypeAdapters {
} }
} }
private static class UuidTypeAdapter implements JsonSerializer<UUID>, JsonDeserializer<UUID> { private static final class UuidTypeAdapter implements JsonSerializer<UUID>, JsonDeserializer<UUID> {
public JsonElement serialize(UUID src, Type typeOfSrc, JsonSerializationContext context) { public JsonElement serialize(UUID src, Type typeOfSrc, JsonSerializationContext context) {
return new JsonPrimitive(src.toString()); return new JsonPrimitive(src.toString());
} }
@ -470,7 +584,7 @@ final class DefaultTypeAdapters {
} }
} }
private static class LocaleTypeAdapter private static final class LocaleTypeAdapter
implements JsonSerializer<Locale>, JsonDeserializer<Locale> { implements JsonSerializer<Locale>, JsonDeserializer<Locale> {
public JsonElement serialize(Locale src, Type typeOfSrc, JsonSerializationContext context) { public JsonElement serialize(Locale src, Type typeOfSrc, JsonSerializationContext context) {
return new JsonPrimitive(src.toString()); return new JsonPrimitive(src.toString());
@ -507,9 +621,9 @@ final class DefaultTypeAdapters {
} }
} }
@SuppressWarnings({"unchecked", "rawtypes"}) @SuppressWarnings("unchecked")
private static class CollectionTypeAdapter implements JsonSerializer<Collection>, private static final class CollectionTypeAdapter implements JsonSerializer<Collection>,
JsonDeserializer<Collection>, InstanceCreator<Collection> { JsonDeserializer<Collection> {
public JsonElement serialize(Collection src, Type typeOfSrc, JsonSerializationContext context) { public JsonElement serialize(Collection src, Type typeOfSrc, JsonSerializationContext context) {
if (src == null) { if (src == null) {
return JsonNull.createJsonNull(); return JsonNull.createJsonNull();
@ -517,7 +631,8 @@ final class DefaultTypeAdapters {
JsonArray array = new JsonArray(); JsonArray array = new JsonArray();
Type childGenericType = null; Type childGenericType = null;
if (typeOfSrc instanceof ParameterizedType) { if (typeOfSrc instanceof ParameterizedType) {
childGenericType = new TypeInfoCollection(typeOfSrc).getElementType(); Class<?> rawTypeOfSrc = $Gson$Types.getRawType(typeOfSrc);
childGenericType = $Gson$Types.getCollectionElementType(typeOfSrc, rawTypeOfSrc);
} }
for (Object child : src) { for (Object child : src) {
if (child == null) { if (child == null) {
@ -540,7 +655,7 @@ final class DefaultTypeAdapters {
// Use ObjectConstructor to create instance instead of hard-coding a specific type. // Use ObjectConstructor to create instance instead of hard-coding a specific type.
// This handles cases where users are using their own subclass of Collection. // This handles cases where users are using their own subclass of Collection.
Collection collection = constructCollectionType(typeOfT, context); Collection collection = constructCollectionType(typeOfT, context);
Type childType = new TypeInfoCollection(typeOfT).getElementType(); Type childType = $Gson$Types.getCollectionElementType(typeOfT, $Gson$Types.getRawType(typeOfT));
for (JsonElement childElement : json.getAsJsonArray()) { for (JsonElement childElement : json.getAsJsonArray()) {
if (childElement == null || childElement.isJsonNull()) { if (childElement == null || childElement.isJsonNull()) {
collection.add(null); collection.add(null);
@ -558,76 +673,9 @@ final class DefaultTypeAdapters {
ObjectConstructor objectConstructor = contextImpl.getObjectConstructor(); ObjectConstructor objectConstructor = contextImpl.getObjectConstructor();
return (Collection) objectConstructor.construct(collectionType); return (Collection) objectConstructor.construct(collectionType);
} }
public Collection createInstance(Type type) {
return new LinkedList();
}
} }
private static class PropertiesCreator implements InstanceCreator<Properties> { private static final class BigDecimalTypeAdapter
public Properties createInstance(Type type) {
return new Properties();
}
}
@SuppressWarnings({"unchecked", "rawtypes"})
static class MapTypeAdapter implements JsonSerializer<Map>, JsonDeserializer<Map>,
InstanceCreator<Map> {
public JsonElement serialize(Map src, Type typeOfSrc, JsonSerializationContext context) {
JsonObject map = new JsonObject();
Type childGenericType = null;
if (typeOfSrc instanceof ParameterizedType) {
childGenericType = new TypeInfoMap(typeOfSrc).getValueType();
}
for (Map.Entry entry : (Set<Map.Entry>) src.entrySet()) {
Object value = entry.getValue();
JsonElement valueElement;
if (value == null) {
valueElement = JsonNull.createJsonNull();
} else {
Type childType = (childGenericType == null)
? value.getClass() : childGenericType;
valueElement = context.serialize(value, childType);
}
map.add(String.valueOf(entry.getKey()), valueElement);
}
return map;
}
public Map deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
throws JsonParseException {
// Use ObjectConstructor to create instance instead of hard-coding a specific type.
// This handles cases where users are using their own subclass of Map.
Map<Object, Object> map = constructMapType(typeOfT, context);
TypeInfoMap mapTypeInfo = new TypeInfoMap(typeOfT);
for (Map.Entry<String, JsonElement> entry : json.getAsJsonObject().entrySet()) {
Object key = context.deserialize(new JsonPrimitive(entry.getKey()), mapTypeInfo.getKeyType());
Object value = context.deserialize(entry.getValue(), mapTypeInfo.getValueType());
map.put(key, value);
}
return map;
}
private Map constructMapType(Type mapType, JsonDeserializationContext context) {
JsonDeserializationContextDefault contextImpl = (JsonDeserializationContextDefault) context;
ObjectConstructor objectConstructor = contextImpl.getObjectConstructor();
return (Map) objectConstructor.construct(mapType);
}
public Map createInstance(Type type) {
return new LinkedHashMap();
}
@Override
public String toString() {
return MapTypeAdapter.class.getSimpleName();
}
}
private static class BigDecimalTypeAdapter
implements JsonSerializer<BigDecimal>, JsonDeserializer<BigDecimal> { implements JsonSerializer<BigDecimal>, JsonDeserializer<BigDecimal> {
public JsonElement serialize(BigDecimal src, Type typeOfSrc, JsonSerializationContext context) { public JsonElement serialize(BigDecimal src, Type typeOfSrc, JsonSerializationContext context) {
return new JsonPrimitive(src); return new JsonPrimitive(src);
@ -635,7 +683,15 @@ final class DefaultTypeAdapters {
public BigDecimal deserialize(JsonElement json, Type typeOfT, public BigDecimal deserialize(JsonElement json, Type typeOfT,
JsonDeserializationContext context) throws JsonParseException { JsonDeserializationContext context) throws JsonParseException {
return json.getAsBigDecimal(); try {
return json.getAsBigDecimal();
} catch (NumberFormatException e) {
throw new JsonSyntaxException(e);
} catch (UnsupportedOperationException e) {
throw new JsonSyntaxException(e);
} catch (IllegalStateException e) {
throw new JsonSyntaxException(e);
}
} }
@Override @Override
@ -644,7 +700,7 @@ final class DefaultTypeAdapters {
} }
} }
private static class BigIntegerTypeAdapter private static final class BigIntegerTypeAdapter
implements JsonSerializer<BigInteger>, JsonDeserializer<BigInteger> { implements JsonSerializer<BigInteger>, JsonDeserializer<BigInteger> {
public JsonElement serialize(BigInteger src, Type typeOfSrc, JsonSerializationContext context) { public JsonElement serialize(BigInteger src, Type typeOfSrc, JsonSerializationContext context) {
@ -653,7 +709,15 @@ final class DefaultTypeAdapters {
public BigInteger deserialize(JsonElement json, Type typeOfT, public BigInteger deserialize(JsonElement json, Type typeOfT,
JsonDeserializationContext context) throws JsonParseException { JsonDeserializationContext context) throws JsonParseException {
return json.getAsBigInteger(); try {
return json.getAsBigInteger();
} catch (NumberFormatException e) {
throw new JsonSyntaxException(e);
} catch (UnsupportedOperationException e) {
throw new JsonSyntaxException(e);
} catch (IllegalStateException e) {
throw new JsonSyntaxException(e);
}
} }
@Override @Override
@ -662,7 +726,7 @@ final class DefaultTypeAdapters {
} }
} }
private static class NumberTypeAdapter private static final class NumberTypeAdapter
implements JsonSerializer<Number>, JsonDeserializer<Number> { implements JsonSerializer<Number>, JsonDeserializer<Number> {
public JsonElement serialize(Number src, Type typeOfSrc, JsonSerializationContext context) { public JsonElement serialize(Number src, Type typeOfSrc, JsonSerializationContext context) {
return new JsonPrimitive(src); return new JsonPrimitive(src);
@ -670,7 +734,15 @@ final class DefaultTypeAdapters {
public Number deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) public Number deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
throws JsonParseException { throws JsonParseException {
return json.getAsNumber(); try {
return json.getAsNumber();
} catch (NumberFormatException e) {
throw new JsonSyntaxException(e);
} catch (UnsupportedOperationException e) {
throw new JsonSyntaxException(e);
} catch (IllegalStateException e) {
throw new JsonSyntaxException(e);
}
} }
@Override @Override
@ -679,7 +751,7 @@ final class DefaultTypeAdapters {
} }
} }
private static class LongSerializer implements JsonSerializer<Long> { private static final class LongSerializer implements JsonSerializer<Long> {
private final LongSerializationPolicy longSerializationPolicy; private final LongSerializationPolicy longSerializationPolicy;
private LongSerializer(LongSerializationPolicy longSerializationPolicy) { private LongSerializer(LongSerializationPolicy longSerializationPolicy) {
@ -696,10 +768,18 @@ final class DefaultTypeAdapters {
} }
} }
private static class LongDeserializer implements JsonDeserializer<Long> { private static final class LongDeserializer implements JsonDeserializer<Long> {
public Long deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) public Long deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
throws JsonParseException { throws JsonParseException {
return json.getAsLong(); try {
return json.getAsLong();
} catch (NumberFormatException e) {
throw new JsonSyntaxException(e);
} catch (UnsupportedOperationException e) {
throw new JsonSyntaxException(e);
} catch (IllegalStateException e) {
throw new JsonSyntaxException(e);
}
} }
@Override @Override
@ -708,7 +788,7 @@ final class DefaultTypeAdapters {
} }
} }
private static class IntegerTypeAdapter private static final class IntegerTypeAdapter
implements JsonSerializer<Integer>, JsonDeserializer<Integer> { implements JsonSerializer<Integer>, JsonDeserializer<Integer> {
public JsonElement serialize(Integer src, Type typeOfSrc, JsonSerializationContext context) { public JsonElement serialize(Integer src, Type typeOfSrc, JsonSerializationContext context) {
return new JsonPrimitive(src); return new JsonPrimitive(src);
@ -716,7 +796,15 @@ final class DefaultTypeAdapters {
public Integer deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) public Integer deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
throws JsonParseException { throws JsonParseException {
return json.getAsInt(); try {
return json.getAsInt();
} catch (NumberFormatException e) {
throw new JsonSyntaxException(e);
} catch (UnsupportedOperationException e) {
throw new JsonSyntaxException(e);
} catch (IllegalStateException e) {
throw new JsonSyntaxException(e);
}
} }
@Override @Override
@ -725,7 +813,7 @@ final class DefaultTypeAdapters {
} }
} }
private static class ShortTypeAdapter private static final class ShortTypeAdapter
implements JsonSerializer<Short>, JsonDeserializer<Short> { implements JsonSerializer<Short>, JsonDeserializer<Short> {
public JsonElement serialize(Short src, Type typeOfSrc, JsonSerializationContext context) { public JsonElement serialize(Short src, Type typeOfSrc, JsonSerializationContext context) {
return new JsonPrimitive(src); return new JsonPrimitive(src);
@ -733,7 +821,15 @@ final class DefaultTypeAdapters {
public Short deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) public Short deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
throws JsonParseException { throws JsonParseException {
return json.getAsShort(); try {
return json.getAsShort();
} catch (NumberFormatException e) {
throw new JsonSyntaxException(e);
} catch (UnsupportedOperationException e) {
throw new JsonSyntaxException(e);
} catch (IllegalStateException e) {
throw new JsonSyntaxException(e);
}
} }
@Override @Override
@ -742,14 +838,22 @@ final class DefaultTypeAdapters {
} }
} }
private static class ByteTypeAdapter implements JsonSerializer<Byte>, JsonDeserializer<Byte> { private static final class ByteTypeAdapter implements JsonSerializer<Byte>, JsonDeserializer<Byte> {
public JsonElement serialize(Byte src, Type typeOfSrc, JsonSerializationContext context) { public JsonElement serialize(Byte src, Type typeOfSrc, JsonSerializationContext context) {
return new JsonPrimitive(src); return new JsonPrimitive(src);
} }
public Byte deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) public Byte deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
throws JsonParseException { throws JsonParseException {
return json.getAsByte(); try {
return json.getAsByte();
} catch (NumberFormatException e) {
throw new JsonSyntaxException(e);
} catch (UnsupportedOperationException e) {
throw new JsonSyntaxException(e);
} catch (IllegalStateException e) {
throw new JsonSyntaxException(e);
}
} }
@Override @Override
@ -758,7 +862,7 @@ final class DefaultTypeAdapters {
} }
} }
static class FloatSerializer implements JsonSerializer<Float> { static final class FloatSerializer implements JsonSerializer<Float> {
private final boolean serializeSpecialFloatingPointValues; private final boolean serializeSpecialFloatingPointValues;
FloatSerializer(boolean serializeSpecialDoubleValues) { FloatSerializer(boolean serializeSpecialDoubleValues) {
@ -777,10 +881,18 @@ final class DefaultTypeAdapters {
} }
} }
private static class FloatDeserializer implements JsonDeserializer<Float> { private static final class FloatDeserializer implements JsonDeserializer<Float> {
public Float deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) public Float deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
throws JsonParseException { throws JsonParseException {
return json.getAsFloat(); try {
return json.getAsFloat();
} catch (NumberFormatException e) {
throw new JsonSyntaxException(e);
} catch (UnsupportedOperationException e) {
throw new JsonSyntaxException(e);
} catch (IllegalStateException e) {
throw new JsonSyntaxException(e);
}
} }
@Override @Override
@ -789,7 +901,7 @@ final class DefaultTypeAdapters {
} }
} }
static class DoubleSerializer implements JsonSerializer<Double> { static final class DoubleSerializer implements JsonSerializer<Double> {
private final boolean serializeSpecialFloatingPointValues; private final boolean serializeSpecialFloatingPointValues;
DoubleSerializer(boolean serializeSpecialDoubleValues) { DoubleSerializer(boolean serializeSpecialDoubleValues) {
@ -808,10 +920,18 @@ final class DefaultTypeAdapters {
} }
} }
private static class DoubleDeserializer implements JsonDeserializer<Double> { private static final class DoubleDeserializer implements JsonDeserializer<Double> {
public Double deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) public Double deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
throws JsonParseException { throws JsonParseException {
return json.getAsDouble(); try {
return json.getAsDouble();
} catch (NumberFormatException e) {
throw new JsonSyntaxException(e);
} catch (UnsupportedOperationException e) {
throw new JsonSyntaxException(e);
} catch (IllegalStateException e) {
throw new JsonSyntaxException(e);
}
} }
@Override @Override
@ -820,7 +940,7 @@ final class DefaultTypeAdapters {
} }
} }
private static class CharacterTypeAdapter private static final class CharacterTypeAdapter
implements JsonSerializer<Character>, JsonDeserializer<Character> { implements JsonSerializer<Character>, JsonDeserializer<Character> {
public JsonElement serialize(Character src, Type typeOfSrc, JsonSerializationContext context) { public JsonElement serialize(Character src, Type typeOfSrc, JsonSerializationContext context) {
return new JsonPrimitive(src); return new JsonPrimitive(src);
@ -837,7 +957,7 @@ final class DefaultTypeAdapters {
} }
} }
private static class StringTypeAdapter private static final class StringTypeAdapter
implements JsonSerializer<String>, JsonDeserializer<String> { implements JsonSerializer<String>, JsonDeserializer<String> {
public JsonElement serialize(String src, Type typeOfSrc, JsonSerializationContext context) { public JsonElement serialize(String src, Type typeOfSrc, JsonSerializationContext context) {
return new JsonPrimitive(src); return new JsonPrimitive(src);
@ -854,7 +974,41 @@ final class DefaultTypeAdapters {
} }
} }
private static class BooleanTypeAdapter private static final class StringBuilderTypeAdapter
implements JsonSerializer<StringBuilder>, JsonDeserializer<StringBuilder> {
public JsonElement serialize(StringBuilder src, Type typeOfSrc, JsonSerializationContext context) {
return new JsonPrimitive(src.toString());
}
public StringBuilder deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
throws JsonParseException {
return new StringBuilder(json.getAsString());
}
@Override
public String toString() {
return StringBuilderTypeAdapter.class.getSimpleName();
}
}
private static final class StringBufferTypeAdapter
implements JsonSerializer<StringBuffer>, JsonDeserializer<StringBuffer> {
public JsonElement serialize(StringBuffer src, Type typeOfSrc, JsonSerializationContext context) {
return new JsonPrimitive(src.toString());
}
public StringBuffer deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
throws JsonParseException {
return new StringBuffer(json.getAsString());
}
@Override
public String toString() {
return StringBufferTypeAdapter.class.getSimpleName();
}
}
private static final class BooleanTypeAdapter
implements JsonSerializer<Boolean>, JsonDeserializer<Boolean> { implements JsonSerializer<Boolean>, JsonDeserializer<Boolean> {
public JsonElement serialize(Boolean src, Type typeOfSrc, JsonSerializationContext context) { public JsonElement serialize(Boolean src, Type typeOfSrc, JsonSerializationContext context) {
return new JsonPrimitive(src); return new JsonPrimitive(src);
@ -862,7 +1016,13 @@ final class DefaultTypeAdapters {
public Boolean deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) public Boolean deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
throws JsonParseException { throws JsonParseException {
return json.getAsBoolean(); try {
return json.getAsBoolean();
} catch (UnsupportedOperationException e) {
throw new JsonSyntaxException(e);
} catch (IllegalStateException e) {
throw new JsonSyntaxException(e);
}
} }
@Override @Override
@ -871,23 +1031,32 @@ final class DefaultTypeAdapters {
} }
} }
private static class TreeSetCreator implements InstanceCreator<TreeSet<?>> { @SuppressWarnings("unchecked")
public TreeSet<?> createInstance(Type type) { private static final class DefaultConstructorCreator<T> implements InstanceCreator<T> {
return new TreeSet<Object>(); private final Class<? extends T> defaultInstance;
} private final DefaultConstructorAllocator allocator;
@Override
public String toString() {
return TreeSetCreator.class.getSimpleName();
}
}
private static class HashSetCreator implements InstanceCreator<HashSet<?>> { public DefaultConstructorCreator(Class<? extends T> defaultInstance,
public HashSet<?> createInstance(Type type) { DefaultConstructorAllocator allocator) {
return new HashSet<Object>(); this.defaultInstance = defaultInstance;
this.allocator = allocator;
} }
public T createInstance(Type type) {
Class<?> rawType = $Gson$Types.getRawType(type);
try {
T specificInstance = (T) allocator.newInstance(rawType);
return (specificInstance == null)
? allocator.newInstance(defaultInstance)
: specificInstance;
} catch (Exception e) {
throw new JsonIOException(e);
}
}
@Override @Override
public String toString() { public String toString() {
return HashSetCreator.class.getSimpleName(); return DefaultConstructorCreator.class.getSimpleName();
} }
} }
} }

View File

@ -16,6 +16,8 @@
package org.mcteam.factions.gson; package org.mcteam.factions.gson;
import org.mcteam.factions.gson.internal.$Gson$Preconditions;
import java.io.IOException; import java.io.IOException;
/** /**
@ -44,12 +46,11 @@ import java.io.IOException;
* *
* @author Joel Leitch * @author Joel Leitch
*/ */
class DelegatingJsonElementVisitor implements JsonElementVisitor { final class DelegatingJsonElementVisitor implements JsonElementVisitor {
private final JsonElementVisitor delegate; private final JsonElementVisitor delegate;
protected DelegatingJsonElementVisitor(JsonElementVisitor delegate) { protected DelegatingJsonElementVisitor(JsonElementVisitor delegate) {
Preconditions.checkNotNull(delegate); this.delegate = $Gson$Preconditions.checkNotNull(delegate);
this.delegate = delegate;
} }
public void endArray(JsonArray array) throws IOException { public void endArray(JsonArray array) throws IOException {
@ -68,37 +69,37 @@ class DelegatingJsonElementVisitor implements JsonElementVisitor {
delegate.startObject(object); delegate.startObject(object);
} }
public void visitArrayMember(JsonArray parent, JsonPrimitive member, public void visitArrayMember(JsonArray parent, JsonPrimitive member,
boolean isFirst) throws IOException { boolean isFirst) throws IOException {
delegate.visitArrayMember(parent, member, isFirst); delegate.visitArrayMember(parent, member, isFirst);
} }
public void visitArrayMember(JsonArray parent, JsonArray member, public void visitArrayMember(JsonArray parent, JsonArray member,
boolean isFirst) throws IOException { boolean isFirst) throws IOException {
delegate.visitArrayMember(parent, member, isFirst); delegate.visitArrayMember(parent, member, isFirst);
} }
public void visitArrayMember(JsonArray parent, JsonObject member, public void visitArrayMember(JsonArray parent, JsonObject member,
boolean isFirst) throws IOException { boolean isFirst) throws IOException {
delegate.visitArrayMember(parent, member, isFirst); delegate.visitArrayMember(parent, member, isFirst);
} }
public void visitObjectMember(JsonObject parent, String memberName, JsonPrimitive member, public void visitObjectMember(JsonObject parent, String memberName, JsonPrimitive member,
boolean isFirst) throws IOException { boolean isFirst) throws IOException {
delegate.visitObjectMember(parent, memberName, member, isFirst); delegate.visitObjectMember(parent, memberName, member, isFirst);
} }
public void visitObjectMember(JsonObject parent, String memberName, JsonArray member, public void visitObjectMember(JsonObject parent, String memberName, JsonArray member,
boolean isFirst) throws IOException { boolean isFirst) throws IOException {
delegate.visitObjectMember(parent, memberName, member, isFirst); delegate.visitObjectMember(parent, memberName, member, isFirst);
} }
public void visitObjectMember(JsonObject parent, String memberName, JsonObject member, public void visitObjectMember(JsonObject parent, String memberName, JsonObject member,
boolean isFirst) throws IOException { boolean isFirst) throws IOException {
delegate.visitObjectMember(parent, memberName, member, isFirst); delegate.visitObjectMember(parent, memberName, member, isFirst);
} }
public void visitNullObjectMember(JsonObject parent, String memberName, public void visitNullObjectMember(JsonObject parent, String memberName,
boolean isFirst) throws IOException { boolean isFirst) throws IOException {
delegate.visitNullObjectMember(parent, memberName, isFirst); delegate.visitNullObjectMember(parent, memberName, isFirst);
} }

View File

@ -16,6 +16,8 @@
package org.mcteam.factions.gson; package org.mcteam.factions.gson;
import org.mcteam.factions.gson.internal.$Gson$Preconditions;
import java.util.Collection; import java.util.Collection;
/** /**
@ -27,9 +29,8 @@ import java.util.Collection;
final class DisjunctionExclusionStrategy implements ExclusionStrategy { final class DisjunctionExclusionStrategy implements ExclusionStrategy {
private final Collection<ExclusionStrategy> strategies; private final Collection<ExclusionStrategy> strategies;
public DisjunctionExclusionStrategy(Collection<ExclusionStrategy> strategies) { DisjunctionExclusionStrategy(Collection<ExclusionStrategy> strategies) {
Preconditions.checkNotNull(strategies); this.strategies = $Gson$Preconditions.checkNotNull(strategies);
this.strategies = strategies;
} }
public boolean shouldSkipField(FieldAttributes f) { public boolean shouldSkipField(FieldAttributes f) {

View File

@ -54,19 +54,19 @@ final class Escaper {
htmlEscapeSet.add('>'); htmlEscapeSet.add('>');
htmlEscapeSet.add('&'); htmlEscapeSet.add('&');
htmlEscapeSet.add('='); htmlEscapeSet.add('=');
htmlEscapeSet.add('\''); htmlEscapeSet.add('\'');
// htmlEscapeSet.add('/'); -- Removing slash for now since it causes some incompatibilities // htmlEscapeSet.add('/'); -- Removing slash for now since it causes some incompatibilities
HTML_ESCAPE_CHARS = Collections.unmodifiableSet(htmlEscapeSet); HTML_ESCAPE_CHARS = Collections.unmodifiableSet(htmlEscapeSet);
} }
private final boolean escapeHtmlCharacters; private final boolean escapeHtmlCharacters;
Escaper(boolean escapeHtmlCharacters) { Escaper(boolean escapeHtmlCharacters) {
this.escapeHtmlCharacters = escapeHtmlCharacters; this.escapeHtmlCharacters = escapeHtmlCharacters;
} }
public String escapeJsonString(CharSequence plainText) { public String escapeJsonString(CharSequence plainText) {
StringBuffer escapedString = new StringBuffer(plainText.length() + 20); StringBuilder escapedString = new StringBuilder(plainText.length() + 20);
try { try {
escapeJsonString(plainText, escapedString); escapeJsonString(plainText, escapedString);
} catch (IOException e) { } catch (IOException e) {
@ -75,14 +75,14 @@ final class Escaper {
return escapedString.toString(); return escapedString.toString();
} }
private void escapeJsonString(CharSequence plainText, StringBuffer out) throws IOException { private void escapeJsonString(CharSequence plainText, StringBuilder out) throws IOException {
int pos = 0; // Index just past the last char in plainText written to out. int pos = 0; // Index just past the last char in plainText written to out.
int len = plainText.length(); int len = plainText.length();
for (int charCount, i = 0; i < len; i += charCount) { for (int charCount, i = 0; i < len; i += charCount) {
int codePoint = Character.codePointAt(plainText, i); int codePoint = Character.codePointAt(plainText, i);
charCount = Character.charCount(codePoint); charCount = Character.charCount(codePoint);
if (!isControlCharacter(codePoint) && !mustEscapeCharInJsString(codePoint)) { if (!isControlCharacter(codePoint) && !mustEscapeCharInJsString(codePoint)) {
continue; continue;
} }
@ -121,7 +121,7 @@ final class Escaper {
} }
out.append(plainText, pos, len); out.append(plainText, pos, len);
} }
private boolean mustEscapeCharInJsString(int codepoint) { private boolean mustEscapeCharInJsString(int codepoint) {
if (!Character.isSupplementaryCodePoint(codepoint)) { if (!Character.isSupplementaryCodePoint(codepoint)) {
char c = (char) codepoint; char c = (char) codepoint;

View File

@ -72,10 +72,24 @@ package org.mcteam.factions.gson;
* .create(); * .create();
* </pre> * </pre>
* *
* <p>For certain model classes, you may only want to serialize a field, but exclude it for
* deserialization. To do that, you can write an {@code ExclusionStrategy} as per normal;
* however, you would register it with the
* {@link GsonBuilder#addDeserializationExclusionStrategy(ExclusionStrategy)} method.
* For example:
* <pre class="code">
* ExclusionStrategy excludeStrings = new UserDefinedExclusionStrategy(String.class);
* Gson gson = new GsonBuilder()
* .addDeserializationExclusionStrategy(excludeStrings)
* .create();
* </pre>
*
* @author Inderjeet Singh * @author Inderjeet Singh
* @author Joel Leitch * @author Joel Leitch
* *
* @see GsonBuilder#setExclusionStrategies(ExclusionStrategy...) * @see GsonBuilder#setExclusionStrategies(ExclusionStrategy...)
* @see GsonBuilder#addDeserializationExclusionStrategy(ExclusionStrategy)
* @see GsonBuilder#addSerializationExclusionStrategy(ExclusionStrategy)
* *
* @since 1.4 * @since 1.4
*/ */

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2009 Google Inc. * Copyright (C) 2011 Google Inc.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.mcteam.factions.gson; package org.mcteam.factions.gson;
import org.mcteam.factions.gson.annotations.Expose; import org.mcteam.factions.gson.annotations.Expose;
@ -20,11 +21,9 @@ import org.mcteam.factions.gson.annotations.Expose;
/** /**
* Excludes fields that do not have the {@link Expose} annotation * Excludes fields that do not have the {@link Expose} annotation
* *
* @author Inderjeet Singh
* @author Joel Leitch * @author Joel Leitch
*/ */
final class ExposeAnnotationDeserializationExclusionStrategy implements ExclusionStrategy { final class ExposeAnnotationDeserializationExclusionStrategy implements ExclusionStrategy {
public boolean shouldSkipClass(Class<?> clazz) { public boolean shouldSkipClass(Class<?> clazz) {
return false; return false;
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2008 Google Inc. * Copyright (C) 2011 Google Inc.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -21,11 +21,9 @@ import org.mcteam.factions.gson.annotations.Expose;
/** /**
* Excludes fields that do not have the {@link Expose} annotation * Excludes fields that do not have the {@link Expose} annotation
* *
* @author Inderjeet Singh
* @author Joel Leitch * @author Joel Leitch
*/ */
final class ExposeAnnotationSerializationExclusionStrategy implements ExclusionStrategy { final class ExposeAnnotationSerializationExclusionStrategy implements ExclusionStrategy {
public boolean shouldSkipClass(Class<?> clazz) { public boolean shouldSkipClass(Class<?> clazz) {
return false; return false;
} }

View File

@ -16,6 +16,9 @@
package org.mcteam.factions.gson; package org.mcteam.factions.gson;
import org.mcteam.factions.gson.internal.$Gson$Preconditions;
import org.mcteam.factions.gson.internal.$Gson$Types;
import java.lang.annotation.Annotation; import java.lang.annotation.Annotation;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.Type; import java.lang.reflect.Type;
@ -35,7 +38,7 @@ import java.util.Collections;
*/ */
public final class FieldAttributes { public final class FieldAttributes {
private static final String MAX_CACHE_PROPERTY_NAME = private static final String MAX_CACHE_PROPERTY_NAME =
"com.bukkit.mcteam.gson.annotation_cache_size_hint"; "org.mcteam.factions.gson.annotation_cache_size_hint";
private static final Cache<Pair<Class<?>, String>, Collection<Annotation>> ANNOTATION_CACHE = private static final Cache<Pair<Class<?>, String>, Collection<Annotation>> ANNOTATION_CACHE =
new LruCache<Pair<Class<?>,String>, Collection<Annotation>>(getMaxCacheSize()); new LruCache<Pair<Class<?>,String>, Collection<Annotation>>(getMaxCacheSize());
@ -46,6 +49,7 @@ public final class FieldAttributes {
private final boolean isSynthetic; private final boolean isSynthetic;
private final int modifiers; private final int modifiers;
private final String name; private final String name;
private final Type resolvedType;
// Fields used for lazy initialization // Fields used for lazy initialization
private Type genericType; private Type genericType;
@ -55,15 +59,16 @@ public final class FieldAttributes {
* Constructs a Field Attributes object from the {@code f}. * Constructs a Field Attributes object from the {@code f}.
* *
* @param f the field to pull attributes from * @param f the field to pull attributes from
* @param declaringType The type in which the field is declared
*/ */
FieldAttributes(final Class<?> declaringClazz, final Field f) { FieldAttributes(Class<?> declaringClazz, Field f, Type declaringType) {
Preconditions.checkNotNull(declaringClazz); this.declaringClazz = $Gson$Preconditions.checkNotNull(declaringClazz);
this.declaringClazz = declaringClazz; this.name = f.getName();
name = f.getName(); this.declaredType = f.getType();
declaredType = f.getType(); this.isSynthetic = f.isSynthetic();
isSynthetic = f.isSynthetic(); this.modifiers = f.getModifiers();
modifiers = f.getModifiers(); this.field = f;
field = f; this.resolvedType = getTypeInfoForField(f, declaringType);
} }
private static int getMaxCacheSize() { private static int getMaxCacheSize() {
@ -216,6 +221,10 @@ public final class FieldAttributes {
return field; return field;
} }
Type getResolvedType() {
return resolvedType;
}
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
private static <T extends Annotation> T getAnnotationFromArray( private static <T extends Annotation> T getAnnotationFromArray(
Collection<Annotation> annotations, Class<T> annotation) { Collection<Annotation> annotations, Class<T> annotation) {
@ -226,4 +235,21 @@ public final class FieldAttributes {
} }
return null; return null;
} }
/**
* Evaluates the "actual" type for the field. If the field is a "TypeVariable" or has a
* "TypeVariable" in a parameterized type then it evaluates the real type.
*
* @param f the actual field object to retrieve the type from
* @param typeDefiningF the type that contains the field {@code f}
* @return the type information for the field
*/
static Type getTypeInfoForField(Field f, Type typeDefiningF) {
Class<?> rawType = $Gson$Types.getRawType(typeDefiningF);
if (!f.getDeclaringClass().isAssignableFrom(rawType)) {
// this field is unrelated to the type; the user probably omitted type information
return f.getGenericType();
}
return $Gson$Types.resolve(typeDefiningF, rawType, f.getGenericType());
}
} }

View File

@ -32,7 +32,6 @@ interface FieldNamingStrategy2 {
* *
* @param f the field that is being translated * @param f the field that is being translated
* @return the translated field name. * @return the translated field name.
* @since 1.3
*/ */
public String translateName(FieldAttributes f); public String translateName(FieldAttributes f);
} }

View File

@ -16,22 +16,22 @@
package org.mcteam.factions.gson; package org.mcteam.factions.gson;
import org.mcteam.factions.gson.internal.$Gson$Preconditions;
/** /**
* Adapts the old "deprecated" {@link FieldNamingStrategy} to the new {@link FieldNamingStrategy2} * Adapts the old FieldNamingStrategy to the new {@link FieldNamingStrategy2}
* type. * type.
* *
* @author Inderjeet Singh * @author Inderjeet Singh
* @author Joel Leitch * @author Joel Leitch
*/ */
final class FieldNamingStrategy2Adapter implements FieldNamingStrategy2 { final class FieldNamingStrategy2Adapter implements FieldNamingStrategy2 {
private final FieldNamingStrategy adaptee; private final FieldNamingStrategy adaptee;
public FieldNamingStrategy2Adapter(FieldNamingStrategy adaptee) { FieldNamingStrategy2Adapter(FieldNamingStrategy adaptee) {
Preconditions.checkNotNull(adaptee); this.adaptee = $Gson$Preconditions.checkNotNull(adaptee);
this.adaptee = adaptee;
} }
@SuppressWarnings("deprecation")
public String translateName(FieldAttributes f) { public String translateName(FieldAttributes f) {
return adaptee.translateName(f.getFieldObject()); return adaptee.translateName(f.getFieldObject());
} }

View File

@ -1,70 +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.GenericArrayType;
import java.lang.reflect.Type;
/**
* An simple pojo-like immutable instance of the {@link GenericArrayType}. This object provides
* us the ability to create reflective types on demand. This object is required for support
* object similar to the one defined below:
* <pre>
* class Foo<T> {
* private final List<T>[] arrayOfListT;
*
* Foo(List<T>[] arrayList) {
* this.arrayOfListT = arrayList;
* }
* }
* </pre>
*
* <p>During parsing or serialization, we know the real variable type parameter {@code T},
* so we can build a new {@code GenericTypeArray} with the "real" type parameters and
* pass that object along instead.
*
* @author Inderjeet Singh
* @author Joel Leitch
*/
final class GenericArrayTypeImpl implements GenericArrayType {
private final Type genericComponentType;
public GenericArrayTypeImpl(Type genericComponentType) {
this.genericComponentType = genericComponentType;
}
public Type getGenericComponentType() {
return genericComponentType;
}
@Override
public boolean equals(Object o) {
if (!(o instanceof GenericArrayType)) {
return false;
}
GenericArrayType that = (GenericArrayType) o;
Type thatComponentType = that.getGenericComponentType();
return genericComponentType == null ?
thatComponentType == null : genericComponentType.equals(thatComponentType);
}
@Override
public int hashCode() {
return (genericComponentType == null) ? 0 : genericComponentType.hashCode();
}
}

View File

@ -16,6 +16,10 @@
package org.mcteam.factions.gson; 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.JsonWriter;
import org.mcteam.factions.gson.stream.MalformedJsonException;
import java.io.IOException; import java.io.IOException;
import java.io.Reader; import java.io.Reader;
import java.io.StringReader; import java.io.StringReader;
@ -27,12 +31,6 @@ import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import org.mcteam.factions.gson.JsonSerializationContextDefault;
import org.mcteam.factions.gson.stream.JsonReader;
import org.mcteam.factions.gson.stream.JsonToken;
import org.mcteam.factions.gson.stream.JsonWriter;
import org.mcteam.factions.gson.stream.MalformedJsonException;
/** /**
* This is the main class for using Gson. Gson is typically used by first constructing a * This is the main class for using Gson. Gson is typically used by first constructing a
* Gson instance and then invoking {@link #toJson(Object)} or {@link #fromJson(String, Class)} * Gson instance and then invoking {@link #toJson(Object)} or {@link #fromJson(String, Class)}
@ -80,8 +78,6 @@ public final class Gson {
//TODO(inder): get rid of all the registerXXX methods and take all such parameters in the //TODO(inder): get rid of all the registerXXX methods and take all such parameters in the
// constructor instead. At the minimum, mark those methods private. // constructor instead. At the minimum, mark those methods private.
private static final String NULL_STRING = "null";
static final boolean DEFAULT_JSON_NON_EXECUTABLE = false; static final boolean DEFAULT_JSON_NON_EXECUTABLE = false;
// Default instances of plug-ins // Default instances of plug-ins
@ -94,15 +90,12 @@ public final class Gson {
static final FieldNamingStrategy2 DEFAULT_NAMING_POLICY = static final FieldNamingStrategy2 DEFAULT_NAMING_POLICY =
new SerializedNameAnnotationInterceptingNamingPolicy(new JavaFieldNamingPolicy()); new SerializedNameAnnotationInterceptingNamingPolicy(new JavaFieldNamingPolicy());
private static final ExclusionStrategy DEFAULT_EXCLUSION_STRATEGY = private static final ExclusionStrategy DEFAULT_EXCLUSION_STRATEGY = createExclusionStrategy();
createExclusionStrategy(VersionConstants.IGNORE_VERSIONS);
private static final String JSON_NON_EXECUTABLE_PREFIX = ")]}'\n"; private static final String JSON_NON_EXECUTABLE_PREFIX = ")]}'\n";
private final ExclusionStrategy serializationStrategy; private final ExclusionStrategy deserializationExclusionStrategy;
private final ExclusionStrategy serializationExclusionStrategy;
private final ExclusionStrategy deserializationStrategy;
private final FieldNamingStrategy2 fieldNamingPolicy; private final FieldNamingStrategy2 fieldNamingPolicy;
private final MappedObjectConstructor objectConstructor; private final MappedObjectConstructor objectConstructor;
@ -154,17 +147,18 @@ public final class Gson {
public Gson() { public Gson() {
this(DEFAULT_EXCLUSION_STRATEGY, DEFAULT_EXCLUSION_STRATEGY, DEFAULT_NAMING_POLICY, this(DEFAULT_EXCLUSION_STRATEGY, DEFAULT_EXCLUSION_STRATEGY, DEFAULT_NAMING_POLICY,
new MappedObjectConstructor(DefaultTypeAdapters.getDefaultInstanceCreators()), new MappedObjectConstructor(DefaultTypeAdapters.getDefaultInstanceCreators()),
false, DefaultTypeAdapters.getDefaultSerializers(), false, DefaultTypeAdapters.getAllDefaultSerializers(),
DefaultTypeAdapters.getDefaultDeserializers(), DEFAULT_JSON_NON_EXECUTABLE, true, false); DefaultTypeAdapters.getAllDefaultDeserializers(), DEFAULT_JSON_NON_EXECUTABLE, true, false);
} }
Gson(ExclusionStrategy serializationStrategy, ExclusionStrategy deserializationStrategy, Gson(ExclusionStrategy deserializationExclusionStrategy,
FieldNamingStrategy2 fieldNamingPolicy, MappedObjectConstructor objectConstructor, ExclusionStrategy serializationExclusionStrategy, FieldNamingStrategy2 fieldNamingPolicy,
boolean serializeNulls, ParameterizedTypeHandlerMap<JsonSerializer<?>> serializers, MappedObjectConstructor objectConstructor, boolean serializeNulls,
ParameterizedTypeHandlerMap<JsonDeserializer<?>> deserializers, ParameterizedTypeHandlerMap<JsonSerializer<?>> serializers,
boolean generateNonExecutableGson, boolean htmlSafe, boolean prettyPrinting) { ParameterizedTypeHandlerMap<JsonDeserializer<?>> deserializers,
this.serializationStrategy = serializationStrategy; boolean generateNonExecutableGson, boolean htmlSafe, boolean prettyPrinting) {
this.deserializationStrategy = deserializationStrategy; this.deserializationExclusionStrategy = deserializationExclusionStrategy;
this.serializationExclusionStrategy = serializationExclusionStrategy;
this.fieldNamingPolicy = fieldNamingPolicy; this.fieldNamingPolicy = fieldNamingPolicy;
this.objectConstructor = objectConstructor; this.objectConstructor = objectConstructor;
this.serializeNulls = serializeNulls; this.serializeNulls = serializeNulls;
@ -175,18 +169,11 @@ public final class Gson {
this.prettyPrinting = prettyPrinting; this.prettyPrinting = prettyPrinting;
} }
private ObjectNavigatorFactory createDefaultObjectNavigatorFactory(ExclusionStrategy strategy) { private static ExclusionStrategy createExclusionStrategy() {
return new ObjectNavigatorFactory(strategy, fieldNamingPolicy);
}
private static ExclusionStrategy createExclusionStrategy(double version) {
List<ExclusionStrategy> strategies = new LinkedList<ExclusionStrategy>(); List<ExclusionStrategy> strategies = new LinkedList<ExclusionStrategy>();
strategies.add(DEFAULT_ANON_LOCAL_CLASS_EXCLUSION_STRATEGY); strategies.add(DEFAULT_ANON_LOCAL_CLASS_EXCLUSION_STRATEGY);
strategies.add(DEFAULT_SYNTHETIC_FIELD_EXCLUSION_STRATEGY); strategies.add(DEFAULT_SYNTHETIC_FIELD_EXCLUSION_STRATEGY);
strategies.add(DEFAULT_MODIFIER_BASED_EXCLUSION_STRATEGY); strategies.add(DEFAULT_MODIFIER_BASED_EXCLUSION_STRATEGY);
if (version != VersionConstants.IGNORE_VERSIONS) {
strategies.add(new VersionExclusionStrategy(version));
}
return new DisjunctionExclusionStrategy(strategies); return new DisjunctionExclusionStrategy(strategies);
} }
@ -227,12 +214,10 @@ public final class Gson {
* @since 1.4 * @since 1.4
*/ */
public JsonElement toJsonTree(Object src, Type typeOfSrc) { public JsonElement toJsonTree(Object src, Type typeOfSrc) {
if (src == null) {
return JsonNull.createJsonNull();
}
JsonSerializationContextDefault context = new JsonSerializationContextDefault( JsonSerializationContextDefault context = new JsonSerializationContextDefault(
createDefaultObjectNavigatorFactory(serializationStrategy), serializeNulls, serializers); new ObjectNavigator(serializationExclusionStrategy), fieldNamingPolicy,
return context.serialize(src, typeOfSrc, true); serializeNulls, serializers);
return context.serialize(src, typeOfSrc);
} }
/** /**
@ -250,7 +235,7 @@ public final class Gson {
*/ */
public String toJson(Object src) { public String toJson(Object src) {
if (src == null) { if (src == null) {
return serializeNulls ? NULL_STRING : ""; return toJson(JsonNull.createJsonNull());
} }
return toJson(src, src.getClass()); return toJson(src, src.getClass());
} }
@ -291,14 +276,10 @@ public final class Gson {
* @since 1.2 * @since 1.2
*/ */
public void toJson(Object src, Appendable writer) throws JsonIOException { public void toJson(Object src, Appendable writer) throws JsonIOException {
try { if (src != null) {
if (src != null) { toJson(src, src.getClass(), writer);
toJson(src, src.getClass(), writer); } else {
} else if (serializeNulls) { toJson(JsonNull.createJsonNull(), writer);
writeOutNullString(writer);
}
} catch (IOException ioe) {
throw new RuntimeException(ioe);
} }
} }
@ -565,21 +546,12 @@ public final class Gson {
return null; return null;
} }
JsonDeserializationContext context = new JsonDeserializationContextDefault( JsonDeserializationContext context = new JsonDeserializationContextDefault(
createDefaultObjectNavigatorFactory(deserializationStrategy), deserializers, new ObjectNavigator(deserializationExclusionStrategy), fieldNamingPolicy,
objectConstructor); deserializers, objectConstructor);
T target = (T) context.deserialize(json, typeOfT); T target = (T) context.deserialize(json, typeOfT);
return target; return target;
} }
/**
* Appends the {@link #NULL_STRING} to the {@code writer} object.
*
* @param writer the object to append the null value to
*/
private void writeOutNullString(Appendable writer) throws IOException {
writer.append(NULL_STRING);
}
@Override @Override
public String toString() { public String toString() {
StringBuilder sb = new StringBuilder("{") StringBuilder sb = new StringBuilder("{")

View File

@ -16,16 +16,19 @@
package org.mcteam.factions.gson; package org.mcteam.factions.gson;
import org.mcteam.factions.gson.DefaultTypeAdapters.DefaultDateTypeAdapter;
import org.mcteam.factions.gson.internal.$Gson$Preconditions;
import java.lang.reflect.Type; import java.lang.reflect.Type;
import java.sql.Timestamp;
import java.text.DateFormat; import java.text.DateFormat;
import java.util.Collection; import java.util.Arrays;
import java.util.Date; import java.util.Date;
import java.util.HashSet; import java.util.HashSet;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Map;
import org.mcteam.factions.gson.DefaultTypeAdapters.DefaultDateTypeAdapter; import java.util.Set;
/** /**
* <p>Use this builder to construct a {@link Gson} instance when you need to set configuration * <p>Use this builder to construct a {@link Gson} instance when you need to set configuration
@ -39,6 +42,7 @@ import org.mcteam.factions.gson.DefaultTypeAdapters.DefaultDateTypeAdapter;
* <pre> * <pre>
* Gson gson = new GsonBuilder() * Gson gson = new GsonBuilder()
* .registerTypeAdapter(Id.class, new IdTypeAdapter()) * .registerTypeAdapter(Id.class, new IdTypeAdapter())
* .enableComplexMapKeySerialization()
* .serializeNulls() * .serializeNulls()
* .setDateFormat(DateFormat.LONG) * .setDateFormat(DateFormat.LONG)
* .setFieldNamingPolicy(FieldNamingPolicy.UPPER_CAMEL_CASE) * .setFieldNamingPolicy(FieldNamingPolicy.UPPER_CAMEL_CASE)
@ -47,22 +51,33 @@ import org.mcteam.factions.gson.DefaultTypeAdapters.DefaultDateTypeAdapter;
* .create(); * .create();
* </pre></p> * </pre></p>
* *
* <p>NOTE: the order of invocation of configuration methods does not matter.</p> * <p>NOTES:
* <ul>
* <li> the order of invocation of configuration methods does not matter.</li>
* <li> The default serialization of {@link Date} and its subclasses in Gson does
* not contain time-zone information. So, if you are using date/time instances,
* use {@code GsonBuilder} and its {@code setDateFormat} methods.</li>
* </ul>
* </p>
* *
* @author Inderjeet Singh * @author Inderjeet Singh
* @author Joel Leitch * @author Joel Leitch
*/ */
public final class GsonBuilder { public final class GsonBuilder {
private static final MapAsArrayTypeAdapter COMPLEX_KEY_MAP_TYPE_ADAPTER =
new MapAsArrayTypeAdapter();
private static final InnerClassExclusionStrategy innerClassExclusionStrategy = private static final InnerClassExclusionStrategy innerClassExclusionStrategy =
new InnerClassExclusionStrategy(); new InnerClassExclusionStrategy();
private static final ExposeAnnotationSerializationExclusionStrategy
exposeAnnotationSerializationExclusionStrategy =
new ExposeAnnotationSerializationExclusionStrategy();
private static final ExposeAnnotationDeserializationExclusionStrategy private static final ExposeAnnotationDeserializationExclusionStrategy
exposeAnnotationDeserializationExclusionStrategy = exposeAnnotationDeserializationExclusionStrategy =
new ExposeAnnotationDeserializationExclusionStrategy(); new ExposeAnnotationDeserializationExclusionStrategy();
private static final ExposeAnnotationSerializationExclusionStrategy
exposeAnnotationSerializationExclusionStrategy =
new ExposeAnnotationSerializationExclusionStrategy();
private final Collection<ExclusionStrategy> exclusionStrategies = private final Set<ExclusionStrategy> serializeExclusionStrategies =
new HashSet<ExclusionStrategy>();
private final Set<ExclusionStrategy> deserializeExclusionStrategies =
new HashSet<ExclusionStrategy>(); new HashSet<ExclusionStrategy>();
private double ignoreVersionsAfter; private double ignoreVersionsAfter;
@ -91,8 +106,10 @@ public final class GsonBuilder {
*/ */
public GsonBuilder() { public GsonBuilder() {
// add default exclusion strategies // add default exclusion strategies
exclusionStrategies.add(Gson.DEFAULT_ANON_LOCAL_CLASS_EXCLUSION_STRATEGY); deserializeExclusionStrategies.add(Gson.DEFAULT_ANON_LOCAL_CLASS_EXCLUSION_STRATEGY);
exclusionStrategies.add(Gson.DEFAULT_SYNTHETIC_FIELD_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 // setup default values
ignoreVersionsAfter = VersionConstants.IGNORE_VERSIONS; ignoreVersionsAfter = VersionConstants.IGNORE_VERSIONS;
@ -178,6 +195,87 @@ public final class GsonBuilder {
return this; 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 <strong>serialized</strong> 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:
*
* <h3>Maps as JSON objects</h3>
* 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}.
*
* <p>Below is an example:
* <pre> {@code
* Gson gson = new GsonBuilder()
* .register(Point.class, new MyPointTypeAdapter())
* .enableComplexMapKeySerialization()
* .create();
*
* Map<Point, String> original = new LinkedHashMap<Point, String>();
* original.put(new Point(5, 6), "a");
* original.put(new Point(8, 8), "b");
* System.out.println(gson.toJson(original, type));
* }</pre>
* The above code prints this JSON object:<pre> {@code
* {
* "(5,6)": "a",
* "(8,8)": "b"
* }
* }</pre>
*
* <h3>Maps as JSON arrays</h3>
* 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}}.
*
* <p>Given the assumption above, a {@code Map<Point, String>} will be
* serialize as an array of arrays (can be viewed as an entry set of pairs).
*
* <p>Below is an example of serializing complex types as JSON arrays:
* <pre> {@code
* Gson gson = new GsonBuilder()
* .enableComplexMapKeySerialization()
* .create();
*
* Map<Point, String> original = new LinkedHashMap<Point, String>();
* 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:
* <pre> {@code
* [
* [
* {
* "x": 5,
* "y": 6
* },
* "a"
* ],
* [
* {
* "x": 8,
* "y": 8
* },
* "b"
* ]
* ]
* }</pre>
*
* @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. * Configures Gson to exclude inner classes during serialization.
* *
@ -250,12 +348,45 @@ public final class GsonBuilder {
* @since 1.4 * @since 1.4
*/ */
public GsonBuilder setExclusionStrategies(ExclusionStrategy... strategies) { public GsonBuilder setExclusionStrategies(ExclusionStrategy... strategies) {
for (ExclusionStrategy strategy : strategies) { List<ExclusionStrategy> strategyList = Arrays.asList(strategies);
exclusionStrategies.add(strategy); serializeExclusionStrategies.addAll(strategyList);
} deserializeExclusionStrategies.addAll(strategyList);
return this; 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 * Configures Gson to output Json that fits in a page for pretty printing. This option only
* affects Json serialization. * 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 * call this method or {@link #setDateFormat(int)} multiple times, but only the last invocation
* will be used to decide the serialization format. * will be used to decide the serialization format.
* *
* <p>The date format will be used to serialize and deserialize {@link java.util.Date}, {@link
* java.sql.Timestamp} and {@link java.sql.Date}.
*
* <p>Note that this pattern must abide by the convention provided by {@code SimpleDateFormat} * <p>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 * class. See the documentation in {@link java.text.SimpleDateFormat} for more information on
* valid date and time patterns.</p> * valid date and time patterns.</p>
@ -354,8 +488,8 @@ public final class GsonBuilder {
* @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern * @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern
*/ */
public GsonBuilder registerTypeAdapter(Type type, Object typeAdapter) { public GsonBuilder registerTypeAdapter(Type type, Object typeAdapter) {
Preconditions.checkArgument(typeAdapter instanceof JsonSerializer<?> $Gson$Preconditions.checkArgument(typeAdapter instanceof JsonSerializer<?>
|| typeAdapter instanceof JsonDeserializer<?> || typeAdapter instanceof InstanceCreator<?>); || typeAdapter instanceof JsonDeserializer<?> || typeAdapter instanceof InstanceCreator<?>);
if (typeAdapter instanceof InstanceCreator<?>) { if (typeAdapter instanceof InstanceCreator<?>) {
registerInstanceCreator(type, (InstanceCreator<?>) typeAdapter); 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 * @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern
* @since 1.7 * @since 1.7
*/ */
GsonBuilder registerTypeHierarchyAdapter(Class<?> baseType, Object typeAdapter) { public GsonBuilder registerTypeHierarchyAdapter(Class<?> baseType, Object typeAdapter) {
Preconditions.checkArgument(typeAdapter instanceof JsonSerializer<?> $Gson$Preconditions.checkArgument(typeAdapter instanceof JsonSerializer<?>
|| typeAdapter instanceof JsonDeserializer<?> || typeAdapter instanceof InstanceCreator<?>); || typeAdapter instanceof JsonDeserializer<?> || typeAdapter instanceof InstanceCreator<?>);
if (typeAdapter instanceof InstanceCreator<?>) { if (typeAdapter instanceof InstanceCreator<?>) {
registerInstanceCreatorForTypeHierarchy(baseType, (InstanceCreator<?>) typeAdapter); 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 * @return an instance of Gson configured with the options currently set in this builder
*/ */
public Gson create() { public Gson create() {
List<ExclusionStrategy> serializationStrategies =
new LinkedList<ExclusionStrategy>(exclusionStrategies);
List<ExclusionStrategy> deserializationStrategies = List<ExclusionStrategy> deserializationStrategies =
new LinkedList<ExclusionStrategy>(exclusionStrategies); new LinkedList<ExclusionStrategy>(deserializeExclusionStrategies);
List<ExclusionStrategy> serializationStrategies =
serializationStrategies.add(modifierBasedExclusionStrategy); new LinkedList<ExclusionStrategy>(serializeExclusionStrategies);
deserializationStrategies.add(modifierBasedExclusionStrategy); deserializationStrategies.add(modifierBasedExclusionStrategy);
serializationStrategies.add(modifierBasedExclusionStrategy);
if (!serializeInnerClasses) { if (!serializeInnerClasses) {
serializationStrategies.add(innerClassExclusionStrategy);
deserializationStrategies.add(innerClassExclusionStrategy); deserializationStrategies.add(innerClassExclusionStrategy);
serializationStrategies.add(innerClassExclusionStrategy);
} }
if (ignoreVersionsAfter != VersionConstants.IGNORE_VERSIONS) { if (ignoreVersionsAfter != VersionConstants.IGNORE_VERSIONS) {
serializationStrategies.add(new VersionExclusionStrategy(ignoreVersionsAfter)); VersionExclusionStrategy versionExclusionStrategy =
deserializationStrategies.add(new VersionExclusionStrategy(ignoreVersionsAfter)); new VersionExclusionStrategy(ignoreVersionsAfter);
deserializationStrategies.add(versionExclusionStrategy);
serializationStrategies.add(versionExclusionStrategy);
} }
if (excludeFieldsWithoutExposeAnnotation) { if (excludeFieldsWithoutExposeAnnotation) {
serializationStrategies.add(exposeAnnotationSerializationExclusionStrategy);
deserializationStrategies.add(exposeAnnotationDeserializationExclusionStrategy); deserializationStrategies.add(exposeAnnotationDeserializationExclusionStrategy);
serializationStrategies.add(exposeAnnotationSerializationExclusionStrategy);
} }
ExclusionStrategy serializationExclusionStrategy =
new DisjunctionExclusionStrategy(serializationStrategies);
ExclusionStrategy deserializationExclusionStrategy =
new DisjunctionExclusionStrategy(deserializationStrategies);
ParameterizedTypeHandlerMap<JsonSerializer<?>> customSerializers = serializers.copyOf(); ParameterizedTypeHandlerMap<JsonSerializer<?>> customSerializers =
ParameterizedTypeHandlerMap<JsonDeserializer<?>> customDeserializers = deserializers.copyOf(); DefaultTypeAdapters.DEFAULT_HIERARCHY_SERIALIZERS.copyOf();
customSerializers.register(serializers.copyOf());
ParameterizedTypeHandlerMap<JsonDeserializer<?>> customDeserializers =
DefaultTypeAdapters.DEFAULT_HIERARCHY_DESERIALIZERS.copyOf();
customDeserializers.register(deserializers.copyOf());
addTypeAdaptersForDate(datePattern, dateStyle, timeStyle, customSerializers, addTypeAdaptersForDate(datePattern, dateStyle, timeStyle, customSerializers,
customDeserializers); customDeserializers);
@ -543,9 +678,11 @@ public final class GsonBuilder {
MappedObjectConstructor objConstructor = new MappedObjectConstructor(customInstanceCreators); MappedObjectConstructor objConstructor = new MappedObjectConstructor(customInstanceCreators);
Gson gson = new Gson(serializationExclusionStrategy, deserializationExclusionStrategy, Gson gson = new Gson(new DisjunctionExclusionStrategy(deserializationStrategies),
fieldNamingPolicy, objConstructor, serializeNulls, customSerializers, new DisjunctionExclusionStrategy(serializationStrategies),
customDeserializers, generateNonExecutableJson, escapeHtmlChars, prettyPrinting); fieldNamingPolicy, objConstructor, serializeNulls,
customSerializers, customDeserializers, generateNonExecutableJson, escapeHtmlChars,
prettyPrinting);
return gson; return gson;
} }
@ -560,12 +697,19 @@ public final class GsonBuilder {
} }
if (dateTypeAdapter != null) { if (dateTypeAdapter != null) {
if (!serializers.hasSpecificHandlerFor(Date.class)) { registerIfAbsent(Date.class, serializers, dateTypeAdapter);
serializers.register(Date.class, dateTypeAdapter); registerIfAbsent(Date.class, deserializers, dateTypeAdapter);
} registerIfAbsent(Timestamp.class, serializers, dateTypeAdapter);
if (!deserializers.hasSpecificHandlerFor(Date.class)) { registerIfAbsent(Timestamp.class, deserializers, dateTypeAdapter);
deserializers.register(Date.class, dateTypeAdapter); registerIfAbsent(java.sql.Date.class, serializers, dateTypeAdapter);
} registerIfAbsent(java.sql.Date.class, deserializers, dateTypeAdapter);
}
}
private static <T> void registerIfAbsent(Class<?> type,
ParameterizedTypeHandlerMap<T> adapters, T adapter) {
if (!adapters.hasSpecificHandlerFor(type)) {
adapters.register(type, adapter);
} }
} }
} }

View File

@ -23,7 +23,7 @@ import java.lang.reflect.Modifier;
* *
* @author Joel Leitch * @author Joel Leitch
*/ */
class InnerClassExclusionStrategy implements ExclusionStrategy { final class InnerClassExclusionStrategy implements ExclusionStrategy {
public boolean shouldSkipField(FieldAttributes f) { public boolean shouldSkipField(FieldAttributes f) {
return isInnerClass(f.getDeclaredClass()); return isInnerClass(f.getDeclaredClass());

View File

@ -295,6 +295,16 @@ public final class JsonArray extends JsonElement implements Iterable<JsonElement
throw new IllegalStateException(); throw new IllegalStateException();
} }
@Override
public boolean equals(Object o) {
return (o == this) || (o instanceof JsonArray && ((JsonArray) o).elements.equals(elements));
}
@Override
public int hashCode() {
return elements.hashCode();
}
@Override @Override
protected void toString(Appendable sb, Escaper escaper) throws IOException { protected void toString(Appendable sb, Escaper escaper) throws IOException {
sb.append('['); sb.append('[');

View File

@ -16,6 +16,8 @@
package org.mcteam.factions.gson; package org.mcteam.factions.gson;
import org.mcteam.factions.gson.internal.$Gson$Types;
import java.lang.reflect.Array; import java.lang.reflect.Array;
import java.lang.reflect.Type; import java.lang.reflect.Type;
@ -29,39 +31,35 @@ import java.lang.reflect.Type;
final class JsonArrayDeserializationVisitor<T> extends JsonDeserializationVisitor<T> { final class JsonArrayDeserializationVisitor<T> extends JsonDeserializationVisitor<T> {
JsonArrayDeserializationVisitor(JsonArray jsonArray, Type arrayType, JsonArrayDeserializationVisitor(JsonArray jsonArray, Type arrayType,
ObjectNavigatorFactory factory, ObjectConstructor objectConstructor, ObjectNavigator objectNavigator, FieldNamingStrategy2 fieldNamingPolicy,
ObjectConstructor objectConstructor,
ParameterizedTypeHandlerMap<JsonDeserializer<?>> deserializers, ParameterizedTypeHandlerMap<JsonDeserializer<?>> deserializers,
JsonDeserializationContext context) { JsonDeserializationContext context) {
super(jsonArray, arrayType, factory, objectConstructor, deserializers, context); super(jsonArray, arrayType, objectNavigator, fieldNamingPolicy, objectConstructor, deserializers, context);
} }
@Override @Override
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
protected T constructTarget() { protected T constructTarget() {
TypeInfo typeInfo = new TypeInfo(targetType);
if (!json.isJsonArray()) { if (!json.isJsonArray()) {
throw new JsonParseException("Expecting array found: " + json); throw new JsonParseException("Expecting array found: " + json);
} }
JsonArray jsonArray = json.getAsJsonArray(); JsonArray jsonArray = json.getAsJsonArray();
if (typeInfo.isArray()) { if ($Gson$Types.isArray(targetType)) {
TypeInfoArray arrayTypeInfo = TypeInfoFactory.getTypeInfoForArray(targetType);
// We know that we are getting back an array of the required type, so // We know that we are getting back an array of the required type, so
// this typecasting is safe. // this typecasting is safe.
return (T) objectConstructor.constructArray(arrayTypeInfo.getSecondLevelType(), return (T) objectConstructor.constructArray($Gson$Types.getArrayComponentType(targetType),
jsonArray.size()); jsonArray.size());
} }
// is a collection // is a collection
return (T) objectConstructor.construct(typeInfo.getRawClass()); return (T) objectConstructor.construct($Gson$Types.getRawType(targetType));
} }
public void visitArray(Object array, Type arrayType) { public void visitArray(Object array, Type arrayType) {
if (!json.isJsonArray()) { if (!json.isJsonArray()) {
throw new JsonParseException("Expecting array found: " + json); throw new JsonParseException("Expecting array found: " + json);
} }
JsonArray jsonArray = json.getAsJsonArray(); JsonArray jsonArray = json.getAsJsonArray();
TypeInfoArray arrayTypeInfo = TypeInfoFactory.getTypeInfoForArray(arrayType);
for (int i = 0; i < jsonArray.size(); i++) { for (int i = 0; i < jsonArray.size(); i++) {
JsonElement jsonChild = jsonArray.get(i); JsonElement jsonChild = jsonArray.get(i);
Object child; Object child;
@ -69,11 +67,12 @@ final class JsonArrayDeserializationVisitor<T> extends JsonDeserializationVisito
if (jsonChild == null || jsonChild.isJsonNull()) { if (jsonChild == null || jsonChild.isJsonNull()) {
child = null; child = null;
} else if (jsonChild instanceof JsonObject) { } else if (jsonChild instanceof JsonObject) {
child = visitChildAsObject(arrayTypeInfo.getComponentRawType(), jsonChild); child = visitChildAsObject($Gson$Types.getArrayComponentType(arrayType), jsonChild);
} else if (jsonChild instanceof JsonArray) { } else if (jsonChild instanceof JsonArray) {
child = visitChildAsArray(arrayTypeInfo.getSecondLevelType(), jsonChild.getAsJsonArray()); child = visitChildAsArray($Gson$Types.getArrayComponentType(arrayType),
jsonChild.getAsJsonArray());
} else if (jsonChild instanceof JsonPrimitive) { } else if (jsonChild instanceof JsonPrimitive) {
child = visitChildAsObject(arrayTypeInfo.getComponentRawType(), child = visitChildAsObject($Gson$Types.getArrayComponentType(arrayType),
jsonChild.getAsJsonPrimitive()); jsonChild.getAsJsonPrimitive());
} else { } else {
throw new IllegalStateException(); throw new IllegalStateException();
@ -96,12 +95,12 @@ final class JsonArrayDeserializationVisitor<T> extends JsonDeserializationVisito
} }
public void visitObjectField(FieldAttributes f, Type typeOfF, Object obj) { 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); + obj);
} }
public boolean visitFieldUsingCustomHandler(FieldAttributes f, Type actualTypeOfField, Object parent) { 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); + parent);
} }

View File

@ -25,14 +25,17 @@ import java.lang.reflect.Type;
*/ */
final class JsonDeserializationContextDefault implements JsonDeserializationContext { final class JsonDeserializationContextDefault implements JsonDeserializationContext {
private final ObjectNavigatorFactory navigatorFactory; private final ObjectNavigator objectNavigator;
private final FieldNamingStrategy2 fieldNamingPolicy;
private final ParameterizedTypeHandlerMap<JsonDeserializer<?>> deserializers; private final ParameterizedTypeHandlerMap<JsonDeserializer<?>> deserializers;
private final MappedObjectConstructor objectConstructor; private final MappedObjectConstructor objectConstructor;
JsonDeserializationContextDefault(ObjectNavigatorFactory navigatorFactory, JsonDeserializationContextDefault(ObjectNavigator objectNavigator,
FieldNamingStrategy2 fieldNamingPolicy,
ParameterizedTypeHandlerMap<JsonDeserializer<?>> deserializers, ParameterizedTypeHandlerMap<JsonDeserializer<?>> deserializers,
MappedObjectConstructor objectConstructor) { MappedObjectConstructor objectConstructor) {
this.navigatorFactory = navigatorFactory; this.objectNavigator = objectNavigator;
this.fieldNamingPolicy = fieldNamingPolicy;
this.deserializers = deserializers; this.deserializers = deserializers;
this.objectConstructor = objectConstructor; this.objectConstructor = objectConstructor;
} }
@ -59,18 +62,18 @@ final class JsonDeserializationContextDefault implements JsonDeserializationCont
private <T> T fromJsonArray(Type arrayType, JsonArray jsonArray, private <T> T fromJsonArray(Type arrayType, JsonArray jsonArray,
JsonDeserializationContext context) throws JsonParseException { JsonDeserializationContext context) throws JsonParseException {
JsonArrayDeserializationVisitor<T> visitor = new JsonArrayDeserializationVisitor<T>( JsonArrayDeserializationVisitor<T> visitor = new JsonArrayDeserializationVisitor<T>(
jsonArray, arrayType, navigatorFactory, objectConstructor, deserializers, context); jsonArray, arrayType, objectNavigator, fieldNamingPolicy,
ObjectNavigator on = navigatorFactory.create(new ObjectTypePair(null, arrayType, true)); objectConstructor, deserializers, context);
on.accept(visitor); objectNavigator.accept(new ObjectTypePair(null, arrayType, true), visitor);
return visitor.getTarget(); return visitor.getTarget();
} }
private <T> T fromJsonObject(Type typeOfT, JsonObject jsonObject, private <T> T fromJsonObject(Type typeOfT, JsonObject jsonObject,
JsonDeserializationContext context) throws JsonParseException { JsonDeserializationContext context) throws JsonParseException {
JsonObjectDeserializationVisitor<T> visitor = new JsonObjectDeserializationVisitor<T>( JsonObjectDeserializationVisitor<T> visitor = new JsonObjectDeserializationVisitor<T>(
jsonObject, typeOfT, navigatorFactory, objectConstructor, deserializers, context); jsonObject, typeOfT, objectNavigator, fieldNamingPolicy,
ObjectNavigator on = navigatorFactory.create(new ObjectTypePair(null, typeOfT, true)); objectConstructor, deserializers, context);
on.accept(visitor); objectNavigator.accept(new ObjectTypePair(null, typeOfT, true), visitor);
return visitor.getTarget(); return visitor.getTarget();
} }
@ -78,10 +81,8 @@ final class JsonDeserializationContextDefault implements JsonDeserializationCont
private <T> T fromJsonPrimitive(Type typeOfT, JsonPrimitive json, private <T> T fromJsonPrimitive(Type typeOfT, JsonPrimitive json,
JsonDeserializationContext context) throws JsonParseException { JsonDeserializationContext context) throws JsonParseException {
JsonObjectDeserializationVisitor<T> visitor = new JsonObjectDeserializationVisitor<T>( JsonObjectDeserializationVisitor<T> visitor = new JsonObjectDeserializationVisitor<T>(
json, typeOfT, navigatorFactory, objectConstructor, deserializers, context); json, typeOfT, objectNavigator, fieldNamingPolicy, objectConstructor, deserializers, context);
ObjectNavigator on = objectNavigator.accept(new ObjectTypePair(json.getAsObject(), typeOfT, true), visitor);
navigatorFactory.create(new ObjectTypePair(json.getAsObject(), typeOfT, true));
on.accept(visitor);
Object target = visitor.getTarget(); Object target = visitor.getTarget();
return (T) target; return (T) target;
} }

View File

@ -16,6 +16,8 @@
package org.mcteam.factions.gson; package org.mcteam.factions.gson;
import org.mcteam.factions.gson.internal.$Gson$Preconditions;
import java.lang.reflect.Type; import java.lang.reflect.Type;
/** /**
@ -28,7 +30,8 @@ import java.lang.reflect.Type;
*/ */
abstract class JsonDeserializationVisitor<T> implements ObjectNavigator.Visitor { abstract class JsonDeserializationVisitor<T> implements ObjectNavigator.Visitor {
protected final ObjectNavigatorFactory factory; protected final ObjectNavigator objectNavigator;
protected final FieldNamingStrategy2 fieldNamingPolicy;
protected final ObjectConstructor objectConstructor; protected final ObjectConstructor objectConstructor;
protected final ParameterizedTypeHandlerMap<JsonDeserializer<?>> deserializers; protected final ParameterizedTypeHandlerMap<JsonDeserializer<?>> deserializers;
protected T target; protected T target;
@ -37,16 +40,17 @@ abstract class JsonDeserializationVisitor<T> implements ObjectNavigator.Visitor
protected final JsonDeserializationContext context; protected final JsonDeserializationContext context;
protected boolean constructed; protected boolean constructed;
public JsonDeserializationVisitor(JsonElement json, Type targetType, JsonDeserializationVisitor(JsonElement json, Type targetType,
ObjectNavigatorFactory factory, ObjectConstructor objectConstructor, ObjectNavigator objectNavigator, FieldNamingStrategy2 fieldNamingPolicy,
ObjectConstructor objectConstructor,
ParameterizedTypeHandlerMap<JsonDeserializer<?>> deserializers, ParameterizedTypeHandlerMap<JsonDeserializer<?>> deserializers,
JsonDeserializationContext context) { JsonDeserializationContext context) {
Preconditions.checkNotNull(json);
this.targetType = targetType; this.targetType = targetType;
this.factory = factory; this.objectNavigator = objectNavigator;
this.fieldNamingPolicy = fieldNamingPolicy;
this.objectConstructor = objectConstructor; this.objectConstructor = objectConstructor;
this.deserializers = deserializers; this.deserializers = deserializers;
this.json = json; this.json = $Gson$Preconditions.checkNotNull(json);
this.context = context; this.context = context;
this.constructed = false; this.constructed = false;
} }
@ -72,14 +76,14 @@ abstract class JsonDeserializationVisitor<T> implements ObjectNavigator.Visitor
Pair<JsonDeserializer<?>, ObjectTypePair> pair = objTypePair.getMatchingHandler(deserializers); Pair<JsonDeserializer<?>, ObjectTypePair> pair = objTypePair.getMatchingHandler(deserializers);
if (pair == null) { if (pair == null) {
return false; return false;
} }
Object value = invokeCustomDeserializer(json, pair); Object value = invokeCustomDeserializer(json, pair);
target = (T) value; target = (T) value;
constructed = true; constructed = true;
return true; return true;
} }
protected Object invokeCustomDeserializer(JsonElement element, protected Object invokeCustomDeserializer(JsonElement element,
Pair<JsonDeserializer<?>, ObjectTypePair> pair) { Pair<JsonDeserializer<?>, ObjectTypePair> pair) {
if (element == null || element.isJsonNull()) { if (element == null || element.isJsonNull()) {
return null; return null;
@ -91,20 +95,19 @@ abstract class JsonDeserializationVisitor<T> implements ObjectNavigator.Visitor
final Object visitChildAsObject(Type childType, JsonElement jsonChild) { final Object visitChildAsObject(Type childType, JsonElement jsonChild) {
JsonDeserializationVisitor<?> childVisitor = JsonDeserializationVisitor<?> childVisitor =
new JsonObjectDeserializationVisitor<Object>(jsonChild, childType, new JsonObjectDeserializationVisitor<Object>(jsonChild, childType,
factory, objectConstructor, deserializers, context); objectNavigator, fieldNamingPolicy, objectConstructor, deserializers, context);
return visitChild(childType, childVisitor); return visitChild(childType, childVisitor);
} }
final Object visitChildAsArray(Type childType, JsonArray jsonChild) { final Object visitChildAsArray(Type childType, JsonArray jsonChild) {
JsonDeserializationVisitor<?> childVisitor = JsonDeserializationVisitor<?> childVisitor =
new JsonArrayDeserializationVisitor<Object>(jsonChild.getAsJsonArray(), childType, new JsonArrayDeserializationVisitor<Object>(jsonChild.getAsJsonArray(), childType,
factory, objectConstructor, deserializers, context); objectNavigator, fieldNamingPolicy, objectConstructor, deserializers, context);
return visitChild(childType, childVisitor); return visitChild(childType, childVisitor);
} }
private Object visitChild(Type type, JsonDeserializationVisitor<?> childVisitor) { private Object visitChild(Type type, JsonDeserializationVisitor<?> childVisitor) {
ObjectNavigator on = factory.create(new ObjectTypePair(null, type, false)); objectNavigator.accept(new ObjectTypePair(null, type, false), childVisitor);
on.accept(childVisitor);
// the underlying object may have changed during the construction phase // the underlying object may have changed during the construction phase
// This happens primarily because of custom deserializers // This happens primarily because of custom deserializers
return childVisitor.getTarget(); return childVisitor.getTarget();

View File

@ -16,6 +16,8 @@
package org.mcteam.factions.gson; package org.mcteam.factions.gson;
import org.mcteam.factions.gson.internal.$Gson$Preconditions;
import java.lang.reflect.Type; import java.lang.reflect.Type;
/** /**
@ -28,7 +30,7 @@ import java.lang.reflect.Type;
* @author Inderjeet Singh * @author Inderjeet Singh
* @author Joel Leitch * @author Joel Leitch
*/ */
class JsonDeserializerExceptionWrapper<T> implements JsonDeserializer<T> { final class JsonDeserializerExceptionWrapper<T> implements JsonDeserializer<T> {
private final JsonDeserializer<T> delegate; private final JsonDeserializer<T> delegate;
@ -40,8 +42,7 @@ class JsonDeserializerExceptionWrapper<T> implements JsonDeserializer<T> {
* @throws IllegalArgumentException if {@code delegate} is {@code null}. * @throws IllegalArgumentException if {@code delegate} is {@code null}.
*/ */
JsonDeserializerExceptionWrapper(JsonDeserializer<T> delegate) { JsonDeserializerExceptionWrapper(JsonDeserializer<T> delegate) {
Preconditions.checkNotNull(delegate); this.delegate = $Gson$Preconditions.checkNotNull(delegate);
this.delegate = delegate;
} }
public T deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) public T deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
@ -56,14 +57,14 @@ class JsonDeserializerExceptionWrapper<T> implements JsonDeserializer<T> {
StringBuilder errorMsg = new StringBuilder() StringBuilder errorMsg = new StringBuilder()
.append("The JsonDeserializer ") .append("The JsonDeserializer ")
.append(delegate) .append(delegate)
.append(" failed to deserialized json object ") .append(" failed to deserialize json object ")
.append(json) .append(json)
.append(" given the type ") .append(" given the type ")
.append(typeOfT); .append(typeOfT);
throw new JsonParseException(errorMsg.toString(), e); throw new JsonParseException(errorMsg.toString(), e);
} }
} }
@Override @Override
public String toString() { public String toString() {
return delegate.toString(); return delegate.toString();

View File

@ -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.
*
* <p>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.</p>
*
* @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;
}
}

View File

@ -53,7 +53,7 @@ public final class JsonNull extends JsonElement {
*/ */
@Override @Override
public boolean equals(Object other) { public boolean equals(Object other) {
return other instanceof JsonNull; return this == other || other instanceof JsonNull;
} }
/** /**

View File

@ -16,6 +16,8 @@
package org.mcteam.factions.gson; package org.mcteam.factions.gson;
import org.mcteam.factions.gson.internal.$Gson$Preconditions;
import java.io.IOException; import java.io.IOException;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.Map; import java.util.Map;
@ -52,11 +54,10 @@ public final class JsonObject extends JsonElement {
* @param value the member object. * @param value the member object.
*/ */
public void add(String property, JsonElement value) { public void add(String property, JsonElement value) {
Preconditions.checkNotNull(property);
if (value == null) { if (value == null) {
value = JsonNull.createJsonNull(); 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); 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 @Override
protected void toString(Appendable sb, Escaper escaper) throws IOException { protected void toString(Appendable sb, Escaper escaper) throws IOException {
sb.append('{'); sb.append('{');

View File

@ -16,6 +16,7 @@
package org.mcteam.factions.gson; package org.mcteam.factions.gson;
import java.lang.reflect.Type; import java.lang.reflect.Type;
/** /**
@ -28,10 +29,11 @@ import java.lang.reflect.Type;
final class JsonObjectDeserializationVisitor<T> extends JsonDeserializationVisitor<T> { final class JsonObjectDeserializationVisitor<T> extends JsonDeserializationVisitor<T> {
JsonObjectDeserializationVisitor(JsonElement json, Type type, JsonObjectDeserializationVisitor(JsonElement json, Type type,
ObjectNavigatorFactory factory, ObjectConstructor objectConstructor, ObjectNavigator objectNavigator, FieldNamingStrategy2 fieldNamingPolicy,
ObjectConstructor objectConstructor,
ParameterizedTypeHandlerMap<JsonDeserializer<?>> deserializers, ParameterizedTypeHandlerMap<JsonDeserializer<?>> deserializers,
JsonDeserializationContext context) { JsonDeserializationContext context) {
super(json, type, factory, objectConstructor, deserializers, context); super(json, type, objectNavigator, fieldNamingPolicy, objectConstructor, deserializers, context);
} }
@Override @Override
@ -52,7 +54,7 @@ final class JsonObjectDeserializationVisitor<T> extends JsonDeserializationVisit
public void visitObjectField(FieldAttributes f, Type typeOfF, Object obj) { public void visitObjectField(FieldAttributes f, Type typeOfF, Object obj) {
try { try {
if (!json.isJsonObject()) { if (!json.isJsonObject()) {
throw new JsonParseException("Expecting object found: " + json); throw new JsonParseException("Expecting object found: " + json);
} }
JsonObject jsonObject = json.getAsJsonObject(); JsonObject jsonObject = json.getAsJsonObject();
String fName = getFieldName(f); String fName = getFieldName(f);
@ -71,7 +73,7 @@ final class JsonObjectDeserializationVisitor<T> extends JsonDeserializationVisit
public void visitArrayField(FieldAttributes f, Type typeOfF, Object obj) { public void visitArrayField(FieldAttributes f, Type typeOfF, Object obj) {
try { try {
if (!json.isJsonObject()) { if (!json.isJsonObject()) {
throw new JsonParseException("Expecting object found: " + json); throw new JsonParseException("Expecting object found: " + json);
} }
JsonObject jsonObject = json.getAsJsonObject(); JsonObject jsonObject = json.getAsJsonObject();
String fName = getFieldName(f); String fName = getFieldName(f);
@ -88,22 +90,21 @@ final class JsonObjectDeserializationVisitor<T> extends JsonDeserializationVisit
} }
private String getFieldName(FieldAttributes f) { private String getFieldName(FieldAttributes f) {
FieldNamingStrategy2 namingPolicy = factory.getFieldNamingPolicy(); return fieldNamingPolicy.translateName(f);
return namingPolicy.translateName(f);
} }
public boolean visitFieldUsingCustomHandler(FieldAttributes f, Type declaredTypeOfField, Object parent) { public boolean visitFieldUsingCustomHandler(FieldAttributes f, Type declaredTypeOfField, Object parent) {
try { try {
String fName = getFieldName(f); String fName = getFieldName(f);
if (!json.isJsonObject()) { if (!json.isJsonObject()) {
throw new JsonParseException("Expecting object found: " + json); throw new JsonParseException("Expecting object found: " + json);
} }
JsonElement child = json.getAsJsonObject().get(fName); 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 if (child == null) { // Child will be null if the field wasn't present in Json
return true; return true;
} else if (child.isJsonNull()) { } else if (child.isJsonNull()) {
if (!typeInfo.isPrimitive()) { if (!isPrimitive) {
f.set(parent, null); f.set(parent, null);
} }
return true; return true;
@ -112,9 +113,9 @@ final class JsonObjectDeserializationVisitor<T> extends JsonDeserializationVisit
Pair<JsonDeserializer<?>, ObjectTypePair> pair = objTypePair.getMatchingHandler(deserializers); Pair<JsonDeserializer<?>, ObjectTypePair> pair = objTypePair.getMatchingHandler(deserializers);
if (pair == null) { if (pair == null) {
return false; return false;
} }
Object value = invokeCustomDeserializer(child, pair); Object value = invokeCustomDeserializer(child, pair);
if (value != null || !typeInfo.isPrimitive()) { if (value != null || !isPrimitive) {
f.set(parent, value); f.set(parent, value);
} }
return true; return true;

View File

@ -15,15 +15,14 @@
*/ */
package org.mcteam.factions.gson; 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.EOFException;
import java.io.IOException; import java.io.IOException;
import java.io.Reader; import java.io.Reader;
import java.io.StringReader; 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 * A parser to parse Json into a parse tree of {@link JsonElement}s
* *

View File

@ -16,6 +16,8 @@
package org.mcteam.factions.gson; package org.mcteam.factions.gson;
import org.mcteam.factions.gson.internal.$Gson$Preconditions;
import java.io.IOException; import java.io.IOException;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.math.BigInteger; import java.math.BigInteger;
@ -92,8 +94,8 @@ public final class JsonPrimitive extends JsonElement {
char c = ((Character) primitive).charValue(); char c = ((Character) primitive).charValue();
this.value = String.valueOf(c); this.value = String.valueOf(c);
} else { } else {
Preconditions.checkArgument(primitive instanceof Number $Gson$Preconditions.checkArgument(primitive instanceof Number
|| isPrimitiveOrString(primitive)); || isPrimitiveOrString(primitive));
this.value = primitive; this.value = primitive;
} }
} }
@ -111,7 +113,6 @@ public final class JsonPrimitive extends JsonElement {
* convenience method to get this element as a {@link Boolean}. * convenience method to get this element as a {@link Boolean}.
* *
* @return 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 @Override
Boolean getAsBooleanWrapper() { Boolean getAsBooleanWrapper() {
@ -122,7 +123,6 @@ public final class JsonPrimitive extends JsonElement {
* convenience method to get this element as a boolean value. * convenience method to get this element as a boolean value.
* *
* @return get this element as a primitive boolean value. * @return get this element as a primitive boolean value.
* @throws ClassCastException if the value contained is not a valid boolean value.
*/ */
@Override @Override
public boolean getAsBoolean() { public boolean getAsBoolean() {
@ -142,7 +142,7 @@ public final class JsonPrimitive extends JsonElement {
* convenience method to get this element as a Number. * convenience method to get this element as a Number.
* *
* @return 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 @Override
public Number getAsNumber() { public Number getAsNumber() {
@ -179,7 +179,6 @@ public final class JsonPrimitive extends JsonElement {
* convenience method to get this element as a String. * convenience method to get this element as a String.
* *
* @return 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 @Override
public String getAsString() { public String getAsString() {
@ -196,7 +195,7 @@ public final class JsonPrimitive extends JsonElement {
* convenience method to get this element as a primitive double. * convenience method to get this element as a primitive double.
* *
* @return 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 @Override
public double getAsDouble() { public double getAsDouble() {
@ -229,7 +228,7 @@ public final class JsonPrimitive extends JsonElement {
* convenience method to get this element as a float. * convenience method to get this element as a float.
* *
* @return 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 @Override
public float getAsFloat() { public float getAsFloat() {
@ -240,7 +239,7 @@ public final class JsonPrimitive extends JsonElement {
* convenience method to get this element as a primitive long. * convenience method to get this element as a primitive long.
* *
* @return 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 @Override
public long getAsLong() { public long getAsLong() {
@ -251,7 +250,7 @@ public final class JsonPrimitive extends JsonElement {
* convenience method to get this element as a primitive short. * convenience method to get this element as a primitive short.
* *
* @return 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 @Override
public short getAsShort() { public short getAsShort() {
@ -262,7 +261,7 @@ public final class JsonPrimitive extends JsonElement {
* convenience method to get this element as a primitive integer. * convenience method to get this element as a primitive integer.
* *
* @return 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 @Override
public int getAsInt() { public int getAsInt() {
@ -356,7 +355,11 @@ public final class JsonPrimitive extends JsonElement {
return getAsNumber().longValue() == other.getAsNumber().longValue(); return getAsNumber().longValue() == other.getAsNumber().longValue();
} }
if (isFloatingPoint(this) && isFloatingPoint(other)) { 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); return value.equals(other.value);
} }

View File

@ -16,6 +16,7 @@
package org.mcteam.factions.gson; package org.mcteam.factions.gson;
import java.lang.reflect.Type; import java.lang.reflect.Type;
/** /**
@ -25,14 +26,17 @@ import java.lang.reflect.Type;
*/ */
final class JsonSerializationContextDefault implements JsonSerializationContext { final class JsonSerializationContextDefault implements JsonSerializationContext {
private final ObjectNavigatorFactory factory; private final ObjectNavigator objectNavigator;
private final FieldNamingStrategy2 fieldNamingPolicy;
private final ParameterizedTypeHandlerMap<JsonSerializer<?>> serializers; private final ParameterizedTypeHandlerMap<JsonSerializer<?>> serializers;
private final boolean serializeNulls; private final boolean serializeNulls;
private final MemoryRefStack ancestors; private final MemoryRefStack ancestors;
JsonSerializationContextDefault(ObjectNavigatorFactory factory, boolean serializeNulls, JsonSerializationContextDefault(ObjectNavigator objectNavigator,
FieldNamingStrategy2 fieldNamingPolicy, boolean serializeNulls,
ParameterizedTypeHandlerMap<JsonSerializer<?>> serializers) { ParameterizedTypeHandlerMap<JsonSerializer<?>> serializers) {
this.factory = factory; this.objectNavigator = objectNavigator;
this.fieldNamingPolicy = fieldNamingPolicy;
this.serializeNulls = serializeNulls; this.serializeNulls = serializeNulls;
this.serializers = serializers; this.serializers = serializers;
this.ancestors = new MemoryRefStack(); this.ancestors = new MemoryRefStack();
@ -42,18 +46,20 @@ final class JsonSerializationContextDefault implements JsonSerializationContext
if (src == null) { if (src == null) {
return JsonNull.createJsonNull(); return JsonNull.createJsonNull();
} }
return serialize(src, src.getClass(), true); return serialize(src, src.getClass(), false);
} }
public JsonElement serialize(Object src, Type typeOfSrc) { public JsonElement serialize(Object src, Type typeOfSrc) {
return serialize(src, typeOfSrc, true); return serialize(src, typeOfSrc, true);
} }
public JsonElement serialize(Object src, Type typeOfSrc, boolean preserveType) { JsonElement serialize(Object src, Type typeOfSrc, boolean preserveType) {
ObjectNavigator on = factory.create(new ObjectTypePair(src, typeOfSrc, preserveType)); if (src == null) {
JsonSerializationVisitor visitor = return JsonNull.createJsonNull();
new JsonSerializationVisitor(factory, serializeNulls, serializers, this, ancestors); }
on.accept(visitor); JsonSerializationVisitor visitor = new JsonSerializationVisitor(
objectNavigator, fieldNamingPolicy, serializeNulls, serializers, this, ancestors);
objectNavigator.accept(new ObjectTypePair(src, typeOfSrc, preserveType), visitor);
return visitor.getJsonElement(); return visitor.getJsonElement();
} }
} }

View File

@ -16,6 +16,9 @@
package org.mcteam.factions.gson; 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.Array;
import java.lang.reflect.Type; import java.lang.reflect.Type;
@ -27,17 +30,19 @@ import java.lang.reflect.Type;
*/ */
final class JsonSerializationVisitor implements ObjectNavigator.Visitor { final class JsonSerializationVisitor implements ObjectNavigator.Visitor {
private final ObjectNavigatorFactory factory; private final ObjectNavigator objectNavigator;
private final FieldNamingStrategy2 fieldNamingPolicy;
private final ParameterizedTypeHandlerMap<JsonSerializer<?>> serializers; private final ParameterizedTypeHandlerMap<JsonSerializer<?>> serializers;
private final boolean serializeNulls; private final boolean serializeNulls;
private final JsonSerializationContext context; private final JsonSerializationContext context;
private final MemoryRefStack ancestors; private final MemoryRefStack ancestors;
private JsonElement root; private JsonElement root;
JsonSerializationVisitor(ObjectNavigatorFactory factory, boolean serializeNulls, JsonSerializationVisitor(ObjectNavigator objectNavigator, FieldNamingStrategy2 fieldNamingPolicy,
ParameterizedTypeHandlerMap<JsonSerializer<?>> serializers, JsonSerializationContext context, boolean serializeNulls, ParameterizedTypeHandlerMap<JsonSerializer<?>> serializers,
MemoryRefStack ancestors) { JsonSerializationContext context, MemoryRefStack ancestors) {
this.factory = factory; this.objectNavigator = objectNavigator;
this.fieldNamingPolicy = fieldNamingPolicy;
this.serializeNulls = serializeNulls; this.serializeNulls = serializeNulls;
this.serializers = serializers; this.serializers = serializers;
this.context = context; this.context = context;
@ -71,15 +76,12 @@ final class JsonSerializationVisitor implements ObjectNavigator.Visitor {
public void visitArray(Object array, Type arrayType) { public void visitArray(Object array, Type arrayType) {
assignToRoot(new JsonArray()); assignToRoot(new JsonArray());
int length = Array.getLength(array); int length = Array.getLength(array);
TypeInfoArray fieldTypeInfo = TypeInfoFactory.getTypeInfoForArray(arrayType); Type componentType = $Gson$Types.getArrayComponentType(arrayType);
Type componentType = fieldTypeInfo.getSecondLevelType();
for (int i = 0; i < length; ++i) { for (int i = 0; i < length; ++i) {
Object child = Array.get(array, i); Object child = Array.get(array, i);
Type childType = componentType;
// we should not get more specific component type yet since it is possible // we should not get more specific component type yet since it is possible
// that a custom // that a custom serializer is registered for the componentType
// serializer is registered for the componentType addAsArrayElement(new ObjectTypePair(child, componentType, false));
addAsArrayElement(new ObjectTypePair(child, childType, false));
} }
} }
@ -127,8 +129,7 @@ final class JsonSerializationVisitor implements ObjectNavigator.Visitor {
} }
private void addChildAsElement(FieldAttributes f, JsonElement childElement) { private void addChildAsElement(FieldAttributes f, JsonElement childElement) {
FieldNamingStrategy2 namingPolicy = factory.getFieldNamingPolicy(); root.getAsJsonObject().add(fieldNamingPolicy.translateName(f), childElement);
root.getAsJsonObject().add(namingPolicy.translateName(f), childElement);
} }
private void addAsArrayElement(ObjectTypePair elementTypePair) { private void addAsArrayElement(ObjectTypePair elementTypePair) {
@ -141,10 +142,9 @@ final class JsonSerializationVisitor implements ObjectNavigator.Visitor {
} }
private JsonElement getJsonElementForChild(ObjectTypePair fieldValueTypePair) { private JsonElement getJsonElementForChild(ObjectTypePair fieldValueTypePair) {
ObjectNavigator on = factory.create(fieldValueTypePair); JsonSerializationVisitor childVisitor = new JsonSerializationVisitor(
JsonSerializationVisitor childVisitor = objectNavigator, fieldNamingPolicy, serializeNulls, serializers, context, ancestors);
new JsonSerializationVisitor(factory, serializeNulls, serializers, context, ancestors); objectNavigator.accept(fieldValueTypePair, childVisitor);
on.accept(childVisitor);
return childVisitor.getJsonElement(); return childVisitor.getJsonElement();
} }
@ -171,7 +171,7 @@ final class JsonSerializationVisitor implements ObjectNavigator.Visitor {
/** /**
* objTypePair.getObject() must not be null * objTypePair.getObject() must not be null
*/ */
@SuppressWarnings({"unchecked", "rawtypes"}) @SuppressWarnings("unchecked")
private JsonElement findAndInvokeCustomSerializer(ObjectTypePair objTypePair) { private JsonElement findAndInvokeCustomSerializer(ObjectTypePair objTypePair) {
Pair<JsonSerializer<?>,ObjectTypePair> pair = objTypePair.getMatchingHandler(serializers); Pair<JsonSerializer<?>,ObjectTypePair> pair = objTypePair.getMatchingHandler(serializers);
if (pair == null) { 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 { try {
Preconditions.checkState(root.isJsonObject()); $Gson$Preconditions.checkState(root.isJsonObject());
Object obj = f.get(parent); Object obj = f.get(parent);
if (obj == null) { if (obj == null) {
if (serializeNulls) { if (serializeNulls) {
@ -214,8 +215,7 @@ final class JsonSerializationVisitor implements ObjectNavigator.Visitor {
} }
private void assignToRoot(JsonElement newRoot) { private void assignToRoot(JsonElement newRoot) {
Preconditions.checkNotNull(newRoot); root = $Gson$Preconditions.checkNotNull(newRoot);
root = newRoot;
} }
private boolean isFieldNull(FieldAttributes f, Object obj) { private boolean isFieldNull(FieldAttributes f, Object obj) {

View File

@ -26,7 +26,6 @@ import org.mcteam.factions.gson.stream.JsonReader;
import org.mcteam.factions.gson.stream.JsonToken; import org.mcteam.factions.gson.stream.JsonToken;
import org.mcteam.factions.gson.stream.MalformedJsonException; import org.mcteam.factions.gson.stream.MalformedJsonException;
/** /**
* A streaming parser that allows reading of multiple {@link JsonElement}s from the specified reader * A streaming parser that allows reading of multiple {@link JsonElement}s from the specified reader
* asynchronously. * asynchronously.

View File

@ -16,6 +16,7 @@
package org.mcteam.factions.gson; package org.mcteam.factions.gson;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.Map; 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 * 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 * LRU (least recently used) algorithm. Object start getting evicted from the cache once the
* {@code maxCapacity} is reached. * {@code maxCapacity} is reached.
* *
* @author Inderjeet Singh * @author Inderjeet Singh
* @author Joel Leitch * @author Joel Leitch
*/ */
@ -32,33 +33,23 @@ final class LruCache<K, V> extends LinkedHashMap<K, V> implements Cache<K, V> {
private final int maxCapacity; private final int maxCapacity;
LruCache(int maxCapacity) { public LruCache(int maxCapacity) {
super(maxCapacity, 0.7F, true); super(maxCapacity, 0.7F, true);
this.maxCapacity = maxCapacity; this.maxCapacity = maxCapacity;
} }
public void addElement(K key, V value) { public synchronized void addElement(K key, V value) {
put(key, value); put(key, value);
} }
@Override public synchronized V getElement(K key) {
public void clear() {
super.clear();
}
public V getElement(K key) {
return get(key); return get(key);
} }
public V removeElement(K key) { public synchronized V removeElement(K key) {
return remove(key); return remove(key);
} }
@Override
public int size() {
return super.size();
}
@Override @Override
protected boolean removeEldestEntry(Map.Entry<K, V> entry) { protected boolean removeEldestEntry(Map.Entry<K, V> entry) {
return size() > maxCapacity; return size() > maxCapacity;

View File

@ -19,7 +19,6 @@ package org.mcteam.factions.gson;
import java.lang.reflect.ParameterizedType; import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type; import java.lang.reflect.Type;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List; import java.util.List;
import java.util.Map; 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 * 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 * just the {@link Object#toString() toString()} of the map key. Attempting to
* convert the above JSON to an object fails with a parse exception: * convert the above JSON to an object fails with a parse exception:
* <pre>com.bukkit.mcteam.gson.JsonParseException: Expecting object found: "(5,6)" * <pre>org.mcteam.factions.gson.JsonParseException: Expecting object found: "(5,6)"
* at com.bukkit.mcteam.gson.JsonObjectDeserializationVisitor.visitFieldUsingCustomHandler * at org.mcteam.factions.gson.JsonObjectDeserializationVisitor.visitFieldUsingCustomHandler
* at com.bukkit.mcteam.gson.ObjectNavigator.navigateClassFields * at org.mcteam.factions.gson.ObjectNavigator.navigateClassFields
* ...</pre> * ...</pre>
* *
* <h3>Maps as JSON arrays</h3> * <h3>Maps as JSON arrays</h3>
@ -90,12 +89,13 @@ import java.util.Map;
* complex. A key is complex if its JSON-serialized form is an array or an * complex. A key is complex if its JSON-serialized form is an array or an
* object. * object.
*/ */
public final class MapAsArrayTypeAdapter final class MapAsArrayTypeAdapter
extends BaseMapTypeAdapter
implements JsonSerializer<Map<?, ?>>, JsonDeserializer<Map<?, ?>> { implements JsonSerializer<Map<?, ?>>, JsonDeserializer<Map<?, ?>> {
public Map<?, ?> deserialize(JsonElement json, Type typeOfT, public Map<?, ?> deserialize(JsonElement json, Type typeOfT,
JsonDeserializationContext context) throws JsonParseException { JsonDeserializationContext context) throws JsonParseException {
Map<Object, Object> result = new LinkedHashMap<Object, Object>(); Map<Object, Object> result = constructMapType(typeOfT, context);
Type[] keyAndValueType = typeToTypeArguments(typeOfT); Type[] keyAndValueType = typeToTypeArguments(typeOfT);
if (json.isJsonArray()) { if (json.isJsonArray()) {
JsonArray array = json.getAsJsonArray(); JsonArray array = json.getAsJsonArray();
@ -123,10 +123,10 @@ public final class MapAsArrayTypeAdapter
boolean serializeAsArray = false; boolean serializeAsArray = false;
List<JsonElement> keysAndValues = new ArrayList<JsonElement>(); List<JsonElement> keysAndValues = new ArrayList<JsonElement>();
for (Map.Entry<?, ?> entry : src.entrySet()) { 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(); serializeAsArray |= key.isJsonObject() || key.isJsonArray();
keysAndValues.add(key); keysAndValues.add(key);
keysAndValues.add(context.serialize(entry.getValue(), keyAndValueType[1])); keysAndValues.add(serialize(context, entry.getValue(), keyAndValueType[1]));
} }
if (serializeAsArray) { if (serializeAsArray) {

View File

@ -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<Map.Entry>) 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<Object, Object> map = constructMapType(typeOfT, context);
Type[] keyAndValueTypes = $Gson$Types.getMapKeyAndValueTypes(typeOfT, $Gson$Types.getRawType(typeOfT));
for (Map.Entry<String, JsonElement> entry : json.getAsJsonObject().entrySet()) {
Object key = context.deserialize(new JsonPrimitive(entry.getKey()), keyAndValueTypes[0]);
Object value = context.deserialize(entry.getValue(), keyAndValueTypes[1]);
map.put(key, value);
}
return map;
}
@Override
public String toString() {
return MapTypeAdapter.class.getSimpleName();
}
}

View File

@ -16,13 +16,10 @@
package org.mcteam.factions.gson; 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.Array;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Type; 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 * This class contains a mapping of all the application specific
@ -35,10 +32,12 @@ import java.util.logging.Logger;
* @author Joel Leitch * @author Joel Leitch
*/ */
final class MappedObjectConstructor implements ObjectConstructor { 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<InstanceCreator<?>> instanceCreatorMap; private final ParameterizedTypeHandlerMap<InstanceCreator<?>> instanceCreatorMap;
public MappedObjectConstructor( public MappedObjectConstructor(
ParameterizedTypeHandlerMap<InstanceCreator<?>> instanceCreators) { ParameterizedTypeHandlerMap<InstanceCreator<?>> instanceCreators) {
instanceCreatorMap = instanceCreators; instanceCreatorMap = instanceCreators;
@ -50,61 +49,27 @@ final class MappedObjectConstructor implements ObjectConstructor {
if (creator != null) { if (creator != null) {
return creator.createInstance(typeOfT); return creator.createInstance(typeOfT);
} }
return (T) constructWithNoArgConstructor(typeOfT); return (T) constructWithAllocators(typeOfT);
} }
public Object constructArray(Type type, int length) { public Object constructArray(Type type, int length) {
return Array.newInstance(TypeUtils.toRawClass(type), length); return Array.newInstance($Gson$Types.getRawType(type), length);
}
private <T> T constructWithNoArgConstructor(Type typeOfT) {
try {
Constructor<T> 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);
}
} }
@SuppressWarnings({"unchecked", "cast"}) @SuppressWarnings({"unchecked", "cast"})
private <T> Constructor<T> getNoArgsConstructor(Type typeOfT) { private <T> T constructWithAllocators(Type typeOfT) {
TypeInfo typeInfo = new TypeInfo(typeOfT); try {
Class<T> clazz = (Class<T>) typeInfo.getRawClass(); Class<T> clazz = (Class<T>) $Gson$Types.getRawType(typeOfT);
Constructor<T>[] declaredConstructors = (Constructor<T>[]) clazz.getDeclaredConstructors(); T obj = defaultConstructorAllocator.newInstance(clazz);
AccessibleObject.setAccessible(declaredConstructors, true); return (obj == null)
for (Constructor<T> constructor : declaredConstructors) { ? unsafeAllocator.newInstance(clazz)
if (constructor.getParameterTypes().length == 0) { : obj;
return constructor; } 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 <T> 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
*/
<T> 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 @Override
public String toString() { public String toString() {
return instanceCreatorMap.toString(); return instanceCreatorMap.toString();

View File

@ -16,6 +16,8 @@
package org.mcteam.factions.gson; package org.mcteam.factions.gson;
import org.mcteam.factions.gson.internal.$Gson$Preconditions;
import java.util.Stack; import java.util.Stack;
/** /**
@ -35,8 +37,7 @@ final class MemoryRefStack {
* @return the object that was added * @return the object that was added
*/ */
public ObjectTypePair push(ObjectTypePair obj) { public ObjectTypePair push(ObjectTypePair obj) {
Preconditions.checkNotNull(obj); $Gson$Preconditions.checkNotNull(obj);
return stack.push(obj); return stack.push(obj);
} }

View File

@ -16,6 +16,8 @@
package org.mcteam.factions.gson; package org.mcteam.factions.gson;
import org.mcteam.factions.gson.internal.$Gson$Preconditions;
import java.lang.annotation.Annotation; import java.lang.annotation.Annotation;
import java.lang.reflect.Type; import java.lang.reflect.Type;
import java.util.Collection; import java.util.Collection;
@ -62,9 +64,8 @@ final class ModifyFirstLetterNamingPolicy extends RecursiveFieldNamingPolicy {
* @param modifier the type of modification that should be performed * @param modifier the type of modification that should be performed
* @throws IllegalArgumentException if {@code modifier} is null * @throws IllegalArgumentException if {@code modifier} is null
*/ */
public ModifyFirstLetterNamingPolicy(LetterModifier modifier) { ModifyFirstLetterNamingPolicy(LetterModifier modifier) {
Preconditions.checkNotNull(modifier); this.letterModifier = $Gson$Preconditions.checkNotNull(modifier);
this.letterModifier = modifier;
} }
@Override @Override
@ -100,8 +101,8 @@ final class ModifyFirstLetterNamingPolicy extends RecursiveFieldNamingPolicy {
} }
private String modifyString(char firstCharacter, String srcString, int indexOfSubstring) { private String modifyString(char firstCharacter, String srcString, int indexOfSubstring) {
return indexOfSubstring < srcString.length() ? return (indexOfSubstring < srcString.length())
firstCharacter + srcString.substring(indexOfSubstring) ? firstCharacter + srcString.substring(indexOfSubstring)
: String.valueOf(firstCharacter); : String.valueOf(firstCharacter);
} }
} }

View File

@ -16,7 +16,6 @@
package org.mcteam.factions.gson; package org.mcteam.factions.gson;
/** /**
* This acts as a "Null Object" pattern for the {@link ExclusionStrategy}. * This acts as a "Null Object" pattern for the {@link ExclusionStrategy}.
* Passing an instance of this class into the {@link ObjectNavigator} will * Passing an instance of this class into the {@link ObjectNavigator} will

View File

@ -16,14 +16,14 @@
package org.mcteam.factions.gson; package org.mcteam.factions.gson;
import java.lang.reflect.AccessibleObject; import org.mcteam.factions.gson.internal.$Gson$Types;
import java.lang.reflect.Field;
import java.lang.reflect.Type; import java.lang.reflect.Type;
/** /**
* Provides ability to apply a visitor to an object and all of its fields * Provides ability to apply a visitor to an object and all of its fields
* recursively. * recursively.
* *
* @author Inderjeet Singh * @author Inderjeet Singh
* @author Joel Leitch * @author Joel Leitch
*/ */
@ -57,7 +57,7 @@ final class ObjectNavigator {
/** /**
* This is called to visit an object using a custom handler * This is called to visit an object using a custom handler
* *
* @return true if a custom handler exists, false otherwise * @return true if a custom handler exists, false otherwise
*/ */
public boolean visitUsingCustomHandler(ObjectTypePair objTypePair); public boolean visitUsingCustomHandler(ObjectTypePair objTypePair);
@ -69,38 +69,33 @@ final class ObjectNavigator {
public boolean visitFieldUsingCustomHandler(FieldAttributes f, Type actualTypeOfField, public boolean visitFieldUsingCustomHandler(FieldAttributes f, Type actualTypeOfField,
Object parent); Object parent);
void visitPrimitive(Object primitive);
/** /**
* Retrieve the current target * Retrieve the current target
*/ */
Object getTarget(); Object getTarget();
void visitPrimitive(Object primitive);
} }
private final ExclusionStrategy exclusionStrategy; private final ExclusionStrategy exclusionStrategy;
private final ObjectTypePair objTypePair; private final ReflectingFieldNavigator reflectingFieldNavigator;
/** /**
* @param objTypePair * @param strategy the concrete exclusion strategy object to be used to filter out fields of an
* The object,type (fully genericized) being navigated
* @param exclusionStrategy
* the concrete strategy object to be used to filter out fields of an
* object. * object.
*/ */
ObjectNavigator(ObjectTypePair objTypePair, ExclusionStrategy exclusionStrategy) { ObjectNavigator(ExclusionStrategy strategy) {
Preconditions.checkNotNull(exclusionStrategy); this.exclusionStrategy = strategy == null ? new NullExclusionStrategy() : strategy;
this.reflectingFieldNavigator = new ReflectingFieldNavigator(exclusionStrategy);
this.objTypePair = objTypePair;
this.exclusionStrategy = exclusionStrategy;
} }
/** /**
* Navigate all the fields of the specified object. If a field is null, it * Navigate all the fields of the specified object. If a field is null, it
* does not get visited. * does not get visited.
* @param objTypePair The object,type (fully genericized) being navigated
*/ */
public void accept(Visitor visitor) { public void accept(ObjectTypePair objTypePair, Visitor visitor) {
TypeInfo objTypeInfo = new TypeInfo(objTypePair.type); if (exclusionStrategy.shouldSkipClass($Gson$Types.getRawType(objTypePair.type))) {
if (exclusionStrategy.shouldSkipClass(objTypeInfo.getRawClass())) {
return; return;
} }
boolean visitedWithCustomHandler = visitor.visitUsingCustomHandler(objTypePair); boolean visitedWithCustomHandler = visitor.visitUsingCustomHandler(objTypePair);
@ -113,24 +108,16 @@ final class ObjectNavigator {
objTypePair.setObject(objectToVisit); objTypePair.setObject(objectToVisit);
visitor.start(objTypePair); visitor.start(objTypePair);
try { try {
if (objTypeInfo.isArray()) { if ($Gson$Types.isArray(objTypePair.type)) {
visitor.visitArray(objectToVisit, objTypePair.type); visitor.visitArray(objectToVisit, objTypePair.type);
} else if (objTypeInfo.getActualType() == Object.class } else if (objTypePair.type == Object.class && isPrimitiveOrString(objectToVisit)) {
&& isPrimitiveOrString(objectToVisit)) {
// TODO(Joel): this is only used for deserialization of "primitives" // TODO(Joel): this is only used for deserialization of "primitives"
// we should rethink this!!! // we should rethink this!!!
visitor.visitPrimitive(objectToVisit); visitor.visitPrimitive(objectToVisit);
objectToVisit = visitor.getTarget(); visitor.getTarget();
} else { } else {
visitor.startVisitingObject(objectToVisit); visitor.startVisitingObject(objectToVisit);
ObjectTypePair currObjTypePair = objTypePair.toMoreSpecificType(); reflectingFieldNavigator.visitFieldsReflectively(objTypePair, visitor);
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);
}
}
} }
} finally { } finally {
visitor.end(objTypePair); 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(); Class<?> realClazz = objectToVisit.getClass();
return realClazz == Object.class || realClazz == String.class return realClazz == Object.class || realClazz == String.class
|| Primitives.unwrap(realClazz).isPrimitive(); || 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);
}
}
}
}
} }

View File

@ -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;
}
}

View File

@ -15,6 +15,7 @@
*/ */
package org.mcteam.factions.gson; package org.mcteam.factions.gson;
import java.lang.reflect.Type; import java.lang.reflect.Type;
/** /**
@ -55,7 +56,7 @@ final class ObjectTypePair {
HANDLER handler = null; HANDLER handler = null;
if (!preserveType && obj != null) { if (!preserveType && obj != null) {
// First try looking up the handler for the actual type // First try looking up the handler for the actual type
ObjectTypePair moreSpecificType = toMoreSpecificType(); ObjectTypePair moreSpecificType = toMoreSpecificType();
handler = handlers.getHandlerFor(moreSpecificType.type); handler = handlers.getHandlerFor(moreSpecificType.type);
if (handler != null) { if (handler != null) {
return new Pair<HANDLER, ObjectTypePair>(handler, moreSpecificType); return new Pair<HANDLER, ObjectTypePair>(handler, moreSpecificType);
@ -66,7 +67,7 @@ final class ObjectTypePair {
return handler == null ? null : new Pair<HANDLER, ObjectTypePair>(handler, this); return handler == null ? null : new Pair<HANDLER, ObjectTypePair>(handler, this);
} }
ObjectTypePair toMoreSpecificType() { ObjectTypePair toMoreSpecificType() {
if (preserveType || obj == null) { if (preserveType || obj == null) {
return this; return this;
} }
@ -77,9 +78,16 @@ final class ObjectTypePair {
return new ObjectTypePair(obj, actualType, preserveType); 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 // This takes care of situations where the field was declared as an Object, but the
// actual value contains something more specific. See Issue 54. // 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). // the actual object is of a raw type (which is a sub-class of the generic type).
static Type getActualTypeIfMoreSpecific(Type type, Class<?> actualClass) { static Type getActualTypeIfMoreSpecific(Type type, Class<?> actualClass) {
if (type instanceof Class<?>) { if (type instanceof Class<?>) {
@ -89,7 +97,7 @@ final class ObjectTypePair {
} }
if (type == Object.class) { if (type == Object.class) {
type = actualClass; type = actualClass;
} }
} }
return type; return type;
} }

View File

@ -26,11 +26,10 @@ package org.mcteam.factions.gson;
* @param <SECOND> * @param <SECOND>
*/ */
final class Pair<FIRST, SECOND> { final class Pair<FIRST, SECOND> {
public final FIRST first;
public final SECOND second;
final FIRST first; public Pair(FIRST first, SECOND second) {
final SECOND second;
Pair(FIRST first, SECOND second) {
this.first = first; this.first = first;
this.second = second; this.second = second;
} }

View File

@ -16,6 +16,8 @@
package org.mcteam.factions.gson; package org.mcteam.factions.gson;
import org.mcteam.factions.gson.internal.$Gson$Types;
import java.lang.reflect.Type; import java.lang.reflect.Type;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; 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 * A map that provides ability to associate handlers for a specific type or all
* of its sub-types * of its sub-types
* *
* @author Inderjeet Singh * @author Inderjeet Singh
* @author Joel Leitch * @author Joel Leitch
* *
* @param <T> The handler that will be looked up by type * @param <T> The handler that will be looked up by type
*/ */
final class ParameterizedTypeHandlerMap<T> { final class ParameterizedTypeHandlerMap<T> {
@ -105,6 +107,21 @@ final class ParameterizedTypeHandlerMap<T> {
} }
} }
public synchronized void register(ParameterizedTypeHandlerMap<T> other) {
if (!modifiable) {
throw new IllegalStateException("Attempted to modify an unmodifiable map.");
}
for (Map.Entry<Type, T> 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<Class<?>, T> entry = other.typeHierarchyList.get(i);
registerForTypeHierarchy(entry);
}
}
public synchronized void registerIfAbsent(Type typeOfT, T value) { public synchronized void registerIfAbsent(Type typeOfT, T value) {
if (!modifiable) { if (!modifiable) {
throw new IllegalStateException("Attempted to modify an unmodifiable map."); throw new IllegalStateException("Attempted to modify an unmodifiable map.");
@ -121,7 +138,7 @@ final class ParameterizedTypeHandlerMap<T> {
public synchronized T getHandlerFor(Type type) { public synchronized T getHandlerFor(Type type) {
T handler = map.get(type); T handler = map.get(type);
if (handler == null) { if (handler == null) {
Class<?> rawClass = TypeUtils.toRawClass(type); Class<?> rawClass = $Gson$Types.getRawType(type);
if (rawClass != type) { if (rawClass != type) {
handler = getHandlerFor(rawClass); handler = getHandlerFor(rawClass);
} }
@ -157,12 +174,10 @@ final class ParameterizedTypeHandlerMap<T> {
public synchronized ParameterizedTypeHandlerMap<T> copyOf() { public synchronized ParameterizedTypeHandlerMap<T> copyOf() {
ParameterizedTypeHandlerMap<T> copy = new ParameterizedTypeHandlerMap<T>(); ParameterizedTypeHandlerMap<T> copy = new ParameterizedTypeHandlerMap<T>();
for (Map.Entry<Type, T> entry : map.entrySet()) { // Instead of individually registering entries in the map, make an efficient copy
copy.register(entry.getKey(), entry.getValue()); // of the list and map
} copy.map.putAll(map);
for (Pair<Class<?>, T> entry : typeHierarchyList) { copy.typeHierarchyList.addAll(typeHierarchyList);
copy.registerForTypeHierarchy(entry);
}
return copy; return copy;
} }
@ -195,6 +210,6 @@ final class ParameterizedTypeHandlerMap<T> {
} }
private String typeToString(Type type) { private String typeToString(Type type) {
return TypeUtils.toRawClass(type).getSimpleName(); return $Gson$Types.getRawType(type).getSimpleName();
} }
} }

View File

@ -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}.
*
* <p>Here's an example class:
* <pre>
* class Foo<T> {
* private List<T> someList;
*
* Foo(List<T> list) {
* this.someList = list;
* }
* }
* </pre>
*
* @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());
}
}

View File

@ -16,10 +16,14 @@
package org.mcteam.factions.gson; package org.mcteam.factions.gson;
import java.lang.reflect.Type;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import org.mcteam.factions.gson.internal.$Gson$Preconditions;
/** /**
* Contains static utility methods pertaining to primitive types and their * Contains static utility methods pertaining to primitive types and their
* corresponding wrapper types. * corresponding wrapper types.
@ -30,13 +34,13 @@ final class Primitives {
private Primitives() {} private Primitives() {}
/** A map from primitive types to their corresponding wrapper types. */ /** A map from primitive types to their corresponding wrapper types. */
public static final Map<Class<?>, Class<?>> PRIMITIVE_TO_WRAPPER_TYPE; private static final Map<Class<?>, Class<?>> PRIMITIVE_TO_WRAPPER_TYPE;
/** A map from wrapper types to their corresponding primitive types. */ /** A map from wrapper types to their corresponding primitive types. */
public static final Map<Class<?>, Class<?>> WRAPPER_TO_PRIMITIVE_TYPE; private static final Map<Class<?>, Class<?>> WRAPPER_TO_PRIMITIVE_TYPE;
// Sad that we can't use a BiMap. :( // Sad that we can't use a BiMap. :(
static { static {
Map<Class<?>, Class<?>> primToWrap = new HashMap<Class<?>, Class<?>>(16); Map<Class<?>, Class<?>> primToWrap = new HashMap<Class<?>, Class<?>>(16);
Map<Class<?>, Class<?>> wrapToPrim = new HashMap<Class<?>, Class<?>>(16); Map<Class<?>, Class<?>> wrapToPrim = new HashMap<Class<?>, Class<?>>(16);
@ -61,6 +65,13 @@ final class Primitives {
backward.put(value, key); 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 * Returns {@code true} if {@code type} is one of the nine
* primitive-wrapper types, such as {@link Integer}. * primitive-wrapper types, such as {@link Integer}.
@ -68,12 +79,8 @@ final class Primitives {
* @see Class#isPrimitive * @see Class#isPrimitive
*/ */
public static boolean isWrapperType(Class<?> type) { public static boolean isWrapperType(Class<?> type) {
return WRAPPER_TO_PRIMITIVE_TYPE.containsKey(checkNotNull(type)); return WRAPPER_TO_PRIMITIVE_TYPE.containsKey(
} $Gson$Preconditions.checkNotNull(type));
private static Class<?> checkNotNull(Class<?> type) {
Preconditions.checkNotNull(type);
return type;
} }
/** /**
@ -86,11 +93,10 @@ final class Primitives {
* </pre> * </pre>
*/ */
public static <T> Class<T> wrap(Class<T> type) { public static <T> Class<T> wrap(Class<T> type) {
checkNotNull(type);
// cast is safe: long.class and Long.class are both of type Class<Long> // cast is safe: long.class and Long.class are both of type Class<Long>
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
Class<T> wrapped = (Class<T>) PRIMITIVE_TO_WRAPPER_TYPE.get(type); Class<T> wrapped = (Class<T>) PRIMITIVE_TO_WRAPPER_TYPE.get(
$Gson$Preconditions.checkNotNull(type));
return (wrapped == null) ? type : wrapped; return (wrapped == null) ? type : wrapped;
} }
@ -104,11 +110,10 @@ final class Primitives {
* </pre> * </pre>
*/ */
public static <T> Class<T> unwrap(Class<T> type) { public static <T> Class<T> unwrap(Class<T> type) {
checkNotNull(type);
// cast is safe: long.class and Long.class are both of type Class<Long> // cast is safe: long.class and Long.class are both of type Class<Long>
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
Class<T> unwrapped = (Class<T>) WRAPPER_TO_PRIMITIVE_TYPE.get(type); Class<T> unwrapped = (Class<T>) WRAPPER_TO_PRIMITIVE_TYPE.get(
$Gson$Preconditions.checkNotNull(type));
return (unwrapped == null) ? type : unwrapped; return (unwrapped == null) ? type : unwrapped;
} }
} }

View File

@ -30,7 +30,6 @@ import java.util.Collection;
abstract class RecursiveFieldNamingPolicy implements FieldNamingStrategy2 { abstract class RecursiveFieldNamingPolicy implements FieldNamingStrategy2 {
public final String translateName(FieldAttributes f) { public final String translateName(FieldAttributes f) {
Preconditions.checkNotNull(f);
return translateName(f.getName(), f.getDeclaredType(), f.getAnnotations()); return translateName(f.getName(), f.getDeclaredType(), f.getAnnotations());
} }

View File

@ -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<Type, List<FieldAttributes>> fieldsCache =
new LruCache<Type, List<FieldAttributes>>(500);
private final ExclusionStrategy exclusionStrategy;
/**
* @param exclusionStrategy the concrete strategy object to be used to filter out fields of an
* object.
*/
ReflectingFieldNavigator(ExclusionStrategy exclusionStrategy) {
this.exclusionStrategy = $Gson$Preconditions.checkNotNull(exclusionStrategy);
}
/**
* @param objTypePair The object,type (fully genericized) being navigated
* @param visitor the visitor to visit each field with
*/
void visitFieldsReflectively(ObjectTypePair objTypePair, Visitor visitor) {
Type moreSpecificType = objTypePair.getMoreSpecificType();
Object obj = objTypePair.getObject();
for (FieldAttributes fieldAttributes : getAllFields(moreSpecificType, objTypePair.getType())) {
if (exclusionStrategy.shouldSkipField(fieldAttributes)
|| exclusionStrategy.shouldSkipClass(fieldAttributes.getDeclaredClass())) {
continue; // skip
}
Type resolvedTypeOfField = 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<FieldAttributes> getAllFields(Type type, Type declaredType) {
List<FieldAttributes> fields = fieldsCache.getElement(type);
if (fields == null) {
fields = new ArrayList<FieldAttributes>();
for (Class<?> curr : getInheritanceHierarchy(type)) {
Field[] currentClazzFields = curr.getDeclaredFields();
AccessibleObject.setAccessible(currentClazzFields, true);
Field[] classFields = currentClazzFields;
for (Field f : classFields) {
fields.add(new FieldAttributes(curr, f, declaredType));
}
}
fieldsCache.addElement(type, fields);
}
return fields;
}
/**
* Returns a list of classes corresponding to the inheritance of specified type
*/
private List<Class<?>> getInheritanceHierarchy(Type type) {
List<Class<?>> classes = new ArrayList<Class<?>>();
Class<?> topLevelClass = $Gson$Types.getRawType(type);
for (Class<?> curr = topLevelClass; curr != null && !curr.equals(Object.class); curr =
curr.getSuperclass()) {
if (!curr.isSynthetic()) {
classes.add(curr);
}
}
return classes;
}
}

View File

@ -19,30 +19,30 @@ package org.mcteam.factions.gson;
import org.mcteam.factions.gson.annotations.SerializedName; import org.mcteam.factions.gson.annotations.SerializedName;
/** /**
* A {@link FieldNamingStrategy2} that acts as a chain of responsibility. If the * 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 * {@link org.mcteam.factions.gson.annotations.SerializedName} annotation is applied to a
* strategy will translate the name to the {@code serializedName.value()}; otherwise it delegates * field then this strategy will translate the name to the {@code
* to the wrapped {@link FieldNamingStrategy2}. * serializedName.value()}; otherwise it delegates to the wrapped
* {@link FieldNamingStrategy2}.
* *
* <p>NOTE: this class performs JSON field name validation for any of the fields marked with * <p>
* an {@code @SerializedName} annotation.</p> * NOTE: this class performs JSON field name validation for any of the fields
* marked with an {@code @SerializedName} annotation.
* </p>
* *
* @see SerializedName * @see SerializedName
* *
* @author Joel Leitch * @author Joel Leitch
*/ */
final class SerializedNameAnnotationInterceptingNamingPolicy implements FieldNamingStrategy2 { final class SerializedNameAnnotationInterceptingNamingPolicy implements FieldNamingStrategy2 {
private static final JsonFieldNameValidator fieldNameValidator = new JsonFieldNameValidator();
private final FieldNamingStrategy2 delegate; private final FieldNamingStrategy2 delegate;
public SerializedNameAnnotationInterceptingNamingPolicy(FieldNamingStrategy2 delegate) { SerializedNameAnnotationInterceptingNamingPolicy(FieldNamingStrategy2 delegate) {
this.delegate = delegate; this.delegate = delegate;
} }
public String translateName(FieldAttributes f) { public String translateName(FieldAttributes f) {
Preconditions.checkNotNull(f);
SerializedName serializedName = f.getAnnotation(SerializedName.class); SerializedName serializedName = f.getAnnotation(SerializedName.class);
return serializedName == null ? delegate.translateName(f) return serializedName == null ? delegate.translateName(f) : serializedName.value();
: fieldNameValidator.validate(serializedName.value());
} }
} }

View File

@ -16,15 +16,14 @@
package org.mcteam.factions.gson; 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.EOFException;
import java.io.IOException; import java.io.IOException;
import java.io.Writer; import java.io.Writer;
import java.util.Map; 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. * Reads and writes GSON parse trees over streams.
*/ */

View File

@ -26,7 +26,7 @@ package org.mcteam.factions.gson;
* *
* @since 1.4 * @since 1.4
*/ */
class SyntheticFieldExclusionStrategy implements ExclusionStrategy { final class SyntheticFieldExclusionStrategy implements ExclusionStrategy {
private final boolean skipSyntheticFields; private final boolean skipSyntheticFields;
SyntheticFieldExclusionStrategy(boolean skipSyntheticFields) { SyntheticFieldExclusionStrategy(boolean skipSyntheticFields) {

View File

@ -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> T adaptType(Object from, Class<T> to);
}

View File

@ -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.
* <pre>
* wrap(int.class) == Integer.class
* wrap(Integer.class) == Integer.class
* wrap(String.class) == String.class
* </pre>
*/
public final Class<?> getWrappedClass() {
return Primitives.wrap(rawClass);
}
/**
* @return the raw class associated with this type
*/
public final Class<?> getRawClass() {
return rawClass;
}
public final boolean isCollectionOrArray() {
return Collection.class.isAssignableFrom(rawClass) || isArray();
}
public final boolean isArray() {
return TypeUtils.isArray(rawClass);
}
public final boolean isEnum() {
return rawClass.isEnum();
}
public final boolean isPrimitive() {
return Primitives.isWrapperType(Primitives.wrap(rawClass));
}
}

View File

@ -1,69 +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.GenericArrayType;
import java.lang.reflect.Type;
/**
* Class to extract information about types used to define a generic array.
*
* @author Inderjeet Singh
* @author Joel Leitch
*/
final class TypeInfoArray extends TypeInfo {
private final Class<?> componentRawType;
private final Type secondLevel;
TypeInfoArray(Type type) {
super(type);
Class<?> rootComponentType = rawClass;
while (rootComponentType.isArray()) {
rootComponentType = rootComponentType.getComponentType();
}
this.componentRawType = rootComponentType;
this.secondLevel = extractSecondLevelType(actualType, rawClass);
}
private static Type extractSecondLevelType(Type actualType, Class<?> rawClass) {
return actualType instanceof GenericArrayType ?
((GenericArrayType) actualType).getGenericComponentType() : rawClass.getComponentType();
}
/**
* @return the raw type unwrapped of the second level of array.
* If the object is (single-dimensional or multi-dimensional) array, it is the class of the
* elements of the array. For example, this method returns Foo.class for Foo[].
* It will return Foo[].class for Foo[][]. For Foo&lt;String&gt;[][] types, it will return the
* type representing Foo&lt;String&gt;[]
* (i.e. <code>new TypeToken<Foo<String>[]>() {}.getType()</code>).
*/
public Type getSecondLevelType() {
return secondLevel;
}
/**
* @return the raw type of the root component.
* If the object is a single-dimensional array then the component type is the class of an
* element of the array.
* If the object is a multi-dimensional array then the component type is the class of the
* inner-most array element. For example, the This method will return Foo.class for Foo[][][].
*/
public Class<?> getComponentRawType() {
return componentRawType;
}
}

View File

@ -1,46 +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.Collection;
/**
* A convenience object for retrieving the map type information.
*
* @author Inderjeet Singh
* @author Joel Leitch
*/
final class TypeInfoCollection {
private final ParameterizedType collectionType;
public TypeInfoCollection(Type collectionType) {
if (!(collectionType instanceof ParameterizedType)) {
throw new IllegalArgumentException(
"Collection objects need to be parameterized unless you use a custom serializer. "
+ "Use the com.bukkit.mcteam.gson.reflect.TypeToken to extract the ParameterizedType.");
}
TypeInfo rawType = new TypeInfo(collectionType);
Preconditions.checkArgument(Collection.class.isAssignableFrom(rawType.getRawClass()));
this.collectionType = (ParameterizedType) collectionType;
}
public Type getElementType() {
return collectionType.getActualTypeArguments()[0];
}
}

View File

@ -1,175 +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.Field;
import java.lang.reflect.GenericArrayType;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.lang.reflect.WildcardType;
/**
* A static factory class used to construct the "TypeInfo" objects.
*
* @author Inderjeet Singh
* @author Joel Leitch
*/
final class TypeInfoFactory {
private TypeInfoFactory() {
// Not instantiable since it provides factory methods only.
}
public static TypeInfoArray getTypeInfoForArray(Type type) {
Preconditions.checkArgument(TypeUtils.isArray(type));
return new TypeInfoArray(type);
}
/**
* Evaluates the "actual" type for the field. If the field is a "TypeVariable" or has a
* "TypeVariable" in a parameterized type then it evaluates the real type.
*
* @param f the actual field object to retrieve the type from
* @param typeDefiningF the type that contains the field {@code f}
* @return the type information for the field
*/
public static TypeInfo getTypeInfoForField(Field f, Type typeDefiningF) {
Class<?> classDefiningF = TypeUtils.toRawClass(typeDefiningF);
Type type = f.getGenericType();
Type actualType = getActualType(type, typeDefiningF, classDefiningF);
return new TypeInfo(actualType);
}
private static Type getActualType(
Type typeToEvaluate, Type parentType, Class<?> rawParentClass) {
if (typeToEvaluate instanceof Class<?>) {
return typeToEvaluate;
} else if (typeToEvaluate instanceof ParameterizedType) {
ParameterizedType castedType = (ParameterizedType) typeToEvaluate;
Type owner = castedType.getOwnerType();
Type[] actualTypeParameters =
extractRealTypes(castedType.getActualTypeArguments(), parentType, rawParentClass);
Type rawType = castedType.getRawType();
return new ParameterizedTypeImpl(rawType, actualTypeParameters, owner);
} else if (typeToEvaluate instanceof GenericArrayType) {
GenericArrayType castedType = (GenericArrayType) typeToEvaluate;
Type componentType = castedType.getGenericComponentType();
Type actualType = getActualType(componentType, parentType, rawParentClass);
if (componentType.equals(actualType)) {
return castedType;
}
return actualType instanceof Class<?> ?
TypeUtils.wrapWithArray(TypeUtils.toRawClass(actualType))
: new GenericArrayTypeImpl(actualType);
} else if (typeToEvaluate instanceof TypeVariable<?>) {
if (parentType instanceof ParameterizedType) {
// The class definition has the actual types used for the type variables.
// Find the matching actual type for the Type Variable used for the field.
// For example, class Foo<A> { A a; }
// new Foo<Integer>(); defines the actual type of A to be Integer.
// So, to find the type of the field a, we will have to look at the class'
// actual type arguments.
TypeVariable<?> fieldTypeVariable = (TypeVariable<?>) typeToEvaluate;
TypeVariable<?>[] classTypeVariables = rawParentClass.getTypeParameters();
ParameterizedType objParameterizedType = (ParameterizedType) parentType;
int indexOfActualTypeArgument = getIndex(classTypeVariables, fieldTypeVariable);
Type[] actualTypeArguments = objParameterizedType.getActualTypeArguments();
return actualTypeArguments[indexOfActualTypeArgument];
} else if (typeToEvaluate instanceof TypeVariable<?>) {
Type theSearchedType = null;
do {
theSearchedType = extractTypeForHierarchy(parentType, (TypeVariable<?>) typeToEvaluate);
} while ((theSearchedType != null) && (theSearchedType instanceof TypeVariable<?>));
if (theSearchedType != null) {
return theSearchedType;
}
}
throw new UnsupportedOperationException("Expecting parameterized type, got " + parentType
+ ".\n Are you missing the use of TypeToken idiom?\n See "
+ "http://sites.google.com/site/gson/gson-user-guide#TOC-Serializing-and-Deserializing-Gener");
} else if (typeToEvaluate instanceof WildcardType) {
WildcardType castedType = (WildcardType) typeToEvaluate;
return getActualType(castedType.getUpperBounds()[0], parentType, rawParentClass);
} else {
throw new IllegalArgumentException("Type \'" + typeToEvaluate + "\' is not a Class, "
+ "ParameterizedType, GenericArrayType or TypeVariable. Can't extract type.");
}
}
private static Type extractTypeForHierarchy(Type parentType, TypeVariable<?> typeToEvaluate) {
Class<?> rawParentType = null;
if (parentType instanceof Class<?>) {
rawParentType = (Class<?>) parentType;
} else if (parentType instanceof ParameterizedType) {
ParameterizedType parentTypeAsPT = (ParameterizedType) parentType;
rawParentType = (Class<?>) parentTypeAsPT.getRawType();
} else {
return null;
}
Type superClass = rawParentType.getGenericSuperclass();
if (superClass instanceof ParameterizedType
&& ((ParameterizedType) superClass).getRawType() == typeToEvaluate.getGenericDeclaration()) {
// Evaluate type on this type
TypeVariable<?>[] classTypeVariables =
((Class<?>) ((ParameterizedType) superClass).getRawType()).getTypeParameters();
int indexOfActualTypeArgument = getIndex(classTypeVariables, typeToEvaluate);
Type[] actualTypeArguments = null;
if (parentType instanceof Class<?>) {
actualTypeArguments = ((ParameterizedType) superClass).getActualTypeArguments();
} else if (parentType instanceof ParameterizedType) {
actualTypeArguments = ((ParameterizedType) parentType).getActualTypeArguments();
} else {
return null;
}
return actualTypeArguments[indexOfActualTypeArgument];
}
Type searchedType = null;
if (superClass != null) {
searchedType = extractTypeForHierarchy(superClass, typeToEvaluate);
}
return searchedType;
}
private static Type[] extractRealTypes(
Type[] actualTypeArguments, Type parentType, Class<?> rawParentClass) {
Preconditions.checkNotNull(actualTypeArguments);
Type[] retTypes = new Type[actualTypeArguments.length];
for (int i = 0; i < actualTypeArguments.length; ++i) {
retTypes[i] = getActualType(actualTypeArguments[i], parentType, rawParentClass);
}
return retTypes;
}
private static int getIndex(TypeVariable<?>[] types, TypeVariable<?> type) {
for (int i = 0; i < types.length; ++i) {
if (type.equals(types[i])) {
return i;
}
}
throw new IllegalStateException(
"How can the type variable not be present in the class declaration!");
}
}

View File

@ -1,58 +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.Map;
import java.util.Properties;
/**
* A convenience object for retrieving the map type information.
*
* @author Inderjeet Singh
* @author Joel Leitch
*/
final class TypeInfoMap {
private final Type keyType;
private final Type valueType;
public TypeInfoMap(Type mapType) {
if (mapType instanceof Class<?> && Properties.class.isAssignableFrom((Class<?>) mapType)) {
keyType = String.class;
valueType = String.class;
} else if (mapType instanceof ParameterizedType) {
TypeInfo rawType = new TypeInfo(mapType);
Preconditions.checkArgument(Map.class.isAssignableFrom(rawType.getRawClass()));
ParameterizedType paramType = (ParameterizedType) mapType;
keyType = paramType.getActualTypeArguments()[0];
valueType = paramType.getActualTypeArguments()[1];
} else {
throw new IllegalArgumentException(
"Map objects need to be parameterized unless you use a custom serializer. "
+ "Use the com.bukkit.mcteam.gson.reflect.TypeToken to extract the ParameterizedType.");
}
}
public Type getKeyType() {
return keyType;
}
public Type getValueType() {
return valueType;
}
}

View File

@ -1,95 +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.Array;
import java.lang.reflect.GenericArrayType;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.WildcardType;
/**
* Utility class containing some methods for obtaining information on types.
*
* @author Inderjeet Singh
* @author Joel Leitch
*/
final class TypeUtils {
/**
* Returns the actual type matching up with the first type variable.
* So, for a {@code typeInfo} instance defined as:
* <pre>
* class Foo<A, B> {
* }
* Type fooType = new TypeToken<Foo<Integer, String>>() {}.getType();
* </pre>
* <code>TypeUtils.getActualTypeForFirstTypeVariable(fooType)</code> 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
}
}

View File

@ -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> T newInstance(Class<T> 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> T newInstance(Class<T> 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> T newInstance(Class<T> 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> T newInstance(Class<T> c) throws Exception {
return (T) newInstance.invoke(null, c, constructorId);
}
};
} catch (Exception ignored) {
}
// give up
return new UnsafeAllocator() {
@Override
public <T> T newInstance(Class<T> c) {
throw new UnsupportedOperationException("Cannot allocate " + c);
}
};
}
}

View File

@ -18,6 +18,7 @@ package org.mcteam.factions.gson;
import org.mcteam.factions.gson.annotations.Since; import org.mcteam.factions.gson.annotations.Since;
import org.mcteam.factions.gson.annotations.Until; 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 * 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 { final class VersionExclusionStrategy implements ExclusionStrategy {
private final double version; private final double version;
public VersionExclusionStrategy(double version) { VersionExclusionStrategy(double version) {
Preconditions.checkArgument(version >= 0.0D); $Gson$Preconditions.checkArgument(version >= 0.0D);
this.version = version; this.version = version;
} }

View File

@ -14,7 +14,7 @@
* limitations under the License. * limitations under the License.
*/ */
package org.mcteam.factions.gson; package org.mcteam.factions.gson.internal;
/** /**
* A simple utility class used to check method Preconditions. * A simple utility class used to check method Preconditions.
@ -29,20 +29,23 @@ package org.mcteam.factions.gson;
* @author Inderjeet Singh * @author Inderjeet Singh
* @author Joel Leitch * @author Joel Leitch
*/ */
final class Preconditions { public final class $Gson$Preconditions {
public static void checkNotNull(Object obj) { public static <T> T checkNotNull(T obj) {
checkArgument(obj != null); if (obj == null) {
throw new NullPointerException();
}
return obj;
} }
public static void checkArgument(boolean condition) { public static void checkArgument(boolean condition) {
if (!condition) { if (!condition) {
throw new IllegalArgumentException("condition failed: " + condition); throw new IllegalArgumentException();
} }
} }
public static void checkState(boolean condition) { public static void checkState(boolean condition) {
if (!condition) { if (!condition) {
throw new IllegalArgumentException("condition failed: " + condition); throw new IllegalStateException();
} }
} }
} }

View File

@ -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<Integer>} and the
* result when the supertype is {@code Collection.class} is {@code Collection<Integer>}.
*/
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<String>}, this returns {@code Iterable<String>} 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<String, String>, but it's declared to
* extend Hashtable<Object, Object>.
*/
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;
}
}

View File

@ -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;

View File

@ -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. * vice-versa.
* *
* <p>The primary class to use is {@link com.bukkit.mcteam.gson.Gson} which can be constructed with * <p>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 com.bukkit.mcteam.gson.GsonBuilder} * {@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).</p> * (to configure various options such as using versioning and so on).</p>
* *
* @author Inderjeet Singh, Joel Leitch * @author Inderjeet Singh, Joel Leitch

View File

@ -16,7 +16,8 @@
package org.mcteam.factions.gson.reflect; 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.GenericArrayType;
import java.lang.reflect.ParameterizedType; import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type; import java.lang.reflect.Type;
@ -25,135 +26,101 @@ import java.util.HashMap;
import java.util.Map; 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.
*
* <p>For example, to create a type literal for {@code List<String>}, 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 <code>Collection&lt;Foo&gt;</code>, you can use:
* <p> * <p>
* <code>Type typeOfCollectionOfFoo = new TypeToken&lt;Collection&lt;Foo&gt;&gt;(){}.getType() * {@code TypeToken<List<String>> list = new TypeToken<List<String>>() {};}
* </code>
*
* <p>Assumes {@code Type} implements {@code equals()} and {@code hashCode()}
* as a value (as opposed to identity) comparison.
* *
* Also implements {@link #isAssignableFrom(Type)} to check type-safe * <p>This syntax cannot be used to create type literals that have wildcard
* assignability. * parameters, such as {@code Class<?>} or {@code List<? extends CharSequence>}.
* *
* @author Bob Lee * @author Bob Lee
* @author Sven Mawson * @author Sven Mawson
* @author Jesse Wilson
*/ */
public abstract class TypeToken<T> { public class TypeToken<T> {
final Class<? super T> rawType; final Class<? super T> rawType;
final Type type; 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. * parameter.
* *
* <p>Clients create an empty anonymous subclass. Doing so embeds the type * <p>Clients create an empty anonymous subclass. Doing so embeds the type
* parameter in the anonymous class's type hierarchy so we can reconstitute * parameter in the anonymous class's type hierarchy so we can reconstitute it
* it at runtime despite erasure. * at runtime despite erasure.
*
* <p>For example:
* <code>
* {@literal TypeToken<List<String>> t = new TypeToken<List<String>>}(){}
* </code>
*/ */
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
protected TypeToken() { protected TypeToken() {
this.type = getSuperclassTypeParameter(getClass()); 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"}) @SuppressWarnings("unchecked")
private TypeToken(Type type) { TypeToken(Type type) {
this.rawType = (Class<? super T>) getRawType(nonNull(type, "type")); this.type = $Gson$Types.canonicalize($Gson$Preconditions.checkNotNull(type));
this.type = type; this.rawType = (Class<? super T>) $Gson$Types.getRawType(this.type);
this.hashCode = this.type.hashCode();
} }
private static <T> 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) { static Type getSuperclassTypeParameter(Class<?> subclass) {
Type superclass = subclass.getGenericSuperclass(); Type superclass = subclass.getGenericSuperclass();
if (superclass instanceof Class<?>) { if (superclass instanceof Class) {
throw new RuntimeException("Missing type parameter."); 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) { public final Class<? super T> getRawType() {
return new SimpleTypeToken<Object>(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() {
return rawType; return rawType;
} }
/** /**
* Gets underlying {@code Type} instance. * Gets underlying {@code Type} instance.
*/ */
public Type getType() { public final Type getType() {
return type; return type;
} }
/** /**
* Check if this type is assignable from the given class object. * 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) { public boolean isAssignableFrom(Class<?> cls) {
return isAssignableFrom((Type) cls); return isAssignableFrom((Type) cls);
} }
/** /**
* Check if this type is assignable from the given Type. * 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) { public boolean isAssignableFrom(Type from) {
if (from == null) { if (from == null) {
return false; return false;
@ -164,12 +131,12 @@ public abstract class TypeToken<T> {
} }
if (type instanceof Class<?>) { if (type instanceof Class<?>) {
return rawType.isAssignableFrom(getRawType(from)); return rawType.isAssignableFrom($Gson$Types.getRawType(from));
} else if (type instanceof ParameterizedType) { } else if (type instanceof ParameterizedType) {
return isAssignableFrom(from, (ParameterizedType) type, return isAssignableFrom(from, (ParameterizedType) type,
new HashMap<String, Type>()); new HashMap<String, Type>());
} else if (type instanceof GenericArrayType) { } else if (type instanceof GenericArrayType) {
return rawType.isAssignableFrom(getRawType(from)) return rawType.isAssignableFrom($Gson$Types.getRawType(from))
&& isAssignableFrom(from, (GenericArrayType) type); && isAssignableFrom(from, (GenericArrayType) type);
} else { } else {
throw buildUnexpectedTypeError( throw buildUnexpectedTypeError(
@ -179,7 +146,11 @@ public abstract class TypeToken<T> {
/** /**
* Check if this type is assignable from the given type token. * 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) { public boolean isAssignableFrom(TypeToken<?> token) {
return isAssignableFrom(token.getType()); return isAssignableFrom(token.getType());
} }
@ -225,7 +196,7 @@ public abstract class TypeToken<T> {
} }
// First figure out the class and any type information. // First figure out the class and any type information.
Class<?> clazz = getRawType(from); Class<?> clazz = $Gson$Types.getRawType(from);
ParameterizedType ptype = null; ParameterizedType ptype = null;
if (from instanceof ParameterizedType) { if (from instanceof ParameterizedType) {
ptype = (ParameterizedType) from; ptype = (ParameterizedType) from;
@ -259,11 +230,7 @@ public abstract class TypeToken<T> {
// Interfaces didn't work, try the superclass. // Interfaces didn't work, try the superclass.
Type sType = clazz.getGenericSuperclass(); Type sType = clazz.getGenericSuperclass();
if (isAssignableFrom(sType, to, new HashMap<String, Type>(typeVarMap))) { return isAssignableFrom(sType, to, new HashMap<String, Type>(typeVarMap));
return true;
}
return false;
} }
/** /**
@ -285,55 +252,6 @@ public abstract class TypeToken<T> {
return false; 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<String, Type> 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( private static AssertionError buildUnexpectedTypeError(
Type token, Class<?>... expected) { Type token, Class<?>... expected) {
@ -350,26 +268,41 @@ public abstract class TypeToken<T> {
} }
/** /**
* 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<String, Type> 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) { public static TypeToken<?> get(Type type) {
return new SimpleTypeToken<Object>(type); return new TypeToken<Object>(type);
} }
/** /**
* Gets type token for the given {@code Class} instance. * Gets type literal for the given {@code Class} instance.
*/ */
public static <T> TypeToken<T> get(Class<T> type) { public static <T> TypeToken<T> get(Class<T> type) {
return new SimpleTypeToken<T>(type); return new TypeToken<T>(type);
}
/**
* Private static class to not create more anonymous classes than
* necessary.
*/
private static class SimpleTypeToken<T> extends TypeToken<T> {
public SimpleTypeToken(Type type) {
super(type);
}
} }
} }

View File

@ -1097,7 +1097,8 @@ public final class JsonReader implements Closeable {
token = JsonToken.NUMBER; token = JsonToken.NUMBER;
} catch (NumberFormatException ignored) { } catch (NumberFormatException ignored) {
// this must be an unquoted string // this must be an unquoted string
throw syntaxError("invalid number or unquoted string"); checkLenient();
token = JsonToken.STRING;
} }
} }
} }