Gson 2.8.0
This commit is contained in:
		
							parent
							
								
									b7ddb71f04
								
							
						
					
					
						commit
						3e520e7e9f
					
				| @ -16,14 +16,16 @@ | ||||
| 
 | ||||
| package com.massivecraft.massivecore.xlib.gson; | ||||
| 
 | ||||
| import com.massivecraft.massivecore.xlib.gson.internal.bind.util.ISO8601Utils; | ||||
| 
 | ||||
| import java.lang.reflect.Type; | ||||
| import java.sql.Timestamp; | ||||
| import java.text.DateFormat; | ||||
| import java.text.ParseException; | ||||
| import java.text.ParsePosition; | ||||
| import java.text.SimpleDateFormat; | ||||
| import java.util.Date; | ||||
| import java.util.Locale; | ||||
| import java.util.TimeZone; | ||||
| 
 | ||||
| /** | ||||
|  * This type adapter supports three subclasses of date: Date, Timestamp, and | ||||
| @ -38,7 +40,6 @@ final class DefaultDateTypeAdapter implements JsonSerializer<Date>, JsonDeserial | ||||
| 
 | ||||
|   private final DateFormat enUsFormat; | ||||
|   private final DateFormat localFormat; | ||||
|   private final DateFormat iso8601Format; | ||||
| 
 | ||||
|   DefaultDateTypeAdapter() { | ||||
|     this(DateFormat.getDateTimeInstance(DateFormat.DEFAULT, DateFormat.DEFAULT, Locale.US), | ||||
| @ -61,12 +62,11 @@ final class DefaultDateTypeAdapter implements JsonSerializer<Date>, JsonDeserial | ||||
|   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 | ||||
|   @Override | ||||
|   public JsonElement serialize(Date src, Type typeOfSrc, JsonSerializationContext context) { | ||||
|     synchronized (localFormat) { | ||||
|       String dateFormatAsString = enUsFormat.format(src); | ||||
| @ -74,6 +74,7 @@ final class DefaultDateTypeAdapter implements JsonSerializer<Date>, JsonDeserial | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   @Override | ||||
|   public Date deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) | ||||
|       throws JsonParseException { | ||||
|     if (!(json instanceof JsonPrimitive)) { | ||||
| @ -94,15 +95,13 @@ final class DefaultDateTypeAdapter implements JsonSerializer<Date>, JsonDeserial | ||||
|   private Date deserializeToDate(JsonElement json) { | ||||
|     synchronized (localFormat) { | ||||
|       try { | ||||
|         return localFormat.parse(json.getAsString()); | ||||
|       } catch (ParseException ignored) { | ||||
|       } | ||||
|       	return localFormat.parse(json.getAsString()); | ||||
|       } catch (ParseException ignored) {} | ||||
|       try { | ||||
|         return enUsFormat.parse(json.getAsString()); | ||||
|       } catch (ParseException ignored) { | ||||
|       } | ||||
|       } catch (ParseException ignored) {} | ||||
|       try { | ||||
|         return iso8601Format.parse(json.getAsString()); | ||||
|         return ISO8601Utils.parse(json.getAsString(), new ParsePosition(0)); | ||||
|       } catch (ParseException e) { | ||||
|         throw new JsonSyntaxException(json.getAsString(), e); | ||||
|       } | ||||
|  | ||||
| @ -99,11 +99,11 @@ public interface ExclusionStrategy { | ||||
|    * @param f the field object that is under test | ||||
|    * @return true if the field should be ignored; otherwise false | ||||
|    */ | ||||
|   boolean shouldSkipField(FieldAttributes f); | ||||
|   public boolean shouldSkipField(FieldAttributes f); | ||||
| 
 | ||||
|   /** | ||||
|    * @param clazz the class object that is under test | ||||
|    * @return true if the class should be ignored; otherwise false | ||||
|    */ | ||||
|   boolean shouldSkipClass(Class<?> clazz); | ||||
|   public boolean shouldSkipClass(Class<?> clazz); | ||||
| } | ||||
|  | ||||
| @ -69,7 +69,7 @@ public final class FieldAttributes { | ||||
|    *   private List<String> red; | ||||
|    * } | ||||
|    * | ||||
|    * Type listParmeterizedType = new TypeToken<List<String>>() {}.getType(); | ||||
|    * Type listParameterizedType = new TypeToken<List<String>>() {}.getType(); | ||||
|    * </pre> | ||||
|    * | ||||
|    * <p>This method would return {@code String.class} for the {@code bar} field and | ||||
|  | ||||
| @ -17,11 +17,12 @@ | ||||
| package com.massivecraft.massivecore.xlib.gson; | ||||
| 
 | ||||
| import java.lang.reflect.Field; | ||||
| import java.util.Locale; | ||||
| 
 | ||||
| /** | ||||
|  * An enumeration that defines a few standard naming conventions for JSON field names. | ||||
|  * This enumeration should be used in conjunction with {@link com.massivecraft.massivecore.xlib.gson.GsonBuilder} | ||||
|  * to configure a {@link com.massivecraft.massivecore.xlib.gson.Gson} instance to properly translate Java field | ||||
|  * This enumeration should be used in conjunction with {@link GsonBuilder} | ||||
|  * to configure a {@link Gson} instance to properly translate Java field | ||||
|  * names into the desired JSON field names. | ||||
|  * | ||||
|  * @author Inderjeet Singh | ||||
| @ -34,7 +35,7 @@ public enum FieldNamingPolicy implements FieldNamingStrategy { | ||||
|    * unchanged. | ||||
|    */ | ||||
|   IDENTITY() { | ||||
|     public String translateName(Field f) { | ||||
|     @Override public String translateName(Field f) { | ||||
|       return f.getName(); | ||||
|     } | ||||
|   }, | ||||
| @ -50,7 +51,7 @@ public enum FieldNamingPolicy implements FieldNamingStrategy { | ||||
|    * </ul> | ||||
|    */ | ||||
|   UPPER_CAMEL_CASE() { | ||||
|     public String translateName(Field f) { | ||||
|     @Override public String translateName(Field f) { | ||||
|       return upperCaseFirstLetter(f.getName()); | ||||
|     } | ||||
|   }, | ||||
| @ -69,7 +70,7 @@ public enum FieldNamingPolicy implements FieldNamingStrategy { | ||||
|    * @since 1.4 | ||||
|    */ | ||||
|   UPPER_CAMEL_CASE_WITH_SPACES() { | ||||
|     public String translateName(Field f) { | ||||
|     @Override public String translateName(Field f) { | ||||
|       return upperCaseFirstLetter(separateCamelCase(f.getName(), " ")); | ||||
|     } | ||||
|   }, | ||||
| @ -87,8 +88,8 @@ public enum FieldNamingPolicy implements FieldNamingStrategy { | ||||
|    * </ul> | ||||
|    */ | ||||
|   LOWER_CASE_WITH_UNDERSCORES() { | ||||
|     public String translateName(Field f) { | ||||
|       return separateCamelCase(f.getName(), "_").toLowerCase(); | ||||
|     @Override public String translateName(Field f) { | ||||
|       return separateCamelCase(f.getName(), "_").toLowerCase(Locale.ENGLISH); | ||||
|     } | ||||
|   }, | ||||
| 
 | ||||
| @ -110,8 +111,8 @@ public enum FieldNamingPolicy implements FieldNamingStrategy { | ||||
|    * @since 1.4 | ||||
|    */ | ||||
|   LOWER_CASE_WITH_DASHES() { | ||||
|     public String translateName(Field f) { | ||||
|       return separateCamelCase(f.getName(), "-").toLowerCase(); | ||||
|     @Override public String translateName(Field f) { | ||||
|       return separateCamelCase(f.getName(), "-").toLowerCase(Locale.ENGLISH); | ||||
|     } | ||||
|   }; | ||||
| 
 | ||||
| @ -119,7 +120,7 @@ public enum FieldNamingPolicy implements FieldNamingStrategy { | ||||
|    * Converts the field name that uses camel-case define word separation into | ||||
|    * separate words that are separated by the provided {@code separatorString}. | ||||
|    */ | ||||
|   private static String separateCamelCase(String name, String separator) { | ||||
|   static String separateCamelCase(String name, String separator) { | ||||
|     StringBuilder translation = new StringBuilder(); | ||||
|     for (int i = 0; i < name.length(); i++) { | ||||
|       char character = name.charAt(i); | ||||
| @ -134,7 +135,7 @@ public enum FieldNamingPolicy implements FieldNamingStrategy { | ||||
|   /** | ||||
|    * Ensures the JSON field names begins with an upper case letter. | ||||
|    */ | ||||
|   private static String upperCaseFirstLetter(String name) { | ||||
|   static String upperCaseFirstLetter(String name) { | ||||
|     StringBuilder fieldNameBuilder = new StringBuilder(); | ||||
|     int index = 0; | ||||
|     char firstCharacter = name.charAt(index); | ||||
|  | ||||
| @ -36,5 +36,5 @@ public interface FieldNamingStrategy { | ||||
|    * @return the translated field name. | ||||
|    * @since 1.3 | ||||
|    */ | ||||
|   String translateName(Field f); | ||||
|   public String translateName(Field f); | ||||
| } | ||||
|  | ||||
| @ -16,47 +16,33 @@ | ||||
| 
 | ||||
| package com.massivecraft.massivecore.xlib.gson; | ||||
| 
 | ||||
| import com.massivecraft.massivecore.xlib.gson.annotations.Expose; | ||||
| import com.massivecraft.massivecore.xlib.gson.annotations.Since; | ||||
| import com.massivecraft.massivecore.xlib.gson.internal.ConstructorConstructor; | ||||
| import com.massivecraft.massivecore.xlib.gson.internal.Excluder; | ||||
| import com.massivecraft.massivecore.xlib.gson.internal.Primitives; | ||||
| import com.massivecraft.massivecore.xlib.gson.internal.Streams; | ||||
| import com.massivecraft.massivecore.xlib.gson.internal.bind.ArrayTypeAdapter; | ||||
| import com.massivecraft.massivecore.xlib.gson.internal.bind.CollectionTypeAdapterFactory; | ||||
| import com.massivecraft.massivecore.xlib.gson.internal.bind.DateTypeAdapter; | ||||
| import com.massivecraft.massivecore.xlib.gson.internal.bind.JsonAdapterAnnotationTypeAdapterFactory; | ||||
| import com.massivecraft.massivecore.xlib.gson.internal.bind.JsonTreeReader; | ||||
| import com.massivecraft.massivecore.xlib.gson.internal.bind.JsonTreeWriter; | ||||
| import com.massivecraft.massivecore.xlib.gson.internal.bind.MapTypeAdapterFactory; | ||||
| import com.massivecraft.massivecore.xlib.gson.internal.bind.ObjectTypeAdapter; | ||||
| import com.massivecraft.massivecore.xlib.gson.internal.bind.ReflectiveTypeAdapterFactory; | ||||
| import com.massivecraft.massivecore.xlib.gson.internal.bind.SqlDateTypeAdapter; | ||||
| import com.massivecraft.massivecore.xlib.gson.internal.bind.TimeTypeAdapter; | ||||
| import com.massivecraft.massivecore.xlib.gson.internal.bind.TypeAdapters; | ||||
| import com.massivecraft.massivecore.xlib.gson.internal.bind.*; | ||||
| import com.massivecraft.massivecore.xlib.gson.reflect.TypeToken; | ||||
| import com.massivecraft.massivecore.xlib.gson.stream.JsonReader; | ||||
| import com.massivecraft.massivecore.xlib.gson.stream.JsonToken; | ||||
| import com.massivecraft.massivecore.xlib.gson.stream.JsonWriter; | ||||
| import com.massivecraft.massivecore.xlib.gson.stream.MalformedJsonException; | ||||
| 
 | ||||
| import java.io.EOFException; | ||||
| import java.io.IOException; | ||||
| import java.io.Reader; | ||||
| import java.io.StringReader; | ||||
| import java.io.StringWriter; | ||||
| import java.io.Writer; | ||||
| import java.io.*; | ||||
| import java.lang.reflect.Type; | ||||
| import java.math.BigDecimal; | ||||
| import java.math.BigInteger; | ||||
| import java.util.ArrayList; | ||||
| import java.util.Collections; | ||||
| import java.util.HashMap; | ||||
| import java.util.List; | ||||
| import java.util.Map; | ||||
| import java.util.*; | ||||
| import java.util.concurrent.ConcurrentHashMap; | ||||
| import java.util.concurrent.atomic.AtomicLong; | ||||
| import java.util.concurrent.atomic.AtomicLongArray; | ||||
| 
 | ||||
| /** | ||||
|  * 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)} | ||||
|  * methods on it. | ||||
|  * methods on it. Gson instances are Thread-safe so you can reuse them freely across multiple | ||||
|  * threads. | ||||
|  * | ||||
|  * <p>You can create a Gson instance by invoking {@code new Gson()} if the default configuration | ||||
|  * is all you need. You can also use {@link GsonBuilder} to build a Gson instance with various | ||||
| @ -75,7 +61,7 @@ import java.util.Map; | ||||
|  * <p>If the object that your are serializing/deserializing is a {@code ParameterizedType} | ||||
|  * (i.e. contains at least one type parameter and may be an array) then you must use the | ||||
|  * {@link #toJson(Object, Type)} or {@link #fromJson(String, Type)} method.  Here is an | ||||
|  * example for serializing and deserialing a {@code ParameterizedType}: | ||||
|  * example for serializing and deserializing a {@code ParameterizedType}: | ||||
|  * | ||||
|  * <pre> | ||||
|  * Type listType = new TypeToken<List<String>>() {}.getType(); | ||||
| @ -90,7 +76,7 @@ import java.util.Map; | ||||
|  * <p>See the <a href="https://sites.google.com/site/gson/gson-user-guide">Gson User Guide</a> | ||||
|  * for a more complete set of examples.</p> | ||||
|  * | ||||
|  * @see com.massivecraft.massivecore.xlib.gson.reflect.TypeToken | ||||
|  * @see TypeToken | ||||
|  * | ||||
|  * @author Inderjeet Singh | ||||
|  * @author Joel Leitch | ||||
| @ -98,7 +84,14 @@ import java.util.Map; | ||||
|  */ | ||||
| public final class Gson { | ||||
|   static final boolean DEFAULT_JSON_NON_EXECUTABLE = false; | ||||
|   static final boolean DEFAULT_LENIENT = false; | ||||
|   static final boolean DEFAULT_PRETTY_PRINT = false; | ||||
|   static final boolean DEFAULT_ESCAPE_HTML = true; | ||||
|   static final boolean DEFAULT_SERIALIZE_NULLS = false; | ||||
|   static final boolean DEFAULT_COMPLEX_MAP_KEYS = false; | ||||
|   static final boolean DEFAULT_SPECIALIZE_FLOAT_VALUES = false; | ||||
| 
 | ||||
|   private static final TypeToken<?> NULL_KEY_SURROGATE = new TypeToken<Object>() {}; | ||||
|   private static final String JSON_NON_EXECUTABLE_PREFIX = ")]}'\n"; | ||||
| 
 | ||||
|   /** | ||||
| @ -111,32 +104,19 @@ public final class Gson { | ||||
|   private final ThreadLocal<Map<TypeToken<?>, FutureTypeAdapter<?>>> calls | ||||
|       = new ThreadLocal<>(); | ||||
| 
 | ||||
|   private final Map<TypeToken<?>, TypeAdapter<?>> typeTokenCache | ||||
|       = Collections.synchronizedMap(new HashMap<TypeToken<?>, TypeAdapter<?>>()); | ||||
|   private final Map<TypeToken<?>, TypeAdapter<?>> typeTokenCache = new ConcurrentHashMap<>(); | ||||
| 
 | ||||
|   private final List<TypeAdapterFactory> factories; | ||||
|   private final ConstructorConstructor constructorConstructor; | ||||
| 
 | ||||
|   private final Excluder excluder; | ||||
|   private final FieldNamingStrategy fieldNamingStrategy; | ||||
|   private final boolean serializeNulls; | ||||
|   private final boolean htmlSafe; | ||||
|   private final boolean generateNonExecutableJson; | ||||
|   private final boolean prettyPrinting; | ||||
| 
 | ||||
|   final JsonDeserializationContext deserializationContext = new JsonDeserializationContext() { | ||||
|     @SuppressWarnings("unchecked") | ||||
| 	public <T> T deserialize(JsonElement json, Type typeOfT) throws JsonParseException { | ||||
|       return (T) fromJson(json, typeOfT); | ||||
|     } | ||||
|   }; | ||||
| 
 | ||||
|   final JsonSerializationContext serializationContext = new JsonSerializationContext() { | ||||
|     public JsonElement serialize(Object src) { | ||||
|       return toJsonTree(src); | ||||
|     } | ||||
|     public JsonElement serialize(Object src, Type typeOfSrc) { | ||||
|       return toJsonTree(src, typeOfSrc); | ||||
|     } | ||||
|   }; | ||||
|   private final boolean lenient; | ||||
|   private final JsonAdapterAnnotationTypeAdapterFactory jsonAdapterFactory; | ||||
| 
 | ||||
|   /** | ||||
|    * Constructs a Gson object with default configuration. The default configuration has the | ||||
| @ -158,10 +138,10 @@ public final class Gson { | ||||
|    *   ignores the millisecond portion of the date during serialization. You can change | ||||
|    *   this by invoking {@link GsonBuilder#setDateFormat(int)} or | ||||
|    *   {@link GsonBuilder#setDateFormat(String)}. </li> | ||||
|    *   <li>By default, Gson ignores the {@link com.massivecraft.massivecore.xlib.gson.annotations.Expose} annotation. | ||||
|    *   <li>By default, Gson ignores the {@link Expose} annotation. | ||||
|    *   You can enable Gson to serialize/deserialize only those fields marked with this annotation | ||||
|    *   through {@link GsonBuilder#excludeFieldsWithoutExposeAnnotation()}. </li> | ||||
|    *   <li>By default, Gson ignores the {@link com.massivecraft.massivecore.xlib.gson.annotations.Since} annotation. You | ||||
|    *   <li>By default, Gson ignores the {@link Since} annotation. You | ||||
|    *   can enable Gson to use this annotation through {@link GsonBuilder#setVersion(double)}.</li> | ||||
|    *   <li>The default field naming policy for the output Json is same as in Java. So, a Java class | ||||
|    *   field <code>versionNumber</code> will be output as <code>"versionNumber"</code> in | ||||
| @ -174,22 +154,26 @@ public final class Gson { | ||||
|    */ | ||||
|   public Gson() { | ||||
|     this(Excluder.DEFAULT, FieldNamingPolicy.IDENTITY, | ||||
|         Collections.<Type, InstanceCreator<?>>emptyMap(), false, false, DEFAULT_JSON_NON_EXECUTABLE, | ||||
|         true, false, false, LongSerializationPolicy.DEFAULT, | ||||
|         Collections.<TypeAdapterFactory>emptyList()); | ||||
|         Collections.<Type, InstanceCreator<?>>emptyMap(), DEFAULT_SERIALIZE_NULLS, | ||||
|         DEFAULT_COMPLEX_MAP_KEYS, DEFAULT_JSON_NON_EXECUTABLE, DEFAULT_ESCAPE_HTML, | ||||
|         DEFAULT_PRETTY_PRINT, DEFAULT_LENIENT, DEFAULT_SPECIALIZE_FLOAT_VALUES, | ||||
|         LongSerializationPolicy.DEFAULT, Collections.<TypeAdapterFactory>emptyList()); | ||||
|   } | ||||
| 
 | ||||
|   Gson(final Excluder excluder, final FieldNamingStrategy fieldNamingPolicy, | ||||
|       final Map<Type, InstanceCreator<?>> instanceCreators, boolean serializeNulls, | ||||
|       boolean complexMapKeySerialization, boolean generateNonExecutableGson, boolean htmlSafe, | ||||
|       boolean prettyPrinting, boolean serializeSpecialFloatingPointValues, | ||||
|       LongSerializationPolicy longSerializationPolicy, | ||||
|       List<TypeAdapterFactory> typeAdapterFactories) { | ||||
|   Gson(final Excluder excluder, final FieldNamingStrategy fieldNamingStrategy, | ||||
|        final Map<Type, InstanceCreator<?>> instanceCreators, boolean serializeNulls, | ||||
|        boolean complexMapKeySerialization, boolean generateNonExecutableGson, boolean htmlSafe, | ||||
|        boolean prettyPrinting, boolean lenient, boolean serializeSpecialFloatingPointValues, | ||||
|        LongSerializationPolicy longSerializationPolicy, | ||||
|        List<TypeAdapterFactory> typeAdapterFactories) { | ||||
|     this.constructorConstructor = new ConstructorConstructor(instanceCreators); | ||||
|     this.excluder = excluder; | ||||
|     this.fieldNamingStrategy = fieldNamingStrategy; | ||||
|     this.serializeNulls = serializeNulls; | ||||
|     this.generateNonExecutableJson = generateNonExecutableGson; | ||||
|     this.htmlSafe = htmlSafe; | ||||
|     this.prettyPrinting = prettyPrinting; | ||||
|     this.lenient = lenient; | ||||
| 
 | ||||
|     List<TypeAdapterFactory> factories = new ArrayList<>(); | ||||
| 
 | ||||
| @ -209,13 +193,18 @@ public final class Gson { | ||||
|     factories.add(TypeAdapters.BOOLEAN_FACTORY); | ||||
|     factories.add(TypeAdapters.BYTE_FACTORY); | ||||
|     factories.add(TypeAdapters.SHORT_FACTORY); | ||||
|     factories.add(TypeAdapters.newFactory(long.class, Long.class, | ||||
|             longAdapter(longSerializationPolicy))); | ||||
|     TypeAdapter<Number> longAdapter = longAdapter(longSerializationPolicy); | ||||
|     factories.add(TypeAdapters.newFactory(long.class, Long.class, longAdapter)); | ||||
|     factories.add(TypeAdapters.newFactory(double.class, Double.class, | ||||
|             doubleAdapter(serializeSpecialFloatingPointValues))); | ||||
|     factories.add(TypeAdapters.newFactory(float.class, Float.class, | ||||
|             floatAdapter(serializeSpecialFloatingPointValues))); | ||||
|     factories.add(TypeAdapters.NUMBER_FACTORY); | ||||
|     factories.add(TypeAdapters.ATOMIC_INTEGER_FACTORY); | ||||
|     factories.add(TypeAdapters.ATOMIC_BOOLEAN_FACTORY); | ||||
|     factories.add(TypeAdapters.newFactory(AtomicLong.class, atomicLongAdapter(longAdapter))); | ||||
|     factories.add(TypeAdapters.newFactory(AtomicLongArray.class, atomicLongArrayAdapter(longAdapter))); | ||||
|     factories.add(TypeAdapters.ATOMIC_INTEGER_ARRAY_FACTORY); | ||||
|     factories.add(TypeAdapters.CHARACTER_FACTORY); | ||||
|     factories.add(TypeAdapters.STRING_BUILDER_FACTORY); | ||||
|     factories.add(TypeAdapters.STRING_BUFFER_FACTORY); | ||||
| @ -224,6 +213,7 @@ public final class Gson { | ||||
|     factories.add(TypeAdapters.URL_FACTORY); | ||||
|     factories.add(TypeAdapters.URI_FACTORY); | ||||
|     factories.add(TypeAdapters.UUID_FACTORY); | ||||
|     factories.add(TypeAdapters.CURRENCY_FACTORY); | ||||
|     factories.add(TypeAdapters.LOCALE_FACTORY); | ||||
|     factories.add(TypeAdapters.INET_ADDRESS_FACTORY); | ||||
|     factories.add(TypeAdapters.BIT_SET_FACTORY); | ||||
| @ -238,14 +228,31 @@ public final class Gson { | ||||
|     // type adapters for composite and user-defined types | ||||
|     factories.add(new CollectionTypeAdapterFactory(constructorConstructor)); | ||||
|     factories.add(new MapTypeAdapterFactory(constructorConstructor, complexMapKeySerialization)); | ||||
|     factories.add(new JsonAdapterAnnotationTypeAdapterFactory(constructorConstructor)); | ||||
|     this.jsonAdapterFactory = new JsonAdapterAnnotationTypeAdapterFactory(constructorConstructor); | ||||
|     factories.add(jsonAdapterFactory); | ||||
|     factories.add(TypeAdapters.ENUM_FACTORY); | ||||
|     factories.add(new ReflectiveTypeAdapterFactory( | ||||
|         constructorConstructor, fieldNamingPolicy, excluder)); | ||||
|         constructorConstructor, fieldNamingStrategy, excluder, jsonAdapterFactory)); | ||||
| 
 | ||||
|     this.factories = Collections.unmodifiableList(factories); | ||||
|   } | ||||
| 
 | ||||
|   public Excluder excluder() { | ||||
|     return excluder; | ||||
|   } | ||||
| 
 | ||||
|   public FieldNamingStrategy fieldNamingStrategy() { | ||||
|     return fieldNamingStrategy; | ||||
|   } | ||||
| 
 | ||||
|   public boolean serializeNulls() { | ||||
|     return serializeNulls; | ||||
|   } | ||||
| 
 | ||||
|   public boolean htmlSafe() { | ||||
|     return htmlSafe; | ||||
|   } | ||||
| 
 | ||||
|   private TypeAdapter<Number> doubleAdapter(boolean serializeSpecialFloatingPointValues) { | ||||
|     if (serializeSpecialFloatingPointValues) { | ||||
|       return TypeAdapters.DOUBLE; | ||||
| @ -294,7 +301,7 @@ public final class Gson { | ||||
|     }; | ||||
|   } | ||||
| 
 | ||||
|   private void checkValidFloatingPoint(double value) { | ||||
|   static void checkValidFloatingPoint(double value) { | ||||
|     if (Double.isNaN(value) || Double.isInfinite(value)) { | ||||
|       throw new IllegalArgumentException(value | ||||
|           + " is not a valid double value as per JSON specification. To override this" | ||||
| @ -302,7 +309,7 @@ public final class Gson { | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   private TypeAdapter<Number> longAdapter(LongSerializationPolicy longSerializationPolicy) { | ||||
|   private static TypeAdapter<Number> longAdapter(LongSerializationPolicy longSerializationPolicy) { | ||||
|     if (longSerializationPolicy == LongSerializationPolicy.DEFAULT) { | ||||
|       return TypeAdapters.LONG; | ||||
|     } | ||||
| @ -324,6 +331,45 @@ public final class Gson { | ||||
|     }; | ||||
|   } | ||||
| 
 | ||||
|   private static TypeAdapter<AtomicLong> atomicLongAdapter(final TypeAdapter<Number> longAdapter) { | ||||
|     return new TypeAdapter<AtomicLong>() { | ||||
|       @Override public void write(JsonWriter out, AtomicLong value) throws IOException { | ||||
|         longAdapter.write(out, value.get()); | ||||
|       } | ||||
|       @Override public AtomicLong read(JsonReader in) throws IOException { | ||||
|         Number value = longAdapter.read(in); | ||||
|         return new AtomicLong(value.longValue()); | ||||
|       } | ||||
|     }.nullSafe(); | ||||
|   } | ||||
| 
 | ||||
|   private static TypeAdapter<AtomicLongArray> atomicLongArrayAdapter(final TypeAdapter<Number> longAdapter) { | ||||
|     return new TypeAdapter<AtomicLongArray>() { | ||||
|       @Override public void write(JsonWriter out, AtomicLongArray value) throws IOException { | ||||
|         out.beginArray(); | ||||
|         for (int i = 0, length = value.length(); i < length; i++) { | ||||
|           longAdapter.write(out, value.get(i)); | ||||
|         } | ||||
|         out.endArray(); | ||||
|       } | ||||
|       @Override public AtomicLongArray read(JsonReader in) throws IOException { | ||||
|         List<Long> list = new ArrayList<>(); | ||||
|         in.beginArray(); | ||||
|         while (in.hasNext()) { | ||||
|             long value = longAdapter.read(in).longValue(); | ||||
|             list.add(value); | ||||
|         } | ||||
|         in.endArray(); | ||||
|         int length = list.size(); | ||||
|         AtomicLongArray array = new AtomicLongArray(length); | ||||
|         for (int i = 0; i < length; ++i) { | ||||
|           array.set(i, list.get(i)); | ||||
|         } | ||||
|         return array; | ||||
|       } | ||||
|     }.nullSafe(); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * Returns the type adapter for {@code} type. | ||||
|    * | ||||
| @ -332,7 +378,7 @@ public final class Gson { | ||||
|    */ | ||||
|   @SuppressWarnings("unchecked") | ||||
|   public <T> TypeAdapter<T> getAdapter(TypeToken<T> type) { | ||||
|     TypeAdapter<?> cached = typeTokenCache.get(type); | ||||
|     TypeAdapter<?> cached = typeTokenCache.get(type == null ? NULL_KEY_SURROGATE : type); | ||||
|     if (cached != null) { | ||||
|       return (TypeAdapter<T>) cached; | ||||
|     } | ||||
| @ -386,9 +432,9 @@ public final class Gson { | ||||
|    *  class StatsTypeAdapterFactory implements TypeAdapterFactory { | ||||
|    *    public int numReads = 0; | ||||
|    *    public int numWrites = 0; | ||||
|    *    public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) { | ||||
|    *      final TypeAdapter<T> delegate = gson.getDelegateAdapter(this, type); | ||||
|    *      return new TypeAdapter<T>() { | ||||
|    *    public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) { | ||||
|    *      final TypeAdapter<T> delegate = gson.getDelegateAdapter(this, type); | ||||
|    *      return new TypeAdapter<T>() { | ||||
|    *        public void write(JsonWriter out, T value) throws IOException { | ||||
|    *          ++numWrites; | ||||
|    *          delegate.write(out, value); | ||||
| @ -409,6 +455,10 @@ public final class Gson { | ||||
|    *  System.out.println("Num JSON reads" + stats.numReads); | ||||
|    *  System.out.println("Num JSON writes" + stats.numWrites); | ||||
|    *  }</pre> | ||||
|    *  Note that this call will skip all factories registered before {@code skipPast}. In case of | ||||
|    *  multiple TypeAdapterFactories registered it is up to the caller of this function to insure | ||||
|    *  that the order of registration does not prevent this method from reaching a factory they | ||||
|    *  would expect to reply from this call. | ||||
|    *  Note that since you can not override type adapter factories for String and Java primitive | ||||
|    *  types, our stats factory will not count the number of String or primitives that will be | ||||
|    *  read or written. | ||||
| @ -420,12 +470,13 @@ public final class Gson { | ||||
|    * @since 2.2 | ||||
|    */ | ||||
|   public <T> TypeAdapter<T> getDelegateAdapter(TypeAdapterFactory skipPast, TypeToken<T> type) { | ||||
|     boolean skipPastFound = false; | ||||
|     // Skip past if and only if the specified factory is present in the factories. | ||||
|     // This is useful because the factories created through JsonAdapter annotations are not | ||||
|     // registered in this list. | ||||
|     if (!factories.contains(skipPast)) skipPastFound = true; | ||||
|     // Hack. If the skipPast factory isn't registered, assume the factory is being requested via | ||||
|     // our @JsonAdapter annotation. | ||||
|     if (!factories.contains(skipPast)) { | ||||
|       skipPast = jsonAdapterFactory; | ||||
|     } | ||||
| 
 | ||||
|     boolean skipPastFound = false; | ||||
|     for (TypeAdapterFactory factory : factories) { | ||||
|       if (!skipPastFound) { | ||||
|         if (factory == skipPast) { | ||||
| @ -480,7 +531,7 @@ public final class Gson { | ||||
|    * | ||||
|    * @param src the object for which JSON representation is to be created | ||||
|    * @param typeOfSrc The specific genericized type of src. You can obtain | ||||
|    * this type by using the {@link com.massivecraft.massivecore.xlib.gson.reflect.TypeToken} class. For example, | ||||
|    * this type by using the {@link TypeToken} class. For example, | ||||
|    * to get the type for {@code Collection<Foo>}, you should use: | ||||
|    * <pre> | ||||
|    * Type typeOfSrc = new TypeToken<Collection<Foo>>(){}.getType(); | ||||
| @ -522,7 +573,7 @@ public final class Gson { | ||||
|    * | ||||
|    * @param src the object for which JSON representation is to be created | ||||
|    * @param typeOfSrc The specific genericized type of src. You can obtain | ||||
|    * this type by using the {@link com.massivecraft.massivecore.xlib.gson.reflect.TypeToken} class. For example, | ||||
|    * this type by using the {@link TypeToken} class. For example, | ||||
|    * to get the type for {@code Collection<Foo>}, you should use: | ||||
|    * <pre> | ||||
|    * Type typeOfSrc = new TypeToken<Collection<Foo>>(){}.getType(); | ||||
| @ -564,7 +615,7 @@ public final class Gson { | ||||
|    * | ||||
|    * @param src the object for which JSON representation is to be created | ||||
|    * @param typeOfSrc The specific genericized type of src. You can obtain | ||||
|    * this type by using the {@link com.massivecraft.massivecore.xlib.gson.reflect.TypeToken} class. For example, | ||||
|    * this type by using the {@link TypeToken} class. For example, | ||||
|    * to get the type for {@code Collection<Foo>}, you should use: | ||||
|    * <pre> | ||||
|    * Type typeOfSrc = new TypeToken<Collection<Foo>>(){}.getType(); | ||||
| @ -633,15 +684,14 @@ public final class Gson { | ||||
|       JsonWriter jsonWriter = newJsonWriter(Streams.writerForAppendable(writer)); | ||||
|       toJson(jsonElement, jsonWriter); | ||||
|     } catch (IOException e) { | ||||
|       throw new RuntimeException(e); | ||||
|       throw new JsonIOException(e); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * Returns a new JSON writer configured for this GSON and with the non-execute | ||||
|    * prefix if that is configured. | ||||
|    * Returns a new JSON writer configured for the settings on this Gson instance. | ||||
|    */ | ||||
|   private JsonWriter newJsonWriter(Writer writer) throws IOException { | ||||
|   public JsonWriter newJsonWriter(Writer writer) throws IOException { | ||||
|     if (generateNonExecutableJson) { | ||||
|       writer.write(JSON_NON_EXECUTABLE_PREFIX); | ||||
|     } | ||||
| @ -653,6 +703,15 @@ public final class Gson { | ||||
|     return jsonWriter; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * Returns a new JSON reader configured for the settings on this Gson instance. | ||||
|    */ | ||||
|   public JsonReader newJsonReader(Reader reader) { | ||||
|     JsonReader jsonReader = new JsonReader(reader); | ||||
|     jsonReader.setLenient(lenient); | ||||
|     return jsonReader; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * Writes the JSON for {@code jsonElement} to {@code writer}. | ||||
|    * @throws JsonIOException if there was a problem writing to the writer | ||||
| @ -706,7 +765,7 @@ public final class Gson { | ||||
|    * @param <T> the type of the desired object | ||||
|    * @param json the string from which the object is to be deserialized | ||||
|    * @param typeOfT The specific genericized type of src. You can obtain this type by using the | ||||
|    * {@link com.massivecraft.massivecore.xlib.gson.reflect.TypeToken} class. For example, to get the type for | ||||
|    * {@link TypeToken} class. For example, to get the type for | ||||
|    * {@code Collection<Foo>}, you should use: | ||||
|    * <pre> | ||||
|    * Type typeOfT = new TypeToken<Collection<Foo>>(){}.getType(); | ||||
| @ -744,7 +803,7 @@ public final class Gson { | ||||
|    * @since 1.2 | ||||
|    */ | ||||
|   public <T> T fromJson(Reader json, Class<T> classOfT) throws JsonSyntaxException, JsonIOException { | ||||
|     JsonReader jsonReader = new JsonReader(json); | ||||
|     JsonReader jsonReader = newJsonReader(json); | ||||
|     Object object = fromJson(jsonReader, classOfT); | ||||
|     assertFullConsumption(object, jsonReader); | ||||
|     return Primitives.wrap(classOfT).cast(object); | ||||
| @ -759,7 +818,7 @@ public final class Gson { | ||||
|    * @param <T> the type of the desired object | ||||
|    * @param json the reader producing Json from which the object is to be deserialized | ||||
|    * @param typeOfT The specific genericized type of src. You can obtain this type by using the | ||||
|    * {@link com.massivecraft.massivecore.xlib.gson.reflect.TypeToken} class. For example, to get the type for | ||||
|    * {@link TypeToken} class. For example, to get the type for | ||||
|    * {@code Collection<Foo>}, you should use: | ||||
|    * <pre> | ||||
|    * Type typeOfT = new TypeToken<Collection<Foo>>(){}.getType(); | ||||
| @ -771,7 +830,7 @@ public final class Gson { | ||||
|    */ | ||||
|   @SuppressWarnings("unchecked") | ||||
|   public <T> T fromJson(Reader json, Type typeOfT) throws JsonIOException, JsonSyntaxException { | ||||
|     JsonReader jsonReader = new JsonReader(json); | ||||
|     JsonReader jsonReader = newJsonReader(json); | ||||
|     T object = (T) fromJson(jsonReader, typeOfT); | ||||
|     assertFullConsumption(object, jsonReader); | ||||
|     return object; | ||||
| @ -858,7 +917,7 @@ public final class Gson { | ||||
|    * @param json the root of the parse tree of {@link JsonElement}s from which the object is to | ||||
|    * be deserialized | ||||
|    * @param typeOfT The specific genericized type of src. You can obtain this type by using the | ||||
|    * {@link com.massivecraft.massivecore.xlib.gson.reflect.TypeToken} class. For example, to get the type for | ||||
|    * {@link TypeToken} class. For example, to get the type for | ||||
|    * {@code Collection<Foo>}, you should use: | ||||
|    * <pre> | ||||
|    * Type typeOfT = new TypeToken<Collection<Foo>>(){}.getType(); | ||||
|  | ||||
| @ -16,20 +16,18 @@ | ||||
| 
 | ||||
| package com.massivecraft.massivecore.xlib.gson; | ||||
| 
 | ||||
| import com.massivecraft.massivecore.xlib.gson.annotations.Expose; | ||||
| import com.massivecraft.massivecore.xlib.gson.internal.$Gson$Preconditions; | ||||
| import com.massivecraft.massivecore.xlib.gson.internal.Excluder; | ||||
| import com.massivecraft.massivecore.xlib.gson.internal.bind.TreeTypeAdapter; | ||||
| import com.massivecraft.massivecore.xlib.gson.internal.bind.TypeAdapters; | ||||
| import com.massivecraft.massivecore.xlib.gson.reflect.TypeToken; | ||||
| import com.massivecraft.massivecore.xlib.gson.stream.JsonReader; | ||||
| 
 | ||||
| import java.lang.reflect.Type; | ||||
| import java.sql.Timestamp; | ||||
| import java.text.DateFormat; | ||||
| import java.util.ArrayList; | ||||
| import java.util.Collections; | ||||
| import java.util.Date; | ||||
| import java.util.HashMap; | ||||
| import java.util.List; | ||||
| import java.util.Map; | ||||
| import java.util.*; | ||||
| 
 | ||||
| /** | ||||
|  * <p>Use this builder to construct a {@link Gson} instance when you need to set configuration | ||||
| @ -74,15 +72,16 @@ public final class GsonBuilder { | ||||
|   private final List<TypeAdapterFactory> factories = new ArrayList<>(); | ||||
|   /** tree-style hierarchy factories. These come after factories for backwards compatibility. */ | ||||
|   private final List<TypeAdapterFactory> hierarchyFactories = new ArrayList<>(); | ||||
|   private boolean serializeNulls; | ||||
|   private boolean serializeNulls = Gson.DEFAULT_SERIALIZE_NULLS; | ||||
|   private String datePattern; | ||||
|   private int dateStyle = DateFormat.DEFAULT; | ||||
|   private int timeStyle = DateFormat.DEFAULT; | ||||
|   private boolean complexMapKeySerialization; | ||||
|   private boolean serializeSpecialFloatingPointValues; | ||||
|   private boolean escapeHtmlChars = true; | ||||
|   private boolean prettyPrinting; | ||||
|   private boolean generateNonExecutableJson; | ||||
|   private boolean complexMapKeySerialization = Gson.DEFAULT_COMPLEX_MAP_KEYS; | ||||
|   private boolean serializeSpecialFloatingPointValues = Gson.DEFAULT_SPECIALIZE_FLOAT_VALUES; | ||||
|   private boolean escapeHtmlChars = Gson.DEFAULT_ESCAPE_HTML; | ||||
|   private boolean prettyPrinting = Gson.DEFAULT_PRETTY_PRINT; | ||||
|   private boolean generateNonExecutableJson = Gson.DEFAULT_JSON_NON_EXECUTABLE; | ||||
|   private boolean lenient = Gson.DEFAULT_LENIENT; | ||||
| 
 | ||||
|   /** | ||||
|    * Creates a GsonBuilder instance that can be used to build Gson with various configuration | ||||
| @ -137,7 +136,7 @@ public final class GsonBuilder { | ||||
| 
 | ||||
|   /** | ||||
|    * Configures Gson to exclude all fields from consideration for serialization or deserialization | ||||
|    * that do not have the {@link com.massivecraft.massivecore.xlib.gson.annotations.Expose} annotation. | ||||
|    * that do not have the {@link Expose} annotation. | ||||
|    * | ||||
|    * @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern | ||||
|    */ | ||||
| @ -293,7 +292,7 @@ public final class GsonBuilder { | ||||
|    * Configures Gson to apply a set of exclusion strategies during both serialization and | ||||
|    * deserialization. Each of the {@code strategies} will be applied as a disjunction rule. | ||||
|    * This means that if one of the {@code strategies} suggests that a field (or class) should be | ||||
|    * skipped then that field (or object) is skipped during serializaiton/deserialization. | ||||
|    * skipped then that field (or object) is skipped during serialization/deserialization. | ||||
|    * | ||||
|    * @param strategies the set of strategy object to apply during object (de)serialization. | ||||
|    * @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern | ||||
| @ -351,6 +350,19 @@ public final class GsonBuilder { | ||||
|     return this; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * By default, Gson is strict and only accepts JSON as specified by | ||||
|    * <a href="http://www.ietf.org/rfc/rfc4627.txt">RFC 4627</a>. This option makes the parser | ||||
|    * liberal in what it accepts. | ||||
|    * | ||||
|    * @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern | ||||
|    * @see JsonReader#setLenient(boolean) | ||||
|    */ | ||||
|   public GsonBuilder setLenient() { | ||||
|     lenient = true; | ||||
|     return this; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * By default, Gson escapes HTML characters such as < > etc. Use this option to configure | ||||
|    * Gson to pass-through HTML characters as is. | ||||
| @ -544,7 +556,7 @@ public final class GsonBuilder { | ||||
| 
 | ||||
|     return new Gson(excluder, fieldNamingPolicy, instanceCreators, | ||||
|         serializeNulls, complexMapKeySerialization, | ||||
|         generateNonExecutableJson, escapeHtmlChars, prettyPrinting, | ||||
|         generateNonExecutableJson, escapeHtmlChars, prettyPrinting, lenient, | ||||
|         serializeSpecialFloatingPointValues, longSerializationPolicy, factories); | ||||
|   } | ||||
| 
 | ||||
|  | ||||
| @ -88,5 +88,5 @@ public interface InstanceCreator<T> { | ||||
|    * @param type the parameterized T represented as a {@link Type}. | ||||
|    * @return a default object instance of type T. | ||||
|    */ | ||||
|   T createInstance(Type type); | ||||
|   public T createInstance(Type type); | ||||
| } | ||||
|  | ||||
| @ -49,6 +49,42 @@ public final class JsonArray extends JsonElement implements Iterable<JsonElement | ||||
|     return result; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * Adds the specified boolean to self. | ||||
|    * | ||||
|    * @param bool the boolean that needs to be added to the array. | ||||
|    */ | ||||
|   public void add(Boolean bool) { | ||||
|     elements.add(bool == null ? JsonNull.INSTANCE : new JsonPrimitive(bool)); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * Adds the specified character to self. | ||||
|    * | ||||
|    * @param character the character that needs to be added to the array. | ||||
|    */ | ||||
|   public void add(Character character) { | ||||
|     elements.add(character == null ? JsonNull.INSTANCE : new JsonPrimitive(character)); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * Adds the specified number to self. | ||||
|    * | ||||
|    * @param number the number that needs to be added to the array. | ||||
|    */ | ||||
|   public void add(Number number) { | ||||
|     elements.add(number == null ? JsonNull.INSTANCE : new JsonPrimitive(number)); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * Adds the specified string to self. | ||||
|    * | ||||
|    * @param string the string that needs to be added to the array. | ||||
|    */ | ||||
|   public void add(String string) { | ||||
|     elements.add(string == null ? JsonNull.INSTANCE : new JsonPrimitive(string)); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * Adds the specified element to self. | ||||
|    * | ||||
| @ -126,7 +162,7 @@ public final class JsonArray extends JsonElement implements Iterable<JsonElement | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * Returns an iterator to navigate the elemetns of the array. Since the array is an ordered list, | ||||
|    * Returns an iterator to navigate the elements of the array. Since the array is an ordered list, | ||||
|    * the iterator navigates the elements in the order they were inserted. | ||||
|    * | ||||
|    * @return an iterator to navigate the elements of the array. | ||||
|  | ||||
| @ -40,5 +40,5 @@ public interface JsonDeserializationContext { | ||||
|    * @return An object of type typeOfT. | ||||
|    * @throws JsonParseException if the parse tree does not contain expected data. | ||||
|    */ | ||||
|   <T> T deserialize(JsonElement json, Type typeOfT) throws JsonParseException; | ||||
|   public <T> T deserialize(JsonElement json, Type typeOfT) throws JsonParseException; | ||||
| } | ||||
| @ -86,6 +86,6 @@ public interface JsonDeserializer<T> { | ||||
|    * @return a deserialized object of the specified type typeOfT which is a subclass of {@code T} | ||||
|    * @throws JsonParseException if json is not in the expected format of {@code typeofT} | ||||
|    */ | ||||
|   T deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) | ||||
|   public T deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) | ||||
|       throws JsonParseException; | ||||
| } | ||||
|  | ||||
| @ -31,7 +31,7 @@ import java.util.Set; | ||||
|  */ | ||||
| public final class JsonObject extends JsonElement { | ||||
|   private final LinkedTreeMap<String, JsonElement> members = | ||||
| 	  new LinkedTreeMap<>(); | ||||
|           new LinkedTreeMap<>(); | ||||
| 
 | ||||
|   @Override | ||||
|   JsonObject deepCopy() { | ||||
| @ -132,6 +132,15 @@ public final class JsonObject extends JsonElement { | ||||
|     return members.entrySet(); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * Returns the number of key/value pairs in the object. | ||||
|    * | ||||
|    * @return the number of key/value pairs in the object. | ||||
|    */ | ||||
|   public int size() { | ||||
|     return members.size(); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * Convenience method to check if a member with the specified name is present in this object. | ||||
|    * | ||||
|  | ||||
| @ -33,7 +33,7 @@ public interface JsonSerializationContext { | ||||
|    * @param src the object that needs to be serialized. | ||||
|    * @return a tree of {@link JsonElement}s corresponding to the serialized form of {@code src}. | ||||
|    */ | ||||
|   JsonElement serialize(Object src); | ||||
|   public JsonElement serialize(Object src); | ||||
| 
 | ||||
|   /** | ||||
|    * Invokes default serialization on the specified object passing the specific type information. | ||||
| @ -45,5 +45,5 @@ public interface JsonSerializationContext { | ||||
|    * @param typeOfSrc the actual genericized type of src object. | ||||
|    * @return a tree of {@link JsonElement}s corresponding to the serialized form of {@code src}. | ||||
|    */ | ||||
|   JsonElement serialize(Object src, Type typeOfSrc); | ||||
|   public JsonElement serialize(Object src, Type typeOfSrc); | ||||
| } | ||||
|  | ||||
| @ -21,7 +21,7 @@ import java.lang.reflect.Type; | ||||
| /** | ||||
|  * Interface representing a custom serializer for Json. You should write a custom serializer, if | ||||
|  * you are not happy with the default serialization done by Gson. You will also need to register | ||||
|  * this serializer through {@link com.massivecraft.massivecore.xlib.gson.GsonBuilder#registerTypeAdapter(Type, Object)}. | ||||
|  * this serializer through {@link GsonBuilder#registerTypeAdapter(Type, Object)}. | ||||
|  * | ||||
|  * <p>Let us look at example where defining a serializer will be useful. The {@code Id} class | ||||
|  * defined below has two fields: {@code clazz} and {@code value}.</p> | ||||
| @ -85,5 +85,5 @@ public interface JsonSerializer<T> { | ||||
|    * @param typeOfSrc the actual type (fully genericized version) of the source object. | ||||
|    * @return a JsonElement corresponding to the specified object. | ||||
|    */ | ||||
|   JsonElement serialize(T src, Type typeOfSrc, JsonSerializationContext context); | ||||
|   public JsonElement serialize(T src, Type typeOfSrc, JsonSerializationContext context); | ||||
| } | ||||
|  | ||||
| @ -32,7 +32,7 @@ public enum LongSerializationPolicy { | ||||
|    * {@code {"f":123}}. | ||||
|    */ | ||||
|   DEFAULT() { | ||||
|     public JsonElement serialize(Long value) { | ||||
|     @Override public JsonElement serialize(Long value) { | ||||
|       return new JsonPrimitive(value); | ||||
|     } | ||||
|   }, | ||||
| @ -43,7 +43,7 @@ public enum LongSerializationPolicy { | ||||
|    * {@code {"f":"123"}}. | ||||
|    */ | ||||
|   STRING() { | ||||
|     public JsonElement serialize(Long value) { | ||||
|     @Override public JsonElement serialize(Long value) { | ||||
|       return new JsonPrimitive(String.valueOf(value)); | ||||
|     } | ||||
|   }; | ||||
|  | ||||
| @ -22,11 +22,7 @@ import com.massivecraft.massivecore.xlib.gson.stream.JsonReader; | ||||
| import com.massivecraft.massivecore.xlib.gson.stream.JsonToken; | ||||
| import com.massivecraft.massivecore.xlib.gson.stream.JsonWriter; | ||||
| 
 | ||||
| import java.io.IOException; | ||||
| import java.io.Reader; | ||||
| import java.io.StringReader; | ||||
| import java.io.StringWriter; | ||||
| import java.io.Writer; | ||||
| import java.io.*; | ||||
| 
 | ||||
| /** | ||||
|  * Converts Java objects to and from JSON. | ||||
| @ -132,7 +128,7 @@ public abstract class TypeAdapter<T> { | ||||
|    * Unlike Gson's similar {@link Gson#toJson(JsonElement, Appendable) toJson} | ||||
|    * method, this write is strict. Create a {@link | ||||
|    * JsonWriter#setLenient(boolean) lenient} {@code JsonWriter} and call | ||||
|    * {@link #write(com.massivecraft.massivecore.xlib.gson.stream.JsonWriter, Object)} for lenient | ||||
|    * {@link #write(JsonWriter, Object)} for lenient | ||||
|    * writing. | ||||
|    * | ||||
|    * @param value the Java object to convert. May be null. | ||||
| @ -206,15 +202,19 @@ public abstract class TypeAdapter<T> { | ||||
|    * Converts {@code value} to a JSON document. Unlike Gson's similar {@link | ||||
|    * Gson#toJson(Object) toJson} method, this write is strict. Create a {@link | ||||
|    * JsonWriter#setLenient(boolean) lenient} {@code JsonWriter} and call | ||||
|    * {@link #write(com.massivecraft.massivecore.xlib.gson.stream.JsonWriter, Object)} for lenient | ||||
|    * {@link #write(JsonWriter, Object)} for lenient | ||||
|    * writing. | ||||
|    * | ||||
|    * @param value the Java object to convert. May be null. | ||||
|    * @since 2.2 | ||||
|    */ | ||||
|   public final String toJson(T value) throws IOException { | ||||
|   public final String toJson(T value) { | ||||
|     StringWriter stringWriter = new StringWriter(); | ||||
|     toJson(stringWriter, value); | ||||
|     try { | ||||
|       toJson(stringWriter, value); | ||||
|     } catch (IOException e) { | ||||
|       throw new AssertionError(e); // No I/O writing to a StringWriter. | ||||
|     } | ||||
|     return stringWriter.toString(); | ||||
|   } | ||||
| 
 | ||||
|  | ||||
| @ -80,7 +80,7 @@ import com.massivecraft.massivecore.xlib.gson.reflect.TypeToken; | ||||
|  * mapping from lowercase name to enum value is computed eagerly. | ||||
|  * | ||||
|  * <p>As with type adapters, factories must be <i>registered</i> with a {@link | ||||
|  * com.massivecraft.massivecore.xlib.gson.GsonBuilder} for them to take effect: <pre>   {@code | ||||
|  * GsonBuilder} for them to take effect: <pre>   {@code | ||||
|  * | ||||
|  *  GsonBuilder builder = new GsonBuilder(); | ||||
|  *  builder.registerTypeAdapterFactory(new LowercaseEnumTypeAdapterFactory()); | ||||
|  | ||||
| @ -16,18 +16,18 @@ | ||||
| 
 | ||||
| package com.massivecraft.massivecore.xlib.gson.annotations; | ||||
| 
 | ||||
| import java.lang.annotation.ElementType; | ||||
| import java.lang.annotation.Retention; | ||||
| import java.lang.annotation.RetentionPolicy; | ||||
| import java.lang.annotation.Target; | ||||
| import com.massivecraft.massivecore.xlib.gson.Gson; | ||||
| import com.massivecraft.massivecore.xlib.gson.GsonBuilder; | ||||
| 
 | ||||
| import java.lang.annotation.*; | ||||
| 
 | ||||
| /** | ||||
|  * An annotation that indicates this member should be exposed for JSON | ||||
|  * serialization or deserialization. | ||||
|  * | ||||
|  * <p>This annotation has no effect unless you build {@link com.massivecraft.massivecore.xlib.gson.Gson} | ||||
|  * with a {@link com.massivecraft.massivecore.xlib.gson.GsonBuilder} and invoke | ||||
|  * {@link com.massivecraft.massivecore.xlib.gson.GsonBuilder#excludeFieldsWithoutExposeAnnotation()} | ||||
|  * <p>This annotation has no effect unless you build {@link Gson} | ||||
|  * with a {@link GsonBuilder} and invoke | ||||
|  * {@link GsonBuilder#excludeFieldsWithoutExposeAnnotation()} | ||||
|  * method.</p> | ||||
|  * | ||||
|  * <p>Here is an example of how this annotation is meant to be used: | ||||
| @ -57,6 +57,7 @@ import java.lang.annotation.Target; | ||||
|  * @author Inderjeet Singh | ||||
|  * @author Joel Leitch | ||||
|  */ | ||||
| @Documented | ||||
| @Retention(RetentionPolicy.RUNTIME) | ||||
| @Target(ElementType.FIELD) | ||||
| public @interface Expose { | ||||
| @ -67,7 +68,7 @@ public @interface Expose { | ||||
|    * serialized output. Defaults to {@code true}. | ||||
|    * @since 1.4 | ||||
|    */ | ||||
|   boolean serialize() default true; | ||||
|   public boolean serialize() default true; | ||||
| 
 | ||||
|   /** | ||||
|    * If {@code true}, the field marked with this annotation is deserialized from the JSON. | ||||
| @ -75,5 +76,5 @@ public @interface Expose { | ||||
|    * Defaults to {@code true}. | ||||
|    * @since 1.4 | ||||
|    */ | ||||
|   boolean deserialize() default true; | ||||
|   public boolean deserialize() default true; | ||||
| } | ||||
|  | ||||
| @ -16,6 +16,7 @@ | ||||
| 
 | ||||
| package com.massivecraft.massivecore.xlib.gson.annotations; | ||||
| 
 | ||||
| import com.massivecraft.massivecore.xlib.gson.GsonBuilder; | ||||
| import com.massivecraft.massivecore.xlib.gson.TypeAdapter; | ||||
| import com.massivecraft.massivecore.xlib.gson.TypeAdapterFactory; | ||||
| 
 | ||||
| @ -73,7 +74,7 @@ import java.lang.annotation.Target; | ||||
|  * </pre> | ||||
|  * | ||||
|  * It's possible to specify different type adapters on a field, that | ||||
|  * field's type, and in the {@link com.massivecraft.massivecore.xlib.gson.GsonBuilder}. Field | ||||
|  * field's type, and in the {@link GsonBuilder}. Field | ||||
|  * annotations take precedence over {@code GsonBuilder}-registered type | ||||
|  * adapters, which in turn take precedence over annotated types. | ||||
|  * | ||||
| @ -95,4 +96,7 @@ public @interface JsonAdapter { | ||||
|   /** Either a {@link TypeAdapter} or {@link TypeAdapterFactory}. */ | ||||
|   Class<?> value(); | ||||
| 
 | ||||
|   /** false, to be able to handle {@code null} values within the adapter, default value is true. */ | ||||
|   boolean nullSafe() default true; | ||||
| 
 | ||||
| } | ||||
|  | ||||
| @ -16,30 +16,33 @@ | ||||
| 
 | ||||
| package com.massivecraft.massivecore.xlib.gson.annotations; | ||||
| 
 | ||||
| import java.lang.annotation.ElementType; | ||||
| import java.lang.annotation.Retention; | ||||
| import java.lang.annotation.RetentionPolicy; | ||||
| import java.lang.annotation.Target; | ||||
| import com.massivecraft.massivecore.xlib.gson.FieldNamingPolicy; | ||||
| import com.massivecraft.massivecore.xlib.gson.Gson; | ||||
| import com.massivecraft.massivecore.xlib.gson.GsonBuilder; | ||||
| 
 | ||||
| import java.lang.annotation.*; | ||||
| 
 | ||||
| /** | ||||
|  * An annotation that indicates this member should be serialized to JSON with | ||||
|  * the provided name value as its field name. | ||||
|  * | ||||
|  * <p>This annotation will override any {@link com.massivecraft.massivecore.xlib.gson.FieldNamingPolicy}, including | ||||
|  * the default field naming policy, that may have been set on the {@link com.massivecraft.massivecore.xlib.gson.Gson} | ||||
|  * <p>This annotation will override any {@link FieldNamingPolicy}, including | ||||
|  * the default field naming policy, that may have been set on the {@link Gson} | ||||
|  * instance.  A different naming policy can set using the {@code GsonBuilder} class.  See | ||||
|  * {@link com.massivecraft.massivecore.xlib.gson.GsonBuilder#setFieldNamingPolicy(com.massivecraft.massivecore.xlib.gson.FieldNamingPolicy)} | ||||
|  * {@link GsonBuilder#setFieldNamingPolicy(FieldNamingPolicy)} | ||||
|  * for more information.</p> | ||||
|  * | ||||
|  * <p>Here is an example of how this annotation is meant to be used:</p> | ||||
|  * <pre> | ||||
|  * public class SomeClassWithFields { | ||||
|  *   @SerializedName("name") private final String someField; | ||||
|  *   private final String someOtherField; | ||||
|  * public class MyClass { | ||||
|  *   @SerializedName("name") String a; | ||||
|  *   @SerializedName(value="name1", alternate={"name2", "name3"}) String b; | ||||
|  *   String c; | ||||
|  * | ||||
|  *   public SomeClassWithFields(String a, String b) { | ||||
|  *     this.someField = a; | ||||
|  *     this.someOtherField = b; | ||||
|  *   public MyClass(String a, String b, String c) { | ||||
|  *     this.a = a; | ||||
|  *     this.b = b; | ||||
|  *     this.c = c; | ||||
|  *   } | ||||
|  * } | ||||
|  * </pre> | ||||
| @ -47,28 +50,44 @@ import java.lang.annotation.Target; | ||||
|  * <p>The following shows the output that is generated when serializing an instance of the | ||||
|  * above example class:</p> | ||||
|  * <pre> | ||||
|  * SomeClassWithFields objectToSerialize = new SomeClassWithFields("a", "b"); | ||||
|  * MyClass target = new MyClass("v1", "v2", "v3"); | ||||
|  * Gson gson = new Gson(); | ||||
|  * String jsonRepresentation = gson.toJson(objectToSerialize); | ||||
|  * System.out.println(jsonRepresentation); | ||||
|  * String json = gson.toJson(target); | ||||
|  * System.out.println(json); | ||||
|  * | ||||
|  * ===== OUTPUT ===== | ||||
|  * {"name":"a","someOtherField":"b"} | ||||
|  * {"name":"v1","name1":"v2","c":"v3"} | ||||
|  * </pre> | ||||
|  * | ||||
|  * <p>NOTE: The value you specify in this annotation must be a valid JSON field name.</p> | ||||
|  * While deserializing, all values specified in the annotation will be deserialized into the field. | ||||
|  * For example: | ||||
|  * <pre> | ||||
|  *   MyClass target = gson.fromJson("{'name1':'v1'}", MyClass.class); | ||||
|  *   assertEquals("v1", target.b); | ||||
|  *   target = gson.fromJson("{'name2':'v2'}", MyClass.class); | ||||
|  *   assertEquals("v2", target.b); | ||||
|  *   target = gson.fromJson("{'name3':'v3'}", MyClass.class); | ||||
|  *   assertEquals("v3", target.b); | ||||
|  * </pre> | ||||
|  * Note that MyClass.b is now deserialized from either name1, name2 or name3. | ||||
|  * | ||||
|  * @see com.massivecraft.massivecore.xlib.gson.FieldNamingPolicy | ||||
|  * @see FieldNamingPolicy | ||||
|  * | ||||
|  * @author Inderjeet Singh | ||||
|  * @author Joel Leitch | ||||
|  */ | ||||
| @Documented | ||||
| @Retention(RetentionPolicy.RUNTIME) | ||||
| @Target(ElementType.FIELD) | ||||
| @Target({ElementType.FIELD, ElementType.METHOD}) | ||||
| public @interface SerializedName { | ||||
| 
 | ||||
|   /** | ||||
|    * @return the desired name of the field when it is serialized | ||||
|    * @return the desired name of the field when it is serialized or deserialized | ||||
|    */ | ||||
|   String value(); | ||||
|   /** | ||||
|    * @return the alternative names of the field when it is deserialized | ||||
|    */ | ||||
|   String[] alternate() default {}; | ||||
| } | ||||
|  | ||||
| @ -16,19 +16,19 @@ | ||||
| 
 | ||||
| package com.massivecraft.massivecore.xlib.gson.annotations; | ||||
| 
 | ||||
| import java.lang.annotation.ElementType; | ||||
| import java.lang.annotation.Retention; | ||||
| import java.lang.annotation.RetentionPolicy; | ||||
| import java.lang.annotation.Target; | ||||
| import com.massivecraft.massivecore.xlib.gson.Gson; | ||||
| import com.massivecraft.massivecore.xlib.gson.GsonBuilder; | ||||
| 
 | ||||
| import java.lang.annotation.*; | ||||
| 
 | ||||
| /** | ||||
|  * An annotation that indicates the version number since a member or a type has been present. | ||||
|  * This annotation is useful to manage versioning of your Json classes for a web-service. | ||||
|  * | ||||
|  * <p> | ||||
|  * This annotation has no effect unless you build {@link com.massivecraft.massivecore.xlib.gson.Gson} with a | ||||
|  * {@link com.massivecraft.massivecore.xlib.gson.GsonBuilder} and invoke | ||||
|  * {@link com.massivecraft.massivecore.xlib.gson.GsonBuilder#setVersion(double)} method. | ||||
|  * This annotation has no effect unless you build {@link Gson} with a | ||||
|  * {@link GsonBuilder} and invoke | ||||
|  * {@link GsonBuilder#setVersion(double)} method. | ||||
|  * | ||||
|  * <p>Here is an example of how this annotation is meant to be used:</p> | ||||
|  * <pre> | ||||
| @ -50,6 +50,7 @@ import java.lang.annotation.Target; | ||||
|  * @author Inderjeet Singh | ||||
|  * @author Joel Leitch | ||||
|  */ | ||||
| @Documented | ||||
| @Retention(RetentionPolicy.RUNTIME) | ||||
| @Target({ElementType.FIELD, ElementType.TYPE}) | ||||
| public @interface Since { | ||||
|  | ||||
| @ -16,10 +16,10 @@ | ||||
| 
 | ||||
| package com.massivecraft.massivecore.xlib.gson.annotations; | ||||
| 
 | ||||
| import java.lang.annotation.ElementType; | ||||
| import java.lang.annotation.Retention; | ||||
| import java.lang.annotation.RetentionPolicy; | ||||
| import java.lang.annotation.Target; | ||||
| import com.massivecraft.massivecore.xlib.gson.Gson; | ||||
| import com.massivecraft.massivecore.xlib.gson.GsonBuilder; | ||||
| 
 | ||||
| import java.lang.annotation.*; | ||||
| 
 | ||||
| /** | ||||
|  * An annotation that indicates the version number until a member or a type should be present. | ||||
| @ -28,9 +28,9 @@ import java.lang.annotation.Target; | ||||
|  * is useful to manage versioning of your JSON classes for a web-service. | ||||
|  * | ||||
|  * <p> | ||||
|  * This annotation has no effect unless you build {@link com.massivecraft.massivecore.xlib.gson.Gson} with a | ||||
|  * {@link com.massivecraft.massivecore.xlib.gson.GsonBuilder} and invoke | ||||
|  * {@link com.massivecraft.massivecore.xlib.gson.GsonBuilder#setVersion(double)} method. | ||||
|  * This annotation has no effect unless you build {@link Gson} with a | ||||
|  * {@link GsonBuilder} and invoke | ||||
|  * {@link GsonBuilder#setVersion(double)} method. | ||||
|  * | ||||
|  * <p>Here is an example of how this annotation is meant to be used:</p> | ||||
|  * <pre> | ||||
| @ -54,6 +54,7 @@ import java.lang.annotation.Target; | ||||
|  * @author Joel Leitch | ||||
|  * @since 1.3 | ||||
|  */ | ||||
| @Documented | ||||
| @Retention(RetentionPolicy.RUNTIME) | ||||
| @Target({ElementType.FIELD, ElementType.TYPE}) | ||||
| public @interface Until { | ||||
|  | ||||
| @ -30,6 +30,10 @@ package com.massivecraft.massivecore.xlib.gson.internal; | ||||
|  * @author Joel Leitch | ||||
|  */ | ||||
| public final class $Gson$Preconditions { | ||||
|   private $Gson$Preconditions() { | ||||
|     throw new UnsupportedOperationException(); | ||||
|   } | ||||
| 
 | ||||
|   public static <T> T checkNotNull(T obj) { | ||||
|     if (obj == null) { | ||||
|       throw new NullPointerException(); | ||||
|  | ||||
| @ -17,19 +17,8 @@ | ||||
| package com.massivecraft.massivecore.xlib.gson.internal; | ||||
| 
 | ||||
| import java.io.Serializable; | ||||
| import java.lang.reflect.Array; | ||||
| import java.lang.reflect.GenericArrayType; | ||||
| import java.lang.reflect.GenericDeclaration; | ||||
| import java.lang.reflect.Modifier; | ||||
| 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; | ||||
| import java.lang.reflect.*; | ||||
| import java.util.*; | ||||
| 
 | ||||
| import static com.massivecraft.massivecore.xlib.gson.internal.$Gson$Preconditions.checkArgument; | ||||
| import static com.massivecraft.massivecore.xlib.gson.internal.$Gson$Preconditions.checkNotNull; | ||||
| @ -43,7 +32,9 @@ import static com.massivecraft.massivecore.xlib.gson.internal.$Gson$Precondition | ||||
| public final class $Gson$Types { | ||||
|   static final Type[] EMPTY_TYPE_ARRAY = new Type[] {}; | ||||
| 
 | ||||
|   private $Gson$Types() {} | ||||
|   private $Gson$Types() { | ||||
|     throw new UnsupportedOperationException(); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * Returns a new parameterized type, applying {@code typeArguments} to | ||||
| @ -210,7 +201,7 @@ public final class $Gson$Types { | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   private static int hashCodeOrZero(Object o) { | ||||
|   static int hashCodeOrZero(Object o) { | ||||
|     return o != null ? o.hashCode() : 0; | ||||
|   } | ||||
| 
 | ||||
| @ -428,7 +419,7 @@ public final class $Gson$Types { | ||||
|         : null; | ||||
|   } | ||||
| 
 | ||||
|   private static void checkNotPrimitive(Type type) { | ||||
|   static void checkNotPrimitive(Type type) { | ||||
|     checkArgument(!(type instanceof Class<?>) || !((Class<?>) type).isPrimitive()); | ||||
|   } | ||||
| 
 | ||||
|  | ||||
| @ -24,19 +24,11 @@ import java.lang.reflect.Constructor; | ||||
| import java.lang.reflect.InvocationTargetException; | ||||
| import java.lang.reflect.ParameterizedType; | ||||
| import java.lang.reflect.Type; | ||||
| import java.util.ArrayList; | ||||
| import java.util.Collection; | ||||
| import java.util.EnumSet; | ||||
| import java.util.LinkedHashMap; | ||||
| import java.util.LinkedHashSet; | ||||
| import java.util.LinkedList; | ||||
| import java.util.Map; | ||||
| import java.util.Queue; | ||||
| import java.util.Set; | ||||
| import java.util.SortedMap; | ||||
| import java.util.SortedSet; | ||||
| import java.util.TreeMap; | ||||
| import java.util.TreeSet; | ||||
| import java.util.*; | ||||
| import java.util.concurrent.ConcurrentHashMap; | ||||
| import java.util.concurrent.ConcurrentMap; | ||||
| import java.util.concurrent.ConcurrentNavigableMap; | ||||
| import java.util.concurrent.ConcurrentSkipListMap; | ||||
| 
 | ||||
| /** | ||||
|  * Returns a function that can construct an instance of a requested type. | ||||
| @ -58,7 +50,7 @@ public final class ConstructorConstructor { | ||||
|     final InstanceCreator<T> typeCreator = (InstanceCreator<T>) instanceCreators.get(type); | ||||
|     if (typeCreator != null) { | ||||
|       return new ObjectConstructor<T>() { | ||||
|         public T construct() { | ||||
|         @Override public T construct() { | ||||
|           return typeCreator.createInstance(type); | ||||
|         } | ||||
|       }; | ||||
| @ -70,7 +62,7 @@ public final class ConstructorConstructor { | ||||
|         (InstanceCreator<T>) instanceCreators.get(rawType); | ||||
|     if (rawTypeCreator != null) { | ||||
|       return new ObjectConstructor<T>() { | ||||
|         public T construct() { | ||||
|         @Override public T construct() { | ||||
|           return rawTypeCreator.createInstance(type); | ||||
|         } | ||||
|       }; | ||||
| @ -98,7 +90,7 @@ public final class ConstructorConstructor { | ||||
|       } | ||||
|       return new ObjectConstructor<T>() { | ||||
|         @SuppressWarnings("unchecked") // T is the same raw type as is requested | ||||
|         public T construct() { | ||||
|         @Override public T construct() { | ||||
|           try { | ||||
|             Object[] args = null; | ||||
|             return (T) constructor.newInstance(args); | ||||
| @ -122,7 +114,7 @@ public final class ConstructorConstructor { | ||||
| 
 | ||||
|   /** | ||||
|    * Constructors for common interface types like Map and List and their | ||||
|    * subytpes. | ||||
|    * subtypes. | ||||
|    */ | ||||
|   @SuppressWarnings("unchecked") // use runtime checks to guarantee that 'T' is what it is | ||||
|   private <T> ObjectConstructor<T> newDefaultImplementationConstructor( | ||||
| @ -130,14 +122,14 @@ public final class ConstructorConstructor { | ||||
|     if (Collection.class.isAssignableFrom(rawType)) { | ||||
|       if (SortedSet.class.isAssignableFrom(rawType)) { | ||||
|         return new ObjectConstructor<T>() { | ||||
|           public T construct() { | ||||
|           @Override public T construct() { | ||||
|             return (T) new TreeSet<>(); | ||||
|           } | ||||
|         }; | ||||
|       } else if (EnumSet.class.isAssignableFrom(rawType)) { | ||||
|         return new ObjectConstructor<T>() { | ||||
|           @SuppressWarnings("rawtypes") | ||||
|           public T construct() { | ||||
|           @Override public T construct() { | ||||
|             if (type instanceof ParameterizedType) { | ||||
|               Type elementType = ((ParameterizedType) type).getActualTypeArguments()[0]; | ||||
|               if (elementType instanceof Class) { | ||||
| @ -152,19 +144,19 @@ public final class ConstructorConstructor { | ||||
|         }; | ||||
|       } else if (Set.class.isAssignableFrom(rawType)) { | ||||
|         return new ObjectConstructor<T>() { | ||||
|           public T construct() { | ||||
|           @Override public T construct() { | ||||
|             return (T) new LinkedHashSet<>(); | ||||
|           } | ||||
|         }; | ||||
|       } else if (Queue.class.isAssignableFrom(rawType)) { | ||||
|         return new ObjectConstructor<T>() { | ||||
|           public T construct() { | ||||
|             return (T) new LinkedList<>(); | ||||
|           @Override public T construct() { | ||||
|             return (T) new ArrayDeque<>(); | ||||
|           } | ||||
|         }; | ||||
|       } else { | ||||
|         return new ObjectConstructor<T>() { | ||||
|           public T construct() { | ||||
|           @Override public T construct() { | ||||
|             return (T) new ArrayList<>(); | ||||
|           } | ||||
|         }; | ||||
| @ -172,22 +164,34 @@ public final class ConstructorConstructor { | ||||
|     } | ||||
| 
 | ||||
|     if (Map.class.isAssignableFrom(rawType)) { | ||||
|       if (SortedMap.class.isAssignableFrom(rawType)) { | ||||
|       if (ConcurrentNavigableMap.class.isAssignableFrom(rawType)) { | ||||
|         return new ObjectConstructor<T>() { | ||||
|           public T construct() { | ||||
|           @Override public T construct() { | ||||
|             return (T) new ConcurrentSkipListMap<>(); | ||||
|           } | ||||
|         }; | ||||
|       } else if (ConcurrentMap.class.isAssignableFrom(rawType)) { | ||||
|         return new ObjectConstructor<T>() { | ||||
|           @Override public T construct() { | ||||
|             return (T) new ConcurrentHashMap<>(); | ||||
|           } | ||||
|         }; | ||||
|       } else if (SortedMap.class.isAssignableFrom(rawType)) { | ||||
|         return new ObjectConstructor<T>() { | ||||
|           @Override public T construct() { | ||||
|             return (T) new TreeMap<>(); | ||||
|           } | ||||
|         }; | ||||
|       } else if (type instanceof ParameterizedType && !(String.class.isAssignableFrom( | ||||
|           TypeToken.get(((ParameterizedType) type).getActualTypeArguments()[0]).getRawType()))) { | ||||
|         return new ObjectConstructor<T>() { | ||||
|           public T construct() { | ||||
|           @Override public T construct() { | ||||
|             return (T) new LinkedHashMap<>(); | ||||
|           } | ||||
|         }; | ||||
|       } else { | ||||
|         return new ObjectConstructor<T>() { | ||||
|           public T construct() { | ||||
|           @Override public T construct() { | ||||
|             return (T) new LinkedTreeMap<String, Object>(); | ||||
|           } | ||||
|         }; | ||||
| @ -202,7 +206,7 @@ public final class ConstructorConstructor { | ||||
|     return new ObjectConstructor<T>() { | ||||
|       private final UnsafeAllocator unsafeAllocator = UnsafeAllocator.create(); | ||||
|       @SuppressWarnings("unchecked") | ||||
|       public T construct() { | ||||
|       @Override public T construct() { | ||||
|         try { | ||||
|           Object newInstance = unsafeAllocator.newInstance(rawType); | ||||
|           return (T) newInstance; | ||||
|  | ||||
| @ -16,11 +16,7 @@ | ||||
| 
 | ||||
| package com.massivecraft.massivecore.xlib.gson.internal; | ||||
| 
 | ||||
| import com.massivecraft.massivecore.xlib.gson.ExclusionStrategy; | ||||
| import com.massivecraft.massivecore.xlib.gson.FieldAttributes; | ||||
| import com.massivecraft.massivecore.xlib.gson.Gson; | ||||
| import com.massivecraft.massivecore.xlib.gson.TypeAdapter; | ||||
| import com.massivecraft.massivecore.xlib.gson.TypeAdapterFactory; | ||||
| import com.massivecraft.massivecore.xlib.gson.*; | ||||
| import com.massivecraft.massivecore.xlib.gson.annotations.Expose; | ||||
| import com.massivecraft.massivecore.xlib.gson.annotations.Since; | ||||
| import com.massivecraft.massivecore.xlib.gson.annotations.Until; | ||||
| @ -63,7 +59,7 @@ public final class Excluder implements TypeAdapterFactory, Cloneable { | ||||
|     try { | ||||
|       return (Excluder) super.clone(); | ||||
|     } catch (CloneNotSupportedException e) { | ||||
|       throw new AssertionError(); | ||||
|       throw new AssertionError(e); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|  | ||||
| @ -26,6 +26,7 @@ import java.math.BigDecimal; | ||||
| public final class LazilyParsedNumber extends Number { | ||||
|   private final String value; | ||||
| 
 | ||||
|   /** @param value must not be null */ | ||||
|   public LazilyParsedNumber(String value) { | ||||
|     this.value = value; | ||||
|   } | ||||
| @ -75,4 +76,21 @@ public final class LazilyParsedNumber extends Number { | ||||
|   private Object writeReplace() throws ObjectStreamException { | ||||
|     return new BigDecimal(value); | ||||
|   } | ||||
| 
 | ||||
|   @Override | ||||
|   public int hashCode() { | ||||
|     return value.hashCode(); | ||||
|   } | ||||
| 
 | ||||
|   @Override | ||||
|   public boolean equals(Object obj) { | ||||
|     if (this == obj) { | ||||
|       return true; | ||||
|     } | ||||
|     if (obj instanceof LazilyParsedNumber) { | ||||
|       LazilyParsedNumber other = (LazilyParsedNumber) obj; | ||||
|       return value == other.value || value.equals(other.value); | ||||
|     } | ||||
|     return false; | ||||
|   } | ||||
| } | ||||
| @ -19,15 +19,7 @@ package com.massivecraft.massivecore.xlib.gson.internal; | ||||
| 
 | ||||
| import java.io.ObjectStreamException; | ||||
| import java.io.Serializable; | ||||
| import java.util.AbstractMap; | ||||
| import java.util.AbstractSet; | ||||
| import java.util.Arrays; | ||||
| import java.util.Comparator; | ||||
| import java.util.ConcurrentModificationException; | ||||
| import java.util.Iterator; | ||||
| import java.util.LinkedHashMap; | ||||
| import java.util.NoSuchElementException; | ||||
| import java.util.Set; | ||||
| import java.util.*; | ||||
| 
 | ||||
| /** | ||||
|  * A map of comparable keys to values. Unlike {@code TreeMap}, this class uses | ||||
| @ -762,6 +754,9 @@ public final class LinkedHashTreeMap<K, V> extends AbstractMap<K, V> implements | ||||
|     Node<K, V> lastReturned = null; | ||||
|     int expectedModCount = modCount; | ||||
| 
 | ||||
|     LinkedTreeMapIterator() { | ||||
|     } | ||||
| 
 | ||||
|     public final boolean hasNext() { | ||||
|       return next != header; | ||||
|     } | ||||
|  | ||||
| @ -19,14 +19,7 @@ package com.massivecraft.massivecore.xlib.gson.internal; | ||||
| 
 | ||||
| import java.io.ObjectStreamException; | ||||
| import java.io.Serializable; | ||||
| import java.util.AbstractMap; | ||||
| import java.util.AbstractSet; | ||||
| import java.util.Comparator; | ||||
| import java.util.ConcurrentModificationException; | ||||
| import java.util.Iterator; | ||||
| import java.util.LinkedHashMap; | ||||
| import java.util.NoSuchElementException; | ||||
| import java.util.Set; | ||||
| import java.util.*; | ||||
| 
 | ||||
| /** | ||||
|  * A map of comparable keys to values. Unlike {@code TreeMap}, this class uses | ||||
| @ -528,6 +521,9 @@ public final class LinkedTreeMap<K, V> extends AbstractMap<K, V> implements Seri | ||||
|     Node<K, V> lastReturned = null; | ||||
|     int expectedModCount = modCount; | ||||
| 
 | ||||
|     LinkedTreeMapIterator() { | ||||
|     } | ||||
| 
 | ||||
|     public final boolean hasNext() { | ||||
|       return next != header; | ||||
|     } | ||||
|  | ||||
| @ -29,5 +29,5 @@ public interface ObjectConstructor<T> { | ||||
|   /** | ||||
|    * Returns a new instance. | ||||
|    */ | ||||
|   T construct(); | ||||
|   public T construct(); | ||||
| } | ||||
| @ -29,7 +29,9 @@ import java.util.Map; | ||||
|  * @author Kevin Bourrillion | ||||
|  */ | ||||
| public final class Primitives { | ||||
|   private Primitives() {} | ||||
|   private Primitives() { | ||||
|     throw new UnsupportedOperationException(); | ||||
|   } | ||||
| 
 | ||||
|   /** A map from primitive types to their corresponding wrapper types. */ | ||||
|   private static final Map<Class<?>, Class<?>> PRIMITIVE_TO_WRAPPER_TYPE; | ||||
|  | ||||
| @ -16,11 +16,7 @@ | ||||
| 
 | ||||
| package com.massivecraft.massivecore.xlib.gson.internal; | ||||
| 
 | ||||
| import com.massivecraft.massivecore.xlib.gson.JsonElement; | ||||
| import com.massivecraft.massivecore.xlib.gson.JsonIOException; | ||||
| import com.massivecraft.massivecore.xlib.gson.JsonNull; | ||||
| import com.massivecraft.massivecore.xlib.gson.JsonParseException; | ||||
| import com.massivecraft.massivecore.xlib.gson.JsonSyntaxException; | ||||
| import com.massivecraft.massivecore.xlib.gson.*; | ||||
| import com.massivecraft.massivecore.xlib.gson.internal.bind.TypeAdapters; | ||||
| import com.massivecraft.massivecore.xlib.gson.stream.JsonReader; | ||||
| import com.massivecraft.massivecore.xlib.gson.stream.JsonWriter; | ||||
| @ -34,6 +30,10 @@ import java.io.Writer; | ||||
|  * Reads and writes GSON parse trees over streams. | ||||
|  */ | ||||
| public final class Streams { | ||||
|   private Streams() { | ||||
|     throw new UnsupportedOperationException(); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * Takes a reader in any state and returns the next value as a JsonElement. | ||||
|    */ | ||||
| @ -81,7 +81,7 @@ public final class Streams { | ||||
|     private final Appendable appendable; | ||||
|     private final CurrentWrite currentWrite = new CurrentWrite(); | ||||
| 
 | ||||
|     private AppendableWriter(Appendable appendable) { | ||||
|     AppendableWriter(Appendable appendable) { | ||||
|       this.appendable = appendable; | ||||
|     } | ||||
| 
 | ||||
|  | ||||
| @ -20,6 +20,7 @@ import java.io.ObjectInputStream; | ||||
| import java.io.ObjectStreamClass; | ||||
| import java.lang.reflect.Field; | ||||
| import java.lang.reflect.Method; | ||||
| import java.lang.reflect.Modifier; | ||||
| 
 | ||||
| /** | ||||
|  * Do sneaky things to allocate objects without invoking their constructors. | ||||
| @ -45,6 +46,7 @@ public abstract class UnsafeAllocator { | ||||
|         @Override | ||||
|         @SuppressWarnings("unchecked") | ||||
|         public <T> T newInstance(Class<T> c) throws Exception { | ||||
|           assertInstantiable(c); | ||||
|           return (T) allocateInstance.invoke(unsafe, c); | ||||
|         } | ||||
|       }; | ||||
| @ -68,6 +70,7 @@ public abstract class UnsafeAllocator { | ||||
|         @Override | ||||
|         @SuppressWarnings("unchecked") | ||||
|         public <T> T newInstance(Class<T> c) throws Exception { | ||||
|           assertInstantiable(c); | ||||
|           return (T) newInstance.invoke(null, c, constructorId); | ||||
|         } | ||||
|       }; | ||||
| @ -87,6 +90,7 @@ public abstract class UnsafeAllocator { | ||||
|         @Override | ||||
|         @SuppressWarnings("unchecked") | ||||
|         public <T> T newInstance(Class<T> c) throws Exception { | ||||
|           assertInstantiable(c); | ||||
|           return (T) newInstance.invoke(null, c, Object.class); | ||||
|         } | ||||
|       }; | ||||
| @ -101,4 +105,19 @@ public abstract class UnsafeAllocator { | ||||
|       } | ||||
|     }; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * Check if the class can be instantiated by unsafe allocator. If the instance has interface or abstract modifiers | ||||
|    * throw an {@link java.lang.UnsupportedOperationException} | ||||
|    * @param c instance of the class to be checked | ||||
|    */ | ||||
|   private static void assertInstantiable(Class<?> c) { | ||||
|     int modifiers = c.getModifiers(); | ||||
|     if (Modifier.isInterface(modifiers)) { | ||||
|       throw new UnsupportedOperationException("Interface can't be instantiated! Interface name: " + c.getName()); | ||||
|     } | ||||
|     if (Modifier.isAbstract(modifiers)) { | ||||
|       throw new UnsupportedOperationException("Abstract class can't be instantiated! Class name: " + c.getName()); | ||||
|     } | ||||
|   } | ||||
| } | ||||
|  | ||||
| @ -38,7 +38,7 @@ import java.util.List; | ||||
| public final class ArrayTypeAdapter<E> extends TypeAdapter<Object> { | ||||
|   public static final TypeAdapterFactory FACTORY = new TypeAdapterFactory() { | ||||
|     @SuppressWarnings({"unchecked", "rawtypes"}) | ||||
|     public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> typeToken) { | ||||
|     @Override public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> typeToken) { | ||||
|       Type type = typeToken.getType(); | ||||
|       if (!(type instanceof GenericArrayType || type instanceof Class && ((Class<?>) type).isArray())) { | ||||
|         return null; | ||||
| @ -56,11 +56,11 @@ public final class ArrayTypeAdapter<E> extends TypeAdapter<Object> { | ||||
| 
 | ||||
|   public ArrayTypeAdapter(Gson context, TypeAdapter<E> componentTypeAdapter, Class<E> componentType) { | ||||
|     this.componentTypeAdapter = | ||||
| 		new TypeAdapterRuntimeTypeWrapper<>(context, componentTypeAdapter, componentType); | ||||
|             new TypeAdapterRuntimeTypeWrapper<>(context, componentTypeAdapter, componentType); | ||||
|     this.componentType = componentType; | ||||
|   } | ||||
| 
 | ||||
|   public Object read(JsonReader in) throws IOException { | ||||
|   @Override public Object read(JsonReader in) throws IOException { | ||||
|     if (in.peek() == JsonToken.NULL) { | ||||
|       in.nextNull(); | ||||
|       return null; | ||||
|  | ||||
| @ -41,6 +41,7 @@ public final class CollectionTypeAdapterFactory implements TypeAdapterFactory { | ||||
|     this.constructorConstructor = constructorConstructor; | ||||
|   } | ||||
| 
 | ||||
|   @Override | ||||
|   public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> typeToken) { | ||||
|     Type type = typeToken.getType(); | ||||
| 
 | ||||
| @ -63,14 +64,14 @@ public final class CollectionTypeAdapterFactory implements TypeAdapterFactory { | ||||
|     private final ObjectConstructor<? extends Collection<E>> constructor; | ||||
| 
 | ||||
|     public Adapter(Gson context, Type elementType, | ||||
|         TypeAdapter<E> elementTypeAdapter, | ||||
|         ObjectConstructor<? extends Collection<E>> constructor) { | ||||
|                    TypeAdapter<E> elementTypeAdapter, | ||||
|                    ObjectConstructor<? extends Collection<E>> constructor) { | ||||
|       this.elementTypeAdapter = | ||||
| 		  new TypeAdapterRuntimeTypeWrapper<>(context, elementTypeAdapter, elementType); | ||||
|               new TypeAdapterRuntimeTypeWrapper<>(context, elementTypeAdapter, elementType); | ||||
|       this.constructor = constructor; | ||||
|     } | ||||
| 
 | ||||
|     public Collection<E> read(JsonReader in) throws IOException { | ||||
|     @Override public Collection<E> read(JsonReader in) throws IOException { | ||||
|       if (in.peek() == JsonToken.NULL) { | ||||
|         in.nextNull(); | ||||
|         return null; | ||||
| @ -86,7 +87,7 @@ public final class CollectionTypeAdapterFactory implements TypeAdapterFactory { | ||||
|       return collection; | ||||
|     } | ||||
| 
 | ||||
|     public void write(JsonWriter out, Collection<E> collection) throws IOException { | ||||
|     @Override public void write(JsonWriter out, Collection<E> collection) throws IOException { | ||||
|       if (collection == null) { | ||||
|         out.nullValue(); | ||||
|         return; | ||||
|  | ||||
| @ -20,6 +20,7 @@ import com.massivecraft.massivecore.xlib.gson.Gson; | ||||
| import com.massivecraft.massivecore.xlib.gson.JsonSyntaxException; | ||||
| import com.massivecraft.massivecore.xlib.gson.TypeAdapter; | ||||
| import com.massivecraft.massivecore.xlib.gson.TypeAdapterFactory; | ||||
| import com.massivecraft.massivecore.xlib.gson.internal.bind.util.ISO8601Utils; | ||||
| import com.massivecraft.massivecore.xlib.gson.reflect.TypeToken; | ||||
| import com.massivecraft.massivecore.xlib.gson.stream.JsonReader; | ||||
| import com.massivecraft.massivecore.xlib.gson.stream.JsonToken; | ||||
| @ -28,10 +29,9 @@ import com.massivecraft.massivecore.xlib.gson.stream.JsonWriter; | ||||
| import java.io.IOException; | ||||
| import java.text.DateFormat; | ||||
| import java.text.ParseException; | ||||
| import java.text.SimpleDateFormat; | ||||
| import java.text.ParsePosition; | ||||
| import java.util.Date; | ||||
| import java.util.Locale; | ||||
| import java.util.TimeZone; | ||||
| 
 | ||||
| /** | ||||
|  * Adapter for Date. Although this class appears stateless, it is not. | ||||
| @ -42,7 +42,7 @@ import java.util.TimeZone; | ||||
| public final class DateTypeAdapter extends TypeAdapter<Date> { | ||||
|   public static final TypeAdapterFactory FACTORY = new TypeAdapterFactory() { | ||||
|     @SuppressWarnings("unchecked") // we use a runtime check to make sure the 'T's equal | ||||
|     public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> typeToken) { | ||||
|     @Override public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> typeToken) { | ||||
|       return typeToken.getRawType() == Date.class ? (TypeAdapter<T>) new DateTypeAdapter() : null; | ||||
|     } | ||||
|   }; | ||||
| @ -51,13 +51,6 @@ public final class DateTypeAdapter extends TypeAdapter<Date> { | ||||
|       = DateFormat.getDateTimeInstance(DateFormat.DEFAULT, DateFormat.DEFAULT, Locale.US); | ||||
|   private final DateFormat localFormat | ||||
|       = DateFormat.getDateTimeInstance(DateFormat.DEFAULT, DateFormat.DEFAULT); | ||||
|   private final DateFormat iso8601Format = buildIso8601Format(); | ||||
| 
 | ||||
|   private static DateFormat buildIso8601Format() { | ||||
|     DateFormat iso8601Format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.US); | ||||
|     iso8601Format.setTimeZone(TimeZone.getTimeZone("UTC")); | ||||
|     return iso8601Format; | ||||
|   } | ||||
| 
 | ||||
|   @Override public Date read(JsonReader in) throws IOException { | ||||
|     if (in.peek() == JsonToken.NULL) { | ||||
| @ -77,7 +70,7 @@ public final class DateTypeAdapter extends TypeAdapter<Date> { | ||||
|     } catch (ParseException ignored) { | ||||
|     } | ||||
|     try { | ||||
|       return iso8601Format.parse(json); | ||||
|     	return ISO8601Utils.parse(json, new ParsePosition(0)); | ||||
|     } catch (ParseException e) { | ||||
|       throw new JsonSyntaxException(json, e); | ||||
|     } | ||||
| @ -91,4 +84,6 @@ public final class DateTypeAdapter extends TypeAdapter<Date> { | ||||
|     String dateFormatAsString = enUsFormat.format(value); | ||||
|     out.value(dateFormatAsString); | ||||
|   } | ||||
|    | ||||
|    | ||||
| } | ||||
|  | ||||
| @ -16,9 +16,7 @@ | ||||
| 
 | ||||
| package com.massivecraft.massivecore.xlib.gson.internal.bind; | ||||
| 
 | ||||
| import com.massivecraft.massivecore.xlib.gson.Gson; | ||||
| import com.massivecraft.massivecore.xlib.gson.TypeAdapter; | ||||
| import com.massivecraft.massivecore.xlib.gson.TypeAdapterFactory; | ||||
| import com.massivecraft.massivecore.xlib.gson.*; | ||||
| import com.massivecraft.massivecore.xlib.gson.annotations.JsonAdapter; | ||||
| import com.massivecraft.massivecore.xlib.gson.internal.ConstructorConstructor; | ||||
| import com.massivecraft.massivecore.xlib.gson.reflect.TypeToken; | ||||
| @ -30,7 +28,6 @@ import com.massivecraft.massivecore.xlib.gson.reflect.TypeToken; | ||||
|  * @since 2.3 | ||||
|  */ | ||||
| public final class JsonAdapterAnnotationTypeAdapterFactory implements TypeAdapterFactory { | ||||
| 
 | ||||
|   private final ConstructorConstructor constructorConstructor; | ||||
| 
 | ||||
|   public JsonAdapterAnnotationTypeAdapterFactory(ConstructorConstructor constructorConstructor) { | ||||
| @ -38,30 +35,44 @@ public final class JsonAdapterAnnotationTypeAdapterFactory implements TypeAdapte | ||||
|   } | ||||
| 
 | ||||
|   @SuppressWarnings("unchecked") | ||||
|   @Override | ||||
|   public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> targetType) { | ||||
|     JsonAdapter annotation = targetType.getRawType().getAnnotation(JsonAdapter.class); | ||||
|     Class<? super T> rawType = targetType.getRawType(); | ||||
|     JsonAdapter annotation = rawType.getAnnotation(JsonAdapter.class); | ||||
|     if (annotation == null) { | ||||
|       return null; | ||||
|     } | ||||
|     return (TypeAdapter<T>) getTypeAdapter(constructorConstructor, gson, targetType, annotation); | ||||
|   } | ||||
| 
 | ||||
|   @SuppressWarnings("unchecked") // Casts guarded by conditionals. | ||||
|   static TypeAdapter<?> getTypeAdapter(ConstructorConstructor constructorConstructor, Gson gson, | ||||
|       TypeToken<?> fieldType, JsonAdapter annotation) { | ||||
|     Class<?> value = annotation.value(); | ||||
|     if (TypeAdapter.class.isAssignableFrom(value)) { | ||||
|           Class<TypeAdapter<?>> typeAdapter = (Class<TypeAdapter<?>>) value; | ||||
|       return constructorConstructor.get(TypeToken.get(typeAdapter)).construct(); | ||||
|     } | ||||
|     if (TypeAdapterFactory.class.isAssignableFrom(value)) { | ||||
|           Class<TypeAdapterFactory> typeAdapterFactory = (Class<TypeAdapterFactory>) value; | ||||
|       return constructorConstructor.get(TypeToken.get(typeAdapterFactory)) | ||||
|           .construct() | ||||
|           .create(gson, fieldType); | ||||
|   @SuppressWarnings({ "unchecked", "rawtypes" }) // Casts guarded by conditionals. | ||||
|   TypeAdapter<?> getTypeAdapter(ConstructorConstructor constructorConstructor, Gson gson, | ||||
|       TypeToken<?> type, JsonAdapter annotation) { | ||||
|     Object instance = constructorConstructor.get(TypeToken.get(annotation.value())).construct(); | ||||
| 
 | ||||
|     TypeAdapter<?> typeAdapter; | ||||
|     if (instance instanceof TypeAdapter) { | ||||
|       typeAdapter = (TypeAdapter<?>) instance; | ||||
|     } else if (instance instanceof TypeAdapterFactory) { | ||||
|       typeAdapter = ((TypeAdapterFactory) instance).create(gson, type); | ||||
|     } else if (instance instanceof JsonSerializer || instance instanceof JsonDeserializer) { | ||||
|       JsonSerializer<?> serializer = instance instanceof JsonSerializer | ||||
|           ? (JsonSerializer) instance | ||||
|           : null; | ||||
|       JsonDeserializer<?> deserializer = instance instanceof JsonDeserializer | ||||
|           ? (JsonDeserializer) instance | ||||
|           : null; | ||||
|       typeAdapter = new TreeTypeAdapter(serializer, deserializer, gson, type, null); | ||||
|     } else { | ||||
|       throw new IllegalArgumentException( | ||||
|           "@JsonAdapter value must be TypeAdapter, TypeAdapterFactory, " | ||||
|               + "JsonSerializer or JsonDeserializer reference."); | ||||
|     } | ||||
| 
 | ||||
|     throw new IllegalArgumentException( | ||||
|         "@JsonAdapter value must be TypeAdapter or TypeAdapterFactory reference."); | ||||
|     if (typeAdapter != null && annotation.nullSafe()) { | ||||
|       typeAdapter = typeAdapter.nullSafe(); | ||||
|     } | ||||
| 
 | ||||
|     return typeAdapter; | ||||
|   } | ||||
| } | ||||
|  | ||||
| @ -16,19 +16,13 @@ | ||||
| 
 | ||||
| package com.massivecraft.massivecore.xlib.gson.internal.bind; | ||||
| 
 | ||||
| import com.massivecraft.massivecore.xlib.gson.JsonArray; | ||||
| import com.massivecraft.massivecore.xlib.gson.JsonElement; | ||||
| import com.massivecraft.massivecore.xlib.gson.JsonNull; | ||||
| import com.massivecraft.massivecore.xlib.gson.JsonObject; | ||||
| import com.massivecraft.massivecore.xlib.gson.JsonPrimitive; | ||||
| import com.massivecraft.massivecore.xlib.gson.*; | ||||
| import com.massivecraft.massivecore.xlib.gson.stream.JsonReader; | ||||
| import com.massivecraft.massivecore.xlib.gson.stream.JsonToken; | ||||
| 
 | ||||
| import java.io.IOException; | ||||
| import java.io.Reader; | ||||
| import java.util.ArrayList; | ||||
| import java.util.Iterator; | ||||
| import java.util.List; | ||||
| import java.util.Map; | ||||
| 
 | ||||
| /** | ||||
| @ -48,35 +42,57 @@ public final class JsonTreeReader extends JsonReader { | ||||
|   }; | ||||
|   private static final Object SENTINEL_CLOSED = new Object(); | ||||
| 
 | ||||
|   private final List<Object> stack = new ArrayList<>(); | ||||
|   /* | ||||
|    * The nesting stack. Using a manual array rather than an ArrayList saves 20%. | ||||
|    */ | ||||
|   private Object[] stack = new Object[32]; | ||||
|   private int stackSize = 0; | ||||
| 
 | ||||
|   /* | ||||
|    * The path members. It corresponds directly to stack: At indices where the | ||||
|    * stack contains an object (EMPTY_OBJECT, DANGLING_NAME or NONEMPTY_OBJECT), | ||||
|    * pathNames contains the name at this scope. Where it contains an array | ||||
|    * (EMPTY_ARRAY, NONEMPTY_ARRAY) pathIndices contains the current index in | ||||
|    * that array. Otherwise the value is undefined, and we take advantage of that | ||||
|    * by incrementing pathIndices when doing so isn't useful. | ||||
|    */ | ||||
|   private String[] pathNames = new String[32]; | ||||
|   private int[] pathIndices = new int[32]; | ||||
| 
 | ||||
|   public JsonTreeReader(JsonElement element) { | ||||
|     super(UNREADABLE_READER); | ||||
|     stack.add(element); | ||||
|     push(element); | ||||
|   } | ||||
| 
 | ||||
|   @Override public void beginArray() throws IOException { | ||||
|     expect(JsonToken.BEGIN_ARRAY); | ||||
|     JsonArray array = (JsonArray) peekStack(); | ||||
|     stack.add(array.iterator()); | ||||
|     push(array.iterator()); | ||||
|     pathIndices[stackSize - 1] = 0; | ||||
|   } | ||||
| 
 | ||||
|   @Override public void endArray() throws IOException { | ||||
|     expect(JsonToken.END_ARRAY); | ||||
|     popStack(); // empty iterator | ||||
|     popStack(); // array | ||||
|     if (stackSize > 0) { | ||||
|       pathIndices[stackSize - 1]++; | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   @Override public void beginObject() throws IOException { | ||||
|     expect(JsonToken.BEGIN_OBJECT); | ||||
|     JsonObject object = (JsonObject) peekStack(); | ||||
|     stack.add(object.entrySet().iterator()); | ||||
|     push(object.entrySet().iterator()); | ||||
|   } | ||||
| 
 | ||||
|   @Override public void endObject() throws IOException { | ||||
|     expect(JsonToken.END_OBJECT); | ||||
|     popStack(); // empty iterator | ||||
|     popStack(); // object | ||||
|     if (stackSize > 0) { | ||||
|       pathIndices[stackSize - 1]++; | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   @Override public boolean hasNext() throws IOException { | ||||
| @ -85,19 +101,19 @@ public final class JsonTreeReader extends JsonReader { | ||||
|   } | ||||
| 
 | ||||
|   @Override public JsonToken peek() throws IOException { | ||||
|     if (stack.isEmpty()) { | ||||
|     if (stackSize == 0) { | ||||
|       return JsonToken.END_DOCUMENT; | ||||
|     } | ||||
| 
 | ||||
|     Object o = peekStack(); | ||||
|     if (o instanceof Iterator) { | ||||
|       boolean isObject = stack.get(stack.size() - 2) instanceof JsonObject; | ||||
|       boolean isObject = stack[stackSize - 2] instanceof JsonObject; | ||||
|       Iterator<?> iterator = (Iterator<?>) o; | ||||
|       if (iterator.hasNext()) { | ||||
|         if (isObject) { | ||||
|           return JsonToken.NAME; | ||||
|         } else { | ||||
|           stack.add(iterator.next()); | ||||
|           push(iterator.next()); | ||||
|           return peek(); | ||||
|         } | ||||
|       } else { | ||||
| @ -128,16 +144,19 @@ public final class JsonTreeReader extends JsonReader { | ||||
|   } | ||||
| 
 | ||||
|   private Object peekStack() { | ||||
|     return stack.get(stack.size() - 1); | ||||
|     return stack[stackSize - 1]; | ||||
|   } | ||||
| 
 | ||||
|   private Object popStack() { | ||||
|     return stack.remove(stack.size() - 1); | ||||
|     Object result = stack[--stackSize]; | ||||
|     stack[stackSize] = null; | ||||
|     return result; | ||||
|   } | ||||
| 
 | ||||
|   private void expect(JsonToken expected) throws IOException { | ||||
|     if (peek() != expected) { | ||||
|       throw new IllegalStateException("Expected " + expected + " but was " + peek()); | ||||
|       throw new IllegalStateException( | ||||
|           "Expected " + expected + " but was " + peek() + locationString()); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
| @ -145,72 +164,101 @@ public final class JsonTreeReader extends JsonReader { | ||||
|     expect(JsonToken.NAME); | ||||
|     Iterator<?> i = (Iterator<?>) peekStack(); | ||||
|     Map.Entry<?, ?> entry = (Map.Entry<?, ?>) i.next(); | ||||
|     stack.add(entry.getValue()); | ||||
|     return (String) entry.getKey(); | ||||
|     String result = (String) entry.getKey(); | ||||
|     pathNames[stackSize - 1] = result; | ||||
|     push(entry.getValue()); | ||||
|     return result; | ||||
|   } | ||||
| 
 | ||||
|   @Override public String nextString() throws IOException { | ||||
|     JsonToken token = peek(); | ||||
|     if (token != JsonToken.STRING && token != JsonToken.NUMBER) { | ||||
|       throw new IllegalStateException("Expected " + JsonToken.STRING + " but was " + token); | ||||
|       throw new IllegalStateException( | ||||
|           "Expected " + JsonToken.STRING + " but was " + token + locationString()); | ||||
|     } | ||||
|     return ((JsonPrimitive) popStack()).getAsString(); | ||||
|     String result = ((JsonPrimitive) popStack()).getAsString(); | ||||
|     if (stackSize > 0) { | ||||
|       pathIndices[stackSize - 1]++; | ||||
|     } | ||||
|     return result; | ||||
|   } | ||||
| 
 | ||||
|   @Override public boolean nextBoolean() throws IOException { | ||||
|     expect(JsonToken.BOOLEAN); | ||||
|     return ((JsonPrimitive) popStack()).getAsBoolean(); | ||||
|     boolean result = ((JsonPrimitive) popStack()).getAsBoolean(); | ||||
|     if (stackSize > 0) { | ||||
|       pathIndices[stackSize - 1]++; | ||||
|     } | ||||
|     return result; | ||||
|   } | ||||
| 
 | ||||
|   @Override public void nextNull() throws IOException { | ||||
|     expect(JsonToken.NULL); | ||||
|     popStack(); | ||||
|     if (stackSize > 0) { | ||||
|       pathIndices[stackSize - 1]++; | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   @Override public double nextDouble() throws IOException { | ||||
|     JsonToken token = peek(); | ||||
|     if (token != JsonToken.NUMBER && token != JsonToken.STRING) { | ||||
|       throw new IllegalStateException("Expected " + JsonToken.NUMBER + " but was " + token); | ||||
|       throw new IllegalStateException( | ||||
|           "Expected " + JsonToken.NUMBER + " but was " + token + locationString()); | ||||
|     } | ||||
|     double result = ((JsonPrimitive) peekStack()).getAsDouble(); | ||||
|     if (!isLenient() && (Double.isNaN(result) || Double.isInfinite(result))) { | ||||
|       throw new NumberFormatException("JSON forbids NaN and infinities: " + result); | ||||
|     } | ||||
|     popStack(); | ||||
|     if (stackSize > 0) { | ||||
|       pathIndices[stackSize - 1]++; | ||||
|     } | ||||
|     return result; | ||||
|   } | ||||
| 
 | ||||
|   @Override public long nextLong() throws IOException { | ||||
|     JsonToken token = peek(); | ||||
|     if (token != JsonToken.NUMBER && token != JsonToken.STRING) { | ||||
|       throw new IllegalStateException("Expected " + JsonToken.NUMBER + " but was " + token); | ||||
|       throw new IllegalStateException( | ||||
|           "Expected " + JsonToken.NUMBER + " but was " + token + locationString()); | ||||
|     } | ||||
|     long result = ((JsonPrimitive) peekStack()).getAsLong(); | ||||
|     popStack(); | ||||
|     if (stackSize > 0) { | ||||
|       pathIndices[stackSize - 1]++; | ||||
|     } | ||||
|     return result; | ||||
|   } | ||||
| 
 | ||||
|   @Override public int nextInt() throws IOException { | ||||
|     JsonToken token = peek(); | ||||
|     if (token != JsonToken.NUMBER && token != JsonToken.STRING) { | ||||
|       throw new IllegalStateException("Expected " + JsonToken.NUMBER + " but was " + token); | ||||
|       throw new IllegalStateException( | ||||
|           "Expected " + JsonToken.NUMBER + " but was " + token + locationString()); | ||||
|     } | ||||
|     int result = ((JsonPrimitive) peekStack()).getAsInt(); | ||||
|     popStack(); | ||||
|     if (stackSize > 0) { | ||||
|       pathIndices[stackSize - 1]++; | ||||
|     } | ||||
|     return result; | ||||
|   } | ||||
| 
 | ||||
|   @Override public void close() throws IOException { | ||||
|     stack.clear(); | ||||
|     stack.add(SENTINEL_CLOSED); | ||||
|     stack = new Object[] { SENTINEL_CLOSED }; | ||||
|     stackSize = 1; | ||||
|   } | ||||
| 
 | ||||
|   @Override public void skipValue() throws IOException { | ||||
|     if (peek() == JsonToken.NAME) { | ||||
|       nextName(); | ||||
|       pathNames[stackSize - 2] = "null"; | ||||
|     } else { | ||||
|       popStack(); | ||||
|       pathNames[stackSize - 1] = "null"; | ||||
|     } | ||||
|     pathIndices[stackSize - 1]++; | ||||
|   } | ||||
| 
 | ||||
|   @Override public String toString() { | ||||
| @ -221,7 +269,45 @@ public final class JsonTreeReader extends JsonReader { | ||||
|     expect(JsonToken.NAME); | ||||
|     Iterator<?> i = (Iterator<?>) peekStack(); | ||||
|     Map.Entry<?, ?> entry = (Map.Entry<?, ?>) i.next(); | ||||
|     stack.add(entry.getValue()); | ||||
|     stack.add(new JsonPrimitive((String)entry.getKey())); | ||||
|     push(entry.getValue()); | ||||
|     push(new JsonPrimitive((String) entry.getKey())); | ||||
|   } | ||||
| 
 | ||||
|   private void push(Object newTop) { | ||||
|     if (stackSize == stack.length) { | ||||
|       Object[] newStack = new Object[stackSize * 2]; | ||||
|       int[] newPathIndices = new int[stackSize * 2]; | ||||
|       String[] newPathNames = new String[stackSize * 2]; | ||||
|       System.arraycopy(stack, 0, newStack, 0, stackSize); | ||||
|       System.arraycopy(pathIndices, 0, newPathIndices, 0, stackSize); | ||||
|       System.arraycopy(pathNames, 0, newPathNames, 0, stackSize); | ||||
|       stack = newStack; | ||||
|       pathIndices = newPathIndices; | ||||
|       pathNames = newPathNames; | ||||
|     } | ||||
|     stack[stackSize++] = newTop; | ||||
|   } | ||||
| 
 | ||||
|   @Override public String getPath() { | ||||
|     StringBuilder result = new StringBuilder().append('$'); | ||||
|     for (int i = 0; i < stackSize; i++) { | ||||
|       if (stack[i] instanceof JsonArray) { | ||||
|         if (stack[++i] instanceof Iterator) { | ||||
|           result.append('[').append(pathIndices[i]).append(']'); | ||||
|         } | ||||
|       } else if (stack[i] instanceof JsonObject) { | ||||
|         if (stack[++i] instanceof Iterator) { | ||||
|           result.append('.'); | ||||
|           if (pathNames[i] != null) { | ||||
|             result.append(pathNames[i]); | ||||
|           } | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|     return result.toString(); | ||||
|   } | ||||
| 
 | ||||
|   private String locationString() { | ||||
|     return " at path " + getPath(); | ||||
|   } | ||||
| } | ||||
|  | ||||
| @ -16,11 +16,7 @@ | ||||
| 
 | ||||
| package com.massivecraft.massivecore.xlib.gson.internal.bind; | ||||
| 
 | ||||
| import com.massivecraft.massivecore.xlib.gson.JsonArray; | ||||
| import com.massivecraft.massivecore.xlib.gson.JsonElement; | ||||
| import com.massivecraft.massivecore.xlib.gson.JsonNull; | ||||
| import com.massivecraft.massivecore.xlib.gson.JsonObject; | ||||
| import com.massivecraft.massivecore.xlib.gson.JsonPrimitive; | ||||
| import com.massivecraft.massivecore.xlib.gson.*; | ||||
| import com.massivecraft.massivecore.xlib.gson.stream.JsonWriter; | ||||
| 
 | ||||
| import java.io.IOException; | ||||
| @ -160,6 +156,14 @@ public final class JsonTreeWriter extends JsonWriter { | ||||
|     return this; | ||||
|   } | ||||
| 
 | ||||
|   @Override public JsonWriter value(Boolean value) throws IOException { | ||||
|     if (value == null) { | ||||
|       return nullValue(); | ||||
|     } | ||||
|     put(new JsonPrimitive(value)); | ||||
|     return this; | ||||
|   } | ||||
| 
 | ||||
|   @Override public JsonWriter value(double value) throws IOException { | ||||
|     if (!isLenient() && (Double.isNaN(value) || Double.isInfinite(value))) { | ||||
|       throw new IllegalArgumentException("JSON forbids NaN and infinities: " + value); | ||||
|  | ||||
| @ -16,17 +16,8 @@ | ||||
| 
 | ||||
| package com.massivecraft.massivecore.xlib.gson.internal.bind; | ||||
| 
 | ||||
| import com.massivecraft.massivecore.xlib.gson.Gson; | ||||
| import com.massivecraft.massivecore.xlib.gson.JsonElement; | ||||
| import com.massivecraft.massivecore.xlib.gson.JsonPrimitive; | ||||
| import com.massivecraft.massivecore.xlib.gson.JsonSyntaxException; | ||||
| import com.massivecraft.massivecore.xlib.gson.TypeAdapter; | ||||
| import com.massivecraft.massivecore.xlib.gson.TypeAdapterFactory; | ||||
| import com.massivecraft.massivecore.xlib.gson.internal.$Gson$Types; | ||||
| import com.massivecraft.massivecore.xlib.gson.internal.ConstructorConstructor; | ||||
| import com.massivecraft.massivecore.xlib.gson.internal.JsonReaderInternalAccess; | ||||
| import com.massivecraft.massivecore.xlib.gson.internal.ObjectConstructor; | ||||
| import com.massivecraft.massivecore.xlib.gson.internal.Streams; | ||||
| import com.massivecraft.massivecore.xlib.gson.*; | ||||
| import com.massivecraft.massivecore.xlib.gson.internal.*; | ||||
| import com.massivecraft.massivecore.xlib.gson.reflect.TypeToken; | ||||
| import com.massivecraft.massivecore.xlib.gson.stream.JsonReader; | ||||
| import com.massivecraft.massivecore.xlib.gson.stream.JsonToken; | ||||
| @ -61,7 +52,7 @@ 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.google.gson.JsonParseException: Expecting object found: "(5,6)" | ||||
|  * <pre>JsonParseException: Expecting object found: "(5,6)" | ||||
|  *   at com.google.gson.JsonObjectDeserializationVisitor.visitFieldUsingCustomHandler | ||||
|  *   at com.google.gson.ObjectNavigator.navigateClassFields | ||||
|  *   ...</pre> | ||||
| @ -105,15 +96,15 @@ import java.util.Map; | ||||
|  */ | ||||
| public final class MapTypeAdapterFactory implements TypeAdapterFactory { | ||||
|   private final ConstructorConstructor constructorConstructor; | ||||
|   private final boolean complexMapKeySerialization; | ||||
|   final boolean complexMapKeySerialization; | ||||
| 
 | ||||
|   public MapTypeAdapterFactory(ConstructorConstructor constructorConstructor, | ||||
|       boolean complexMapKeySerialization) { | ||||
|                                boolean complexMapKeySerialization) { | ||||
|     this.constructorConstructor = constructorConstructor; | ||||
|     this.complexMapKeySerialization = complexMapKeySerialization; | ||||
|   } | ||||
| 
 | ||||
|   public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> typeToken) { | ||||
|   @Override public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> typeToken) { | ||||
|     Type type = typeToken.getType(); | ||||
| 
 | ||||
|     Class<? super T> rawType = typeToken.getRawType(); | ||||
| @ -149,16 +140,16 @@ public final class MapTypeAdapterFactory implements TypeAdapterFactory { | ||||
|     private final ObjectConstructor<? extends Map<K, V>> constructor; | ||||
| 
 | ||||
|     public Adapter(Gson context, Type keyType, TypeAdapter<K> keyTypeAdapter, | ||||
|         Type valueType, TypeAdapter<V> valueTypeAdapter, | ||||
|         ObjectConstructor<? extends Map<K, V>> constructor) { | ||||
|                    Type valueType, TypeAdapter<V> valueTypeAdapter, | ||||
|                    ObjectConstructor<? extends Map<K, V>> constructor) { | ||||
|       this.keyTypeAdapter = | ||||
| 		  new TypeAdapterRuntimeTypeWrapper<>(context, keyTypeAdapter, keyType); | ||||
|               new TypeAdapterRuntimeTypeWrapper<>(context, keyTypeAdapter, keyType); | ||||
|       this.valueTypeAdapter = | ||||
| 		  new TypeAdapterRuntimeTypeWrapper<>(context, valueTypeAdapter, valueType); | ||||
|               new TypeAdapterRuntimeTypeWrapper<>(context, valueTypeAdapter, valueType); | ||||
|       this.constructor = constructor; | ||||
|     } | ||||
| 
 | ||||
|     public Map<K, V> read(JsonReader in) throws IOException { | ||||
|     @Override public Map<K, V> read(JsonReader in) throws IOException { | ||||
|       JsonToken peek = in.peek(); | ||||
|       if (peek == JsonToken.NULL) { | ||||
|         in.nextNull(); | ||||
| @ -196,7 +187,7 @@ public final class MapTypeAdapterFactory implements TypeAdapterFactory { | ||||
|       return map; | ||||
|     } | ||||
| 
 | ||||
|     public void write(JsonWriter out, Map<K, V> map) throws IOException { | ||||
|     @Override public void write(JsonWriter out, Map<K, V> map) throws IOException { | ||||
|       if (map == null) { | ||||
|         out.nullValue(); | ||||
|         return; | ||||
|  | ||||
| @ -37,7 +37,7 @@ import java.util.Map; | ||||
| public final class ObjectTypeAdapter extends TypeAdapter<Object> { | ||||
|   public static final TypeAdapterFactory FACTORY = new TypeAdapterFactory() { | ||||
|     @SuppressWarnings("unchecked") | ||||
|     public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) { | ||||
|     @Override public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) { | ||||
|       if (type.getRawType() == Object.class) { | ||||
|         return (TypeAdapter<T>) new ObjectTypeAdapter(gson); | ||||
|       } | ||||
| @ -47,7 +47,7 @@ public final class ObjectTypeAdapter extends TypeAdapter<Object> { | ||||
| 
 | ||||
|   private final Gson gson; | ||||
| 
 | ||||
|   private ObjectTypeAdapter(Gson gson) { | ||||
|   ObjectTypeAdapter(Gson gson) { | ||||
|     this.gson = gson; | ||||
|   } | ||||
| 
 | ||||
|  | ||||
| @ -16,18 +16,10 @@ | ||||
| 
 | ||||
| package com.massivecraft.massivecore.xlib.gson.internal.bind; | ||||
| 
 | ||||
| import com.massivecraft.massivecore.xlib.gson.FieldNamingStrategy; | ||||
| import com.massivecraft.massivecore.xlib.gson.Gson; | ||||
| import com.massivecraft.massivecore.xlib.gson.JsonSyntaxException; | ||||
| import com.massivecraft.massivecore.xlib.gson.TypeAdapter; | ||||
| import com.massivecraft.massivecore.xlib.gson.TypeAdapterFactory; | ||||
| import com.massivecraft.massivecore.xlib.gson.*; | ||||
| import com.massivecraft.massivecore.xlib.gson.annotations.JsonAdapter; | ||||
| import com.massivecraft.massivecore.xlib.gson.annotations.SerializedName; | ||||
| import com.massivecraft.massivecore.xlib.gson.internal.$Gson$Types; | ||||
| import com.massivecraft.massivecore.xlib.gson.internal.ConstructorConstructor; | ||||
| import com.massivecraft.massivecore.xlib.gson.internal.Excluder; | ||||
| import com.massivecraft.massivecore.xlib.gson.internal.ObjectConstructor; | ||||
| import com.massivecraft.massivecore.xlib.gson.internal.Primitives; | ||||
| import com.massivecraft.massivecore.xlib.gson.internal.*; | ||||
| import com.massivecraft.massivecore.xlib.gson.reflect.TypeToken; | ||||
| import com.massivecraft.massivecore.xlib.gson.stream.JsonReader; | ||||
| import com.massivecraft.massivecore.xlib.gson.stream.JsonToken; | ||||
| @ -36,10 +28,7 @@ import com.massivecraft.massivecore.xlib.gson.stream.JsonWriter; | ||||
| import java.io.IOException; | ||||
| import java.lang.reflect.Field; | ||||
| import java.lang.reflect.Type; | ||||
| import java.util.LinkedHashMap; | ||||
| import java.util.Map; | ||||
| 
 | ||||
| import static com.massivecraft.massivecore.xlib.gson.internal.bind.JsonAdapterAnnotationTypeAdapterFactory.getTypeAdapter; | ||||
| import java.util.*; | ||||
| 
 | ||||
| /** | ||||
|  * Type adapter that reflects over the fields and methods of a class. | ||||
| @ -48,12 +37,15 @@ public final class ReflectiveTypeAdapterFactory implements TypeAdapterFactory { | ||||
|   private final ConstructorConstructor constructorConstructor; | ||||
|   private final FieldNamingStrategy fieldNamingPolicy; | ||||
|   private final Excluder excluder; | ||||
|   private final JsonAdapterAnnotationTypeAdapterFactory jsonAdapterFactory; | ||||
| 
 | ||||
|   public ReflectiveTypeAdapterFactory(ConstructorConstructor constructorConstructor, | ||||
|       FieldNamingStrategy fieldNamingPolicy, Excluder excluder) { | ||||
|                                       FieldNamingStrategy fieldNamingPolicy, Excluder excluder, | ||||
|                                       JsonAdapterAnnotationTypeAdapterFactory jsonAdapterFactory) { | ||||
|     this.constructorConstructor = constructorConstructor; | ||||
|     this.fieldNamingPolicy = fieldNamingPolicy; | ||||
|     this.excluder = excluder; | ||||
|     this.jsonAdapterFactory = jsonAdapterFactory; | ||||
|   } | ||||
| 
 | ||||
|   public boolean excludeField(Field f, boolean serialize) { | ||||
| @ -64,16 +56,29 @@ public final class ReflectiveTypeAdapterFactory implements TypeAdapterFactory { | ||||
|     return !excluder.excludeClass(f.getType(), serialize) && !excluder.excludeField(f, serialize); | ||||
|   } | ||||
| 
 | ||||
|   private String getFieldName(Field f) { | ||||
|     return getFieldName(fieldNamingPolicy, f); | ||||
|   /** first element holds the default name */ | ||||
|   private List<String> getFieldNames(Field f) { | ||||
|     SerializedName annotation = f.getAnnotation(SerializedName.class); | ||||
|     if (annotation == null) { | ||||
|       String name = fieldNamingPolicy.translateName(f); | ||||
|       return Collections.singletonList(name); | ||||
|     } | ||||
| 
 | ||||
|     String serializedName = annotation.value(); | ||||
|     String[] alternates = annotation.alternate(); | ||||
|     if (alternates.length == 0) { | ||||
|       return Collections.singletonList(serializedName); | ||||
|     } | ||||
| 
 | ||||
|     List<String> fieldNames = new ArrayList<>(alternates.length + 1); | ||||
|     fieldNames.add(serializedName); | ||||
|     for (String alternate : alternates) { | ||||
|       fieldNames.add(alternate); | ||||
|     } | ||||
|     return fieldNames; | ||||
|   } | ||||
| 
 | ||||
|   static String getFieldName(FieldNamingStrategy fieldNamingPolicy, Field f) { | ||||
|     SerializedName serializedName = f.getAnnotation(SerializedName.class); | ||||
|     return serializedName == null ? fieldNamingPolicy.translateName(f) : serializedName.value(); | ||||
|   } | ||||
| 
 | ||||
|   public <T> TypeAdapter<T> create(Gson gson, final TypeToken<T> type) { | ||||
|   @Override public <T> TypeAdapter<T> create(Gson gson, final TypeToken<T> type) { | ||||
|     Class<? super T> raw = type.getRawType(); | ||||
| 
 | ||||
|     if (!Object.class.isAssignableFrom(raw)) { | ||||
| @ -85,18 +90,27 @@ public final class ReflectiveTypeAdapterFactory implements TypeAdapterFactory { | ||||
|   } | ||||
| 
 | ||||
|   private ReflectiveTypeAdapterFactory.BoundField createBoundField( | ||||
|       final Gson context, final Field field, final String name, | ||||
|       final TypeToken<?> fieldType, boolean serialize, boolean deserialize) { | ||||
|           final Gson context, final Field field, final String name, | ||||
|           final TypeToken<?> fieldType, boolean serialize, boolean deserialize) { | ||||
|     final boolean isPrimitive = Primitives.isPrimitive(fieldType.getRawType()); | ||||
|     // special casing primitives here saves ~5% on Android... | ||||
|     JsonAdapter annotation = field.getAnnotation(JsonAdapter.class); | ||||
|     TypeAdapter<?> mapped = null; | ||||
|     if (annotation != null) { | ||||
|       mapped = jsonAdapterFactory.getTypeAdapter( | ||||
|           constructorConstructor, context, fieldType, annotation); | ||||
|     } | ||||
|     final boolean jsonAdapterPresent = mapped != null; | ||||
|     if (mapped == null) mapped = context.getAdapter(fieldType); | ||||
| 
 | ||||
|     final TypeAdapter<?> typeAdapter = mapped; | ||||
|     return new ReflectiveTypeAdapterFactory.BoundField(name, serialize, deserialize) { | ||||
|       final TypeAdapter<?> typeAdapter = getFieldAdapter(context, field, fieldType); | ||||
|       @SuppressWarnings({"unchecked", "rawtypes"}) // the type adapter and field type always agree | ||||
|       @Override void write(JsonWriter writer, Object value) | ||||
|           throws IOException, IllegalAccessException { | ||||
|         Object fieldValue = field.get(value); | ||||
|         TypeAdapter t = | ||||
|           new TypeAdapterRuntimeTypeWrapper(context, this.typeAdapter, fieldType.getType()); | ||||
|         TypeAdapter t = jsonAdapterPresent ? typeAdapter | ||||
|             : new TypeAdapterRuntimeTypeWrapper(context, typeAdapter, fieldType.getType()); | ||||
|         t.write(writer, fieldValue); | ||||
|       } | ||||
|       @Override void read(JsonReader reader, Object value) | ||||
| @ -106,7 +120,7 @@ public final class ReflectiveTypeAdapterFactory implements TypeAdapterFactory { | ||||
|           field.set(value, fieldValue); | ||||
|         } | ||||
|       } | ||||
|       public boolean writeField(Object value) throws IOException, IllegalAccessException { | ||||
|       @Override public boolean writeField(Object value) throws IOException, IllegalAccessException { | ||||
|         if (!serialized) return false; | ||||
|         Object fieldValue = field.get(value); | ||||
|         return fieldValue != value; // avoid recursion for example for Throwable.cause | ||||
| @ -114,15 +128,6 @@ public final class ReflectiveTypeAdapterFactory implements TypeAdapterFactory { | ||||
|     }; | ||||
|   } | ||||
| 
 | ||||
|   private TypeAdapter<?> getFieldAdapter(Gson gson, Field field, TypeToken<?> fieldType) { | ||||
|     JsonAdapter annotation = field.getAnnotation(JsonAdapter.class); | ||||
|     if (annotation != null) { | ||||
|       TypeAdapter<?> adapter = getTypeAdapter(constructorConstructor, gson, fieldType, annotation); | ||||
|       if (adapter != null) return adapter; | ||||
|     } | ||||
|     return gson.getAdapter(fieldType); | ||||
|   } | ||||
| 
 | ||||
|   private Map<String, BoundField> getBoundFields(Gson context, TypeToken<?> type, Class<?> raw) { | ||||
|     Map<String, BoundField> result = new LinkedHashMap<>(); | ||||
|     if (raw.isInterface()) { | ||||
| @ -140,9 +145,16 @@ public final class ReflectiveTypeAdapterFactory implements TypeAdapterFactory { | ||||
|         } | ||||
|         field.setAccessible(true); | ||||
|         Type fieldType = $Gson$Types.resolve(type.getType(), raw, field.getGenericType()); | ||||
|         BoundField boundField = createBoundField(context, field, getFieldName(field), | ||||
|             TypeToken.get(fieldType), serialize, deserialize); | ||||
|         BoundField previous = result.put(boundField.name, boundField); | ||||
|         List<String> fieldNames = getFieldNames(field); | ||||
|         BoundField previous = null; | ||||
|         for (int i = 0; i < fieldNames.size(); ++i) { | ||||
|           String name = fieldNames.get(i); | ||||
|           if (i != 0) serialize = false; // only serialize the default name | ||||
|           BoundField boundField = createBoundField(context, field, name, | ||||
|               TypeToken.get(fieldType), serialize, deserialize); | ||||
|           BoundField replaced = result.put(name, boundField); | ||||
|           if (previous == null) previous = replaced; | ||||
|         } | ||||
|         if (previous != null) { | ||||
|           throw new IllegalArgumentException(declaredType | ||||
|               + " declares multiple JSON fields named " + previous.name); | ||||
| @ -173,7 +185,7 @@ public final class ReflectiveTypeAdapterFactory implements TypeAdapterFactory { | ||||
|     private final ObjectConstructor<T> constructor; | ||||
|     private final Map<String, BoundField> boundFields; | ||||
| 
 | ||||
|     private Adapter(ObjectConstructor<T> constructor, Map<String, BoundField> boundFields) { | ||||
|     Adapter(ObjectConstructor<T> constructor, Map<String, BoundField> boundFields) { | ||||
|       this.constructor = constructor; | ||||
|       this.boundFields = boundFields; | ||||
|     } | ||||
| @ -221,7 +233,7 @@ public final class ReflectiveTypeAdapterFactory implements TypeAdapterFactory { | ||||
|           } | ||||
|         } | ||||
|       } catch (IllegalAccessException e) { | ||||
|         throw new AssertionError(); | ||||
|         throw new AssertionError(e); | ||||
|       } | ||||
|       out.endObject(); | ||||
|     } | ||||
|  | ||||
| @ -39,7 +39,7 @@ import java.text.SimpleDateFormat; | ||||
| public final class SqlDateTypeAdapter extends TypeAdapter<java.sql.Date> { | ||||
|   public static final TypeAdapterFactory FACTORY = new TypeAdapterFactory() { | ||||
|     @SuppressWarnings("unchecked") // we use a runtime check to make sure the 'T's equal | ||||
|     public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> typeToken) { | ||||
|     @Override public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> typeToken) { | ||||
|       return typeToken.getRawType() == java.sql.Date.class | ||||
|           ? (TypeAdapter<T>) new SqlDateTypeAdapter() : null; | ||||
|     } | ||||
|  | ||||
| @ -41,7 +41,7 @@ import java.util.Date; | ||||
| public final class TimeTypeAdapter extends TypeAdapter<Time> { | ||||
|   public static final TypeAdapterFactory FACTORY = new TypeAdapterFactory() { | ||||
|     @SuppressWarnings("unchecked") // we use a runtime check to make sure the 'T's equal | ||||
|     public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> typeToken) { | ||||
|     @Override public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> typeToken) { | ||||
|       return typeToken.getRawType() == Time.class ? (TypeAdapter<T>) new TimeTypeAdapter() : null; | ||||
|     } | ||||
|   }; | ||||
|  | ||||
| @ -14,8 +14,9 @@ | ||||
|  * limitations under the License. | ||||
|  */ | ||||
| 
 | ||||
| package com.massivecraft.massivecore.xlib.gson; | ||||
| package com.massivecraft.massivecore.xlib.gson.internal.bind; | ||||
| 
 | ||||
| import com.massivecraft.massivecore.xlib.gson.*; | ||||
| import com.massivecraft.massivecore.xlib.gson.internal.$Gson$Preconditions; | ||||
| import com.massivecraft.massivecore.xlib.gson.internal.Streams; | ||||
| import com.massivecraft.massivecore.xlib.gson.reflect.TypeToken; | ||||
| @ -23,24 +24,26 @@ import com.massivecraft.massivecore.xlib.gson.stream.JsonReader; | ||||
| import com.massivecraft.massivecore.xlib.gson.stream.JsonWriter; | ||||
| 
 | ||||
| import java.io.IOException; | ||||
| import java.lang.reflect.Type; | ||||
| 
 | ||||
| /** | ||||
|  * Adapts a Gson 1.x tree-style adapter as a streaming TypeAdapter. Since the | ||||
|  * tree adapter may be serialization-only or deserialization-only, this class | ||||
|  * has a facility to lookup a delegate type adapter on demand. | ||||
|  */ | ||||
| final class TreeTypeAdapter<T> extends TypeAdapter<T> { | ||||
| public final class TreeTypeAdapter<T> extends TypeAdapter<T> { | ||||
|   private final JsonSerializer<T> serializer; | ||||
|   private final JsonDeserializer<T> deserializer; | ||||
|   private final Gson gson; | ||||
|   private final TypeToken<T> typeToken; | ||||
|   private final TypeAdapterFactory skipPast; | ||||
|   private final GsonContextImpl context = new GsonContextImpl(); | ||||
| 
 | ||||
|   /** The delegate is lazily created because it may not be needed, and creating it may fail. */ | ||||
|   private TypeAdapter<T> delegate; | ||||
| 
 | ||||
|   private TreeTypeAdapter(JsonSerializer<T> serializer, JsonDeserializer<T> deserializer, | ||||
|       Gson gson, TypeToken<T> typeToken, TypeAdapterFactory skipPast) { | ||||
|   public TreeTypeAdapter(JsonSerializer<T> serializer, JsonDeserializer<T> deserializer, | ||||
|                          Gson gson, TypeToken<T> typeToken, TypeAdapterFactory skipPast) { | ||||
|     this.serializer = serializer; | ||||
|     this.deserializer = deserializer; | ||||
|     this.gson = gson; | ||||
| @ -56,7 +59,7 @@ final class TreeTypeAdapter<T> extends TypeAdapter<T> { | ||||
|     if (value.isJsonNull()) { | ||||
|       return null; | ||||
|     } | ||||
|     return deserializer.deserialize(value, typeToken.getType(), gson.deserializationContext); | ||||
|     return deserializer.deserialize(value, typeToken.getType(), context); | ||||
|   } | ||||
| 
 | ||||
|   @Override public void write(JsonWriter out, T value) throws IOException { | ||||
| @ -68,7 +71,7 @@ final class TreeTypeAdapter<T> extends TypeAdapter<T> { | ||||
|       out.nullValue(); | ||||
|       return; | ||||
|     } | ||||
|     JsonElement tree = serializer.serialize(value, typeToken.getType(), gson.serializationContext); | ||||
|     JsonElement tree = serializer.serialize(value, typeToken.getType(), context); | ||||
|     Streams.write(tree, out); | ||||
|   } | ||||
| 
 | ||||
| @ -106,14 +109,14 @@ final class TreeTypeAdapter<T> extends TypeAdapter<T> { | ||||
|     return new SingleTypeFactory(typeAdapter, null, false, hierarchyType); | ||||
|   } | ||||
| 
 | ||||
|   private static class SingleTypeFactory implements TypeAdapterFactory { | ||||
|   private static final class SingleTypeFactory implements TypeAdapterFactory { | ||||
|     private final TypeToken<?> exactType; | ||||
|     private final boolean matchRawType; | ||||
|     private final Class<?> hierarchyType; | ||||
|     private final JsonSerializer<?> serializer; | ||||
|     private final JsonDeserializer<?> deserializer; | ||||
| 
 | ||||
|     private SingleTypeFactory(Object typeAdapter, TypeToken<?> exactType, boolean matchRawType, | ||||
|     SingleTypeFactory(Object typeAdapter, TypeToken<?> exactType, boolean matchRawType, | ||||
|         Class<?> hierarchyType) { | ||||
|       serializer = typeAdapter instanceof JsonSerializer | ||||
|           ? (JsonSerializer<?>) typeAdapter | ||||
| @ -128,15 +131,28 @@ final class TreeTypeAdapter<T> extends TypeAdapter<T> { | ||||
|     } | ||||
| 
 | ||||
|     @SuppressWarnings("unchecked") // guarded by typeToken.equals() call | ||||
|     @Override | ||||
|     public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) { | ||||
|       boolean matches = exactType != null | ||||
|           ? exactType.equals(type) || matchRawType && exactType.getType() == type.getRawType() | ||||
|           : hierarchyType.isAssignableFrom(type.getRawType()); | ||||
|       return matches | ||||
|           ? new TreeTypeAdapter<>((JsonSerializer<T>) serializer, | ||||
| 									 (JsonDeserializer<T>) deserializer, gson, type, this | ||||
| 	  ) | ||||
|               (JsonDeserializer<T>) deserializer, gson, type, this) | ||||
|           : null; | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   private final class GsonContextImpl implements JsonSerializationContext, JsonDeserializationContext { | ||||
|     @Override public JsonElement serialize(Object src) { | ||||
|       return gson.toJsonTree(src); | ||||
|     } | ||||
|     @Override public JsonElement serialize(Object src, Type typeOfSrc) { | ||||
|       return gson.toJsonTree(src, typeOfSrc); | ||||
|     } | ||||
|     @SuppressWarnings("unchecked") | ||||
|     @Override public <R> R deserialize(JsonElement json, Type typeOfT) throws JsonParseException { | ||||
|       return (R) gson.fromJson(json, typeOfT); | ||||
|     } | ||||
|   }; | ||||
| } | ||||
| @ -16,16 +16,7 @@ | ||||
| 
 | ||||
| package com.massivecraft.massivecore.xlib.gson.internal.bind; | ||||
| 
 | ||||
| import com.massivecraft.massivecore.xlib.gson.Gson; | ||||
| import com.massivecraft.massivecore.xlib.gson.JsonArray; | ||||
| import com.massivecraft.massivecore.xlib.gson.JsonElement; | ||||
| import com.massivecraft.massivecore.xlib.gson.JsonIOException; | ||||
| import com.massivecraft.massivecore.xlib.gson.JsonNull; | ||||
| import com.massivecraft.massivecore.xlib.gson.JsonObject; | ||||
| import com.massivecraft.massivecore.xlib.gson.JsonPrimitive; | ||||
| import com.massivecraft.massivecore.xlib.gson.JsonSyntaxException; | ||||
| import com.massivecraft.massivecore.xlib.gson.TypeAdapter; | ||||
| import com.massivecraft.massivecore.xlib.gson.TypeAdapterFactory; | ||||
| import com.massivecraft.massivecore.xlib.gson.*; | ||||
| import com.massivecraft.massivecore.xlib.gson.annotations.SerializedName; | ||||
| import com.massivecraft.massivecore.xlib.gson.internal.LazilyParsedNumber; | ||||
| import com.massivecraft.massivecore.xlib.gson.reflect.TypeToken; | ||||
| @ -41,21 +32,18 @@ import java.net.URI; | ||||
| import java.net.URISyntaxException; | ||||
| import java.net.URL; | ||||
| import java.sql.Timestamp; | ||||
| import java.util.BitSet; | ||||
| import java.util.Calendar; | ||||
| import java.util.Date; | ||||
| import java.util.GregorianCalendar; | ||||
| import java.util.HashMap; | ||||
| import java.util.Locale; | ||||
| import java.util.Map; | ||||
| import java.util.StringTokenizer; | ||||
| import java.util.UUID; | ||||
| import java.util.*; | ||||
| import java.util.concurrent.atomic.AtomicBoolean; | ||||
| import java.util.concurrent.atomic.AtomicInteger; | ||||
| import java.util.concurrent.atomic.AtomicIntegerArray; | ||||
| 
 | ||||
| /** | ||||
|  * Type adapters for basic types. | ||||
|  */ | ||||
| public final class TypeAdapters { | ||||
|   private TypeAdapters() {} | ||||
|   private TypeAdapters() { | ||||
|     throw new UnsupportedOperationException(); | ||||
|   } | ||||
| 
 | ||||
|   @SuppressWarnings("rawtypes") | ||||
|   public static final TypeAdapter<Class> CLASS = new TypeAdapter<Class>() { | ||||
| @ -82,7 +70,7 @@ public final class TypeAdapters { | ||||
|   public static final TypeAdapterFactory CLASS_FACTORY = newFactory(Class.class, CLASS); | ||||
| 
 | ||||
|   public static final TypeAdapter<BitSet> BIT_SET = new TypeAdapter<BitSet>() { | ||||
|     public BitSet read(JsonReader in) throws IOException { | ||||
|     @Override public BitSet read(JsonReader in) throws IOException { | ||||
|       if (in.peek() == JsonToken.NULL) { | ||||
|         in.nextNull(); | ||||
|         return null; | ||||
| @ -123,7 +111,7 @@ public final class TypeAdapters { | ||||
|       return bitset; | ||||
|     } | ||||
| 
 | ||||
|     public void write(JsonWriter out, BitSet src) throws IOException { | ||||
|     @Override public void write(JsonWriter out, BitSet src) throws IOException { | ||||
|       if (src == null) { | ||||
|         out.nullValue(); | ||||
|         return; | ||||
| @ -154,10 +142,6 @@ public final class TypeAdapters { | ||||
|     } | ||||
|     @Override | ||||
|     public void write(JsonWriter out, Boolean value) throws IOException { | ||||
|       if (value == null) { | ||||
|         out.nullValue(); | ||||
|         return; | ||||
|       } | ||||
|       out.value(value); | ||||
|     } | ||||
|   }; | ||||
| @ -246,10 +230,66 @@ public final class TypeAdapters { | ||||
|       out.value(value); | ||||
|     } | ||||
|   }; | ||||
| 
 | ||||
|   public static final TypeAdapterFactory INTEGER_FACTORY | ||||
|       = newFactory(int.class, Integer.class, INTEGER); | ||||
| 
 | ||||
|   public static final TypeAdapter<AtomicInteger> ATOMIC_INTEGER = new TypeAdapter<AtomicInteger>() { | ||||
|     @Override public AtomicInteger read(JsonReader in) throws IOException { | ||||
|       try { | ||||
|         return new AtomicInteger(in.nextInt()); | ||||
|       } catch (NumberFormatException e) { | ||||
|         throw new JsonSyntaxException(e); | ||||
|       } | ||||
|     } | ||||
|     @Override public void write(JsonWriter out, AtomicInteger value) throws IOException { | ||||
|       out.value(value.get()); | ||||
|     } | ||||
|   }.nullSafe(); | ||||
|   public static final TypeAdapterFactory ATOMIC_INTEGER_FACTORY = | ||||
|       newFactory(AtomicInteger.class, TypeAdapters.ATOMIC_INTEGER); | ||||
| 
 | ||||
|   public static final TypeAdapter<AtomicBoolean> ATOMIC_BOOLEAN = new TypeAdapter<AtomicBoolean>() { | ||||
|     @Override public AtomicBoolean read(JsonReader in) throws IOException { | ||||
|       return new AtomicBoolean(in.nextBoolean()); | ||||
|     } | ||||
|     @Override public void write(JsonWriter out, AtomicBoolean value) throws IOException { | ||||
|       out.value(value.get()); | ||||
|     } | ||||
|   }.nullSafe(); | ||||
|   public static final TypeAdapterFactory ATOMIC_BOOLEAN_FACTORY = | ||||
|       newFactory(AtomicBoolean.class, TypeAdapters.ATOMIC_BOOLEAN); | ||||
| 
 | ||||
|   public static final TypeAdapter<AtomicIntegerArray> ATOMIC_INTEGER_ARRAY = new TypeAdapter<AtomicIntegerArray>() { | ||||
|     @Override public AtomicIntegerArray read(JsonReader in) throws IOException { | ||||
|         List<Integer> list = new ArrayList<>(); | ||||
|         in.beginArray(); | ||||
|         while (in.hasNext()) { | ||||
|           try { | ||||
|             int integer = in.nextInt(); | ||||
|             list.add(integer); | ||||
|           } catch (NumberFormatException e) { | ||||
|             throw new JsonSyntaxException(e); | ||||
|           } | ||||
|         } | ||||
|         in.endArray(); | ||||
|         int length = list.size(); | ||||
|         AtomicIntegerArray array = new AtomicIntegerArray(length); | ||||
|         for (int i = 0; i < length; ++i) { | ||||
|           array.set(i, list.get(i)); | ||||
|         } | ||||
|         return array; | ||||
|     } | ||||
|     @Override public void write(JsonWriter out, AtomicIntegerArray value) throws IOException { | ||||
|       out.beginArray(); | ||||
|       for (int i = 0, length = value.length(); i < length; i++) { | ||||
|         out.value(value.get(i)); | ||||
|       } | ||||
|       out.endArray(); | ||||
|     } | ||||
|   }.nullSafe(); | ||||
|   public static final TypeAdapterFactory ATOMIC_INTEGER_ARRAY_FACTORY = | ||||
|       newFactory(AtomicIntegerArray.class, TypeAdapters.ATOMIC_INTEGER_ARRAY); | ||||
| 
 | ||||
|   public static final TypeAdapter<Number> LONG = new TypeAdapter<Number>() { | ||||
|     @Override | ||||
|     public Number read(JsonReader in) throws IOException { | ||||
| @ -513,9 +553,21 @@ public final class TypeAdapters { | ||||
| 
 | ||||
|   public static final TypeAdapterFactory UUID_FACTORY = newFactory(UUID.class, UUID); | ||||
| 
 | ||||
|   public static final TypeAdapter<Currency> CURRENCY = new TypeAdapter<Currency>() { | ||||
|     @Override | ||||
|     public Currency read(JsonReader in) throws IOException { | ||||
|       return Currency.getInstance(in.nextString()); | ||||
|     } | ||||
|     @Override | ||||
|     public void write(JsonWriter out, Currency value) throws IOException { | ||||
|       out.value(value.getCurrencyCode()); | ||||
|     } | ||||
|   }.nullSafe(); | ||||
|   public static final TypeAdapterFactory CURRENCY_FACTORY = newFactory(Currency.class, CURRENCY); | ||||
| 
 | ||||
|   public static final TypeAdapterFactory TIMESTAMP_FACTORY = new TypeAdapterFactory() { | ||||
|     @SuppressWarnings("unchecked") // we use a runtime check to make sure the 'T's equal | ||||
|     public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> typeToken) { | ||||
|     @Override public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> typeToken) { | ||||
|       if (typeToken.getRawType() != Timestamp.class) { | ||||
|         return null; | ||||
|       } | ||||
| @ -725,15 +777,18 @@ public final class TypeAdapters { | ||||
|           SerializedName annotation = classOfT.getField(name).getAnnotation(SerializedName.class); | ||||
|           if (annotation != null) { | ||||
|             name = annotation.value(); | ||||
|             for (String alternate : annotation.alternate()) { | ||||
|               nameToConstant.put(alternate, constant); | ||||
|             } | ||||
|           } | ||||
|           nameToConstant.put(name, constant); | ||||
|           constantToName.put(constant, name); | ||||
|         } | ||||
|       } catch (NoSuchFieldException e) { | ||||
|         throw new AssertionError(); | ||||
|         throw new AssertionError(e); | ||||
|       } | ||||
|     } | ||||
|     public T read(JsonReader in) throws IOException { | ||||
|     @Override public T read(JsonReader in) throws IOException { | ||||
|       if (in.peek() == JsonToken.NULL) { | ||||
|         in.nextNull(); | ||||
|         return null; | ||||
| @ -741,14 +796,14 @@ public final class TypeAdapters { | ||||
|       return nameToConstant.get(in.nextString()); | ||||
|     } | ||||
| 
 | ||||
|     public void write(JsonWriter out, T value) throws IOException { | ||||
|     @Override public void write(JsonWriter out, T value) throws IOException { | ||||
|       out.value(value == null ? null : constantToName.get(value)); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   public static final TypeAdapterFactory ENUM_FACTORY = new TypeAdapterFactory() { | ||||
|     @SuppressWarnings({"rawtypes", "unchecked"}) | ||||
|     public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> typeToken) { | ||||
|     @Override public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> typeToken) { | ||||
|       Class<? super T> rawType = typeToken.getRawType(); | ||||
|       if (!Enum.class.isAssignableFrom(rawType) || rawType == Enum.class) { | ||||
|         return null; | ||||
| @ -764,7 +819,7 @@ public final class TypeAdapters { | ||||
|       final TypeToken<TT> type, final TypeAdapter<TT> typeAdapter) { | ||||
|     return new TypeAdapterFactory() { | ||||
|       @SuppressWarnings("unchecked") // we use a runtime check to make sure the 'T's equal | ||||
|       public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> typeToken) { | ||||
|       @Override public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> typeToken) { | ||||
|         return typeToken.equals(type) ? (TypeAdapter<T>) typeAdapter : null; | ||||
|       } | ||||
|     }; | ||||
| @ -774,7 +829,7 @@ public final class TypeAdapters { | ||||
|       final Class<TT> type, final TypeAdapter<TT> typeAdapter) { | ||||
|     return new TypeAdapterFactory() { | ||||
|       @SuppressWarnings("unchecked") // we use a runtime check to make sure the 'T's equal | ||||
|       public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> typeToken) { | ||||
|       @Override public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> typeToken) { | ||||
|         return typeToken.getRawType() == type ? (TypeAdapter<T>) typeAdapter : null; | ||||
|       } | ||||
|       @Override public String toString() { | ||||
| @ -787,7 +842,7 @@ public final class TypeAdapters { | ||||
|       final Class<TT> unboxed, final Class<TT> boxed, final TypeAdapter<? super TT> typeAdapter) { | ||||
|     return new TypeAdapterFactory() { | ||||
|       @SuppressWarnings("unchecked") // we use a runtime check to make sure the 'T's equal | ||||
|       public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> typeToken) { | ||||
|       @Override public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> typeToken) { | ||||
|         Class<? super T> rawType = typeToken.getRawType(); | ||||
|         return (rawType == unboxed || rawType == boxed) ? (TypeAdapter<T>) typeAdapter : null; | ||||
|       } | ||||
| @ -802,7 +857,7 @@ public final class TypeAdapters { | ||||
|       final Class<? extends TT> sub, final TypeAdapter<? super TT> typeAdapter) { | ||||
|     return new TypeAdapterFactory() { | ||||
|       @SuppressWarnings("unchecked") // we use a runtime check to make sure the 'T's equal | ||||
|       public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> typeToken) { | ||||
|       @Override public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> typeToken) { | ||||
|         Class<? super T> rawType = typeToken.getRawType(); | ||||
|         return (rawType == base || rawType == sub) ? (TypeAdapter<T>) typeAdapter : null; | ||||
|       } | ||||
| @ -813,12 +868,33 @@ public final class TypeAdapters { | ||||
|     }; | ||||
|   } | ||||
| 
 | ||||
|   public static <TT> TypeAdapterFactory newTypeHierarchyFactory( | ||||
|       final Class<TT> clazz, final TypeAdapter<TT> typeAdapter) { | ||||
|   /** | ||||
|    * Returns a factory for all subtypes of {@code typeAdapter}. We do a runtime check to confirm | ||||
|    * that the deserialized type matches the type requested. | ||||
|    */ | ||||
|   public static <T1> TypeAdapterFactory newTypeHierarchyFactory( | ||||
|       final Class<T1> clazz, final TypeAdapter<T1> typeAdapter) { | ||||
|     return new TypeAdapterFactory() { | ||||
|       @SuppressWarnings("unchecked") | ||||
|       public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> typeToken) { | ||||
|         return clazz.isAssignableFrom(typeToken.getRawType()) ? (TypeAdapter<T>) typeAdapter : null; | ||||
|       @Override public <T2> TypeAdapter<T2> create(Gson gson, TypeToken<T2> typeToken) { | ||||
|         final Class<? super T2> requestedType = typeToken.getRawType(); | ||||
|         if (!clazz.isAssignableFrom(requestedType)) { | ||||
|           return null; | ||||
|         } | ||||
|         return (TypeAdapter<T2>) new TypeAdapter<T1>() { | ||||
|           @Override public void write(JsonWriter out, T1 value) throws IOException { | ||||
|             typeAdapter.write(out, value); | ||||
|           } | ||||
| 
 | ||||
|           @Override public T1 read(JsonReader in) throws IOException { | ||||
|             T1 result = typeAdapter.read(in); | ||||
|             if (result != null && !requestedType.isInstance(result)) { | ||||
|               throw new JsonSyntaxException("Expected a " + requestedType.getName() | ||||
|                   + " but was " + result.getClass().getName()); | ||||
|             } | ||||
|             return result; | ||||
|           } | ||||
|         }; | ||||
|       } | ||||
|       @Override public String toString() { | ||||
|         return "Factory[typeHierarchy=" + clazz.getName() + ",adapter=" + typeAdapter + "]"; | ||||
|  | ||||
| @ -0,0 +1,352 @@ | ||||
| package com.massivecraft.massivecore.xlib.gson.internal.bind.util; | ||||
| 
 | ||||
| import java.text.ParseException; | ||||
| import java.text.ParsePosition; | ||||
| import java.util.*; | ||||
| 
 | ||||
| /** | ||||
|  * Utilities methods for manipulating dates in iso8601 format. This is much much faster and GC friendly than using SimpleDateFormat so | ||||
|  * highly suitable if you (un)serialize lots of date objects. | ||||
|  *  | ||||
|  * Supported parse format: [yyyy-MM-dd|yyyyMMdd][T(hh:mm[:ss[.sss]]|hhmm[ss[.sss]])]?[Z|[+-]hh[:]mm]] | ||||
|  *  | ||||
|  * @see <a href="http://www.w3.org/TR/NOTE-datetime">this specification</a> | ||||
|  */ | ||||
| //Date parsing code from Jackson databind ISO8601Utils.java | ||||
| // https://github.com/FasterXML/jackson-databind/blob/master/src/main/java/com/fasterxml/jackson/databind/util/ISO8601Utils.java | ||||
| public class ISO8601Utils | ||||
| { | ||||
|     /** | ||||
|      * ID to represent the 'UTC' string, default timezone since Jackson 2.7 | ||||
|      *  | ||||
|      * @since 2.7 | ||||
|      */ | ||||
|     private static final String UTC_ID = "UTC"; | ||||
|     /** | ||||
|      * The UTC timezone, prefetched to avoid more lookups. | ||||
|      *  | ||||
|      * @since 2.7 | ||||
|      */ | ||||
|     private static final TimeZone TIMEZONE_UTC = TimeZone.getTimeZone(UTC_ID); | ||||
| 
 | ||||
|     /* | ||||
|     /********************************************************** | ||||
|     /* Formatting | ||||
|     /********************************************************** | ||||
|      */ | ||||
| 
 | ||||
|     /** | ||||
|      * Format a date into 'yyyy-MM-ddThh:mm:ssZ' (default timezone, no milliseconds precision) | ||||
|      *  | ||||
|      * @param date the date to format | ||||
|      * @return the date formatted as 'yyyy-MM-ddThh:mm:ssZ' | ||||
|      */ | ||||
|     public static String format(Date date) { | ||||
|         return format(date, false, TIMEZONE_UTC); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Format a date into 'yyyy-MM-ddThh:mm:ss[.sss]Z' (GMT timezone) | ||||
|      *  | ||||
|      * @param date the date to format | ||||
|      * @param millis true to include millis precision otherwise false | ||||
|      * @return the date formatted as 'yyyy-MM-ddThh:mm:ss[.sss]Z' | ||||
|      */ | ||||
|     public static String format(Date date, boolean millis) { | ||||
|         return format(date, millis, TIMEZONE_UTC); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Format date into yyyy-MM-ddThh:mm:ss[.sss][Z|[+-]hh:mm] | ||||
|      *  | ||||
|      * @param date the date to format | ||||
|      * @param millis true to include millis precision otherwise false | ||||
|      * @param tz timezone to use for the formatting (UTC will produce 'Z') | ||||
|      * @return the date formatted as yyyy-MM-ddThh:mm:ss[.sss][Z|[+-]hh:mm] | ||||
|      */ | ||||
|     public static String format(Date date, boolean millis, TimeZone tz) { | ||||
|         Calendar calendar = new GregorianCalendar(tz, Locale.US); | ||||
|         calendar.setTime(date); | ||||
| 
 | ||||
|         // estimate capacity of buffer as close as we can (yeah, that's pedantic ;) | ||||
|         int capacity = "yyyy-MM-ddThh:mm:ss".length(); | ||||
|         capacity += millis ? ".sss".length() : 0; | ||||
|         capacity += tz.getRawOffset() == 0 ? "Z".length() : "+hh:mm".length(); | ||||
|         StringBuilder formatted = new StringBuilder(capacity); | ||||
| 
 | ||||
|         padInt(formatted, calendar.get(Calendar.YEAR), "yyyy".length()); | ||||
|         formatted.append('-'); | ||||
|         padInt(formatted, calendar.get(Calendar.MONTH) + 1, "MM".length()); | ||||
|         formatted.append('-'); | ||||
|         padInt(formatted, calendar.get(Calendar.DAY_OF_MONTH), "dd".length()); | ||||
|         formatted.append('T'); | ||||
|         padInt(formatted, calendar.get(Calendar.HOUR_OF_DAY), "hh".length()); | ||||
|         formatted.append(':'); | ||||
|         padInt(formatted, calendar.get(Calendar.MINUTE), "mm".length()); | ||||
|         formatted.append(':'); | ||||
|         padInt(formatted, calendar.get(Calendar.SECOND), "ss".length()); | ||||
|         if (millis) { | ||||
|             formatted.append('.'); | ||||
|             padInt(formatted, calendar.get(Calendar.MILLISECOND), "sss".length()); | ||||
|         } | ||||
| 
 | ||||
|         int offset = tz.getOffset(calendar.getTimeInMillis()); | ||||
|         if (offset != 0) { | ||||
|             int hours = Math.abs((offset / (60 * 1000)) / 60); | ||||
|             int minutes = Math.abs((offset / (60 * 1000)) % 60); | ||||
|             formatted.append(offset < 0 ? '-' : '+'); | ||||
|             padInt(formatted, hours, "hh".length()); | ||||
|             formatted.append(':'); | ||||
|             padInt(formatted, minutes, "mm".length()); | ||||
|         } else { | ||||
|             formatted.append('Z'); | ||||
|         } | ||||
| 
 | ||||
|         return formatted.toString(); | ||||
|     } | ||||
| 
 | ||||
|     /* | ||||
|     /********************************************************** | ||||
|     /* Parsing | ||||
|     /********************************************************** | ||||
|      */ | ||||
| 
 | ||||
|     /** | ||||
|      * Parse a date from ISO-8601 formatted string. It expects a format | ||||
|      * [yyyy-MM-dd|yyyyMMdd][T(hh:mm[:ss[.sss]]|hhmm[ss[.sss]])]?[Z|[+-]hh[:mm]]] | ||||
|      *  | ||||
|      * @param date ISO string to parse in the appropriate format. | ||||
|      * @param pos The position to start parsing from, updated to where parsing stopped. | ||||
|      * @return the parsed date | ||||
|      * @throws ParseException if the date is not in the appropriate format | ||||
|      */ | ||||
|     public static Date parse(String date, ParsePosition pos) throws ParseException { | ||||
|         Exception fail = null; | ||||
|         try { | ||||
|             int offset = pos.getIndex(); | ||||
| 
 | ||||
|             // extract year | ||||
|             int year = parseInt(date, offset, offset += 4); | ||||
|             if (checkOffset(date, offset, '-')) { | ||||
|                 offset += 1; | ||||
|             } | ||||
| 
 | ||||
|             // extract month | ||||
|             int month = parseInt(date, offset, offset += 2); | ||||
|             if (checkOffset(date, offset, '-')) { | ||||
|                 offset += 1; | ||||
|             } | ||||
| 
 | ||||
|             // extract day | ||||
|             int day = parseInt(date, offset, offset += 2); | ||||
|             // default time value | ||||
|             int hour = 0; | ||||
|             int minutes = 0; | ||||
|             int seconds = 0; | ||||
|             int milliseconds = 0; // always use 0 otherwise returned date will include millis of current time | ||||
| 
 | ||||
|             // if the value has no time component (and no time zone), we are done | ||||
|             boolean hasT = checkOffset(date, offset, 'T'); | ||||
|              | ||||
|             if (!hasT && (date.length() <= offset)) { | ||||
|                 Calendar calendar = new GregorianCalendar(year, month - 1, day); | ||||
| 
 | ||||
|                 pos.setIndex(offset); | ||||
|                 return calendar.getTime(); | ||||
|             } | ||||
| 
 | ||||
|             if (hasT) { | ||||
| 
 | ||||
|                 // extract hours, minutes, seconds and milliseconds | ||||
|                 hour = parseInt(date, offset += 1, offset += 2); | ||||
|                 if (checkOffset(date, offset, ':')) { | ||||
|                     offset += 1; | ||||
|                 } | ||||
| 
 | ||||
|                 minutes = parseInt(date, offset, offset += 2); | ||||
|                 if (checkOffset(date, offset, ':')) { | ||||
|                     offset += 1; | ||||
|                 } | ||||
|                 // second and milliseconds can be optional | ||||
|                 if (date.length() > offset) { | ||||
|                     char c = date.charAt(offset); | ||||
|                     if (c != 'Z' && c != '+' && c != '-') { | ||||
|                         seconds = parseInt(date, offset, offset += 2); | ||||
|                         if (seconds > 59 && seconds < 63) seconds = 59; // truncate up to 3 leap seconds | ||||
|                         // milliseconds can be optional in the format | ||||
|                         if (checkOffset(date, offset, '.')) { | ||||
|                             offset += 1; | ||||
|                             int endOffset = indexOfNonDigit(date, offset + 1); // assume at least one digit | ||||
|                             int parseEndOffset = Math.min(endOffset, offset + 3); // parse up to 3 digits | ||||
|                             int fraction = parseInt(date, offset, parseEndOffset); | ||||
|                             // compensate for "missing" digits | ||||
|                             switch (parseEndOffset - offset) { // number of digits parsed | ||||
|                             case 2: | ||||
|                                 milliseconds = fraction * 10; | ||||
|                                 break; | ||||
|                             case 1: | ||||
|                                 milliseconds = fraction * 100; | ||||
|                                 break; | ||||
|                             default: | ||||
|                                 milliseconds = fraction; | ||||
|                             } | ||||
|                             offset = endOffset; | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             // extract timezone | ||||
|             if (date.length() <= offset) { | ||||
|                 throw new IllegalArgumentException("No time zone indicator"); | ||||
|             } | ||||
| 
 | ||||
|             TimeZone timezone = null; | ||||
|             char timezoneIndicator = date.charAt(offset); | ||||
| 
 | ||||
|             if (timezoneIndicator == 'Z') { | ||||
|                 timezone = TIMEZONE_UTC; | ||||
|                 offset += 1; | ||||
|             } else if (timezoneIndicator == '+' || timezoneIndicator == '-') { | ||||
|                 String timezoneOffset = date.substring(offset); | ||||
| 
 | ||||
|                 // When timezone has no minutes, we should append it, valid timezones are, for example: +00:00, +0000 and +00 | ||||
|                 timezoneOffset = timezoneOffset.length() >= 5 ? timezoneOffset : timezoneOffset + "00"; | ||||
| 
 | ||||
|                 offset += timezoneOffset.length(); | ||||
|                 // 18-Jun-2015, tatu: Minor simplification, skip offset of "+0000"/"+00:00" | ||||
|                 if ("+0000".equals(timezoneOffset) || "+00:00".equals(timezoneOffset)) { | ||||
|                     timezone = TIMEZONE_UTC; | ||||
|                 } else { | ||||
|                     // 18-Jun-2015, tatu: Looks like offsets only work from GMT, not UTC... | ||||
|                     //    not sure why, but that's the way it looks. Further, Javadocs for | ||||
|                     //    `java.util.TimeZone` specifically instruct use of GMT as base for | ||||
|                     //    custom timezones... odd. | ||||
|                     String timezoneId = "GMT" + timezoneOffset; | ||||
| //                    String timezoneId = "UTC" + timezoneOffset; | ||||
| 
 | ||||
|                     timezone = TimeZone.getTimeZone(timezoneId); | ||||
| 
 | ||||
|                     String act = timezone.getID(); | ||||
|                     if (!act.equals(timezoneId)) { | ||||
|                         /* 22-Jan-2015, tatu: Looks like canonical version has colons, but we may be given | ||||
|                          *    one without. If so, don't sweat. | ||||
|                          *   Yes, very inefficient. Hopefully not hit often. | ||||
|                          *   If it becomes a perf problem, add 'loose' comparison instead. | ||||
|                          */ | ||||
|                         String cleaned = act.replace(":", ""); | ||||
|                         if (!cleaned.equals(timezoneId)) { | ||||
|                             throw new IndexOutOfBoundsException("Mismatching time zone indicator: "+timezoneId+" given, resolves to " | ||||
|                                     +timezone.getID()); | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
|             } else { | ||||
|                 throw new IndexOutOfBoundsException("Invalid time zone indicator '" + timezoneIndicator+"'"); | ||||
|             } | ||||
| 
 | ||||
|             Calendar calendar = new GregorianCalendar(timezone); | ||||
|             calendar.setLenient(false); | ||||
|             calendar.set(Calendar.YEAR, year); | ||||
|             calendar.set(Calendar.MONTH, month - 1); | ||||
|             calendar.set(Calendar.DAY_OF_MONTH, day); | ||||
|             calendar.set(Calendar.HOUR_OF_DAY, hour); | ||||
|             calendar.set(Calendar.MINUTE, minutes); | ||||
|             calendar.set(Calendar.SECOND, seconds); | ||||
|             calendar.set(Calendar.MILLISECOND, milliseconds); | ||||
| 
 | ||||
|             pos.setIndex(offset); | ||||
|             return calendar.getTime(); | ||||
|             // If we get a ParseException it'll already have the right message/offset. | ||||
|             // Other exception types can convert here. | ||||
|         } catch (IndexOutOfBoundsException e) { | ||||
|             fail = e; | ||||
|         } catch (NumberFormatException e) { | ||||
|             fail = e; | ||||
|         } catch (IllegalArgumentException e) { | ||||
|             fail = e; | ||||
|         } | ||||
|         String input = (date == null) ? null : ('"' + date + "'"); | ||||
|         String msg = fail.getMessage(); | ||||
|         if (msg == null || msg.isEmpty()) { | ||||
|             msg = "("+fail.getClass().getName()+")"; | ||||
|         } | ||||
|         ParseException ex = new ParseException("Failed to parse date [" + input + "]: " + msg, pos.getIndex()); | ||||
|         ex.initCause(fail); | ||||
|         throw ex; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Check if the expected character exist at the given offset in the value. | ||||
|      *  | ||||
|      * @param value the string to check at the specified offset | ||||
|      * @param offset the offset to look for the expected character | ||||
|      * @param expected the expected character | ||||
|      * @return true if the expected character exist at the given offset | ||||
|      */ | ||||
|     private static boolean checkOffset(String value, int offset, char expected) { | ||||
|         return (offset < value.length()) && (value.charAt(offset) == expected); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Parse an integer located between 2 given offsets in a string | ||||
|      *  | ||||
|      * @param value the string to parse | ||||
|      * @param beginIndex the start index for the integer in the string | ||||
|      * @param endIndex the end index for the integer in the string | ||||
|      * @return the int | ||||
|      * @throws NumberFormatException if the value is not a number | ||||
|      */ | ||||
|     private static int parseInt(String value, int beginIndex, int endIndex) throws NumberFormatException { | ||||
|         if (beginIndex < 0 || endIndex > value.length() || beginIndex > endIndex) { | ||||
|             throw new NumberFormatException(value); | ||||
|         } | ||||
|         // use same logic as in Integer.parseInt() but less generic we're not supporting negative values | ||||
|         int i = beginIndex; | ||||
|         int result = 0; | ||||
|         int digit; | ||||
|         if (i < endIndex) { | ||||
|             digit = Character.digit(value.charAt(i++), 10); | ||||
|             if (digit < 0) { | ||||
|                 throw new NumberFormatException("Invalid number: " + value.substring(beginIndex, endIndex)); | ||||
|             } | ||||
|             result = -digit; | ||||
|         } | ||||
|         while (i < endIndex) { | ||||
|             digit = Character.digit(value.charAt(i++), 10); | ||||
|             if (digit < 0) { | ||||
|                 throw new NumberFormatException("Invalid number: " + value.substring(beginIndex, endIndex)); | ||||
|             } | ||||
|             result *= 10; | ||||
|             result -= digit; | ||||
|         } | ||||
|         return -result; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Zero pad a number to a specified length | ||||
|      *  | ||||
|      * @param buffer buffer to use for padding | ||||
|      * @param value the integer value to pad if necessary. | ||||
|      * @param length the length of the string we should zero pad | ||||
|      */ | ||||
|     private static void padInt(StringBuilder buffer, int value, int length) { | ||||
|         String strValue = Integer.toString(value); | ||||
|         for (int i = length - strValue.length(); i > 0; i--) { | ||||
|             buffer.append('0'); | ||||
|         } | ||||
|         buffer.append(strValue); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Returns the index of the first character in the string that is not a digit, starting at offset. | ||||
|      */ | ||||
|     private static int indexOfNonDigit(String string, int offset) { | ||||
|         for (int i = offset; i < string.length(); i++) { | ||||
|             char c = string.charAt(i); | ||||
|             if (c < '0' || c > '9') return i; | ||||
|         } | ||||
|         return string.length(); | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| @ -303,4 +303,19 @@ public class TypeToken<T> { | ||||
|   public static <T> TypeToken<T> get(Class<T> type) { | ||||
|     return new TypeToken<>(type); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * Gets type literal for the parameterized type represented by applying {@code typeArguments} to | ||||
|    * {@code rawType}. | ||||
|    */ | ||||
|   public static TypeToken<?> getParameterized(Type rawType, Type... typeArguments) { | ||||
|     return new TypeToken<Object>($Gson$Types.newParameterizedTypeWithOwner(null, rawType, typeArguments)); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * Gets type literal for the array type whose elements are all instances of {@code componentType}. | ||||
|    */ | ||||
|   public static TypeToken<?> getArray(Type componentType) { | ||||
|     return new TypeToken<Object>($Gson$Types.arrayOf(componentType)); | ||||
|   } | ||||
| } | ||||
|  | ||||
| @ -25,7 +25,7 @@ import java.io.IOException; | ||||
| import java.io.Reader; | ||||
| 
 | ||||
| /** | ||||
|  * Reads a JSON (<a href="http://www.ietf.org/rfc/rfc4627.txt">RFC 4627</a>) | ||||
|  * Reads a JSON (<a href="http://www.ietf.org/rfc/rfc7159.txt">RFC 7159</a>) | ||||
|  * encoded value as a stream of tokens. This stream includes both literal | ||||
|  * values (strings, numbers, booleans, and nulls) as well as the begin and | ||||
|  * end delimiters of objects and arrays. The tokens are traversed in | ||||
| @ -243,7 +243,7 @@ public class JsonReader implements Closeable { | ||||
|   private int lineNumber = 0; | ||||
|   private int lineStart = 0; | ||||
| 
 | ||||
|   private int peeked = PEEKED_NONE; | ||||
|   int peeked = PEEKED_NONE; | ||||
| 
 | ||||
|   /** | ||||
|    * A peeked value that was composed entirely of digits with an optional | ||||
| @ -295,7 +295,7 @@ public class JsonReader implements Closeable { | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * Configure this parser to be  be liberal in what it accepts. By default, | ||||
|    * Configure this parser to be liberal in what it accepts. By default, | ||||
|    * this parser is strict and only accepts JSON as specified by <a | ||||
|    * href="http://www.ietf.org/rfc/rfc4627.txt">RFC 4627</a>. Setting the | ||||
|    * parser to lenient causes it to ignore the following syntax errors: | ||||
| @ -348,8 +348,7 @@ public class JsonReader implements Closeable { | ||||
|       pathIndices[stackSize - 1] = 0; | ||||
|       peeked = PEEKED_NONE; | ||||
|     } else { | ||||
|       throw new IllegalStateException("Expected BEGIN_ARRAY but was " + peek() | ||||
|           + " at line " + getLineNumber() + " column " + getColumnNumber() + " path " + getPath()); | ||||
|       throw new IllegalStateException("Expected BEGIN_ARRAY but was " + peek() + locationString()); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
| @ -367,8 +366,7 @@ public class JsonReader implements Closeable { | ||||
|       pathIndices[stackSize - 1]++; | ||||
|       peeked = PEEKED_NONE; | ||||
|     } else { | ||||
|       throw new IllegalStateException("Expected END_ARRAY but was " + peek() | ||||
|           + " at line " + getLineNumber() + " column " + getColumnNumber() + " path " + getPath()); | ||||
|       throw new IllegalStateException("Expected END_ARRAY but was " + peek() + locationString()); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
| @ -385,8 +383,7 @@ public class JsonReader implements Closeable { | ||||
|       push(JsonScope.EMPTY_OBJECT); | ||||
|       peeked = PEEKED_NONE; | ||||
|     } else { | ||||
|       throw new IllegalStateException("Expected BEGIN_OBJECT but was " + peek() | ||||
|           + " at line " + getLineNumber() + " column " + getColumnNumber() + " path " + getPath()); | ||||
|       throw new IllegalStateException("Expected BEGIN_OBJECT but was " + peek() + locationString()); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
| @ -405,8 +402,7 @@ public class JsonReader implements Closeable { | ||||
|       pathIndices[stackSize - 1]++; | ||||
|       peeked = PEEKED_NONE; | ||||
|     } else { | ||||
|       throw new IllegalStateException("Expected END_OBJECT but was " + peek() | ||||
|           + " at line " + getLineNumber() + " column " + getColumnNumber() + " path " + getPath()); | ||||
|       throw new IllegalStateException("Expected END_OBJECT but was " + peek() + locationString()); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
| @ -463,7 +459,7 @@ public class JsonReader implements Closeable { | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   private int doPeek() throws IOException { | ||||
|   int doPeek() throws IOException { | ||||
|     int peekStack = stack[stackSize - 1]; | ||||
|     if (peekStack == JsonScope.EMPTY_ARRAY) { | ||||
|       stack[stackSize - 1] = JsonScope.NONEMPTY_ARRAY; | ||||
| @ -572,9 +568,6 @@ public class JsonReader implements Closeable { | ||||
|       checkLenient(); | ||||
|       return peeked = PEEKED_SINGLE_QUOTED; | ||||
|     case '"': | ||||
|       if (stackSize == 1) { | ||||
|         checkLenient(); | ||||
|       } | ||||
|       return peeked = PEEKED_DOUBLE_QUOTED; | ||||
|     case '[': | ||||
|       return peeked = PEEKED_BEGIN_ARRAY; | ||||
| @ -584,10 +577,6 @@ public class JsonReader implements Closeable { | ||||
|       pos--; // Don't consume the first character in a literal value. | ||||
|     } | ||||
| 
 | ||||
|     if (stackSize == 1) { | ||||
|       checkLenient(); // Top-level value isn't an array or an object. | ||||
|     } | ||||
| 
 | ||||
|     int result = peekKeyword(); | ||||
|     if (result != PEEKED_NONE) { | ||||
|       return result; | ||||
| @ -779,7 +768,7 @@ public class JsonReader implements Closeable { | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * Returns the next token, a {@link com.massivecraft.massivecore.xlib.gson.stream.JsonToken#NAME property name}, and | ||||
|    * Returns the next token, a {@link JsonToken#NAME property name}, and | ||||
|    * consumes it. | ||||
|    * | ||||
|    * @throws java.io.IOException if the next token in the stream is not a property | ||||
| @ -798,8 +787,7 @@ public class JsonReader implements Closeable { | ||||
|     } else if (p == PEEKED_DOUBLE_QUOTED_NAME) { | ||||
|       result = nextQuotedValue('"'); | ||||
|     } else { | ||||
|       throw new IllegalStateException("Expected a name but was " + peek() | ||||
|           + " at line " + getLineNumber() + " column " + getColumnNumber() + " path " + getPath()); | ||||
|       throw new IllegalStateException("Expected a name but was " + peek() + locationString()); | ||||
|     } | ||||
|     peeked = PEEKED_NONE; | ||||
|     pathNames[stackSize - 1] = result; | ||||
| @ -807,7 +795,7 @@ public class JsonReader implements Closeable { | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * Returns the {@link com.massivecraft.massivecore.xlib.gson.stream.JsonToken#STRING string} value of the next token, | ||||
|    * Returns the {@link JsonToken#STRING string} value of the next token, | ||||
|    * consuming it. If the next token is a number, this method will return its | ||||
|    * string form. | ||||
|    * | ||||
| @ -835,8 +823,7 @@ public class JsonReader implements Closeable { | ||||
|       result = new String(buffer, pos, peekedNumberLength); | ||||
|       pos += peekedNumberLength; | ||||
|     } else { | ||||
|       throw new IllegalStateException("Expected a string but was " + peek() | ||||
|           + " at line " + getLineNumber() + " column " + getColumnNumber() + " path " + getPath()); | ||||
|       throw new IllegalStateException("Expected a string but was " + peek() + locationString()); | ||||
|     } | ||||
|     peeked = PEEKED_NONE; | ||||
|     pathIndices[stackSize - 1]++; | ||||
| @ -844,7 +831,7 @@ public class JsonReader implements Closeable { | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * Returns the {@link com.massivecraft.massivecore.xlib.gson.stream.JsonToken#BOOLEAN boolean} value of the next token, | ||||
|    * Returns the {@link JsonToken#BOOLEAN boolean} value of the next token, | ||||
|    * consuming it. | ||||
|    * | ||||
|    * @throws IllegalStateException if the next token is not a boolean or if | ||||
| @ -864,8 +851,7 @@ public class JsonReader implements Closeable { | ||||
|       pathIndices[stackSize - 1]++; | ||||
|       return false; | ||||
|     } | ||||
|     throw new IllegalStateException("Expected a boolean but was " + peek() | ||||
|         + " at line " + getLineNumber() + " column " + getColumnNumber() + " path " + getPath()); | ||||
|     throw new IllegalStateException("Expected a boolean but was " + peek() + locationString()); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
| @ -884,13 +870,12 @@ public class JsonReader implements Closeable { | ||||
|       peeked = PEEKED_NONE; | ||||
|       pathIndices[stackSize - 1]++; | ||||
|     } else { | ||||
|       throw new IllegalStateException("Expected null but was " + peek() | ||||
|           + " at line " + getLineNumber() + " column " + getColumnNumber() + " path " + getPath()); | ||||
|       throw new IllegalStateException("Expected null but was " + peek() + locationString()); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * Returns the {@link com.massivecraft.massivecore.xlib.gson.stream.JsonToken#NUMBER double} value of the next token, | ||||
|    * Returns the {@link JsonToken#NUMBER double} value of the next token, | ||||
|    * consuming it. If the next token is a string, this method will attempt to | ||||
|    * parse it as a double using {@link Double#parseDouble(String)}. | ||||
|    * | ||||
| @ -918,15 +903,14 @@ public class JsonReader implements Closeable { | ||||
|     } else if (p == PEEKED_UNQUOTED) { | ||||
|       peekedString = nextUnquotedValue(); | ||||
|     } else if (p != PEEKED_BUFFERED) { | ||||
|       throw new IllegalStateException("Expected a double but was " + peek() | ||||
|           + " at line " + getLineNumber() + " column " + getColumnNumber() + " path " + getPath()); | ||||
|       throw new IllegalStateException("Expected a double but was " + peek() + locationString()); | ||||
|     } | ||||
| 
 | ||||
|     peeked = PEEKED_BUFFERED; | ||||
|     double result = Double.parseDouble(peekedString); // don't catch this NumberFormatException. | ||||
|     if (!lenient && (Double.isNaN(result) || Double.isInfinite(result))) { | ||||
|       throw new MalformedJsonException("JSON forbids NaN and infinities: " + result | ||||
|           + " at line " + getLineNumber() + " column " + getColumnNumber() + " path " + getPath()); | ||||
|       throw new MalformedJsonException( | ||||
|           "JSON forbids NaN and infinities: " + result + locationString()); | ||||
|     } | ||||
|     peekedString = null; | ||||
|     peeked = PEEKED_NONE; | ||||
| @ -935,7 +919,7 @@ public class JsonReader implements Closeable { | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * Returns the {@link com.massivecraft.massivecore.xlib.gson.stream.JsonToken#NUMBER long} value of the next token, | ||||
|    * Returns the {@link JsonToken#NUMBER long} value of the next token, | ||||
|    * consuming it. If the next token is a string, this method will attempt to | ||||
|    * parse it as a long. If the next token's numeric value cannot be exactly | ||||
|    * represented by a Java {@code long}, this method throws. | ||||
| @ -959,8 +943,12 @@ public class JsonReader implements Closeable { | ||||
|     if (p == PEEKED_NUMBER) { | ||||
|       peekedString = new String(buffer, pos, peekedNumberLength); | ||||
|       pos += peekedNumberLength; | ||||
|     } else if (p == PEEKED_SINGLE_QUOTED || p == PEEKED_DOUBLE_QUOTED) { | ||||
|       peekedString = nextQuotedValue(p == PEEKED_SINGLE_QUOTED ? '\'' : '"'); | ||||
|     } else if (p == PEEKED_SINGLE_QUOTED || p == PEEKED_DOUBLE_QUOTED || p == PEEKED_UNQUOTED) { | ||||
|       if (p == PEEKED_UNQUOTED) { | ||||
|         peekedString = nextUnquotedValue(); | ||||
|       } else { | ||||
|         peekedString = nextQuotedValue(p == PEEKED_SINGLE_QUOTED ? '\'' : '"'); | ||||
|       } | ||||
|       try { | ||||
|         long result = Long.parseLong(peekedString); | ||||
|         peeked = PEEKED_NONE; | ||||
| @ -970,16 +958,14 @@ public class JsonReader implements Closeable { | ||||
|         // Fall back to parse as a double below. | ||||
|       } | ||||
|     } else { | ||||
|       throw new IllegalStateException("Expected a long but was " + peek() | ||||
|           + " at line " + getLineNumber() + " column " + getColumnNumber() + " path " + getPath()); | ||||
|       throw new IllegalStateException("Expected a long but was " + peek() + locationString()); | ||||
|     } | ||||
| 
 | ||||
|     peeked = PEEKED_BUFFERED; | ||||
|     double asDouble = Double.parseDouble(peekedString); // don't catch this NumberFormatException. | ||||
|     long result = (long) asDouble; | ||||
|     if (result != asDouble) { // Make sure no precision was lost casting to 'long'. | ||||
|       throw new NumberFormatException("Expected a long but was " + peekedString | ||||
|           + " at line " + getLineNumber() + " column " + getColumnNumber() + " path " + getPath()); | ||||
|       throw new NumberFormatException("Expected a long but was " + peekedString + locationString()); | ||||
|     } | ||||
|     peekedString = null; | ||||
|     peeked = PEEKED_NONE; | ||||
| @ -1157,7 +1143,7 @@ public class JsonReader implements Closeable { | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * Returns the {@link com.massivecraft.massivecore.xlib.gson.stream.JsonToken#NUMBER int} value of the next token, | ||||
|    * Returns the {@link JsonToken#NUMBER int} value of the next token, | ||||
|    * consuming it. If the next token is a string, this method will attempt to | ||||
|    * parse it as an int. If the next token's numeric value cannot be exactly | ||||
|    * represented by a Java {@code int}, this method throws. | ||||
| @ -1176,8 +1162,7 @@ public class JsonReader implements Closeable { | ||||
|     if (p == PEEKED_LONG) { | ||||
|       result = (int) peekedLong; | ||||
|       if (peekedLong != result) { // Make sure no precision was lost casting to 'int'. | ||||
|         throw new NumberFormatException("Expected an int but was " + peekedLong | ||||
|             + " at line " + getLineNumber() + " column " + getColumnNumber() + " path " + getPath()); | ||||
|         throw new NumberFormatException("Expected an int but was " + peekedLong + locationString()); | ||||
|       } | ||||
|       peeked = PEEKED_NONE; | ||||
|       pathIndices[stackSize - 1]++; | ||||
| @ -1187,8 +1172,12 @@ public class JsonReader implements Closeable { | ||||
|     if (p == PEEKED_NUMBER) { | ||||
|       peekedString = new String(buffer, pos, peekedNumberLength); | ||||
|       pos += peekedNumberLength; | ||||
|     } else if (p == PEEKED_SINGLE_QUOTED || p == PEEKED_DOUBLE_QUOTED) { | ||||
|       peekedString = nextQuotedValue(p == PEEKED_SINGLE_QUOTED ? '\'' : '"'); | ||||
|     } else if (p == PEEKED_SINGLE_QUOTED || p == PEEKED_DOUBLE_QUOTED || p == PEEKED_UNQUOTED) { | ||||
|       if (p == PEEKED_UNQUOTED) { | ||||
|         peekedString = nextUnquotedValue(); | ||||
|       } else { | ||||
|         peekedString = nextQuotedValue(p == PEEKED_SINGLE_QUOTED ? '\'' : '"'); | ||||
|       } | ||||
|       try { | ||||
|         result = Integer.parseInt(peekedString); | ||||
|         peeked = PEEKED_NONE; | ||||
| @ -1198,16 +1187,14 @@ public class JsonReader implements Closeable { | ||||
|         // Fall back to parse as a double below. | ||||
|       } | ||||
|     } else { | ||||
|       throw new IllegalStateException("Expected an int but was " + peek() | ||||
|           + " at line " + getLineNumber() + " column " + getColumnNumber() + " path " + getPath()); | ||||
|       throw new IllegalStateException("Expected an int but was " + peek() + locationString()); | ||||
|     } | ||||
| 
 | ||||
|     peeked = PEEKED_BUFFERED; | ||||
|     double asDouble = Double.parseDouble(peekedString); // don't catch this NumberFormatException. | ||||
|     result = (int) asDouble; | ||||
|     if (result != asDouble) { // Make sure no precision was lost casting to 'int'. | ||||
|       throw new NumberFormatException("Expected an int but was " + peekedString | ||||
|           + " at line " + getLineNumber() + " column " + getColumnNumber() + " path " + getPath()); | ||||
|       throw new NumberFormatException("Expected an int but was " + peekedString + locationString()); | ||||
|     } | ||||
|     peekedString = null; | ||||
|     peeked = PEEKED_NONE; | ||||
| @ -1315,14 +1302,6 @@ public class JsonReader implements Closeable { | ||||
|     return false; | ||||
|   } | ||||
| 
 | ||||
|   private int getLineNumber() { | ||||
|     return lineNumber + 1; | ||||
|   } | ||||
| 
 | ||||
|   private int getColumnNumber() { | ||||
|     return pos - lineStart + 1; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * Returns the next character in the stream that is neither whitespace nor a | ||||
|    * part of a comment. When this returns, the returned character is always at | ||||
| @ -1412,8 +1391,7 @@ public class JsonReader implements Closeable { | ||||
|       } | ||||
|     } | ||||
|     if (throwOnEof) { | ||||
|       throw new EOFException("End of input" | ||||
|           + " at line " + getLineNumber() + " column " + getColumnNumber()); | ||||
|       throw new EOFException("End of input" + locationString()); | ||||
|     } else { | ||||
|       return -1; | ||||
|     } | ||||
| @ -1465,8 +1443,13 @@ public class JsonReader implements Closeable { | ||||
|   } | ||||
| 
 | ||||
|   @Override public String toString() { | ||||
|     return getClass().getSimpleName() | ||||
|         + " at line " + getLineNumber() + " column " + getColumnNumber(); | ||||
|     return getClass().getSimpleName() + locationString(); | ||||
|   } | ||||
| 
 | ||||
|   private String locationString() { | ||||
|     int line = lineNumber + 1; | ||||
|     int column = pos - lineStart + 1; | ||||
|     return " at line " + line + " column " + column + " path " + getPath(); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
| @ -1561,8 +1544,11 @@ public class JsonReader implements Closeable { | ||||
|     case '\'': | ||||
|     case '"': | ||||
|     case '\\': | ||||
|     case '/':	 | ||||
|     	return escaped; | ||||
|     default: | ||||
|       return escaped; | ||||
|     	// throw error when none of the above cases are matched | ||||
|     	throw syntaxError("Invalid escape sequence"); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
| @ -1571,8 +1557,7 @@ public class JsonReader implements Closeable { | ||||
|    * with this reader's content. | ||||
|    */ | ||||
|   private IOException syntaxError(String message) throws IOException { | ||||
|     throw new MalformedJsonException(message | ||||
|         + " at line " + getLineNumber() + " column " + getColumnNumber() + " path " + getPath()); | ||||
|     throw new MalformedJsonException(message + locationString()); | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
| @ -1615,9 +1600,8 @@ public class JsonReader implements Closeable { | ||||
|         } else if (p == PEEKED_UNQUOTED_NAME) { | ||||
|           reader.peeked = PEEKED_UNQUOTED; | ||||
|         } else { | ||||
|           throw new IllegalStateException("Expected a name but was " + reader.peek() + " " | ||||
|               + " at line " + reader.getLineNumber() + " column " + reader.getColumnNumber() | ||||
|               + " path " + reader.getPath()); | ||||
|           throw new IllegalStateException( | ||||
|               "Expected a name but was " + reader.peek() + reader.locationString()); | ||||
|         } | ||||
|       } | ||||
|     }; | ||||
|  | ||||
| @ -21,16 +21,10 @@ import java.io.Flushable; | ||||
| import java.io.IOException; | ||||
| import java.io.Writer; | ||||
| 
 | ||||
| import static com.massivecraft.massivecore.xlib.gson.stream.JsonScope.DANGLING_NAME; | ||||
| import static com.massivecraft.massivecore.xlib.gson.stream.JsonScope.EMPTY_ARRAY; | ||||
| import static com.massivecraft.massivecore.xlib.gson.stream.JsonScope.EMPTY_DOCUMENT; | ||||
| import static com.massivecraft.massivecore.xlib.gson.stream.JsonScope.EMPTY_OBJECT; | ||||
| import static com.massivecraft.massivecore.xlib.gson.stream.JsonScope.NONEMPTY_ARRAY; | ||||
| import static com.massivecraft.massivecore.xlib.gson.stream.JsonScope.NONEMPTY_DOCUMENT; | ||||
| import static com.massivecraft.massivecore.xlib.gson.stream.JsonScope.NONEMPTY_OBJECT; | ||||
| import static com.massivecraft.massivecore.xlib.gson.stream.JsonScope.*; | ||||
| 
 | ||||
| /** | ||||
|  * Writes a JSON (<a href="http://www.ietf.org/rfc/rfc4627.txt">RFC 4627</a>) | ||||
|  * Writes a JSON (<a href="http://www.ietf.org/rfc/rfc7159.txt">RFC 7159</a>) | ||||
|  * encoded value to a stream, one token at a time. The stream includes both | ||||
|  * literal values (strings, numbers, booleans and nulls) as well as the begin | ||||
|  * and end delimiters of objects and arrays. | ||||
| @ -77,7 +71,7 @@ import static com.massivecraft.massivecore.xlib.gson.stream.JsonScope.NONEMPTY_O | ||||
|  * This code encodes the above structure: <pre>   {@code | ||||
|  *   public void writeJsonStream(OutputStream out, List<Message> messages) throws IOException { | ||||
|  *     JsonWriter writer = new JsonWriter(new OutputStreamWriter(out, "UTF-8")); | ||||
|  *     writer.setIndentSpaces(4); | ||||
|  *     writer.setIndent("    "); | ||||
|  *     writeMessagesArray(writer, messages); | ||||
|  *     writer.close(); | ||||
|  *   } | ||||
| @ -130,7 +124,7 @@ import static com.massivecraft.massivecore.xlib.gson.stream.JsonScope.NONEMPTY_O | ||||
| public class JsonWriter implements Closeable, Flushable { | ||||
| 
 | ||||
|   /* | ||||
|    * From RFC 4627, "All Unicode characters may be placed within the | ||||
|    * From RFC 7159, "All Unicode characters may be placed within the | ||||
|    * quotation marks except for the characters that must be escaped: | ||||
|    * quotation mark, reverse solidus, and the control characters | ||||
|    * (U+0000 through U+001F)." | ||||
| @ -222,7 +216,7 @@ public class JsonWriter implements Closeable, Flushable { | ||||
|   /** | ||||
|    * Configure this writer to relax its syntax rules. By default, this writer | ||||
|    * only emits well-formed JSON as specified by <a | ||||
|    * href="http://www.ietf.org/rfc/rfc4627.txt">RFC 4627</a>. Setting the writer | ||||
|    * href="http://www.ietf.org/rfc/rfc7159.txt">RFC 7159</a>. Setting the writer | ||||
|    * to lenient permits the following: | ||||
|    * <ul> | ||||
|    *   <li>Top-level values of any type. With strict writing, the top-level | ||||
| @ -322,7 +316,7 @@ public class JsonWriter implements Closeable, Flushable { | ||||
|    * bracket. | ||||
|    */ | ||||
|   private JsonWriter open(int empty, String openBracket) throws IOException { | ||||
|     beforeValue(true); | ||||
|     beforeValue(); | ||||
|     push(empty); | ||||
|     out.write(openBracket); | ||||
|     return this; | ||||
| @ -415,11 +409,28 @@ public class JsonWriter implements Closeable, Flushable { | ||||
|       return nullValue(); | ||||
|     } | ||||
|     writeDeferredName(); | ||||
|     beforeValue(false); | ||||
|     beforeValue(); | ||||
|     string(value); | ||||
|     return this; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * Writes {@code value} directly to the writer without quoting or | ||||
|    * escaping. | ||||
|    * | ||||
|    * @param value the literal string value, or null to encode a null literal. | ||||
|    * @return this writer. | ||||
|    */ | ||||
|   public JsonWriter jsonValue(String value) throws IOException { | ||||
|     if (value == null) { | ||||
|       return nullValue(); | ||||
|     } | ||||
|     writeDeferredName(); | ||||
|     beforeValue(); | ||||
|     out.append(value); | ||||
|     return this; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * Encodes {@code null}. | ||||
|    * | ||||
| @ -434,7 +445,7 @@ public class JsonWriter implements Closeable, Flushable { | ||||
|         return this; // skip the name and the value | ||||
|       } | ||||
|     } | ||||
|     beforeValue(false); | ||||
|     beforeValue(); | ||||
|     out.write("null"); | ||||
|     return this; | ||||
|   } | ||||
| @ -446,7 +457,22 @@ public class JsonWriter implements Closeable, Flushable { | ||||
|    */ | ||||
|   public JsonWriter value(boolean value) throws IOException { | ||||
|     writeDeferredName(); | ||||
|     beforeValue(false); | ||||
|     beforeValue(); | ||||
|     out.write(value ? "true" : "false"); | ||||
|     return this; | ||||
|   } | ||||
| 
 | ||||
|   /** | ||||
|    * Encodes {@code value}. | ||||
|    * | ||||
|    * @return this writer. | ||||
|    */ | ||||
|   public JsonWriter value(Boolean value) throws IOException { | ||||
|     if (value == null) { | ||||
|       return nullValue(); | ||||
|     } | ||||
|     writeDeferredName(); | ||||
|     beforeValue(); | ||||
|     out.write(value ? "true" : "false"); | ||||
|     return this; | ||||
|   } | ||||
| @ -463,7 +489,7 @@ public class JsonWriter implements Closeable, Flushable { | ||||
|       throw new IllegalArgumentException("Numeric values must be finite, but was " + value); | ||||
|     } | ||||
|     writeDeferredName(); | ||||
|     beforeValue(false); | ||||
|     beforeValue(); | ||||
|     out.append(Double.toString(value)); | ||||
|     return this; | ||||
|   } | ||||
| @ -475,7 +501,7 @@ public class JsonWriter implements Closeable, Flushable { | ||||
|    */ | ||||
|   public JsonWriter value(long value) throws IOException { | ||||
|     writeDeferredName(); | ||||
|     beforeValue(false); | ||||
|     beforeValue(); | ||||
|     out.write(Long.toString(value)); | ||||
|     return this; | ||||
|   } | ||||
| @ -498,7 +524,7 @@ public class JsonWriter implements Closeable, Flushable { | ||||
|         && (string.equals("-Infinity") || string.equals("Infinity") || string.equals("NaN"))) { | ||||
|       throw new IllegalArgumentException("Numeric values must be finite, but was " + value); | ||||
|     } | ||||
|     beforeValue(false); | ||||
|     beforeValue(); | ||||
|     out.append(string); | ||||
|     return this; | ||||
|   } | ||||
| @ -591,12 +617,9 @@ public class JsonWriter implements Closeable, Flushable { | ||||
|    * Inserts any necessary separators and whitespace before a literal value, | ||||
|    * inline array, or inline object. Also adjusts the stack to expect either a | ||||
|    * closing bracket or another element. | ||||
|    * | ||||
|    * @param root true if the value is a new array or object, the two values | ||||
|    *     permitted as top-level elements. | ||||
|    */ | ||||
|   @SuppressWarnings("fallthrough") | ||||
|   private void beforeValue(boolean root) throws IOException { | ||||
|   private void beforeValue() throws IOException { | ||||
|     switch (peek()) { | ||||
|     case NONEMPTY_DOCUMENT: | ||||
|       if (!lenient) { | ||||
| @ -605,10 +628,6 @@ public class JsonWriter implements Closeable, Flushable { | ||||
|       } | ||||
|       // fall-through | ||||
|     case EMPTY_DOCUMENT: // first in document | ||||
|       if (!lenient && !root) { | ||||
|         throw new IllegalStateException( | ||||
|             "JSON must start with an array or an object."); | ||||
|       } | ||||
|       replaceTop(NONEMPTY_DOCUMENT); | ||||
|       break; | ||||
| 
 | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user