package com.google.gson; import com.google.gson.internal.ConstructorConstructor; import com.google.gson.internal.Excluder; import com.google.gson.internal.Primitives; import com.google.gson.internal.Streams; import com.google.gson.internal.bind.ArrayTypeAdapter; import com.google.gson.internal.bind.CollectionTypeAdapterFactory; import com.google.gson.internal.bind.DateTypeAdapter; import com.google.gson.internal.bind.JsonTreeReader; import com.google.gson.internal.bind.JsonTreeWriter; import com.google.gson.internal.bind.MapTypeAdapterFactory; import com.google.gson.internal.bind.ObjectTypeAdapter; import com.google.gson.internal.bind.ReflectiveTypeAdapterFactory; import com.google.gson.internal.bind.SqlDateTypeAdapter; import com.google.gson.internal.bind.TimeTypeAdapter; import com.google.gson.internal.bind.TypeAdapters; import com.google.gson.reflect.TypeToken; import com.google.gson.stream.JsonReader; import com.google.gson.stream.JsonToken; import com.google.gson.stream.JsonWriter; import com.google.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.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; public final class Gson { private final ThreadLocal<Map<TypeToken<?>, FutureTypeAdapter<?>>> calls = new ThreadLocal() { protected Map<TypeToken<?>, Gson.FutureTypeAdapter<?>> initialValue() { return new HashMap(); } }; private final Map<TypeToken<?>, TypeAdapter<?>> typeTokenCache = Collections.synchronizedMap(new HashMap()); private final List<TypeAdapterFactory> factories; private final ConstructorConstructor constructorConstructor; private final boolean serializeNulls; private final boolean htmlSafe; private final boolean generateNonExecutableJson; private final boolean prettyPrinting; final JsonDeserializationContext deserializationContext = new JsonDeserializationContext() { public <T> T deserialize(JsonElement json, Type typeOfT) throws JsonParseException { return Gson.this.fromJson(json, typeOfT); } }; final JsonSerializationContext serializationContext = new JsonSerializationContext() { public JsonElement serialize(Object src) { return Gson.this.toJsonTree(src); } }; public Gson() { this(Excluder.DEFAULT, FieldNamingPolicy.IDENTITY, Collections.emptyMap(), false, false, false, true, false, false, LongSerializationPolicy.DEFAULT, Collections.emptyList()); } Gson(Excluder excluder, FieldNamingStrategy fieldNamingPolicy, Map<Type, InstanceCreator<?>> instanceCreators, boolean serializeNulls, boolean complexMapKeySerialization, boolean generateNonExecutableGson, boolean htmlSafe, boolean prettyPrinting, boolean serializeSpecialFloatingPointValues, LongSerializationPolicy longSerializationPolicy, List<TypeAdapterFactory> typeAdapterFactories) { this.constructorConstructor = new ConstructorConstructor(instanceCreators); this.serializeNulls = serializeNulls; this.generateNonExecutableJson = generateNonExecutableGson; this.htmlSafe = htmlSafe; this.prettyPrinting = prettyPrinting; List factories = new ArrayList(); factories.add(TypeAdapters.JSON_ELEMENT_FACTORY); factories.add(ObjectTypeAdapter.FACTORY); factories.addAll(typeAdapterFactories); factories.add(TypeAdapters.STRING_FACTORY); factories.add(TypeAdapters.INTEGER_FACTORY); factories.add(TypeAdapters.BOOLEAN_FACTORY); factories.add(TypeAdapters.BYTE_FACTORY); factories.add(TypeAdapters.SHORT_FACTORY); factories.add(TypeAdapters.newFactory(Long.TYPE, Long.class, longAdapter(longSerializationPolicy))); factories.add(TypeAdapters.newFactory(Double.TYPE, Double.class, doubleAdapter(serializeSpecialFloatingPointValues))); factories.add(TypeAdapters.newFactory(Float.TYPE, Float.class, floatAdapter(serializeSpecialFloatingPointValues))); factories.add(TypeAdapters.NUMBER_FACTORY); factories.add(TypeAdapters.CHARACTER_FACTORY); factories.add(TypeAdapters.STRING_BUILDER_FACTORY); factories.add(TypeAdapters.STRING_BUFFER_FACTORY); factories.add(TypeAdapters.newFactory(BigDecimal.class, TypeAdapters.BIG_DECIMAL)); factories.add(TypeAdapters.newFactory(BigInteger.class, TypeAdapters.BIG_INTEGER)); factories.add(TypeAdapters.URL_FACTORY); factories.add(TypeAdapters.URI_FACTORY); factories.add(TypeAdapters.UUID_FACTORY); factories.add(TypeAdapters.LOCALE_FACTORY); factories.add(TypeAdapters.INET_ADDRESS_FACTORY); factories.add(TypeAdapters.BIT_SET_FACTORY); factories.add(DateTypeAdapter.FACTORY); factories.add(TypeAdapters.CALENDAR_FACTORY); factories.add(TimeTypeAdapter.FACTORY); factories.add(SqlDateTypeAdapter.FACTORY); factories.add(TypeAdapters.TIMESTAMP_FACTORY); factories.add(ArrayTypeAdapter.FACTORY); factories.add(TypeAdapters.ENUM_FACTORY); factories.add(TypeAdapters.CLASS_FACTORY); factories.add(excluder); factories.add(new CollectionTypeAdapterFactory(this.constructorConstructor)); factories.add(new MapTypeAdapterFactory(this.constructorConstructor, complexMapKeySerialization)); factories.add(new ReflectiveTypeAdapterFactory(this.constructorConstructor, fieldNamingPolicy, excluder)); this.factories = Collections.unmodifiableList(factories); } private TypeAdapter<Number> doubleAdapter(boolean serializeSpecialFloatingPointValues) { if (serializeSpecialFloatingPointValues) { return TypeAdapters.DOUBLE; } return new TypeAdapter() { public Double read(JsonReader in) throws IOException { if (in.peek() == JsonToken.NULL) { in.nextNull(); return null; } return Double.valueOf(in.nextDouble()); } public void write(JsonWriter out, Number value) throws IOException { if (value == null) { out.nullValue(); return; } double doubleValue = value.doubleValue(); Gson.this.checkValidFloatingPoint(doubleValue); out.value(value); } }; } private TypeAdapter<Number> floatAdapter(boolean serializeSpecialFloatingPointValues) { if (serializeSpecialFloatingPointValues) { return TypeAdapters.FLOAT; } return new TypeAdapter() { public Float read(JsonReader in) throws IOException { if (in.peek() == JsonToken.NULL) { in.nextNull(); return null; } return Float.valueOf((float)in.nextDouble()); } public void write(JsonWriter out, Number value) throws IOException { if (value == null) { out.nullValue(); return; } float floatValue = value.floatValue(); Gson.this.checkValidFloatingPoint(floatValue); out.value(value); } }; } private 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" + " behavior, use GsonBuilder.serializeSpecialDoubleValues() method."); } private TypeAdapter<Number> longAdapter(LongSerializationPolicy longSerializationPolicy) { if (longSerializationPolicy == LongSerializationPolicy.DEFAULT) { return TypeAdapters.LONG; } return new TypeAdapter() { public Number read(JsonReader in) throws IOException { if (in.peek() == JsonToken.NULL) { in.nextNull(); return null; } return Long.valueOf(in.nextLong()); } public void write(JsonWriter out, Number value) throws IOException { if (value == null) { out.nullValue(); return; } out.value(value.toString()); } }; } public <T> TypeAdapter<T> getAdapter(TypeToken<T> type) { TypeAdapter cached = (TypeAdapter)this.typeTokenCache.get(type); if (cached != null) { return cached; } Map threadCalls = (Map)this.calls.get(); FutureTypeAdapter ongoingCall = (FutureTypeAdapter)threadCalls.get(type); if (ongoingCall != null) { return ongoingCall; } FutureTypeAdapter call = new FutureTypeAdapter(); threadCalls.put(type, call); try { for (TypeAdapterFactory factory : this.factories) { TypeAdapter candidate = factory.create(this, type); if (candidate != null) { call.setDelegate(candidate); this.typeTokenCache.put(type, candidate); return candidate; } } throw new IllegalArgumentException("GSON cannot handle " + type); } finally { threadCalls.remove(type); } } public <T> TypeAdapter<T> getDelegateAdapter(TypeAdapterFactory skipPast, TypeToken<T> type) { boolean skipPastFound = false; for (TypeAdapterFactory factory : this.factories) { if (!skipPastFound) { if (factory == skipPast) { skipPastFound = true; } } else { TypeAdapter candidate = factory.create(this, type); if (candidate != null) return candidate; } } throw new IllegalArgumentException("GSON cannot serialize " + type); } public <T> TypeAdapter<T> getAdapter(Class<T> type) { return getAdapter(TypeToken.get(type)); } public JsonElement toJsonTree(Object src) { if (src == null) { return JsonNull.INSTANCE; } return toJsonTree(src, src.getClass()); } public JsonElement toJsonTree(Object src, Type typeOfSrc) { JsonTreeWriter writer = new JsonTreeWriter(); toJson(src, typeOfSrc, writer); return writer.get(); } public String toJson(Object src) { if (src == null) { return toJson(JsonNull.INSTANCE); } return toJson(src, src.getClass()); } public String toJson(Object src, Type typeOfSrc) { StringWriter writer = new StringWriter(); toJson(src, typeOfSrc, writer); return writer.toString(); } public void toJson(Object src, Type typeOfSrc, Appendable writer) throws JsonIOException { try { JsonWriter jsonWriter = newJsonWriter(Streams.writerForAppendable(writer)); toJson(src, typeOfSrc, jsonWriter); } catch (IOException e) { throw new JsonIOException(e); } } public void toJson(Object src, Type typeOfSrc, JsonWriter writer) throws JsonIOException { TypeAdapter adapter = getAdapter(TypeToken.get(typeOfSrc)); boolean oldLenient = writer.isLenient(); writer.setLenient(true); boolean oldHtmlSafe = writer.isHtmlSafe(); writer.setHtmlSafe(this.htmlSafe); boolean oldSerializeNulls = writer.getSerializeNulls(); writer.setSerializeNulls(this.serializeNulls); try { adapter.write(writer, src); } catch (IOException e) { throw new JsonIOException(e); } finally { writer.setLenient(oldLenient); writer.setHtmlSafe(oldHtmlSafe); writer.setSerializeNulls(oldSerializeNulls); } } public String toJson(JsonElement jsonElement) { StringWriter writer = new StringWriter(); toJson(jsonElement, writer); return writer.toString(); } public void toJson(JsonElement jsonElement, Appendable writer) throws JsonIOException { try { JsonWriter jsonWriter = newJsonWriter(Streams.writerForAppendable(writer)); toJson(jsonElement, jsonWriter); } catch (IOException e) { throw new RuntimeException(e); } } private JsonWriter newJsonWriter(Writer writer) throws IOException { if (this.generateNonExecutableJson) { writer.write(")]}'\n"); } JsonWriter jsonWriter = new JsonWriter(writer); if (this.prettyPrinting) { jsonWriter.setIndent(" "); } jsonWriter.setSerializeNulls(this.serializeNulls); return jsonWriter; } public void toJson(JsonElement jsonElement, JsonWriter writer) throws JsonIOException { boolean oldLenient = writer.isLenient(); writer.setLenient(true); boolean oldHtmlSafe = writer.isHtmlSafe(); writer.setHtmlSafe(this.htmlSafe); boolean oldSerializeNulls = writer.getSerializeNulls(); writer.setSerializeNulls(this.serializeNulls); try { Streams.write(jsonElement, writer); } catch (IOException e) { throw new JsonIOException(e); } finally { writer.setLenient(oldLenient); writer.setHtmlSafe(oldHtmlSafe); writer.setSerializeNulls(oldSerializeNulls); } } public <T> T fromJson(String json, Class<T> classOfT) throws JsonSyntaxException { Object object = fromJson(json, classOfT); return Primitives.wrap(classOfT).cast(object); } public <T> T fromJson(String json, Type typeOfT) throws JsonSyntaxException { if (json == null) { return null; } StringReader reader = new StringReader(json); Object target = fromJson(reader, typeOfT); return target; } public <T> T fromJson(Reader json, Type typeOfT) throws JsonIOException, JsonSyntaxException { JsonReader jsonReader = new JsonReader(json); Object object = fromJson(jsonReader, typeOfT); assertFullConsumption(object, jsonReader); return object; } private static void assertFullConsumption(Object obj, JsonReader reader) { try { if ((obj != null) && (reader.peek() != JsonToken.END_DOCUMENT)) throw new JsonIOException("JSON document was not fully consumed."); } catch (MalformedJsonException e) { throw new JsonSyntaxException(e); } catch (IOException e) { throw new JsonIOException(e); } } public <T> T fromJson(JsonReader reader, Type typeOfT) throws JsonIOException, JsonSyntaxException { boolean isEmpty = true; boolean oldLenient = reader.isLenient(); reader.setLenient(true); try { reader.peek(); isEmpty = false; TypeAdapter typeAdapter = getAdapter(TypeToken.get(typeOfT)); return typeAdapter.read(reader); } catch (EOFException e) { Object localObject1; if (isEmpty) { return null; } throw new JsonSyntaxException(e); } catch (IllegalStateException e) { throw new JsonSyntaxException(e); } catch (IOException e) { throw new JsonSyntaxException(e); } finally { reader.setLenient(oldLenient); } } public <T> T fromJson(JsonElement json, Type typeOfT) throws JsonSyntaxException { if (json == null) { return null; } return fromJson(new JsonTreeReader(json), typeOfT); } public String toString() { StringBuilder sb = new StringBuilder("{").append("serializeNulls:").append(this.serializeNulls).append("factories:").append(this.factories).append(",instanceCreators:").append(this.constructorConstructor).append("}"); return sb.toString(); } static class FutureTypeAdapter<T> extends TypeAdapter<T> { private TypeAdapter<T> delegate; public void setDelegate(TypeAdapter<T> typeAdapter) { if (this.delegate != null) { throw new AssertionError(); } this.delegate = typeAdapter; } public T read(JsonReader in) throws IOException { if (this.delegate == null) { throw new IllegalStateException(); } return this.delegate.read(in); } public void write(JsonWriter out, T value) throws IOException { if (this.delegate == null) { throw new IllegalStateException(); } this.delegate.write(out, value); } } }