updating built-in GSON to 1.7.1 release
This commit is contained in:
parent
ef2de46dd6
commit
6035b204dc
@ -16,7 +16,6 @@
|
||||
|
||||
package org.mcteam.factions.gson;
|
||||
|
||||
|
||||
/**
|
||||
* Strategy for excluding anonymous and local classes.
|
||||
*
|
||||
|
44
src/org/mcteam/factions/gson/BaseMapTypeAdapter.java
Normal file
44
src/org/mcteam/factions/gson/BaseMapTypeAdapter.java
Normal 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);
|
||||
}
|
||||
}
|
@ -48,14 +48,4 @@ interface Cache<K, V> {
|
||||
* @return the value for the given {@code key}
|
||||
*/
|
||||
V removeElement(K key);
|
||||
|
||||
/**
|
||||
* Removes everything from this cache.
|
||||
*/
|
||||
void clear();
|
||||
|
||||
/**
|
||||
* @return the number of objects in this cache
|
||||
*/
|
||||
int size();
|
||||
}
|
||||
|
@ -16,6 +16,8 @@
|
||||
|
||||
package org.mcteam.factions.gson;
|
||||
|
||||
import org.mcteam.factions.gson.internal.$Gson$Preconditions;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.Collection;
|
||||
@ -51,8 +53,8 @@ final class CamelCaseSeparatorNamingPolicy extends RecursiveFieldNamingPolicy {
|
||||
* is null or empty.
|
||||
*/
|
||||
public CamelCaseSeparatorNamingPolicy(String separatorString) {
|
||||
Preconditions.checkNotNull(separatorString);
|
||||
Preconditions.checkArgument(!"".equals(separatorString));
|
||||
$Gson$Preconditions.checkNotNull(separatorString);
|
||||
$Gson$Preconditions.checkArgument(!"".equals(separatorString));
|
||||
this.separatorString = separatorString;
|
||||
}
|
||||
|
||||
|
@ -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 {
|
||||
}
|
||||
}
|
@ -16,19 +16,23 @@
|
||||
|
||||
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.math.BigDecimal;
|
||||
import java.math.BigInteger;
|
||||
import java.net.InetAddress;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.URL;
|
||||
import java.net.UnknownHostException;
|
||||
import java.sql.Time;
|
||||
import java.sql.Timestamp;
|
||||
import java.text.DateFormat;
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Calendar;
|
||||
import java.util.Collection;
|
||||
import java.util.Date;
|
||||
@ -36,12 +40,14 @@ import java.util.GregorianCalendar;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.Queue;
|
||||
import java.util.Set;
|
||||
import java.util.SortedSet;
|
||||
import java.util.StringTokenizer;
|
||||
import java.util.TimeZone;
|
||||
import java.util.TreeSet;
|
||||
import java.util.UUID;
|
||||
|
||||
@ -62,13 +68,15 @@ final class DefaultTypeAdapters {
|
||||
private static final DefaultTimestampDeserializer TIMESTAMP_DESERIALIZER =
|
||||
new DefaultTimestampDeserializer();
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
@SuppressWarnings("unchecked")
|
||||
private static final EnumTypeAdapter ENUM_TYPE_ADAPTER = new EnumTypeAdapter();
|
||||
private static final UrlTypeAdapter URL_TYPE_ADAPTER = new UrlTypeAdapter();
|
||||
private static final UriTypeAdapter URI_TYPE_ADAPTER = new UriTypeAdapter();
|
||||
private static final UuidTypeAdapter UUUID_TYPE_ADAPTER = new UuidTypeAdapter();
|
||||
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 BigDecimalTypeAdapter BIG_DECIMAL_TYPE_ADAPTER = new BigDecimalTypeAdapter();
|
||||
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 ShortTypeAdapter SHORT_TYPE_ADAPTER = new ShortTypeAdapter();
|
||||
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 =
|
||||
new GregorianCalendarTypeAdapter();
|
||||
new GregorianCalendarTypeAdapter();
|
||||
|
||||
// The constants DEFAULT_SERIALIZERS, DEFAULT_DESERIALIZERS, and DEFAULT_INSTANCE_CREATORS
|
||||
// must be defined after the constants for the type adapters. Otherwise, the type adapter
|
||||
// constants will appear as nulls.
|
||||
private static final ParameterizedTypeHandlerMap<JsonSerializer<?>> DEFAULT_SERIALIZERS =
|
||||
createDefaultSerializers();
|
||||
static final ParameterizedTypeHandlerMap<JsonSerializer<?>> DEFAULT_HIERARCHY_SERIALIZERS =
|
||||
createDefaultHierarchySerializers();
|
||||
private static final ParameterizedTypeHandlerMap<JsonDeserializer<?>> DEFAULT_DESERIALIZERS =
|
||||
createDefaultDeserializers();
|
||||
static final ParameterizedTypeHandlerMap<JsonDeserializer<?>> DEFAULT_HIERARCHY_DESERIALIZERS =
|
||||
createDefaultHierarchyDeserializers();
|
||||
private static final ParameterizedTypeHandlerMap<InstanceCreator<?>> DEFAULT_INSTANCE_CREATORS =
|
||||
createDefaultInstanceCreators();
|
||||
|
||||
@ -104,13 +117,10 @@ final class DefaultTypeAdapters {
|
||||
ParameterizedTypeHandlerMap<JsonSerializer<?>> map =
|
||||
new ParameterizedTypeHandlerMap<JsonSerializer<?>>();
|
||||
|
||||
map.registerForTypeHierarchy(Enum.class, ENUM_TYPE_ADAPTER);
|
||||
map.register(URL.class, URL_TYPE_ADAPTER);
|
||||
map.register(URI.class, URI_TYPE_ADAPTER);
|
||||
map.register(UUID.class, UUUID_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(java.sql.Date.class, JAVA_SQL_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(String.class, STRING_TYPE_ADAPTER);
|
||||
map.register(StringBuilder.class, STRING_BUILDER_TYPE_ADAPTER);
|
||||
map.register(StringBuffer.class, STRING_BUFFER_TYPE_ADAPTER);
|
||||
|
||||
map.makeUnmodifiable();
|
||||
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() {
|
||||
ParameterizedTypeHandlerMap<JsonDeserializer<?>> map =
|
||||
new ParameterizedTypeHandlerMap<JsonDeserializer<?>>();
|
||||
map.registerForTypeHierarchy(Enum.class, wrapDeserializer(ENUM_TYPE_ADAPTER));
|
||||
map.register(URL.class, wrapDeserializer(URL_TYPE_ADAPTER));
|
||||
map.register(URI.class, wrapDeserializer(URI_TYPE_ADAPTER));
|
||||
map.register(UUID.class, wrapDeserializer(UUUID_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(java.sql.Date.class, wrapDeserializer(JAVA_SQL_DATE_TYPE_ADAPTER));
|
||||
map.register(Timestamp.class, wrapDeserializer(TIMESTAMP_DESERIALIZER));
|
||||
map.register(Time.class, wrapDeserializer(TIME_TYPE_ADAPTER));
|
||||
map.register(Calendar.class, GREGORIAN_CALENDAR_TYPE_ADAPTER);
|
||||
map.register(GregorianCalendar.class, GREGORIAN_CALENDAR_TYPE_ADAPTER);
|
||||
map.register(BigDecimal.class, wrapDeserializer(BIG_DECIMAL_TYPE_ADAPTER));
|
||||
map.register(BigInteger.class, wrapDeserializer(BIG_INTEGER_TYPE_ADAPTER));
|
||||
map.register(BigDecimal.class, BIG_DECIMAL_TYPE_ADAPTER);
|
||||
map.register(BigInteger.class, BIG_INTEGER_TYPE_ADAPTER);
|
||||
|
||||
// Add primitive deserializers
|
||||
map.register(Boolean.class, wrapDeserializer(BOOLEAN_TYPE_ADAPTER));
|
||||
map.register(boolean.class, wrapDeserializer(BOOLEAN_TYPE_ADAPTER));
|
||||
map.register(Byte.class, wrapDeserializer(BYTE_TYPE_ADAPTER));
|
||||
map.register(byte.class, wrapDeserializer(BYTE_TYPE_ADAPTER));
|
||||
map.register(Boolean.class, BOOLEAN_TYPE_ADAPTER);
|
||||
map.register(boolean.class, BOOLEAN_TYPE_ADAPTER);
|
||||
map.register(Byte.class, BYTE_TYPE_ADAPTER);
|
||||
map.register(byte.class, BYTE_TYPE_ADAPTER);
|
||||
map.register(Character.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, wrapDeserializer(DOUBLE_TYPE_ADAPTER));
|
||||
map.register(Float.class, wrapDeserializer(FLOAT_TYPE_ADAPTER));
|
||||
map.register(float.class, wrapDeserializer(FLOAT_TYPE_ADAPTER));
|
||||
map.register(Integer.class, wrapDeserializer(INTEGER_TYPE_ADAPTER));
|
||||
map.register(int.class, wrapDeserializer(INTEGER_TYPE_ADAPTER));
|
||||
map.register(Long.class, wrapDeserializer(LONG_DESERIALIZER));
|
||||
map.register(long.class, wrapDeserializer(LONG_DESERIALIZER));
|
||||
map.register(Number.class, wrapDeserializer(NUMBER_TYPE_ADAPTER));
|
||||
map.register(Short.class, wrapDeserializer(SHORT_TYPE_ADAPTER));
|
||||
map.register(short.class, wrapDeserializer(SHORT_TYPE_ADAPTER));
|
||||
map.register(Double.class, DOUBLE_TYPE_ADAPTER);
|
||||
map.register(double.class, DOUBLE_TYPE_ADAPTER);
|
||||
map.register(Float.class, FLOAT_TYPE_ADAPTER);
|
||||
map.register(float.class, FLOAT_TYPE_ADAPTER);
|
||||
map.register(Integer.class, INTEGER_TYPE_ADAPTER);
|
||||
map.register(int.class, INTEGER_TYPE_ADAPTER);
|
||||
map.register(Long.class, LONG_DESERIALIZER);
|
||||
map.register(long.class, LONG_DESERIALIZER);
|
||||
map.register(Number.class, NUMBER_TYPE_ADAPTER);
|
||||
map.register(Short.class, SHORT_TYPE_ADAPTER);
|
||||
map.register(short.class, SHORT_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();
|
||||
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() {
|
||||
ParameterizedTypeHandlerMap<InstanceCreator<?>> map =
|
||||
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
|
||||
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();
|
||||
return map;
|
||||
}
|
||||
|
||||
@SuppressWarnings({"unchecked", "rawtypes"})
|
||||
@SuppressWarnings("unchecked")
|
||||
private static JsonDeserializer<?> wrapDeserializer(JsonDeserializer<?> deserializer) {
|
||||
return new JsonDeserializerExceptionWrapper(deserializer);
|
||||
}
|
||||
@ -205,6 +251,20 @@ final class DefaultTypeAdapters {
|
||||
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(
|
||||
boolean serializeSpecialFloatingPointValues, LongSerializationPolicy longSerializationPolicy) {
|
||||
ParameterizedTypeHandlerMap<JsonSerializer<?>> serializers =
|
||||
@ -240,30 +300,45 @@ final class DefaultTypeAdapters {
|
||||
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() {
|
||||
this.format = DateFormat.getDateTimeInstance();
|
||||
this(DateFormat.getDateTimeInstance(DateFormat.DEFAULT, DateFormat.DEFAULT, Locale.US),
|
||||
DateFormat.getDateTimeInstance(DateFormat.DEFAULT, DateFormat.DEFAULT));
|
||||
}
|
||||
|
||||
DefaultDateTypeAdapter(final String datePattern) {
|
||||
this.format = new SimpleDateFormat(datePattern);
|
||||
DefaultDateTypeAdapter(String datePattern) {
|
||||
this(new SimpleDateFormat(datePattern, Locale.US), new SimpleDateFormat(datePattern));
|
||||
}
|
||||
|
||||
DefaultDateTypeAdapter(final int style) {
|
||||
this.format = DateFormat.getDateInstance(style);
|
||||
DefaultDateTypeAdapter(int style) {
|
||||
this(DateFormat.getDateInstance(style, Locale.US), DateFormat.getDateInstance(style));
|
||||
}
|
||||
|
||||
public DefaultDateTypeAdapter(final int dateStyle, final int timeStyle) {
|
||||
this.format = DateFormat.getDateTimeInstance(dateStyle, timeStyle);
|
||||
public DefaultDateTypeAdapter(int dateStyle, int 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
|
||||
// See issue 162
|
||||
public JsonElement serialize(Date src, Type typeOfSrc, JsonSerializationContext context) {
|
||||
synchronized (format) {
|
||||
String dateFormatAsString = format.format(src);
|
||||
synchronized (localFormat) {
|
||||
String dateFormatAsString = enUsFormat.format(src);
|
||||
return new JsonPrimitive(dateFormatAsString);
|
||||
}
|
||||
}
|
||||
@ -273,12 +348,33 @@ final class DefaultTypeAdapters {
|
||||
if (!(json instanceof JsonPrimitive)) {
|
||||
throw new JsonParseException("The date should be a string value");
|
||||
}
|
||||
try {
|
||||
synchronized (format) {
|
||||
return format.parse(json.getAsString());
|
||||
Date date = deserializeToDate(json);
|
||||
if (typeOfT == Date.class) {
|
||||
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() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(DefaultDateTypeAdapter.class.getSimpleName());
|
||||
sb.append('(').append(format.getClass().getSimpleName()).append(')');
|
||||
sb.append('(').append(localFormat.getClass().getSimpleName()).append(')');
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
|
||||
static class DefaultJavaSqlDateTypeAdapter implements JsonSerializer<java.sql.Date>,
|
||||
static final class DefaultJavaSqlDateTypeAdapter implements JsonSerializer<java.sql.Date>,
|
||||
JsonDeserializer<java.sql.Date> {
|
||||
private final DateFormat format;
|
||||
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,
|
||||
JsonDeserializationContext context) throws JsonParseException {
|
||||
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;
|
||||
DefaultTimeTypeAdapter() {
|
||||
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> {
|
||||
|
||||
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")
|
||||
private static class EnumTypeAdapter<T extends Enum<T>>
|
||||
private static final class EnumTypeAdapter<T extends Enum<T>>
|
||||
implements JsonSerializer<T>, JsonDeserializer<T> {
|
||||
public JsonElement serialize(T src, Type typeOfSrc, JsonSerializationContext context) {
|
||||
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) {
|
||||
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) {
|
||||
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) {
|
||||
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> {
|
||||
public JsonElement serialize(Locale src, Type typeOfSrc, JsonSerializationContext context) {
|
||||
return new JsonPrimitive(src.toString());
|
||||
@ -507,9 +621,9 @@ final class DefaultTypeAdapters {
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings({"unchecked", "rawtypes"})
|
||||
private static class CollectionTypeAdapter implements JsonSerializer<Collection>,
|
||||
JsonDeserializer<Collection>, InstanceCreator<Collection> {
|
||||
@SuppressWarnings("unchecked")
|
||||
private static final class CollectionTypeAdapter implements JsonSerializer<Collection>,
|
||||
JsonDeserializer<Collection> {
|
||||
public JsonElement serialize(Collection src, Type typeOfSrc, JsonSerializationContext context) {
|
||||
if (src == null) {
|
||||
return JsonNull.createJsonNull();
|
||||
@ -517,7 +631,8 @@ final class DefaultTypeAdapters {
|
||||
JsonArray array = new JsonArray();
|
||||
Type childGenericType = null;
|
||||
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) {
|
||||
if (child == null) {
|
||||
@ -540,7 +655,7 @@ final class DefaultTypeAdapters {
|
||||
// Use ObjectConstructor to create instance instead of hard-coding a specific type.
|
||||
// This handles cases where users are using their own subclass of Collection.
|
||||
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()) {
|
||||
if (childElement == null || childElement.isJsonNull()) {
|
||||
collection.add(null);
|
||||
@ -558,76 +673,9 @@ final class DefaultTypeAdapters {
|
||||
ObjectConstructor objectConstructor = contextImpl.getObjectConstructor();
|
||||
return (Collection) objectConstructor.construct(collectionType);
|
||||
}
|
||||
|
||||
public Collection createInstance(Type type) {
|
||||
return new LinkedList();
|
||||
}
|
||||
}
|
||||
|
||||
private static class PropertiesCreator implements InstanceCreator<Properties> {
|
||||
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
|
||||
private static final class BigDecimalTypeAdapter
|
||||
implements JsonSerializer<BigDecimal>, JsonDeserializer<BigDecimal> {
|
||||
public JsonElement serialize(BigDecimal src, Type typeOfSrc, JsonSerializationContext context) {
|
||||
return new JsonPrimitive(src);
|
||||
@ -635,7 +683,15 @@ final class DefaultTypeAdapters {
|
||||
|
||||
public BigDecimal deserialize(JsonElement json, Type typeOfT,
|
||||
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
|
||||
@ -644,7 +700,7 @@ final class DefaultTypeAdapters {
|
||||
}
|
||||
}
|
||||
|
||||
private static class BigIntegerTypeAdapter
|
||||
private static final class BigIntegerTypeAdapter
|
||||
implements JsonSerializer<BigInteger>, JsonDeserializer<BigInteger> {
|
||||
|
||||
public JsonElement serialize(BigInteger src, Type typeOfSrc, JsonSerializationContext context) {
|
||||
@ -653,7 +709,15 @@ final class DefaultTypeAdapters {
|
||||
|
||||
public BigInteger deserialize(JsonElement json, Type typeOfT,
|
||||
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
|
||||
@ -662,7 +726,7 @@ final class DefaultTypeAdapters {
|
||||
}
|
||||
}
|
||||
|
||||
private static class NumberTypeAdapter
|
||||
private static final class NumberTypeAdapter
|
||||
implements JsonSerializer<Number>, JsonDeserializer<Number> {
|
||||
public JsonElement serialize(Number src, Type typeOfSrc, JsonSerializationContext context) {
|
||||
return new JsonPrimitive(src);
|
||||
@ -670,7 +734,15 @@ final class DefaultTypeAdapters {
|
||||
|
||||
public Number deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
|
||||
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
|
||||
@ -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 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)
|
||||
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
|
||||
@ -708,7 +788,7 @@ final class DefaultTypeAdapters {
|
||||
}
|
||||
}
|
||||
|
||||
private static class IntegerTypeAdapter
|
||||
private static final class IntegerTypeAdapter
|
||||
implements JsonSerializer<Integer>, JsonDeserializer<Integer> {
|
||||
public JsonElement serialize(Integer src, Type typeOfSrc, JsonSerializationContext context) {
|
||||
return new JsonPrimitive(src);
|
||||
@ -716,7 +796,15 @@ final class DefaultTypeAdapters {
|
||||
|
||||
public Integer deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
|
||||
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
|
||||
@ -725,7 +813,7 @@ final class DefaultTypeAdapters {
|
||||
}
|
||||
}
|
||||
|
||||
private static class ShortTypeAdapter
|
||||
private static final class ShortTypeAdapter
|
||||
implements JsonSerializer<Short>, JsonDeserializer<Short> {
|
||||
public JsonElement serialize(Short src, Type typeOfSrc, JsonSerializationContext context) {
|
||||
return new JsonPrimitive(src);
|
||||
@ -733,7 +821,15 @@ final class DefaultTypeAdapters {
|
||||
|
||||
public Short deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
|
||||
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
|
||||
@ -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) {
|
||||
return new JsonPrimitive(src);
|
||||
}
|
||||
|
||||
public Byte deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
|
||||
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
|
||||
@ -758,7 +862,7 @@ final class DefaultTypeAdapters {
|
||||
}
|
||||
}
|
||||
|
||||
static class FloatSerializer implements JsonSerializer<Float> {
|
||||
static final class FloatSerializer implements JsonSerializer<Float> {
|
||||
private final boolean serializeSpecialFloatingPointValues;
|
||||
|
||||
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)
|
||||
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
|
||||
@ -789,7 +901,7 @@ final class DefaultTypeAdapters {
|
||||
}
|
||||
}
|
||||
|
||||
static class DoubleSerializer implements JsonSerializer<Double> {
|
||||
static final class DoubleSerializer implements JsonSerializer<Double> {
|
||||
private final boolean serializeSpecialFloatingPointValues;
|
||||
|
||||
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)
|
||||
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
|
||||
@ -820,7 +940,7 @@ final class DefaultTypeAdapters {
|
||||
}
|
||||
}
|
||||
|
||||
private static class CharacterTypeAdapter
|
||||
private static final class CharacterTypeAdapter
|
||||
implements JsonSerializer<Character>, JsonDeserializer<Character> {
|
||||
public JsonElement serialize(Character src, Type typeOfSrc, JsonSerializationContext context) {
|
||||
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> {
|
||||
public JsonElement serialize(String src, Type typeOfSrc, JsonSerializationContext context) {
|
||||
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> {
|
||||
public JsonElement serialize(Boolean src, Type typeOfSrc, JsonSerializationContext context) {
|
||||
return new JsonPrimitive(src);
|
||||
@ -862,7 +1016,13 @@ final class DefaultTypeAdapters {
|
||||
|
||||
public Boolean deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
|
||||
throws JsonParseException {
|
||||
return json.getAsBoolean();
|
||||
try {
|
||||
return json.getAsBoolean();
|
||||
} catch (UnsupportedOperationException e) {
|
||||
throw new JsonSyntaxException(e);
|
||||
} catch (IllegalStateException e) {
|
||||
throw new JsonSyntaxException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -871,23 +1031,32 @@ final class DefaultTypeAdapters {
|
||||
}
|
||||
}
|
||||
|
||||
private static class TreeSetCreator implements InstanceCreator<TreeSet<?>> {
|
||||
public TreeSet<?> createInstance(Type type) {
|
||||
return new TreeSet<Object>();
|
||||
}
|
||||
@Override
|
||||
public String toString() {
|
||||
return TreeSetCreator.class.getSimpleName();
|
||||
}
|
||||
}
|
||||
@SuppressWarnings("unchecked")
|
||||
private static final class DefaultConstructorCreator<T> implements InstanceCreator<T> {
|
||||
private final Class<? extends T> defaultInstance;
|
||||
private final DefaultConstructorAllocator allocator;
|
||||
|
||||
private static class HashSetCreator implements InstanceCreator<HashSet<?>> {
|
||||
public HashSet<?> createInstance(Type type) {
|
||||
return new HashSet<Object>();
|
||||
public DefaultConstructorCreator(Class<? extends T> defaultInstance,
|
||||
DefaultConstructorAllocator allocator) {
|
||||
this.defaultInstance = defaultInstance;
|
||||
this.allocator = allocator;
|
||||
}
|
||||
|
||||
public T createInstance(Type type) {
|
||||
Class<?> rawType = $Gson$Types.getRawType(type);
|
||||
try {
|
||||
T specificInstance = (T) allocator.newInstance(rawType);
|
||||
return (specificInstance == null)
|
||||
? allocator.newInstance(defaultInstance)
|
||||
: specificInstance;
|
||||
} catch (Exception e) {
|
||||
throw new JsonIOException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return HashSetCreator.class.getSimpleName();
|
||||
return DefaultConstructorCreator.class.getSimpleName();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -16,6 +16,8 @@
|
||||
|
||||
package org.mcteam.factions.gson;
|
||||
|
||||
import org.mcteam.factions.gson.internal.$Gson$Preconditions;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
@ -44,12 +46,11 @@ import java.io.IOException;
|
||||
*
|
||||
* @author Joel Leitch
|
||||
*/
|
||||
class DelegatingJsonElementVisitor implements JsonElementVisitor {
|
||||
final class DelegatingJsonElementVisitor implements JsonElementVisitor {
|
||||
private final JsonElementVisitor delegate;
|
||||
|
||||
protected DelegatingJsonElementVisitor(JsonElementVisitor delegate) {
|
||||
Preconditions.checkNotNull(delegate);
|
||||
this.delegate = delegate;
|
||||
this.delegate = $Gson$Preconditions.checkNotNull(delegate);
|
||||
}
|
||||
|
||||
public void endArray(JsonArray array) throws IOException {
|
||||
|
@ -16,6 +16,8 @@
|
||||
|
||||
package org.mcteam.factions.gson;
|
||||
|
||||
import org.mcteam.factions.gson.internal.$Gson$Preconditions;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
@ -27,9 +29,8 @@ import java.util.Collection;
|
||||
final class DisjunctionExclusionStrategy implements ExclusionStrategy {
|
||||
private final Collection<ExclusionStrategy> strategies;
|
||||
|
||||
public DisjunctionExclusionStrategy(Collection<ExclusionStrategy> strategies) {
|
||||
Preconditions.checkNotNull(strategies);
|
||||
this.strategies = strategies;
|
||||
DisjunctionExclusionStrategy(Collection<ExclusionStrategy> strategies) {
|
||||
this.strategies = $Gson$Preconditions.checkNotNull(strategies);
|
||||
}
|
||||
|
||||
public boolean shouldSkipField(FieldAttributes f) {
|
||||
|
@ -66,7 +66,7 @@ final class Escaper {
|
||||
}
|
||||
|
||||
public String escapeJsonString(CharSequence plainText) {
|
||||
StringBuffer escapedString = new StringBuffer(plainText.length() + 20);
|
||||
StringBuilder escapedString = new StringBuilder(plainText.length() + 20);
|
||||
try {
|
||||
escapeJsonString(plainText, escapedString);
|
||||
} catch (IOException e) {
|
||||
@ -75,7 +75,7 @@ final class Escaper {
|
||||
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 len = plainText.length();
|
||||
|
||||
|
@ -72,10 +72,24 @@ package org.mcteam.factions.gson;
|
||||
* .create();
|
||||
* </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 Joel Leitch
|
||||
*
|
||||
* @see GsonBuilder#setExclusionStrategies(ExclusionStrategy...)
|
||||
* @see GsonBuilder#addDeserializationExclusionStrategy(ExclusionStrategy)
|
||||
* @see GsonBuilder#addSerializationExclusionStrategy(ExclusionStrategy)
|
||||
*
|
||||
* @since 1.4
|
||||
*/
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2009 Google Inc.
|
||||
* 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.
|
||||
@ -13,6 +13,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.mcteam.factions.gson;
|
||||
|
||||
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
|
||||
*
|
||||
* @author Inderjeet Singh
|
||||
* @author Joel Leitch
|
||||
*/
|
||||
final class ExposeAnnotationDeserializationExclusionStrategy implements ExclusionStrategy {
|
||||
|
||||
public boolean shouldSkipClass(Class<?> clazz) {
|
||||
return false;
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2008 Google Inc.
|
||||
* 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.
|
||||
@ -21,11 +21,9 @@ import org.mcteam.factions.gson.annotations.Expose;
|
||||
/**
|
||||
* Excludes fields that do not have the {@link Expose} annotation
|
||||
*
|
||||
* @author Inderjeet Singh
|
||||
* @author Joel Leitch
|
||||
*/
|
||||
final class ExposeAnnotationSerializationExclusionStrategy implements ExclusionStrategy {
|
||||
|
||||
public boolean shouldSkipClass(Class<?> clazz) {
|
||||
return false;
|
||||
}
|
||||
|
@ -16,6 +16,9 @@
|
||||
|
||||
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.reflect.Field;
|
||||
import java.lang.reflect.Type;
|
||||
@ -35,7 +38,7 @@ import java.util.Collections;
|
||||
*/
|
||||
public final class FieldAttributes {
|
||||
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 =
|
||||
new LruCache<Pair<Class<?>,String>, Collection<Annotation>>(getMaxCacheSize());
|
||||
@ -46,6 +49,7 @@ public final class FieldAttributes {
|
||||
private final boolean isSynthetic;
|
||||
private final int modifiers;
|
||||
private final String name;
|
||||
private final Type resolvedType;
|
||||
|
||||
// Fields used for lazy initialization
|
||||
private Type genericType;
|
||||
@ -55,15 +59,16 @@ public final class FieldAttributes {
|
||||
* Constructs a Field Attributes object from the {@code f}.
|
||||
*
|
||||
* @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) {
|
||||
Preconditions.checkNotNull(declaringClazz);
|
||||
this.declaringClazz = declaringClazz;
|
||||
name = f.getName();
|
||||
declaredType = f.getType();
|
||||
isSynthetic = f.isSynthetic();
|
||||
modifiers = f.getModifiers();
|
||||
field = f;
|
||||
FieldAttributes(Class<?> declaringClazz, Field f, Type declaringType) {
|
||||
this.declaringClazz = $Gson$Preconditions.checkNotNull(declaringClazz);
|
||||
this.name = f.getName();
|
||||
this.declaredType = f.getType();
|
||||
this.isSynthetic = f.isSynthetic();
|
||||
this.modifiers = f.getModifiers();
|
||||
this.field = f;
|
||||
this.resolvedType = getTypeInfoForField(f, declaringType);
|
||||
}
|
||||
|
||||
private static int getMaxCacheSize() {
|
||||
@ -216,6 +221,10 @@ public final class FieldAttributes {
|
||||
return field;
|
||||
}
|
||||
|
||||
Type getResolvedType() {
|
||||
return resolvedType;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private static <T extends Annotation> T getAnnotationFromArray(
|
||||
Collection<Annotation> annotations, Class<T> annotation) {
|
||||
@ -226,4 +235,21 @@ public final class FieldAttributes {
|
||||
}
|
||||
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());
|
||||
}
|
||||
}
|
||||
|
@ -32,7 +32,6 @@ interface FieldNamingStrategy2 {
|
||||
*
|
||||
* @param f the field that is being translated
|
||||
* @return the translated field name.
|
||||
* @since 1.3
|
||||
*/
|
||||
public String translateName(FieldAttributes f);
|
||||
}
|
||||
|
@ -16,8 +16,10 @@
|
||||
|
||||
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.
|
||||
*
|
||||
* @author Inderjeet Singh
|
||||
@ -26,12 +28,10 @@ package org.mcteam.factions.gson;
|
||||
final class FieldNamingStrategy2Adapter implements FieldNamingStrategy2 {
|
||||
private final FieldNamingStrategy adaptee;
|
||||
|
||||
public FieldNamingStrategy2Adapter(FieldNamingStrategy adaptee) {
|
||||
Preconditions.checkNotNull(adaptee);
|
||||
this.adaptee = adaptee;
|
||||
FieldNamingStrategy2Adapter(FieldNamingStrategy adaptee) {
|
||||
this.adaptee = $Gson$Preconditions.checkNotNull(adaptee);
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
public String translateName(FieldAttributes f) {
|
||||
return adaptee.translateName(f.getFieldObject());
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
@ -16,6 +16,10 @@
|
||||
|
||||
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.Reader;
|
||||
import java.io.StringReader;
|
||||
@ -27,12 +31,6 @@ import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
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
|
||||
* 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
|
||||
// constructor instead. At the minimum, mark those methods private.
|
||||
|
||||
private static final String NULL_STRING = "null";
|
||||
|
||||
static final boolean DEFAULT_JSON_NON_EXECUTABLE = false;
|
||||
|
||||
// Default instances of plug-ins
|
||||
@ -94,15 +90,12 @@ public final class Gson {
|
||||
static final FieldNamingStrategy2 DEFAULT_NAMING_POLICY =
|
||||
new SerializedNameAnnotationInterceptingNamingPolicy(new JavaFieldNamingPolicy());
|
||||
|
||||
private static final ExclusionStrategy DEFAULT_EXCLUSION_STRATEGY =
|
||||
createExclusionStrategy(VersionConstants.IGNORE_VERSIONS);
|
||||
private static final ExclusionStrategy DEFAULT_EXCLUSION_STRATEGY = createExclusionStrategy();
|
||||
|
||||
private static final String JSON_NON_EXECUTABLE_PREFIX = ")]}'\n";
|
||||
|
||||
private final ExclusionStrategy serializationStrategy;
|
||||
|
||||
private final ExclusionStrategy deserializationStrategy;
|
||||
|
||||
private final ExclusionStrategy deserializationExclusionStrategy;
|
||||
private final ExclusionStrategy serializationExclusionStrategy;
|
||||
private final FieldNamingStrategy2 fieldNamingPolicy;
|
||||
private final MappedObjectConstructor objectConstructor;
|
||||
|
||||
@ -154,17 +147,18 @@ public final class Gson {
|
||||
public Gson() {
|
||||
this(DEFAULT_EXCLUSION_STRATEGY, DEFAULT_EXCLUSION_STRATEGY, DEFAULT_NAMING_POLICY,
|
||||
new MappedObjectConstructor(DefaultTypeAdapters.getDefaultInstanceCreators()),
|
||||
false, DefaultTypeAdapters.getDefaultSerializers(),
|
||||
DefaultTypeAdapters.getDefaultDeserializers(), DEFAULT_JSON_NON_EXECUTABLE, true, false);
|
||||
false, DefaultTypeAdapters.getAllDefaultSerializers(),
|
||||
DefaultTypeAdapters.getAllDefaultDeserializers(), DEFAULT_JSON_NON_EXECUTABLE, true, false);
|
||||
}
|
||||
|
||||
Gson(ExclusionStrategy serializationStrategy, ExclusionStrategy deserializationStrategy,
|
||||
FieldNamingStrategy2 fieldNamingPolicy, MappedObjectConstructor objectConstructor,
|
||||
boolean serializeNulls, ParameterizedTypeHandlerMap<JsonSerializer<?>> serializers,
|
||||
ParameterizedTypeHandlerMap<JsonDeserializer<?>> deserializers,
|
||||
boolean generateNonExecutableGson, boolean htmlSafe, boolean prettyPrinting) {
|
||||
this.serializationStrategy = serializationStrategy;
|
||||
this.deserializationStrategy = deserializationStrategy;
|
||||
Gson(ExclusionStrategy deserializationExclusionStrategy,
|
||||
ExclusionStrategy serializationExclusionStrategy, FieldNamingStrategy2 fieldNamingPolicy,
|
||||
MappedObjectConstructor objectConstructor, boolean serializeNulls,
|
||||
ParameterizedTypeHandlerMap<JsonSerializer<?>> serializers,
|
||||
ParameterizedTypeHandlerMap<JsonDeserializer<?>> deserializers,
|
||||
boolean generateNonExecutableGson, boolean htmlSafe, boolean prettyPrinting) {
|
||||
this.deserializationExclusionStrategy = deserializationExclusionStrategy;
|
||||
this.serializationExclusionStrategy = serializationExclusionStrategy;
|
||||
this.fieldNamingPolicy = fieldNamingPolicy;
|
||||
this.objectConstructor = objectConstructor;
|
||||
this.serializeNulls = serializeNulls;
|
||||
@ -175,18 +169,11 @@ public final class Gson {
|
||||
this.prettyPrinting = prettyPrinting;
|
||||
}
|
||||
|
||||
private ObjectNavigatorFactory createDefaultObjectNavigatorFactory(ExclusionStrategy strategy) {
|
||||
return new ObjectNavigatorFactory(strategy, fieldNamingPolicy);
|
||||
}
|
||||
|
||||
private static ExclusionStrategy createExclusionStrategy(double version) {
|
||||
private static ExclusionStrategy createExclusionStrategy() {
|
||||
List<ExclusionStrategy> strategies = new LinkedList<ExclusionStrategy>();
|
||||
strategies.add(DEFAULT_ANON_LOCAL_CLASS_EXCLUSION_STRATEGY);
|
||||
strategies.add(DEFAULT_SYNTHETIC_FIELD_EXCLUSION_STRATEGY);
|
||||
strategies.add(DEFAULT_MODIFIER_BASED_EXCLUSION_STRATEGY);
|
||||
if (version != VersionConstants.IGNORE_VERSIONS) {
|
||||
strategies.add(new VersionExclusionStrategy(version));
|
||||
}
|
||||
return new DisjunctionExclusionStrategy(strategies);
|
||||
}
|
||||
|
||||
@ -227,12 +214,10 @@ public final class Gson {
|
||||
* @since 1.4
|
||||
*/
|
||||
public JsonElement toJsonTree(Object src, Type typeOfSrc) {
|
||||
if (src == null) {
|
||||
return JsonNull.createJsonNull();
|
||||
}
|
||||
JsonSerializationContextDefault context = new JsonSerializationContextDefault(
|
||||
createDefaultObjectNavigatorFactory(serializationStrategy), serializeNulls, serializers);
|
||||
return context.serialize(src, typeOfSrc, true);
|
||||
new ObjectNavigator(serializationExclusionStrategy), fieldNamingPolicy,
|
||||
serializeNulls, serializers);
|
||||
return context.serialize(src, typeOfSrc);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -250,7 +235,7 @@ public final class Gson {
|
||||
*/
|
||||
public String toJson(Object src) {
|
||||
if (src == null) {
|
||||
return serializeNulls ? NULL_STRING : "";
|
||||
return toJson(JsonNull.createJsonNull());
|
||||
}
|
||||
return toJson(src, src.getClass());
|
||||
}
|
||||
@ -291,14 +276,10 @@ public final class Gson {
|
||||
* @since 1.2
|
||||
*/
|
||||
public void toJson(Object src, Appendable writer) throws JsonIOException {
|
||||
try {
|
||||
if (src != null) {
|
||||
toJson(src, src.getClass(), writer);
|
||||
} else if (serializeNulls) {
|
||||
writeOutNullString(writer);
|
||||
}
|
||||
} catch (IOException ioe) {
|
||||
throw new RuntimeException(ioe);
|
||||
if (src != null) {
|
||||
toJson(src, src.getClass(), writer);
|
||||
} else {
|
||||
toJson(JsonNull.createJsonNull(), writer);
|
||||
}
|
||||
}
|
||||
|
||||
@ -565,21 +546,12 @@ public final class Gson {
|
||||
return null;
|
||||
}
|
||||
JsonDeserializationContext context = new JsonDeserializationContextDefault(
|
||||
createDefaultObjectNavigatorFactory(deserializationStrategy), deserializers,
|
||||
objectConstructor);
|
||||
new ObjectNavigator(deserializationExclusionStrategy), fieldNamingPolicy,
|
||||
deserializers, objectConstructor);
|
||||
T target = (T) context.deserialize(json, typeOfT);
|
||||
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
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder("{")
|
||||
|
@ -16,16 +16,19 @@
|
||||
|
||||
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.sql.Timestamp;
|
||||
import java.text.DateFormat;
|
||||
import java.util.Collection;
|
||||
import java.util.Arrays;
|
||||
import java.util.Date;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import org.mcteam.factions.gson.DefaultTypeAdapters.DefaultDateTypeAdapter;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* <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>
|
||||
* Gson gson = new GsonBuilder()
|
||||
* .registerTypeAdapter(Id.class, new IdTypeAdapter())
|
||||
* .enableComplexMapKeySerialization()
|
||||
* .serializeNulls()
|
||||
* .setDateFormat(DateFormat.LONG)
|
||||
* .setFieldNamingPolicy(FieldNamingPolicy.UPPER_CAMEL_CASE)
|
||||
@ -47,22 +51,33 @@ import org.mcteam.factions.gson.DefaultTypeAdapters.DefaultDateTypeAdapter;
|
||||
* .create();
|
||||
* </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 Joel Leitch
|
||||
*/
|
||||
public final class GsonBuilder {
|
||||
private static final MapAsArrayTypeAdapter COMPLEX_KEY_MAP_TYPE_ADAPTER =
|
||||
new MapAsArrayTypeAdapter();
|
||||
private static final InnerClassExclusionStrategy innerClassExclusionStrategy =
|
||||
new InnerClassExclusionStrategy();
|
||||
private static final ExposeAnnotationSerializationExclusionStrategy
|
||||
exposeAnnotationSerializationExclusionStrategy =
|
||||
new ExposeAnnotationSerializationExclusionStrategy();
|
||||
private static final ExposeAnnotationDeserializationExclusionStrategy
|
||||
exposeAnnotationDeserializationExclusionStrategy =
|
||||
exposeAnnotationDeserializationExclusionStrategy =
|
||||
new ExposeAnnotationDeserializationExclusionStrategy();
|
||||
private static final ExposeAnnotationSerializationExclusionStrategy
|
||||
exposeAnnotationSerializationExclusionStrategy =
|
||||
new ExposeAnnotationSerializationExclusionStrategy();
|
||||
|
||||
private final Collection<ExclusionStrategy> exclusionStrategies =
|
||||
private final Set<ExclusionStrategy> serializeExclusionStrategies =
|
||||
new HashSet<ExclusionStrategy>();
|
||||
private final Set<ExclusionStrategy> deserializeExclusionStrategies =
|
||||
new HashSet<ExclusionStrategy>();
|
||||
|
||||
private double ignoreVersionsAfter;
|
||||
@ -91,8 +106,10 @@ public final class GsonBuilder {
|
||||
*/
|
||||
public GsonBuilder() {
|
||||
// add default exclusion strategies
|
||||
exclusionStrategies.add(Gson.DEFAULT_ANON_LOCAL_CLASS_EXCLUSION_STRATEGY);
|
||||
exclusionStrategies.add(Gson.DEFAULT_SYNTHETIC_FIELD_EXCLUSION_STRATEGY);
|
||||
deserializeExclusionStrategies.add(Gson.DEFAULT_ANON_LOCAL_CLASS_EXCLUSION_STRATEGY);
|
||||
deserializeExclusionStrategies.add(Gson.DEFAULT_SYNTHETIC_FIELD_EXCLUSION_STRATEGY);
|
||||
serializeExclusionStrategies.add(Gson.DEFAULT_ANON_LOCAL_CLASS_EXCLUSION_STRATEGY);
|
||||
serializeExclusionStrategies.add(Gson.DEFAULT_SYNTHETIC_FIELD_EXCLUSION_STRATEGY);
|
||||
|
||||
// setup default values
|
||||
ignoreVersionsAfter = VersionConstants.IGNORE_VERSIONS;
|
||||
@ -178,6 +195,87 @@ public final class GsonBuilder {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enabling this feature will only change the serialized form if the map key is
|
||||
* a complex type (i.e. non-primitive) in its <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.
|
||||
*
|
||||
@ -250,12 +348,45 @@ public final class GsonBuilder {
|
||||
* @since 1.4
|
||||
*/
|
||||
public GsonBuilder setExclusionStrategies(ExclusionStrategy... strategies) {
|
||||
for (ExclusionStrategy strategy : strategies) {
|
||||
exclusionStrategies.add(strategy);
|
||||
}
|
||||
List<ExclusionStrategy> strategyList = Arrays.asList(strategies);
|
||||
serializeExclusionStrategies.addAll(strategyList);
|
||||
deserializeExclusionStrategies.addAll(strategyList);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures Gson to apply the passed in exclusion strategy during serialization.
|
||||
* If this method is invoked numerous times with different exclusion strategy objects
|
||||
* then the exclusion strategies that were added will be applied as a disjunction rule.
|
||||
* This means that if one of the added exclusion strategies suggests that a field (or
|
||||
* class) should be skipped then that field (or object) is skipped during its
|
||||
* serialization.
|
||||
*
|
||||
* @param strategy an exclusion strategy to apply during serialization.
|
||||
* @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern
|
||||
* @since 1.7
|
||||
*/
|
||||
public GsonBuilder addSerializationExclusionStrategy(ExclusionStrategy strategy) {
|
||||
serializeExclusionStrategies.add(strategy);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures Gson to apply the passed in exclusion strategy during deserialization.
|
||||
* If this method is invoked numerous times with different exclusion strategy objects
|
||||
* then the exclusion strategies that were added will be applied as a disjunction rule.
|
||||
* This means that if one of the added exclusion strategies suggests that a field (or
|
||||
* class) should be skipped then that field (or object) is skipped during its
|
||||
* deserialization.
|
||||
*
|
||||
* @param strategy an exclusion strategy to apply during deserialization.
|
||||
* @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern
|
||||
* @since 1.7
|
||||
*/
|
||||
public GsonBuilder addDeserializationExclusionStrategy(ExclusionStrategy strategy) {
|
||||
deserializeExclusionStrategies.add(strategy);
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* Configures Gson to output Json that fits in a page for pretty printing. This option only
|
||||
* affects Json serialization.
|
||||
@ -284,6 +415,9 @@ public final class GsonBuilder {
|
||||
* call this method or {@link #setDateFormat(int)} multiple times, but only the last invocation
|
||||
* will be used to decide the serialization format.
|
||||
*
|
||||
* <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}
|
||||
* class. See the documentation in {@link java.text.SimpleDateFormat} for more information on
|
||||
* 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
|
||||
*/
|
||||
public GsonBuilder registerTypeAdapter(Type type, Object typeAdapter) {
|
||||
Preconditions.checkArgument(typeAdapter instanceof JsonSerializer<?>
|
||||
|| typeAdapter instanceof JsonDeserializer<?> || typeAdapter instanceof InstanceCreator<?>);
|
||||
$Gson$Preconditions.checkArgument(typeAdapter instanceof JsonSerializer<?>
|
||||
|| typeAdapter instanceof JsonDeserializer<?> || typeAdapter instanceof InstanceCreator<?>);
|
||||
if (typeAdapter instanceof InstanceCreator<?>) {
|
||||
registerInstanceCreator(type, (InstanceCreator<?>) typeAdapter);
|
||||
}
|
||||
@ -432,9 +566,9 @@ public final class GsonBuilder {
|
||||
* @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern
|
||||
* @since 1.7
|
||||
*/
|
||||
GsonBuilder registerTypeHierarchyAdapter(Class<?> baseType, Object typeAdapter) {
|
||||
Preconditions.checkArgument(typeAdapter instanceof JsonSerializer<?>
|
||||
|| typeAdapter instanceof JsonDeserializer<?> || typeAdapter instanceof InstanceCreator<?>);
|
||||
public GsonBuilder registerTypeHierarchyAdapter(Class<?> baseType, Object typeAdapter) {
|
||||
$Gson$Preconditions.checkArgument(typeAdapter instanceof JsonSerializer<?>
|
||||
|| typeAdapter instanceof JsonDeserializer<?> || typeAdapter instanceof InstanceCreator<?>);
|
||||
if (typeAdapter instanceof InstanceCreator<?>) {
|
||||
registerInstanceCreatorForTypeHierarchy(baseType, (InstanceCreator<?>) typeAdapter);
|
||||
}
|
||||
@ -498,33 +632,34 @@ public final class GsonBuilder {
|
||||
* @return an instance of Gson configured with the options currently set in this builder
|
||||
*/
|
||||
public Gson create() {
|
||||
List<ExclusionStrategy> serializationStrategies =
|
||||
new LinkedList<ExclusionStrategy>(exclusionStrategies);
|
||||
List<ExclusionStrategy> deserializationStrategies =
|
||||
new LinkedList<ExclusionStrategy>(exclusionStrategies);
|
||||
|
||||
serializationStrategies.add(modifierBasedExclusionStrategy);
|
||||
new LinkedList<ExclusionStrategy>(deserializeExclusionStrategies);
|
||||
List<ExclusionStrategy> serializationStrategies =
|
||||
new LinkedList<ExclusionStrategy>(serializeExclusionStrategies);
|
||||
deserializationStrategies.add(modifierBasedExclusionStrategy);
|
||||
serializationStrategies.add(modifierBasedExclusionStrategy);
|
||||
|
||||
if (!serializeInnerClasses) {
|
||||
serializationStrategies.add(innerClassExclusionStrategy);
|
||||
deserializationStrategies.add(innerClassExclusionStrategy);
|
||||
serializationStrategies.add(innerClassExclusionStrategy);
|
||||
}
|
||||
if (ignoreVersionsAfter != VersionConstants.IGNORE_VERSIONS) {
|
||||
serializationStrategies.add(new VersionExclusionStrategy(ignoreVersionsAfter));
|
||||
deserializationStrategies.add(new VersionExclusionStrategy(ignoreVersionsAfter));
|
||||
VersionExclusionStrategy versionExclusionStrategy =
|
||||
new VersionExclusionStrategy(ignoreVersionsAfter);
|
||||
deserializationStrategies.add(versionExclusionStrategy);
|
||||
serializationStrategies.add(versionExclusionStrategy);
|
||||
}
|
||||
if (excludeFieldsWithoutExposeAnnotation) {
|
||||
serializationStrategies.add(exposeAnnotationSerializationExclusionStrategy);
|
||||
deserializationStrategies.add(exposeAnnotationDeserializationExclusionStrategy);
|
||||
serializationStrategies.add(exposeAnnotationSerializationExclusionStrategy);
|
||||
}
|
||||
ExclusionStrategy serializationExclusionStrategy =
|
||||
new DisjunctionExclusionStrategy(serializationStrategies);
|
||||
ExclusionStrategy deserializationExclusionStrategy =
|
||||
new DisjunctionExclusionStrategy(deserializationStrategies);
|
||||
|
||||
ParameterizedTypeHandlerMap<JsonSerializer<?>> customSerializers = serializers.copyOf();
|
||||
ParameterizedTypeHandlerMap<JsonDeserializer<?>> customDeserializers = deserializers.copyOf();
|
||||
ParameterizedTypeHandlerMap<JsonSerializer<?>> customSerializers =
|
||||
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,
|
||||
customDeserializers);
|
||||
|
||||
@ -543,9 +678,11 @@ public final class GsonBuilder {
|
||||
|
||||
MappedObjectConstructor objConstructor = new MappedObjectConstructor(customInstanceCreators);
|
||||
|
||||
Gson gson = new Gson(serializationExclusionStrategy, deserializationExclusionStrategy,
|
||||
fieldNamingPolicy, objConstructor, serializeNulls, customSerializers,
|
||||
customDeserializers, generateNonExecutableJson, escapeHtmlChars, prettyPrinting);
|
||||
Gson gson = new Gson(new DisjunctionExclusionStrategy(deserializationStrategies),
|
||||
new DisjunctionExclusionStrategy(serializationStrategies),
|
||||
fieldNamingPolicy, objConstructor, serializeNulls,
|
||||
customSerializers, customDeserializers, generateNonExecutableJson, escapeHtmlChars,
|
||||
prettyPrinting);
|
||||
return gson;
|
||||
}
|
||||
|
||||
@ -560,12 +697,19 @@ public final class GsonBuilder {
|
||||
}
|
||||
|
||||
if (dateTypeAdapter != null) {
|
||||
if (!serializers.hasSpecificHandlerFor(Date.class)) {
|
||||
serializers.register(Date.class, dateTypeAdapter);
|
||||
}
|
||||
if (!deserializers.hasSpecificHandlerFor(Date.class)) {
|
||||
deserializers.register(Date.class, dateTypeAdapter);
|
||||
}
|
||||
registerIfAbsent(Date.class, serializers, dateTypeAdapter);
|
||||
registerIfAbsent(Date.class, deserializers, dateTypeAdapter);
|
||||
registerIfAbsent(Timestamp.class, serializers, dateTypeAdapter);
|
||||
registerIfAbsent(Timestamp.class, deserializers, dateTypeAdapter);
|
||||
registerIfAbsent(java.sql.Date.class, serializers, dateTypeAdapter);
|
||||
registerIfAbsent(java.sql.Date.class, deserializers, dateTypeAdapter);
|
||||
}
|
||||
}
|
||||
|
||||
private static <T> void registerIfAbsent(Class<?> type,
|
||||
ParameterizedTypeHandlerMap<T> adapters, T adapter) {
|
||||
if (!adapters.hasSpecificHandlerFor(type)) {
|
||||
adapters.register(type, adapter);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -23,7 +23,7 @@ import java.lang.reflect.Modifier;
|
||||
*
|
||||
* @author Joel Leitch
|
||||
*/
|
||||
class InnerClassExclusionStrategy implements ExclusionStrategy {
|
||||
final class InnerClassExclusionStrategy implements ExclusionStrategy {
|
||||
|
||||
public boolean shouldSkipField(FieldAttributes f) {
|
||||
return isInnerClass(f.getDeclaredClass());
|
||||
|
@ -295,6 +295,16 @@ public final class JsonArray extends JsonElement implements Iterable<JsonElement
|
||||
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
|
||||
protected void toString(Appendable sb, Escaper escaper) throws IOException {
|
||||
sb.append('[');
|
||||
|
@ -16,6 +16,8 @@
|
||||
|
||||
package org.mcteam.factions.gson;
|
||||
|
||||
import org.mcteam.factions.gson.internal.$Gson$Types;
|
||||
|
||||
import java.lang.reflect.Array;
|
||||
import java.lang.reflect.Type;
|
||||
|
||||
@ -29,31 +31,28 @@ import java.lang.reflect.Type;
|
||||
final class JsonArrayDeserializationVisitor<T> extends JsonDeserializationVisitor<T> {
|
||||
|
||||
JsonArrayDeserializationVisitor(JsonArray jsonArray, Type arrayType,
|
||||
ObjectNavigatorFactory factory, ObjectConstructor objectConstructor,
|
||||
ObjectNavigator objectNavigator, FieldNamingStrategy2 fieldNamingPolicy,
|
||||
ObjectConstructor objectConstructor,
|
||||
ParameterizedTypeHandlerMap<JsonDeserializer<?>> deserializers,
|
||||
JsonDeserializationContext context) {
|
||||
super(jsonArray, arrayType, factory, objectConstructor, deserializers, context);
|
||||
super(jsonArray, arrayType, objectNavigator, fieldNamingPolicy, objectConstructor, deserializers, context);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
protected T constructTarget() {
|
||||
|
||||
TypeInfo typeInfo = new TypeInfo(targetType);
|
||||
|
||||
if (!json.isJsonArray()) {
|
||||
throw new JsonParseException("Expecting array found: " + json);
|
||||
}
|
||||
JsonArray jsonArray = json.getAsJsonArray();
|
||||
if (typeInfo.isArray()) {
|
||||
TypeInfoArray arrayTypeInfo = TypeInfoFactory.getTypeInfoForArray(targetType);
|
||||
if ($Gson$Types.isArray(targetType)) {
|
||||
// We know that we are getting back an array of the required type, so
|
||||
// this typecasting is safe.
|
||||
return (T) objectConstructor.constructArray(arrayTypeInfo.getSecondLevelType(),
|
||||
return (T) objectConstructor.constructArray($Gson$Types.getArrayComponentType(targetType),
|
||||
jsonArray.size());
|
||||
}
|
||||
// is a collection
|
||||
return (T) objectConstructor.construct(typeInfo.getRawClass());
|
||||
return (T) objectConstructor.construct($Gson$Types.getRawType(targetType));
|
||||
}
|
||||
|
||||
public void visitArray(Object array, Type arrayType) {
|
||||
@ -61,7 +60,6 @@ final class JsonArrayDeserializationVisitor<T> extends JsonDeserializationVisito
|
||||
throw new JsonParseException("Expecting array found: " + json);
|
||||
}
|
||||
JsonArray jsonArray = json.getAsJsonArray();
|
||||
TypeInfoArray arrayTypeInfo = TypeInfoFactory.getTypeInfoForArray(arrayType);
|
||||
for (int i = 0; i < jsonArray.size(); i++) {
|
||||
JsonElement jsonChild = jsonArray.get(i);
|
||||
Object child;
|
||||
@ -69,11 +67,12 @@ final class JsonArrayDeserializationVisitor<T> extends JsonDeserializationVisito
|
||||
if (jsonChild == null || jsonChild.isJsonNull()) {
|
||||
child = null;
|
||||
} else if (jsonChild instanceof JsonObject) {
|
||||
child = visitChildAsObject(arrayTypeInfo.getComponentRawType(), jsonChild);
|
||||
child = visitChildAsObject($Gson$Types.getArrayComponentType(arrayType), jsonChild);
|
||||
} else if (jsonChild instanceof JsonArray) {
|
||||
child = visitChildAsArray(arrayTypeInfo.getSecondLevelType(), jsonChild.getAsJsonArray());
|
||||
child = visitChildAsArray($Gson$Types.getArrayComponentType(arrayType),
|
||||
jsonChild.getAsJsonArray());
|
||||
} else if (jsonChild instanceof JsonPrimitive) {
|
||||
child = visitChildAsObject(arrayTypeInfo.getComponentRawType(),
|
||||
child = visitChildAsObject($Gson$Types.getArrayComponentType(arrayType),
|
||||
jsonChild.getAsJsonPrimitive());
|
||||
} else {
|
||||
throw new IllegalStateException();
|
||||
|
@ -25,14 +25,17 @@ import java.lang.reflect.Type;
|
||||
*/
|
||||
final class JsonDeserializationContextDefault implements JsonDeserializationContext {
|
||||
|
||||
private final ObjectNavigatorFactory navigatorFactory;
|
||||
private final ObjectNavigator objectNavigator;
|
||||
private final FieldNamingStrategy2 fieldNamingPolicy;
|
||||
private final ParameterizedTypeHandlerMap<JsonDeserializer<?>> deserializers;
|
||||
private final MappedObjectConstructor objectConstructor;
|
||||
|
||||
JsonDeserializationContextDefault(ObjectNavigatorFactory navigatorFactory,
|
||||
JsonDeserializationContextDefault(ObjectNavigator objectNavigator,
|
||||
FieldNamingStrategy2 fieldNamingPolicy,
|
||||
ParameterizedTypeHandlerMap<JsonDeserializer<?>> deserializers,
|
||||
MappedObjectConstructor objectConstructor) {
|
||||
this.navigatorFactory = navigatorFactory;
|
||||
this.objectNavigator = objectNavigator;
|
||||
this.fieldNamingPolicy = fieldNamingPolicy;
|
||||
this.deserializers = deserializers;
|
||||
this.objectConstructor = objectConstructor;
|
||||
}
|
||||
@ -59,18 +62,18 @@ final class JsonDeserializationContextDefault implements JsonDeserializationCont
|
||||
private <T> T fromJsonArray(Type arrayType, JsonArray jsonArray,
|
||||
JsonDeserializationContext context) throws JsonParseException {
|
||||
JsonArrayDeserializationVisitor<T> visitor = new JsonArrayDeserializationVisitor<T>(
|
||||
jsonArray, arrayType, navigatorFactory, objectConstructor, deserializers, context);
|
||||
ObjectNavigator on = navigatorFactory.create(new ObjectTypePair(null, arrayType, true));
|
||||
on.accept(visitor);
|
||||
jsonArray, arrayType, objectNavigator, fieldNamingPolicy,
|
||||
objectConstructor, deserializers, context);
|
||||
objectNavigator.accept(new ObjectTypePair(null, arrayType, true), visitor);
|
||||
return visitor.getTarget();
|
||||
}
|
||||
|
||||
private <T> T fromJsonObject(Type typeOfT, JsonObject jsonObject,
|
||||
JsonDeserializationContext context) throws JsonParseException {
|
||||
JsonObjectDeserializationVisitor<T> visitor = new JsonObjectDeserializationVisitor<T>(
|
||||
jsonObject, typeOfT, navigatorFactory, objectConstructor, deserializers, context);
|
||||
ObjectNavigator on = navigatorFactory.create(new ObjectTypePair(null, typeOfT, true));
|
||||
on.accept(visitor);
|
||||
jsonObject, typeOfT, objectNavigator, fieldNamingPolicy,
|
||||
objectConstructor, deserializers, context);
|
||||
objectNavigator.accept(new ObjectTypePair(null, typeOfT, true), visitor);
|
||||
return visitor.getTarget();
|
||||
}
|
||||
|
||||
@ -78,10 +81,8 @@ final class JsonDeserializationContextDefault implements JsonDeserializationCont
|
||||
private <T> T fromJsonPrimitive(Type typeOfT, JsonPrimitive json,
|
||||
JsonDeserializationContext context) throws JsonParseException {
|
||||
JsonObjectDeserializationVisitor<T> visitor = new JsonObjectDeserializationVisitor<T>(
|
||||
json, typeOfT, navigatorFactory, objectConstructor, deserializers, context);
|
||||
ObjectNavigator on =
|
||||
navigatorFactory.create(new ObjectTypePair(json.getAsObject(), typeOfT, true));
|
||||
on.accept(visitor);
|
||||
json, typeOfT, objectNavigator, fieldNamingPolicy, objectConstructor, deserializers, context);
|
||||
objectNavigator.accept(new ObjectTypePair(json.getAsObject(), typeOfT, true), visitor);
|
||||
Object target = visitor.getTarget();
|
||||
return (T) target;
|
||||
}
|
||||
|
@ -16,6 +16,8 @@
|
||||
|
||||
package org.mcteam.factions.gson;
|
||||
|
||||
import org.mcteam.factions.gson.internal.$Gson$Preconditions;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
|
||||
/**
|
||||
@ -28,7 +30,8 @@ import java.lang.reflect.Type;
|
||||
*/
|
||||
abstract class JsonDeserializationVisitor<T> implements ObjectNavigator.Visitor {
|
||||
|
||||
protected final ObjectNavigatorFactory factory;
|
||||
protected final ObjectNavigator objectNavigator;
|
||||
protected final FieldNamingStrategy2 fieldNamingPolicy;
|
||||
protected final ObjectConstructor objectConstructor;
|
||||
protected final ParameterizedTypeHandlerMap<JsonDeserializer<?>> deserializers;
|
||||
protected T target;
|
||||
@ -37,16 +40,17 @@ abstract class JsonDeserializationVisitor<T> implements ObjectNavigator.Visitor
|
||||
protected final JsonDeserializationContext context;
|
||||
protected boolean constructed;
|
||||
|
||||
public JsonDeserializationVisitor(JsonElement json, Type targetType,
|
||||
ObjectNavigatorFactory factory, ObjectConstructor objectConstructor,
|
||||
JsonDeserializationVisitor(JsonElement json, Type targetType,
|
||||
ObjectNavigator objectNavigator, FieldNamingStrategy2 fieldNamingPolicy,
|
||||
ObjectConstructor objectConstructor,
|
||||
ParameterizedTypeHandlerMap<JsonDeserializer<?>> deserializers,
|
||||
JsonDeserializationContext context) {
|
||||
Preconditions.checkNotNull(json);
|
||||
this.targetType = targetType;
|
||||
this.factory = factory;
|
||||
this.objectNavigator = objectNavigator;
|
||||
this.fieldNamingPolicy = fieldNamingPolicy;
|
||||
this.objectConstructor = objectConstructor;
|
||||
this.deserializers = deserializers;
|
||||
this.json = json;
|
||||
this.json = $Gson$Preconditions.checkNotNull(json);
|
||||
this.context = context;
|
||||
this.constructed = false;
|
||||
}
|
||||
@ -91,20 +95,19 @@ abstract class JsonDeserializationVisitor<T> implements ObjectNavigator.Visitor
|
||||
final Object visitChildAsObject(Type childType, JsonElement jsonChild) {
|
||||
JsonDeserializationVisitor<?> childVisitor =
|
||||
new JsonObjectDeserializationVisitor<Object>(jsonChild, childType,
|
||||
factory, objectConstructor, deserializers, context);
|
||||
objectNavigator, fieldNamingPolicy, objectConstructor, deserializers, context);
|
||||
return visitChild(childType, childVisitor);
|
||||
}
|
||||
|
||||
final Object visitChildAsArray(Type childType, JsonArray jsonChild) {
|
||||
JsonDeserializationVisitor<?> childVisitor =
|
||||
new JsonArrayDeserializationVisitor<Object>(jsonChild.getAsJsonArray(), childType,
|
||||
factory, objectConstructor, deserializers, context);
|
||||
objectNavigator, fieldNamingPolicy, objectConstructor, deserializers, context);
|
||||
return visitChild(childType, childVisitor);
|
||||
}
|
||||
|
||||
private Object visitChild(Type type, JsonDeserializationVisitor<?> childVisitor) {
|
||||
ObjectNavigator on = factory.create(new ObjectTypePair(null, type, false));
|
||||
on.accept(childVisitor);
|
||||
objectNavigator.accept(new ObjectTypePair(null, type, false), childVisitor);
|
||||
// the underlying object may have changed during the construction phase
|
||||
// This happens primarily because of custom deserializers
|
||||
return childVisitor.getTarget();
|
||||
|
@ -16,6 +16,8 @@
|
||||
|
||||
package org.mcteam.factions.gson;
|
||||
|
||||
import org.mcteam.factions.gson.internal.$Gson$Preconditions;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
|
||||
/**
|
||||
@ -28,7 +30,7 @@ import java.lang.reflect.Type;
|
||||
* @author Inderjeet Singh
|
||||
* @author Joel Leitch
|
||||
*/
|
||||
class JsonDeserializerExceptionWrapper<T> implements JsonDeserializer<T> {
|
||||
final class JsonDeserializerExceptionWrapper<T> implements JsonDeserializer<T> {
|
||||
|
||||
private final JsonDeserializer<T> delegate;
|
||||
|
||||
@ -40,8 +42,7 @@ class JsonDeserializerExceptionWrapper<T> implements JsonDeserializer<T> {
|
||||
* @throws IllegalArgumentException if {@code delegate} is {@code null}.
|
||||
*/
|
||||
JsonDeserializerExceptionWrapper(JsonDeserializer<T> delegate) {
|
||||
Preconditions.checkNotNull(delegate);
|
||||
this.delegate = delegate;
|
||||
this.delegate = $Gson$Preconditions.checkNotNull(delegate);
|
||||
}
|
||||
|
||||
public T deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
|
||||
@ -56,7 +57,7 @@ class JsonDeserializerExceptionWrapper<T> implements JsonDeserializer<T> {
|
||||
StringBuilder errorMsg = new StringBuilder()
|
||||
.append("The JsonDeserializer ")
|
||||
.append(delegate)
|
||||
.append(" failed to deserialized json object ")
|
||||
.append(" failed to deserialize json object ")
|
||||
.append(json)
|
||||
.append(" given the type ")
|
||||
.append(typeOfT);
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
@ -53,7 +53,7 @@ public final class JsonNull extends JsonElement {
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
return other instanceof JsonNull;
|
||||
return this == other || other instanceof JsonNull;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -16,6 +16,8 @@
|
||||
|
||||
package org.mcteam.factions.gson;
|
||||
|
||||
import org.mcteam.factions.gson.internal.$Gson$Preconditions;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
@ -52,11 +54,10 @@ public final class JsonObject extends JsonElement {
|
||||
* @param value the member object.
|
||||
*/
|
||||
public void add(String property, JsonElement value) {
|
||||
Preconditions.checkNotNull(property);
|
||||
if (value == null) {
|
||||
value = JsonNull.createJsonNull();
|
||||
}
|
||||
members.put(property, value);
|
||||
members.put($Gson$Preconditions.checkNotNull(property), value);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -188,6 +189,17 @@ public final class JsonObject extends JsonElement {
|
||||
return (JsonObject) members.get(memberName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
return (o == this) || (o instanceof JsonObject
|
||||
&& ((JsonObject) o).members.equals(members));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return members.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void toString(Appendable sb, Escaper escaper) throws IOException {
|
||||
sb.append('{');
|
||||
|
@ -16,6 +16,7 @@
|
||||
|
||||
package org.mcteam.factions.gson;
|
||||
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
|
||||
/**
|
||||
@ -28,10 +29,11 @@ import java.lang.reflect.Type;
|
||||
final class JsonObjectDeserializationVisitor<T> extends JsonDeserializationVisitor<T> {
|
||||
|
||||
JsonObjectDeserializationVisitor(JsonElement json, Type type,
|
||||
ObjectNavigatorFactory factory, ObjectConstructor objectConstructor,
|
||||
ObjectNavigator objectNavigator, FieldNamingStrategy2 fieldNamingPolicy,
|
||||
ObjectConstructor objectConstructor,
|
||||
ParameterizedTypeHandlerMap<JsonDeserializer<?>> deserializers,
|
||||
JsonDeserializationContext context) {
|
||||
super(json, type, factory, objectConstructor, deserializers, context);
|
||||
super(json, type, objectNavigator, fieldNamingPolicy, objectConstructor, deserializers, context);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -88,8 +90,7 @@ final class JsonObjectDeserializationVisitor<T> extends JsonDeserializationVisit
|
||||
}
|
||||
|
||||
private String getFieldName(FieldAttributes f) {
|
||||
FieldNamingStrategy2 namingPolicy = factory.getFieldNamingPolicy();
|
||||
return namingPolicy.translateName(f);
|
||||
return fieldNamingPolicy.translateName(f);
|
||||
}
|
||||
|
||||
public boolean visitFieldUsingCustomHandler(FieldAttributes f, Type declaredTypeOfField, Object parent) {
|
||||
@ -99,11 +100,11 @@ final class JsonObjectDeserializationVisitor<T> extends JsonDeserializationVisit
|
||||
throw new JsonParseException("Expecting object found: " + json);
|
||||
}
|
||||
JsonElement child = json.getAsJsonObject().get(fName);
|
||||
TypeInfo typeInfo = new TypeInfo(declaredTypeOfField);
|
||||
boolean isPrimitive = Primitives.isPrimitive(declaredTypeOfField);
|
||||
if (child == null) { // Child will be null if the field wasn't present in Json
|
||||
return true;
|
||||
} else if (child.isJsonNull()) {
|
||||
if (!typeInfo.isPrimitive()) {
|
||||
if (!isPrimitive) {
|
||||
f.set(parent, null);
|
||||
}
|
||||
return true;
|
||||
@ -114,7 +115,7 @@ final class JsonObjectDeserializationVisitor<T> extends JsonDeserializationVisit
|
||||
return false;
|
||||
}
|
||||
Object value = invokeCustomDeserializer(child, pair);
|
||||
if (value != null || !typeInfo.isPrimitive()) {
|
||||
if (value != null || !isPrimitive) {
|
||||
f.set(parent, value);
|
||||
}
|
||||
return true;
|
||||
|
@ -15,15 +15,14 @@
|
||||
*/
|
||||
package org.mcteam.factions.gson;
|
||||
|
||||
import org.mcteam.factions.gson.stream.JsonReader;
|
||||
import org.mcteam.factions.gson.stream.JsonToken;
|
||||
import org.mcteam.factions.gson.stream.MalformedJsonException;
|
||||
import java.io.EOFException;
|
||||
import java.io.IOException;
|
||||
import java.io.Reader;
|
||||
import java.io.StringReader;
|
||||
|
||||
import org.mcteam.factions.gson.stream.JsonReader;
|
||||
import org.mcteam.factions.gson.stream.JsonToken;
|
||||
import org.mcteam.factions.gson.stream.MalformedJsonException;
|
||||
|
||||
/**
|
||||
* A parser to parse Json into a parse tree of {@link JsonElement}s
|
||||
*
|
||||
|
@ -16,6 +16,8 @@
|
||||
|
||||
package org.mcteam.factions.gson;
|
||||
|
||||
import org.mcteam.factions.gson.internal.$Gson$Preconditions;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.math.BigDecimal;
|
||||
import java.math.BigInteger;
|
||||
@ -92,8 +94,8 @@ public final class JsonPrimitive extends JsonElement {
|
||||
char c = ((Character) primitive).charValue();
|
||||
this.value = String.valueOf(c);
|
||||
} else {
|
||||
Preconditions.checkArgument(primitive instanceof Number
|
||||
|| isPrimitiveOrString(primitive));
|
||||
$Gson$Preconditions.checkArgument(primitive instanceof Number
|
||||
|| isPrimitiveOrString(primitive));
|
||||
this.value = primitive;
|
||||
}
|
||||
}
|
||||
@ -111,7 +113,6 @@ public final class JsonPrimitive extends JsonElement {
|
||||
* convenience method to get this element as a {@link Boolean}.
|
||||
*
|
||||
* @return get this element as a {@link Boolean}.
|
||||
* @throws ClassCastException if the value contained is not a valid boolean value.
|
||||
*/
|
||||
@Override
|
||||
Boolean getAsBooleanWrapper() {
|
||||
@ -122,7 +123,6 @@ public final class JsonPrimitive extends JsonElement {
|
||||
* convenience method to get this element as a boolean value.
|
||||
*
|
||||
* @return get this element as a primitive boolean value.
|
||||
* @throws ClassCastException if the value contained is not a valid boolean value.
|
||||
*/
|
||||
@Override
|
||||
public boolean getAsBoolean() {
|
||||
@ -142,7 +142,7 @@ public final class JsonPrimitive extends JsonElement {
|
||||
* convenience method to get this element as a Number.
|
||||
*
|
||||
* @return get this element as a Number.
|
||||
* @throws ClassCastException if the value contained is not a valid Number.
|
||||
* @throws NumberFormatException if the value contained is not a valid Number.
|
||||
*/
|
||||
@Override
|
||||
public Number getAsNumber() {
|
||||
@ -179,7 +179,6 @@ public final class JsonPrimitive extends JsonElement {
|
||||
* convenience method to get this element as a String.
|
||||
*
|
||||
* @return get this element as a String.
|
||||
* @throws ClassCastException if the value contained is not a valid String.
|
||||
*/
|
||||
@Override
|
||||
public String getAsString() {
|
||||
@ -196,7 +195,7 @@ public final class JsonPrimitive extends JsonElement {
|
||||
* convenience method to get this element as a primitive double.
|
||||
*
|
||||
* @return get this element as a primitive double.
|
||||
* @throws ClassCastException if the value contained is not a valid double.
|
||||
* @throws NumberFormatException if the value contained is not a valid double.
|
||||
*/
|
||||
@Override
|
||||
public double getAsDouble() {
|
||||
@ -229,7 +228,7 @@ public final class JsonPrimitive extends JsonElement {
|
||||
* convenience method to get this element as a float.
|
||||
*
|
||||
* @return get this element as a float.
|
||||
* @throws ClassCastException if the value contained is not a valid float.
|
||||
* @throws NumberFormatException if the value contained is not a valid float.
|
||||
*/
|
||||
@Override
|
||||
public float getAsFloat() {
|
||||
@ -240,7 +239,7 @@ public final class JsonPrimitive extends JsonElement {
|
||||
* convenience method to get this element as a primitive long.
|
||||
*
|
||||
* @return get this element as a primitive long.
|
||||
* @throws ClassCastException if the value contained is not a valid long.
|
||||
* @throws NumberFormatException if the value contained is not a valid long.
|
||||
*/
|
||||
@Override
|
||||
public long getAsLong() {
|
||||
@ -251,7 +250,7 @@ public final class JsonPrimitive extends JsonElement {
|
||||
* convenience method to get this element as a primitive short.
|
||||
*
|
||||
* @return get this element as a primitive short.
|
||||
* @throws ClassCastException if the value contained is not a valid short value.
|
||||
* @throws NumberFormatException if the value contained is not a valid short value.
|
||||
*/
|
||||
@Override
|
||||
public short getAsShort() {
|
||||
@ -262,7 +261,7 @@ public final class JsonPrimitive extends JsonElement {
|
||||
* convenience method to get this element as a primitive integer.
|
||||
*
|
||||
* @return get this element as a primitive integer.
|
||||
* @throws ClassCastException if the value contained is not a valid integer.
|
||||
* @throws NumberFormatException if the value contained is not a valid integer.
|
||||
*/
|
||||
@Override
|
||||
public int getAsInt() {
|
||||
@ -356,7 +355,11 @@ public final class JsonPrimitive extends JsonElement {
|
||||
return getAsNumber().longValue() == other.getAsNumber().longValue();
|
||||
}
|
||||
if (isFloatingPoint(this) && isFloatingPoint(other)) {
|
||||
return getAsNumber().doubleValue() == other.getAsNumber().doubleValue();
|
||||
double a = getAsNumber().doubleValue();
|
||||
// Java standard types other than double return true for two NaN. So, need
|
||||
// special handling for double.
|
||||
double b = other.getAsNumber().doubleValue();
|
||||
return a == b || (Double.isNaN(a) && Double.isNaN(b));
|
||||
}
|
||||
return value.equals(other.value);
|
||||
}
|
||||
|
@ -16,6 +16,7 @@
|
||||
|
||||
package org.mcteam.factions.gson;
|
||||
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
|
||||
/**
|
||||
@ -25,14 +26,17 @@ import java.lang.reflect.Type;
|
||||
*/
|
||||
final class JsonSerializationContextDefault implements JsonSerializationContext {
|
||||
|
||||
private final ObjectNavigatorFactory factory;
|
||||
private final ObjectNavigator objectNavigator;
|
||||
private final FieldNamingStrategy2 fieldNamingPolicy;
|
||||
private final ParameterizedTypeHandlerMap<JsonSerializer<?>> serializers;
|
||||
private final boolean serializeNulls;
|
||||
private final MemoryRefStack ancestors;
|
||||
|
||||
JsonSerializationContextDefault(ObjectNavigatorFactory factory, boolean serializeNulls,
|
||||
JsonSerializationContextDefault(ObjectNavigator objectNavigator,
|
||||
FieldNamingStrategy2 fieldNamingPolicy, boolean serializeNulls,
|
||||
ParameterizedTypeHandlerMap<JsonSerializer<?>> serializers) {
|
||||
this.factory = factory;
|
||||
this.objectNavigator = objectNavigator;
|
||||
this.fieldNamingPolicy = fieldNamingPolicy;
|
||||
this.serializeNulls = serializeNulls;
|
||||
this.serializers = serializers;
|
||||
this.ancestors = new MemoryRefStack();
|
||||
@ -42,18 +46,20 @@ final class JsonSerializationContextDefault implements JsonSerializationContext
|
||||
if (src == null) {
|
||||
return JsonNull.createJsonNull();
|
||||
}
|
||||
return serialize(src, src.getClass(), true);
|
||||
return serialize(src, src.getClass(), false);
|
||||
}
|
||||
|
||||
public JsonElement serialize(Object src, Type typeOfSrc) {
|
||||
return serialize(src, typeOfSrc, true);
|
||||
}
|
||||
|
||||
public JsonElement serialize(Object src, Type typeOfSrc, boolean preserveType) {
|
||||
ObjectNavigator on = factory.create(new ObjectTypePair(src, typeOfSrc, preserveType));
|
||||
JsonSerializationVisitor visitor =
|
||||
new JsonSerializationVisitor(factory, serializeNulls, serializers, this, ancestors);
|
||||
on.accept(visitor);
|
||||
JsonElement serialize(Object src, Type typeOfSrc, boolean preserveType) {
|
||||
if (src == null) {
|
||||
return JsonNull.createJsonNull();
|
||||
}
|
||||
JsonSerializationVisitor visitor = new JsonSerializationVisitor(
|
||||
objectNavigator, fieldNamingPolicy, serializeNulls, serializers, this, ancestors);
|
||||
objectNavigator.accept(new ObjectTypePair(src, typeOfSrc, preserveType), visitor);
|
||||
return visitor.getJsonElement();
|
||||
}
|
||||
}
|
||||
|
@ -16,6 +16,9 @@
|
||||
|
||||
package org.mcteam.factions.gson;
|
||||
|
||||
import org.mcteam.factions.gson.internal.$Gson$Types;
|
||||
import org.mcteam.factions.gson.internal.$Gson$Preconditions;
|
||||
|
||||
import java.lang.reflect.Array;
|
||||
import java.lang.reflect.Type;
|
||||
|
||||
@ -27,17 +30,19 @@ import java.lang.reflect.Type;
|
||||
*/
|
||||
final class JsonSerializationVisitor implements ObjectNavigator.Visitor {
|
||||
|
||||
private final ObjectNavigatorFactory factory;
|
||||
private final ObjectNavigator objectNavigator;
|
||||
private final FieldNamingStrategy2 fieldNamingPolicy;
|
||||
private final ParameterizedTypeHandlerMap<JsonSerializer<?>> serializers;
|
||||
private final boolean serializeNulls;
|
||||
private final JsonSerializationContext context;
|
||||
private final MemoryRefStack ancestors;
|
||||
private JsonElement root;
|
||||
|
||||
JsonSerializationVisitor(ObjectNavigatorFactory factory, boolean serializeNulls,
|
||||
ParameterizedTypeHandlerMap<JsonSerializer<?>> serializers, JsonSerializationContext context,
|
||||
MemoryRefStack ancestors) {
|
||||
this.factory = factory;
|
||||
JsonSerializationVisitor(ObjectNavigator objectNavigator, FieldNamingStrategy2 fieldNamingPolicy,
|
||||
boolean serializeNulls, ParameterizedTypeHandlerMap<JsonSerializer<?>> serializers,
|
||||
JsonSerializationContext context, MemoryRefStack ancestors) {
|
||||
this.objectNavigator = objectNavigator;
|
||||
this.fieldNamingPolicy = fieldNamingPolicy;
|
||||
this.serializeNulls = serializeNulls;
|
||||
this.serializers = serializers;
|
||||
this.context = context;
|
||||
@ -71,15 +76,12 @@ final class JsonSerializationVisitor implements ObjectNavigator.Visitor {
|
||||
public void visitArray(Object array, Type arrayType) {
|
||||
assignToRoot(new JsonArray());
|
||||
int length = Array.getLength(array);
|
||||
TypeInfoArray fieldTypeInfo = TypeInfoFactory.getTypeInfoForArray(arrayType);
|
||||
Type componentType = fieldTypeInfo.getSecondLevelType();
|
||||
Type componentType = $Gson$Types.getArrayComponentType(arrayType);
|
||||
for (int i = 0; i < length; ++i) {
|
||||
Object child = Array.get(array, i);
|
||||
Type childType = componentType;
|
||||
// we should not get more specific component type yet since it is possible
|
||||
// that a custom
|
||||
// serializer is registered for the componentType
|
||||
addAsArrayElement(new ObjectTypePair(child, childType, false));
|
||||
// that a custom serializer is registered for the componentType
|
||||
addAsArrayElement(new ObjectTypePair(child, componentType, false));
|
||||
}
|
||||
}
|
||||
|
||||
@ -127,8 +129,7 @@ final class JsonSerializationVisitor implements ObjectNavigator.Visitor {
|
||||
}
|
||||
|
||||
private void addChildAsElement(FieldAttributes f, JsonElement childElement) {
|
||||
FieldNamingStrategy2 namingPolicy = factory.getFieldNamingPolicy();
|
||||
root.getAsJsonObject().add(namingPolicy.translateName(f), childElement);
|
||||
root.getAsJsonObject().add(fieldNamingPolicy.translateName(f), childElement);
|
||||
}
|
||||
|
||||
private void addAsArrayElement(ObjectTypePair elementTypePair) {
|
||||
@ -141,10 +142,9 @@ final class JsonSerializationVisitor implements ObjectNavigator.Visitor {
|
||||
}
|
||||
|
||||
private JsonElement getJsonElementForChild(ObjectTypePair fieldValueTypePair) {
|
||||
ObjectNavigator on = factory.create(fieldValueTypePair);
|
||||
JsonSerializationVisitor childVisitor =
|
||||
new JsonSerializationVisitor(factory, serializeNulls, serializers, context, ancestors);
|
||||
on.accept(childVisitor);
|
||||
JsonSerializationVisitor childVisitor = new JsonSerializationVisitor(
|
||||
objectNavigator, fieldNamingPolicy, serializeNulls, serializers, context, ancestors);
|
||||
objectNavigator.accept(fieldValueTypePair, childVisitor);
|
||||
return childVisitor.getJsonElement();
|
||||
}
|
||||
|
||||
@ -171,7 +171,7 @@ final class JsonSerializationVisitor implements ObjectNavigator.Visitor {
|
||||
/**
|
||||
* objTypePair.getObject() must not be null
|
||||
*/
|
||||
@SuppressWarnings({"unchecked", "rawtypes"})
|
||||
@SuppressWarnings("unchecked")
|
||||
private JsonElement findAndInvokeCustomSerializer(ObjectTypePair objTypePair) {
|
||||
Pair<JsonSerializer<?>,ObjectTypePair> pair = objTypePair.getMatchingHandler(serializers);
|
||||
if (pair == null) {
|
||||
@ -189,9 +189,10 @@ final class JsonSerializationVisitor implements ObjectNavigator.Visitor {
|
||||
}
|
||||
}
|
||||
|
||||
public boolean visitFieldUsingCustomHandler(FieldAttributes f, Type declaredTypeOfField, Object parent) {
|
||||
public boolean visitFieldUsingCustomHandler(
|
||||
FieldAttributes f, Type declaredTypeOfField, Object parent) {
|
||||
try {
|
||||
Preconditions.checkState(root.isJsonObject());
|
||||
$Gson$Preconditions.checkState(root.isJsonObject());
|
||||
Object obj = f.get(parent);
|
||||
if (obj == null) {
|
||||
if (serializeNulls) {
|
||||
@ -214,8 +215,7 @@ final class JsonSerializationVisitor implements ObjectNavigator.Visitor {
|
||||
}
|
||||
|
||||
private void assignToRoot(JsonElement newRoot) {
|
||||
Preconditions.checkNotNull(newRoot);
|
||||
root = newRoot;
|
||||
root = $Gson$Preconditions.checkNotNull(newRoot);
|
||||
}
|
||||
|
||||
private boolean isFieldNull(FieldAttributes f, Object obj) {
|
||||
|
@ -26,7 +26,6 @@ import org.mcteam.factions.gson.stream.JsonReader;
|
||||
import org.mcteam.factions.gson.stream.JsonToken;
|
||||
import org.mcteam.factions.gson.stream.MalformedJsonException;
|
||||
|
||||
|
||||
/**
|
||||
* A streaming parser that allows reading of multiple {@link JsonElement}s from the specified reader
|
||||
* asynchronously.
|
||||
|
@ -16,6 +16,7 @@
|
||||
|
||||
package org.mcteam.factions.gson;
|
||||
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@ -32,33 +33,23 @@ final class LruCache<K, V> extends LinkedHashMap<K, V> implements Cache<K, V> {
|
||||
|
||||
private final int maxCapacity;
|
||||
|
||||
LruCache(int maxCapacity) {
|
||||
public LruCache(int maxCapacity) {
|
||||
super(maxCapacity, 0.7F, true);
|
||||
this.maxCapacity = maxCapacity;
|
||||
}
|
||||
|
||||
public void addElement(K key, V value) {
|
||||
public synchronized void addElement(K key, V value) {
|
||||
put(key, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
super.clear();
|
||||
}
|
||||
|
||||
public V getElement(K key) {
|
||||
public synchronized V getElement(K key) {
|
||||
return get(key);
|
||||
}
|
||||
|
||||
public V removeElement(K key) {
|
||||
public synchronized V removeElement(K key) {
|
||||
return remove(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return super.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean removeEldestEntry(Map.Entry<K, V> entry) {
|
||||
return size() > maxCapacity;
|
||||
|
@ -19,7 +19,6 @@ package org.mcteam.factions.gson;
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@ -45,9 +44,9 @@ import java.util.Map;
|
||||
* But GSON is unable to deserialize this value because the JSON string name is
|
||||
* just the {@link Object#toString() toString()} of the map key. Attempting to
|
||||
* convert the above JSON to an object fails with a parse exception:
|
||||
* <pre>com.bukkit.mcteam.gson.JsonParseException: Expecting object found: "(5,6)"
|
||||
* at com.bukkit.mcteam.gson.JsonObjectDeserializationVisitor.visitFieldUsingCustomHandler
|
||||
* at com.bukkit.mcteam.gson.ObjectNavigator.navigateClassFields
|
||||
* <pre>org.mcteam.factions.gson.JsonParseException: Expecting object found: "(5,6)"
|
||||
* at org.mcteam.factions.gson.JsonObjectDeserializationVisitor.visitFieldUsingCustomHandler
|
||||
* at org.mcteam.factions.gson.ObjectNavigator.navigateClassFields
|
||||
* ...</pre>
|
||||
*
|
||||
* <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
|
||||
* object.
|
||||
*/
|
||||
public final class MapAsArrayTypeAdapter
|
||||
final class MapAsArrayTypeAdapter
|
||||
extends BaseMapTypeAdapter
|
||||
implements JsonSerializer<Map<?, ?>>, JsonDeserializer<Map<?, ?>> {
|
||||
|
||||
public Map<?, ?> deserialize(JsonElement json, Type typeOfT,
|
||||
JsonDeserializationContext context) throws JsonParseException {
|
||||
Map<Object, Object> result = new LinkedHashMap<Object, Object>();
|
||||
Map<Object, Object> result = constructMapType(typeOfT, context);
|
||||
Type[] keyAndValueType = typeToTypeArguments(typeOfT);
|
||||
if (json.isJsonArray()) {
|
||||
JsonArray array = json.getAsJsonArray();
|
||||
@ -123,10 +123,10 @@ public final class MapAsArrayTypeAdapter
|
||||
boolean serializeAsArray = false;
|
||||
List<JsonElement> keysAndValues = new ArrayList<JsonElement>();
|
||||
for (Map.Entry<?, ?> entry : src.entrySet()) {
|
||||
JsonElement key = context.serialize(entry.getKey(), keyAndValueType[0]);
|
||||
JsonElement key = serialize(context, entry.getKey(), keyAndValueType[0]);
|
||||
serializeAsArray |= key.isJsonObject() || key.isJsonArray();
|
||||
keysAndValues.add(key);
|
||||
keysAndValues.add(context.serialize(entry.getValue(), keyAndValueType[1]));
|
||||
keysAndValues.add(serialize(context, entry.getValue(), keyAndValueType[1]));
|
||||
}
|
||||
|
||||
if (serializeAsArray) {
|
||||
|
78
src/org/mcteam/factions/gson/MapTypeAdapter.java
Normal file
78
src/org/mcteam/factions/gson/MapTypeAdapter.java
Normal 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();
|
||||
}
|
||||
}
|
@ -16,13 +16,10 @@
|
||||
|
||||
package org.mcteam.factions.gson;
|
||||
|
||||
import java.lang.reflect.AccessibleObject;
|
||||
import org.mcteam.factions.gson.internal.$Gson$Types;
|
||||
|
||||
import java.lang.reflect.Array;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
* This class contains a mapping of all the application specific
|
||||
@ -35,7 +32,9 @@ import java.util.logging.Logger;
|
||||
* @author Joel Leitch
|
||||
*/
|
||||
final class MappedObjectConstructor implements ObjectConstructor {
|
||||
private static final Logger log = Logger.getLogger(MappedObjectConstructor.class.getName());
|
||||
private static final UnsafeAllocator unsafeAllocator = UnsafeAllocator.create();
|
||||
private static final DefaultConstructorAllocator defaultConstructorAllocator =
|
||||
new DefaultConstructorAllocator(500);
|
||||
|
||||
private final ParameterizedTypeHandlerMap<InstanceCreator<?>> instanceCreatorMap;
|
||||
|
||||
@ -50,59 +49,25 @@ final class MappedObjectConstructor implements ObjectConstructor {
|
||||
if (creator != null) {
|
||||
return creator.createInstance(typeOfT);
|
||||
}
|
||||
return (T) constructWithNoArgConstructor(typeOfT);
|
||||
return (T) constructWithAllocators(typeOfT);
|
||||
}
|
||||
|
||||
public Object constructArray(Type type, int length) {
|
||||
return Array.newInstance(TypeUtils.toRawClass(type), length);
|
||||
}
|
||||
|
||||
private <T> 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);
|
||||
}
|
||||
return Array.newInstance($Gson$Types.getRawType(type), length);
|
||||
}
|
||||
|
||||
@SuppressWarnings({"unchecked", "cast"})
|
||||
private <T> Constructor<T> getNoArgsConstructor(Type typeOfT) {
|
||||
TypeInfo typeInfo = new TypeInfo(typeOfT);
|
||||
Class<T> clazz = (Class<T>) typeInfo.getRawClass();
|
||||
Constructor<T>[] declaredConstructors = (Constructor<T>[]) clazz.getDeclaredConstructors();
|
||||
AccessibleObject.setAccessible(declaredConstructors, true);
|
||||
for (Constructor<T> constructor : declaredConstructors) {
|
||||
if (constructor.getParameterTypes().length == 0) {
|
||||
return constructor;
|
||||
}
|
||||
private <T> T constructWithAllocators(Type typeOfT) {
|
||||
try {
|
||||
Class<T> clazz = (Class<T>) $Gson$Types.getRawType(typeOfT);
|
||||
T obj = defaultConstructorAllocator.newInstance(clazz);
|
||||
return (obj == null)
|
||||
? unsafeAllocator.newInstance(clazz)
|
||||
: obj;
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(("Unable to invoke no-args constructor for " + typeOfT + ". "
|
||||
+ "Register an InstanceCreator with Gson for this type may fix this problem."), e);
|
||||
}
|
||||
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
|
||||
|
@ -16,6 +16,8 @@
|
||||
|
||||
package org.mcteam.factions.gson;
|
||||
|
||||
import org.mcteam.factions.gson.internal.$Gson$Preconditions;
|
||||
|
||||
import java.util.Stack;
|
||||
|
||||
/**
|
||||
@ -35,8 +37,7 @@ final class MemoryRefStack {
|
||||
* @return the object that was added
|
||||
*/
|
||||
public ObjectTypePair push(ObjectTypePair obj) {
|
||||
Preconditions.checkNotNull(obj);
|
||||
|
||||
$Gson$Preconditions.checkNotNull(obj);
|
||||
return stack.push(obj);
|
||||
}
|
||||
|
||||
|
@ -16,6 +16,8 @@
|
||||
|
||||
package org.mcteam.factions.gson;
|
||||
|
||||
import org.mcteam.factions.gson.internal.$Gson$Preconditions;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.Collection;
|
||||
@ -62,9 +64,8 @@ final class ModifyFirstLetterNamingPolicy extends RecursiveFieldNamingPolicy {
|
||||
* @param modifier the type of modification that should be performed
|
||||
* @throws IllegalArgumentException if {@code modifier} is null
|
||||
*/
|
||||
public ModifyFirstLetterNamingPolicy(LetterModifier modifier) {
|
||||
Preconditions.checkNotNull(modifier);
|
||||
this.letterModifier = modifier;
|
||||
ModifyFirstLetterNamingPolicy(LetterModifier modifier) {
|
||||
this.letterModifier = $Gson$Preconditions.checkNotNull(modifier);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -100,8 +101,8 @@ final class ModifyFirstLetterNamingPolicy extends RecursiveFieldNamingPolicy {
|
||||
}
|
||||
|
||||
private String modifyString(char firstCharacter, String srcString, int indexOfSubstring) {
|
||||
return indexOfSubstring < srcString.length() ?
|
||||
firstCharacter + srcString.substring(indexOfSubstring)
|
||||
return (indexOfSubstring < srcString.length())
|
||||
? firstCharacter + srcString.substring(indexOfSubstring)
|
||||
: String.valueOf(firstCharacter);
|
||||
}
|
||||
}
|
||||
|
@ -16,7 +16,6 @@
|
||||
|
||||
package org.mcteam.factions.gson;
|
||||
|
||||
|
||||
/**
|
||||
* This acts as a "Null Object" pattern for the {@link ExclusionStrategy}.
|
||||
* Passing an instance of this class into the {@link ObjectNavigator} will
|
||||
|
@ -16,8 +16,8 @@
|
||||
|
||||
package org.mcteam.factions.gson;
|
||||
|
||||
import java.lang.reflect.AccessibleObject;
|
||||
import java.lang.reflect.Field;
|
||||
import org.mcteam.factions.gson.internal.$Gson$Types;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
|
||||
/**
|
||||
@ -69,38 +69,33 @@ final class ObjectNavigator {
|
||||
public boolean visitFieldUsingCustomHandler(FieldAttributes f, Type actualTypeOfField,
|
||||
Object parent);
|
||||
|
||||
void visitPrimitive(Object primitive);
|
||||
|
||||
/**
|
||||
* Retrieve the current target
|
||||
*/
|
||||
Object getTarget();
|
||||
|
||||
void visitPrimitive(Object primitive);
|
||||
}
|
||||
|
||||
private final ExclusionStrategy exclusionStrategy;
|
||||
private final ObjectTypePair objTypePair;
|
||||
private final ReflectingFieldNavigator reflectingFieldNavigator;
|
||||
|
||||
/**
|
||||
* @param objTypePair
|
||||
* The object,type (fully genericized) being navigated
|
||||
* @param exclusionStrategy
|
||||
* the concrete strategy object to be used to filter out fields of an
|
||||
* @param strategy the concrete exclusion strategy object to be used to filter out fields of an
|
||||
* object.
|
||||
*/
|
||||
ObjectNavigator(ObjectTypePair objTypePair, ExclusionStrategy exclusionStrategy) {
|
||||
Preconditions.checkNotNull(exclusionStrategy);
|
||||
|
||||
this.objTypePair = objTypePair;
|
||||
this.exclusionStrategy = exclusionStrategy;
|
||||
ObjectNavigator(ExclusionStrategy strategy) {
|
||||
this.exclusionStrategy = strategy == null ? new NullExclusionStrategy() : strategy;
|
||||
this.reflectingFieldNavigator = new ReflectingFieldNavigator(exclusionStrategy);
|
||||
}
|
||||
|
||||
/**
|
||||
* Navigate all the fields of the specified object. If a field is null, it
|
||||
* does not get visited.
|
||||
* @param objTypePair The object,type (fully genericized) being navigated
|
||||
*/
|
||||
public void accept(Visitor visitor) {
|
||||
TypeInfo objTypeInfo = new TypeInfo(objTypePair.type);
|
||||
if (exclusionStrategy.shouldSkipClass(objTypeInfo.getRawClass())) {
|
||||
public void accept(ObjectTypePair objTypePair, Visitor visitor) {
|
||||
if (exclusionStrategy.shouldSkipClass($Gson$Types.getRawType(objTypePair.type))) {
|
||||
return;
|
||||
}
|
||||
boolean visitedWithCustomHandler = visitor.visitUsingCustomHandler(objTypePair);
|
||||
@ -113,24 +108,16 @@ final class ObjectNavigator {
|
||||
objTypePair.setObject(objectToVisit);
|
||||
visitor.start(objTypePair);
|
||||
try {
|
||||
if (objTypeInfo.isArray()) {
|
||||
if ($Gson$Types.isArray(objTypePair.type)) {
|
||||
visitor.visitArray(objectToVisit, objTypePair.type);
|
||||
} else if (objTypeInfo.getActualType() == Object.class
|
||||
&& isPrimitiveOrString(objectToVisit)) {
|
||||
} else if (objTypePair.type == Object.class && isPrimitiveOrString(objectToVisit)) {
|
||||
// TODO(Joel): this is only used for deserialization of "primitives"
|
||||
// we should rethink this!!!
|
||||
visitor.visitPrimitive(objectToVisit);
|
||||
objectToVisit = visitor.getTarget();
|
||||
visitor.getTarget();
|
||||
} else {
|
||||
visitor.startVisitingObject(objectToVisit);
|
||||
ObjectTypePair currObjTypePair = objTypePair.toMoreSpecificType();
|
||||
Class<?> topLevelClass = new TypeInfo(currObjTypePair.type).getRawClass();
|
||||
for (Class<?> curr = topLevelClass; curr != null && !curr.equals(Object.class); curr =
|
||||
curr.getSuperclass()) {
|
||||
if (!curr.isSynthetic()) {
|
||||
navigateClassFields(objectToVisit, curr, visitor);
|
||||
}
|
||||
}
|
||||
reflectingFieldNavigator.visitFieldsReflectively(objTypePair, visitor);
|
||||
}
|
||||
} finally {
|
||||
visitor.end(objTypePair);
|
||||
@ -138,32 +125,9 @@ final class ObjectNavigator {
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isPrimitiveOrString(Object objectToVisit) {
|
||||
private static boolean isPrimitiveOrString(Object objectToVisit) {
|
||||
Class<?> realClazz = objectToVisit.getClass();
|
||||
return realClazz == Object.class || realClazz == String.class
|
||||
|| Primitives.unwrap(realClazz).isPrimitive();
|
||||
}
|
||||
|
||||
private void navigateClassFields(Object obj, Class<?> clazz, Visitor visitor) {
|
||||
Field[] fields = clazz.getDeclaredFields();
|
||||
AccessibleObject.setAccessible(fields, true);
|
||||
for (Field f : fields) {
|
||||
FieldAttributes fieldAttributes = new FieldAttributes(clazz, f);
|
||||
if (exclusionStrategy.shouldSkipField(fieldAttributes)
|
||||
|| exclusionStrategy.shouldSkipClass(fieldAttributes.getDeclaredClass())) {
|
||||
continue; // skip
|
||||
}
|
||||
TypeInfo fieldTypeInfo = TypeInfoFactory.getTypeInfoForField(f, objTypePair.type);
|
||||
Type declaredTypeOfField = fieldTypeInfo.getActualType();
|
||||
boolean visitedWithCustomHandler =
|
||||
visitor.visitFieldUsingCustomHandler(fieldAttributes, declaredTypeOfField, obj);
|
||||
if (!visitedWithCustomHandler) {
|
||||
if (fieldTypeInfo.isArray()) {
|
||||
visitor.visitArrayField(fieldAttributes, declaredTypeOfField, obj);
|
||||
} else {
|
||||
visitor.visitObjectField(fieldAttributes, declaredTypeOfField, obj);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
@ -15,6 +15,7 @@
|
||||
*/
|
||||
package org.mcteam.factions.gson;
|
||||
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
|
||||
/**
|
||||
@ -77,6 +78,13 @@ final class ObjectTypePair {
|
||||
return new ObjectTypePair(obj, actualType, preserveType);
|
||||
}
|
||||
|
||||
Type getMoreSpecificType() {
|
||||
if (preserveType || obj == null) {
|
||||
return type;
|
||||
}
|
||||
return getActualTypeIfMoreSpecific(type, obj.getClass());
|
||||
}
|
||||
|
||||
// This takes care of situations where the field was declared as an Object, but the
|
||||
// actual value contains something more specific. See Issue 54.
|
||||
// TODO (inder): This solution will not work if the field is of a generic type, but
|
||||
|
@ -26,11 +26,10 @@ package org.mcteam.factions.gson;
|
||||
* @param <SECOND>
|
||||
*/
|
||||
final class Pair<FIRST, SECOND> {
|
||||
public final FIRST first;
|
||||
public final SECOND second;
|
||||
|
||||
final FIRST first;
|
||||
final SECOND second;
|
||||
|
||||
Pair(FIRST first, SECOND second) {
|
||||
public Pair(FIRST first, SECOND second) {
|
||||
this.first = first;
|
||||
this.second = second;
|
||||
}
|
||||
|
@ -16,6 +16,8 @@
|
||||
|
||||
package org.mcteam.factions.gson;
|
||||
|
||||
import org.mcteam.factions.gson.internal.$Gson$Types;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
@ -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) {
|
||||
if (!modifiable) {
|
||||
throw new IllegalStateException("Attempted to modify an unmodifiable map.");
|
||||
@ -121,7 +138,7 @@ final class ParameterizedTypeHandlerMap<T> {
|
||||
public synchronized T getHandlerFor(Type type) {
|
||||
T handler = map.get(type);
|
||||
if (handler == null) {
|
||||
Class<?> rawClass = TypeUtils.toRawClass(type);
|
||||
Class<?> rawClass = $Gson$Types.getRawType(type);
|
||||
if (rawClass != type) {
|
||||
handler = getHandlerFor(rawClass);
|
||||
}
|
||||
@ -157,12 +174,10 @@ final class ParameterizedTypeHandlerMap<T> {
|
||||
|
||||
public synchronized ParameterizedTypeHandlerMap<T> copyOf() {
|
||||
ParameterizedTypeHandlerMap<T> copy = new ParameterizedTypeHandlerMap<T>();
|
||||
for (Map.Entry<Type, T> entry : map.entrySet()) {
|
||||
copy.register(entry.getKey(), entry.getValue());
|
||||
}
|
||||
for (Pair<Class<?>, T> entry : typeHierarchyList) {
|
||||
copy.registerForTypeHierarchy(entry);
|
||||
}
|
||||
// Instead of individually registering entries in the map, make an efficient copy
|
||||
// of the list and map
|
||||
copy.map.putAll(map);
|
||||
copy.typeHierarchyList.addAll(typeHierarchyList);
|
||||
return copy;
|
||||
}
|
||||
|
||||
@ -195,6 +210,6 @@ final class ParameterizedTypeHandlerMap<T> {
|
||||
}
|
||||
|
||||
private String typeToString(Type type) {
|
||||
return TypeUtils.toRawClass(type).getSimpleName();
|
||||
return $Gson$Types.getRawType(type).getSimpleName();
|
||||
}
|
||||
}
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
@ -16,10 +16,14 @@
|
||||
|
||||
package org.mcteam.factions.gson;
|
||||
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.mcteam.factions.gson.internal.$Gson$Preconditions;
|
||||
|
||||
/**
|
||||
* Contains static utility methods pertaining to primitive types and their
|
||||
* corresponding wrapper types.
|
||||
@ -30,10 +34,10 @@ final class Primitives {
|
||||
private Primitives() {}
|
||||
|
||||
/** 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. */
|
||||
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. :(
|
||||
|
||||
@ -61,6 +65,13 @@ final class Primitives {
|
||||
backward.put(value, key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this type is a primitive.
|
||||
*/
|
||||
public static boolean isPrimitive(Type type) {
|
||||
return PRIMITIVE_TO_WRAPPER_TYPE.containsKey(type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code true} if {@code type} is one of the nine
|
||||
* primitive-wrapper types, such as {@link Integer}.
|
||||
@ -68,12 +79,8 @@ final class Primitives {
|
||||
* @see Class#isPrimitive
|
||||
*/
|
||||
public static boolean isWrapperType(Class<?> type) {
|
||||
return WRAPPER_TO_PRIMITIVE_TYPE.containsKey(checkNotNull(type));
|
||||
}
|
||||
|
||||
private static Class<?> checkNotNull(Class<?> type) {
|
||||
Preconditions.checkNotNull(type);
|
||||
return type;
|
||||
return WRAPPER_TO_PRIMITIVE_TYPE.containsKey(
|
||||
$Gson$Preconditions.checkNotNull(type));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -86,11 +93,10 @@ final class Primitives {
|
||||
* </pre>
|
||||
*/
|
||||
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>
|
||||
@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;
|
||||
}
|
||||
|
||||
@ -104,11 +110,10 @@ final class Primitives {
|
||||
* </pre>
|
||||
*/
|
||||
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>
|
||||
@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;
|
||||
}
|
||||
}
|
||||
|
@ -30,7 +30,6 @@ import java.util.Collection;
|
||||
abstract class RecursiveFieldNamingPolicy implements FieldNamingStrategy2 {
|
||||
|
||||
public final String translateName(FieldAttributes f) {
|
||||
Preconditions.checkNotNull(f);
|
||||
return translateName(f.getName(), f.getDeclaredType(), f.getAnnotations());
|
||||
}
|
||||
|
||||
|
106
src/org/mcteam/factions/gson/ReflectingFieldNavigator.java
Normal file
106
src/org/mcteam/factions/gson/ReflectingFieldNavigator.java
Normal 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;
|
||||
}
|
||||
}
|
@ -19,30 +19,30 @@ package org.mcteam.factions.gson;
|
||||
import org.mcteam.factions.gson.annotations.SerializedName;
|
||||
|
||||
/**
|
||||
* A {@link FieldNamingStrategy2} that acts as a chain of responsibility. If the
|
||||
* {@link org.mcteam.factions.gson.annotations.SerializedName} annotation is applied to a field then this
|
||||
* strategy will translate the name to the {@code serializedName.value()}; otherwise it delegates
|
||||
* to the wrapped {@link FieldNamingStrategy2}.
|
||||
* A {@link FieldNamingStrategy2} that acts as a chain of responsibility. If the
|
||||
* {@link org.mcteam.factions.gson.annotations.SerializedName} annotation is applied to a
|
||||
* field then this strategy will translate the name to the {@code
|
||||
* serializedName.value()}; otherwise it delegates to the wrapped
|
||||
* {@link FieldNamingStrategy2}.
|
||||
*
|
||||
* <p>NOTE: this class performs JSON field name validation for any of the fields marked with
|
||||
* an {@code @SerializedName} annotation.</p>
|
||||
* <p>
|
||||
* NOTE: this class performs JSON field name validation for any of the fields
|
||||
* marked with an {@code @SerializedName} annotation.
|
||||
* </p>
|
||||
*
|
||||
* @see SerializedName
|
||||
*
|
||||
* @author Joel Leitch
|
||||
*/
|
||||
final class SerializedNameAnnotationInterceptingNamingPolicy implements FieldNamingStrategy2 {
|
||||
private static final JsonFieldNameValidator fieldNameValidator = new JsonFieldNameValidator();
|
||||
private final FieldNamingStrategy2 delegate;
|
||||
|
||||
public SerializedNameAnnotationInterceptingNamingPolicy(FieldNamingStrategy2 delegate) {
|
||||
SerializedNameAnnotationInterceptingNamingPolicy(FieldNamingStrategy2 delegate) {
|
||||
this.delegate = delegate;
|
||||
}
|
||||
|
||||
public String translateName(FieldAttributes f) {
|
||||
Preconditions.checkNotNull(f);
|
||||
SerializedName serializedName = f.getAnnotation(SerializedName.class);
|
||||
return serializedName == null ? delegate.translateName(f)
|
||||
: fieldNameValidator.validate(serializedName.value());
|
||||
return serializedName == null ? delegate.translateName(f) : serializedName.value();
|
||||
}
|
||||
}
|
||||
|
@ -16,15 +16,14 @@
|
||||
|
||||
package org.mcteam.factions.gson;
|
||||
|
||||
import org.mcteam.factions.gson.stream.JsonReader;
|
||||
import org.mcteam.factions.gson.stream.JsonWriter;
|
||||
import org.mcteam.factions.gson.stream.MalformedJsonException;
|
||||
import java.io.EOFException;
|
||||
import java.io.IOException;
|
||||
import java.io.Writer;
|
||||
import java.util.Map;
|
||||
|
||||
import org.mcteam.factions.gson.stream.JsonReader;
|
||||
import org.mcteam.factions.gson.stream.JsonWriter;
|
||||
import org.mcteam.factions.gson.stream.MalformedJsonException;
|
||||
|
||||
/**
|
||||
* Reads and writes GSON parse trees over streams.
|
||||
*/
|
||||
|
@ -26,7 +26,7 @@ package org.mcteam.factions.gson;
|
||||
*
|
||||
* @since 1.4
|
||||
*/
|
||||
class SyntheticFieldExclusionStrategy implements ExclusionStrategy {
|
||||
final class SyntheticFieldExclusionStrategy implements ExclusionStrategy {
|
||||
private final boolean skipSyntheticFields;
|
||||
|
||||
SyntheticFieldExclusionStrategy(boolean skipSyntheticFields) {
|
||||
|
@ -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);
|
||||
}
|
@ -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));
|
||||
}
|
||||
}
|
@ -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<String>[][] types, it will return the
|
||||
* type representing Foo<String>[]
|
||||
* (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;
|
||||
}
|
||||
}
|
@ -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];
|
||||
}
|
||||
}
|
@ -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!");
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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
|
||||
}
|
||||
}
|
104
src/org/mcteam/factions/gson/UnsafeAllocator.java
Normal file
104
src/org/mcteam/factions/gson/UnsafeAllocator.java
Normal 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);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
@ -18,6 +18,7 @@ package org.mcteam.factions.gson;
|
||||
|
||||
import org.mcteam.factions.gson.annotations.Since;
|
||||
import org.mcteam.factions.gson.annotations.Until;
|
||||
import org.mcteam.factions.gson.internal.$Gson$Preconditions;
|
||||
|
||||
/**
|
||||
* This strategy will exclude any files and/or class that are passed the
|
||||
@ -28,8 +29,8 @@ import org.mcteam.factions.gson.annotations.Until;
|
||||
final class VersionExclusionStrategy implements ExclusionStrategy {
|
||||
private final double version;
|
||||
|
||||
public VersionExclusionStrategy(double version) {
|
||||
Preconditions.checkArgument(version >= 0.0D);
|
||||
VersionExclusionStrategy(double version) {
|
||||
$Gson$Preconditions.checkArgument(version >= 0.0D);
|
||||
this.version = version;
|
||||
}
|
||||
|
||||
|
@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.mcteam.factions.gson;
|
||||
package org.mcteam.factions.gson.internal;
|
||||
|
||||
/**
|
||||
* A simple utility class used to check method Preconditions.
|
||||
@ -29,20 +29,23 @@ package org.mcteam.factions.gson;
|
||||
* @author Inderjeet Singh
|
||||
* @author Joel Leitch
|
||||
*/
|
||||
final class Preconditions {
|
||||
public static void checkNotNull(Object obj) {
|
||||
checkArgument(obj != null);
|
||||
public final class $Gson$Preconditions {
|
||||
public static <T> T checkNotNull(T obj) {
|
||||
if (obj == null) {
|
||||
throw new NullPointerException();
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
public static void checkArgument(boolean condition) {
|
||||
if (!condition) {
|
||||
throw new IllegalArgumentException("condition failed: " + condition);
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
}
|
||||
|
||||
public static void checkState(boolean condition) {
|
||||
if (!condition) {
|
||||
throw new IllegalArgumentException("condition failed: " + condition);
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
}
|
||||
}
|
589
src/org/mcteam/factions/gson/internal/$Gson$Types.java
Normal file
589
src/org/mcteam/factions/gson/internal/$Gson$Types.java
Normal 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;
|
||||
}
|
||||
}
|
7
src/org/mcteam/factions/gson/internal/package-info.java
Normal file
7
src/org/mcteam/factions/gson/internal/package-info.java
Normal 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;
|
@ -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.
|
||||
*
|
||||
* <p>The primary class to use is {@link com.bukkit.mcteam.gson.Gson} which can be constructed with
|
||||
* {@code new Gson()} (using default settings) or by using {@link com.bukkit.mcteam.gson.GsonBuilder}
|
||||
* <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 org.mcteam.factions.gson.GsonBuilder}
|
||||
* (to configure various options such as using versioning and so on).</p>
|
||||
*
|
||||
* @author Inderjeet Singh, Joel Leitch
|
||||
|
@ -16,7 +16,8 @@
|
||||
|
||||
package org.mcteam.factions.gson.reflect;
|
||||
|
||||
import java.lang.reflect.Array;
|
||||
import org.mcteam.factions.gson.internal.$Gson$Types;
|
||||
import org.mcteam.factions.gson.internal.$Gson$Preconditions;
|
||||
import java.lang.reflect.GenericArrayType;
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
import java.lang.reflect.Type;
|
||||
@ -25,135 +26,101 @@ import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Represents a generic type {@code T}.
|
||||
* Represents a generic type {@code T}. Java doesn't yet provide a way to
|
||||
* represent generic types, so this class does. Forces clients to create a
|
||||
* subclass of this class which enables retrieval the type information even at
|
||||
* runtime.
|
||||
*
|
||||
* <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<Foo></code>, you can use:
|
||||
* <p>
|
||||
* <code>Type typeOfCollectionOfFoo = new TypeToken<Collection<Foo>>(){}.getType()
|
||||
* </code>
|
||||
* {@code TypeToken<List<String>> list = new TypeToken<List<String>>() {};}
|
||||
*
|
||||
* <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
|
||||
* assignability.
|
||||
* <p>This syntax cannot be used to create type literals that have wildcard
|
||||
* parameters, such as {@code Class<?>} or {@code List<? extends CharSequence>}.
|
||||
*
|
||||
* @author Bob Lee
|
||||
* @author Sven Mawson
|
||||
* @author Jesse Wilson
|
||||
*/
|
||||
public abstract class TypeToken<T> {
|
||||
public class TypeToken<T> {
|
||||
|
||||
final Class<? super T> rawType;
|
||||
final Type type;
|
||||
final int hashCode;
|
||||
|
||||
/**
|
||||
* Constructs a new type token. Derives represented class from type
|
||||
* Constructs a new type literal. Derives represented class from type
|
||||
* parameter.
|
||||
*
|
||||
* <p>Clients create an empty anonymous subclass. Doing so embeds the type
|
||||
* parameter in the anonymous class's type hierarchy so we can reconstitute
|
||||
* it at runtime despite erasure.
|
||||
*
|
||||
* <p>For example:
|
||||
* <code>
|
||||
* {@literal TypeToken<List<String>> t = new TypeToken<List<String>>}(){}
|
||||
* </code>
|
||||
* parameter in the anonymous class's type hierarchy so we can reconstitute it
|
||||
* at runtime despite erasure.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
protected TypeToken() {
|
||||
this.type = getSuperclassTypeParameter(getClass());
|
||||
this.rawType = (Class<? super T>) getRawType(type);
|
||||
this.rawType = (Class<? super T>) $Gson$Types.getRawType(type);
|
||||
this.hashCode = type.hashCode();
|
||||
}
|
||||
|
||||
/**
|
||||
* Unsafe. Constructs a type token manually.
|
||||
* Unsafe. Constructs a type literal manually.
|
||||
*/
|
||||
@SuppressWarnings({"unchecked"})
|
||||
private TypeToken(Type type) {
|
||||
this.rawType = (Class<? super T>) getRawType(nonNull(type, "type"));
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
private static <T> T nonNull(T o, String message) {
|
||||
if (o == null) {
|
||||
throw new NullPointerException(message);
|
||||
}
|
||||
return o;
|
||||
@SuppressWarnings("unchecked")
|
||||
TypeToken(Type type) {
|
||||
this.type = $Gson$Types.canonicalize($Gson$Preconditions.checkNotNull(type));
|
||||
this.rawType = (Class<? super T>) $Gson$Types.getRawType(this.type);
|
||||
this.hashCode = this.type.hashCode();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets type from super class's type parameter.
|
||||
* Returns the type from super class's type parameter in {@link $Gson$Types#canonicalize
|
||||
* canonical form}.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
static Type getSuperclassTypeParameter(Class<?> subclass) {
|
||||
Type superclass = subclass.getGenericSuperclass();
|
||||
if (superclass instanceof Class<?>) {
|
||||
if (superclass instanceof Class) {
|
||||
throw new RuntimeException("Missing type parameter.");
|
||||
}
|
||||
return ((ParameterizedType) superclass).getActualTypeArguments()[0];
|
||||
ParameterizedType parameterized = (ParameterizedType) superclass;
|
||||
return $Gson$Types.canonicalize(parameterized.getActualTypeArguments()[0]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets type token from super class's type parameter.
|
||||
* Returns the raw (non-generic) type for this type.
|
||||
*/
|
||||
static TypeToken<?> fromSuperclassTypeParameter(Class<?> subclass) {
|
||||
return new SimpleTypeToken<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() {
|
||||
public final Class<? super T> getRawType() {
|
||||
return rawType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets underlying {@code Type} instance.
|
||||
*/
|
||||
public Type getType() {
|
||||
public final Type getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if this type is assignable from the given class object.
|
||||
*
|
||||
* @deprecated this implementation may be inconsistent with javac for types
|
||||
* with wildcards.
|
||||
*/
|
||||
@Deprecated
|
||||
public boolean isAssignableFrom(Class<?> cls) {
|
||||
return isAssignableFrom((Type) cls);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if this type is assignable from the given Type.
|
||||
*
|
||||
* @deprecated this implementation may be inconsistent with javac for types
|
||||
* with wildcards.
|
||||
*/
|
||||
@Deprecated
|
||||
public boolean isAssignableFrom(Type from) {
|
||||
if (from == null) {
|
||||
return false;
|
||||
@ -164,12 +131,12 @@ public abstract class TypeToken<T> {
|
||||
}
|
||||
|
||||
if (type instanceof Class<?>) {
|
||||
return rawType.isAssignableFrom(getRawType(from));
|
||||
return rawType.isAssignableFrom($Gson$Types.getRawType(from));
|
||||
} else if (type instanceof ParameterizedType) {
|
||||
return isAssignableFrom(from, (ParameterizedType) type,
|
||||
new HashMap<String, Type>());
|
||||
} else if (type instanceof GenericArrayType) {
|
||||
return rawType.isAssignableFrom(getRawType(from))
|
||||
return rawType.isAssignableFrom($Gson$Types.getRawType(from))
|
||||
&& isAssignableFrom(from, (GenericArrayType) type);
|
||||
} else {
|
||||
throw buildUnexpectedTypeError(
|
||||
@ -179,7 +146,11 @@ public abstract class TypeToken<T> {
|
||||
|
||||
/**
|
||||
* Check if this type is assignable from the given type token.
|
||||
*
|
||||
* @deprecated this implementation may be inconsistent with javac for types
|
||||
* with wildcards.
|
||||
*/
|
||||
@Deprecated
|
||||
public boolean isAssignableFrom(TypeToken<?> token) {
|
||||
return isAssignableFrom(token.getType());
|
||||
}
|
||||
@ -225,7 +196,7 @@ public abstract class TypeToken<T> {
|
||||
}
|
||||
|
||||
// First figure out the class and any type information.
|
||||
Class<?> clazz = getRawType(from);
|
||||
Class<?> clazz = $Gson$Types.getRawType(from);
|
||||
ParameterizedType ptype = null;
|
||||
if (from instanceof ParameterizedType) {
|
||||
ptype = (ParameterizedType) from;
|
||||
@ -259,11 +230,7 @@ public abstract class TypeToken<T> {
|
||||
|
||||
// Interfaces didn't work, try the superclass.
|
||||
Type sType = clazz.getGenericSuperclass();
|
||||
if (isAssignableFrom(sType, to, new HashMap<String, Type>(typeVarMap))) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
return isAssignableFrom(sType, to, new HashMap<String, Type>(typeVarMap));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -285,55 +252,6 @@ public abstract class TypeToken<T> {
|
||||
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(
|
||||
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) {
|
||||
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) {
|
||||
return new SimpleTypeToken<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);
|
||||
}
|
||||
return new TypeToken<T>(type);
|
||||
}
|
||||
}
|
||||
|
@ -1097,7 +1097,8 @@ public final class JsonReader implements Closeable {
|
||||
token = JsonToken.NUMBER;
|
||||
} catch (NumberFormatException ignored) {
|
||||
// this must be an unquoted string
|
||||
throw syntaxError("invalid number or unquoted string");
|
||||
checkLenient();
|
||||
token = JsonToken.STRING;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user