/* * Copyright (C) 2008 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.smartandroid.sa.json; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.math.BigDecimal; import java.math.BigInteger; import java.net.InetAddress; import java.net.MalformedURLException; import java.net.URI; import java.net.URISyntaxException; import java.net.URL; import java.net.UnknownHostException; import java.sql.Time; import java.sql.Timestamp; import java.text.DateFormat; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.BitSet; import java.util.Calendar; import java.util.Collection; import java.util.Date; import java.util.GregorianCalendar; import java.util.HashSet; import java.util.LinkedHashMap; import java.util.LinkedList; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Queue; import java.util.Set; import java.util.SortedSet; import java.util.StringTokenizer; import java.util.TimeZone; import java.util.TreeSet; import java.util.UUID; import com.smartandroid.sa.json.internal.$Gson$Types; /** * List of all the default type adapters ({@link JsonSerializer}s, * {@link JsonDeserializer}s, and {@link InstanceCreator}s. * * @author Inderjeet Singh * @author Joel Leitch */ final class DefaultTypeAdapters { private static final DefaultDateTypeAdapter DATE_TYPE_ADAPTER = new DefaultDateTypeAdapter(); private static final DefaultJavaSqlDateTypeAdapter JAVA_SQL_DATE_TYPE_ADAPTER = new DefaultJavaSqlDateTypeAdapter(); private static final DefaultTimeTypeAdapter TIME_TYPE_ADAPTER = new DefaultTimeTypeAdapter(); private static final DefaultTimestampDeserializer TIMESTAMP_DESERIALIZER = new DefaultTimestampDeserializer(); @SuppressWarnings("unchecked") private static final EnumTypeAdapter ENUM_TYPE_ADAPTER = new EnumTypeAdapter(); private static final UrlTypeAdapter URL_TYPE_ADAPTER = new UrlTypeAdapter(); private static final UriTypeAdapter URI_TYPE_ADAPTER = new UriTypeAdapter(); private static final UuidTypeAdapter UUUID_TYPE_ADAPTER = new UuidTypeAdapter(); private static final LocaleTypeAdapter LOCALE_TYPE_ADAPTER = new LocaleTypeAdapter(); private static final BitSetTypeAdapter BIT_SET_ADAPTER = new BitSetTypeAdapter(); private static final DefaultInetAddressAdapter INET_ADDRESS_ADAPTER = new DefaultInetAddressAdapter(); private static final CollectionTypeAdapter COLLECTION_TYPE_ADAPTER = new CollectionTypeAdapter(); private static final MapTypeAdapter MAP_TYPE_ADAPTER = new MapTypeAdapter(); private static final BigDecimalTypeAdapter BIG_DECIMAL_TYPE_ADAPTER = new BigDecimalTypeAdapter(); private static final BigIntegerTypeAdapter BIG_INTEGER_TYPE_ADAPTER = new BigIntegerTypeAdapter(); private static final BooleanTypeAdapter BOOLEAN_TYPE_ADAPTER = new BooleanTypeAdapter(); private static final ByteTypeAdapter BYTE_TYPE_ADAPTER = new ByteTypeAdapter(); private static final CharacterTypeAdapter CHARACTER_TYPE_ADAPTER = new CharacterTypeAdapter(); private static final DoubleDeserializer DOUBLE_TYPE_ADAPTER = new DoubleDeserializer(); private static final FloatDeserializer FLOAT_TYPE_ADAPTER = new FloatDeserializer(); private static final IntegerTypeAdapter INTEGER_TYPE_ADAPTER = new IntegerTypeAdapter(); private static final LongDeserializer LONG_DESERIALIZER = new LongDeserializer(); private static final NumberTypeAdapter NUMBER_TYPE_ADAPTER = new NumberTypeAdapter(); private static final ShortTypeAdapter SHORT_TYPE_ADAPTER = new ShortTypeAdapter(); private static final StringTypeAdapter STRING_TYPE_ADAPTER = new StringTypeAdapter(); private static final StringBuilderTypeAdapter STRING_BUILDER_TYPE_ADAPTER = new StringBuilderTypeAdapter(); private static final StringBufferTypeAdapter STRING_BUFFER_TYPE_ADAPTER = new StringBufferTypeAdapter(); private static final GregorianCalendarTypeAdapter GREGORIAN_CALENDAR_TYPE_ADAPTER = new GregorianCalendarTypeAdapter(); // The constants DEFAULT_SERIALIZERS, DEFAULT_DESERIALIZERS, and // DEFAULT_INSTANCE_CREATORS // must be defined after the constants for the type adapters. Otherwise, the // type adapter // constants will appear as nulls. private static final ParameterizedTypeHandlerMap<JsonSerializer<?>> DEFAULT_SERIALIZERS = createDefaultSerializers(); static final ParameterizedTypeHandlerMap<JsonSerializer<?>> DEFAULT_HIERARCHY_SERIALIZERS = createDefaultHierarchySerializers(); private static final ParameterizedTypeHandlerMap<JsonDeserializer<?>> DEFAULT_DESERIALIZERS = createDefaultDeserializers(); static final ParameterizedTypeHandlerMap<JsonDeserializer<?>> DEFAULT_HIERARCHY_DESERIALIZERS = createDefaultHierarchyDeserializers(); private static final ParameterizedTypeHandlerMap<InstanceCreator<?>> DEFAULT_INSTANCE_CREATORS = createDefaultInstanceCreators(); private static ParameterizedTypeHandlerMap<JsonSerializer<?>> createDefaultSerializers() { ParameterizedTypeHandlerMap<JsonSerializer<?>> map = new ParameterizedTypeHandlerMap<JsonSerializer<?>>(); map.register(URL.class, URL_TYPE_ADAPTER, true); map.register(URI.class, URI_TYPE_ADAPTER, true); map.register(UUID.class, UUUID_TYPE_ADAPTER, true); map.register(Locale.class, LOCALE_TYPE_ADAPTER, true); map.register(Date.class, DATE_TYPE_ADAPTER, true); map.register(java.sql.Date.class, JAVA_SQL_DATE_TYPE_ADAPTER, true); map.register(Timestamp.class, DATE_TYPE_ADAPTER, true); map.register(Time.class, TIME_TYPE_ADAPTER, true); map.register(Calendar.class, GREGORIAN_CALENDAR_TYPE_ADAPTER, true); map.register(GregorianCalendar.class, GREGORIAN_CALENDAR_TYPE_ADAPTER, true); map.register(BigDecimal.class, BIG_DECIMAL_TYPE_ADAPTER, true); map.register(BigInteger.class, BIG_INTEGER_TYPE_ADAPTER, true); map.register(BitSet.class, BIT_SET_ADAPTER, true); // Add primitive serializers map.register(Boolean.class, BOOLEAN_TYPE_ADAPTER, true); map.register(boolean.class, BOOLEAN_TYPE_ADAPTER, true); map.register(Byte.class, BYTE_TYPE_ADAPTER, true); map.register(byte.class, BYTE_TYPE_ADAPTER, true); map.register(Character.class, CHARACTER_TYPE_ADAPTER, true); map.register(char.class, CHARACTER_TYPE_ADAPTER, true); map.register(Integer.class, INTEGER_TYPE_ADAPTER, true); map.register(int.class, INTEGER_TYPE_ADAPTER, true); map.register(Number.class, NUMBER_TYPE_ADAPTER, true); map.register(Short.class, SHORT_TYPE_ADAPTER, true); map.register(short.class, SHORT_TYPE_ADAPTER, true); map.register(String.class, STRING_TYPE_ADAPTER, true); map.register(StringBuilder.class, STRING_BUILDER_TYPE_ADAPTER, true); map.register(StringBuffer.class, STRING_BUFFER_TYPE_ADAPTER, true); map.makeUnmodifiable(); return map; } private static ParameterizedTypeHandlerMap<JsonSerializer<?>> createDefaultHierarchySerializers() { ParameterizedTypeHandlerMap<JsonSerializer<?>> map = new ParameterizedTypeHandlerMap<JsonSerializer<?>>(); map.registerForTypeHierarchy(Enum.class, ENUM_TYPE_ADAPTER, true); map.registerForTypeHierarchy(InetAddress.class, INET_ADDRESS_ADAPTER, true); map.registerForTypeHierarchy(Collection.class, COLLECTION_TYPE_ADAPTER, true); map.registerForTypeHierarchy(Map.class, MAP_TYPE_ADAPTER, true); map.makeUnmodifiable(); return map; } private static ParameterizedTypeHandlerMap<JsonDeserializer<?>> createDefaultDeserializers() { ParameterizedTypeHandlerMap<JsonDeserializer<?>> map = new ParameterizedTypeHandlerMap<JsonDeserializer<?>>(); map.register(URL.class, wrapDeserializer(URL_TYPE_ADAPTER), true); map.register(URI.class, wrapDeserializer(URI_TYPE_ADAPTER), true); map.register(UUID.class, wrapDeserializer(UUUID_TYPE_ADAPTER), true); map.register(Locale.class, wrapDeserializer(LOCALE_TYPE_ADAPTER), true); map.register(Date.class, wrapDeserializer(DATE_TYPE_ADAPTER), true); map.register(java.sql.Date.class, wrapDeserializer(JAVA_SQL_DATE_TYPE_ADAPTER), true); map.register(Timestamp.class, wrapDeserializer(TIMESTAMP_DESERIALIZER), true); map.register(Time.class, wrapDeserializer(TIME_TYPE_ADAPTER), true); map.register(Calendar.class, GREGORIAN_CALENDAR_TYPE_ADAPTER, true); map.register(GregorianCalendar.class, GREGORIAN_CALENDAR_TYPE_ADAPTER, true); map.register(BigDecimal.class, BIG_DECIMAL_TYPE_ADAPTER, true); map.register(BigInteger.class, BIG_INTEGER_TYPE_ADAPTER, true); map.register(BitSet.class, BIT_SET_ADAPTER, true); // Add primitive deserializers map.register(Boolean.class, BOOLEAN_TYPE_ADAPTER, true); map.register(boolean.class, BOOLEAN_TYPE_ADAPTER, true); map.register(Byte.class, BYTE_TYPE_ADAPTER, true); map.register(byte.class, BYTE_TYPE_ADAPTER, true); map.register(Character.class, wrapDeserializer(CHARACTER_TYPE_ADAPTER), true); map.register(char.class, wrapDeserializer(CHARACTER_TYPE_ADAPTER), true); map.register(Double.class, DOUBLE_TYPE_ADAPTER, true); map.register(double.class, DOUBLE_TYPE_ADAPTER, true); map.register(Float.class, FLOAT_TYPE_ADAPTER, true); map.register(float.class, FLOAT_TYPE_ADAPTER, true); map.register(Integer.class, INTEGER_TYPE_ADAPTER, true); map.register(int.class, INTEGER_TYPE_ADAPTER, true); map.register(Long.class, LONG_DESERIALIZER, true); map.register(long.class, LONG_DESERIALIZER, true); map.register(Number.class, NUMBER_TYPE_ADAPTER, true); map.register(Short.class, SHORT_TYPE_ADAPTER, true); map.register(short.class, SHORT_TYPE_ADAPTER, true); map.register(String.class, wrapDeserializer(STRING_TYPE_ADAPTER), true); map.register(StringBuilder.class, wrapDeserializer(STRING_BUILDER_TYPE_ADAPTER), true); map.register(StringBuffer.class, wrapDeserializer(STRING_BUFFER_TYPE_ADAPTER), true); map.makeUnmodifiable(); return map; } private static ParameterizedTypeHandlerMap<JsonDeserializer<?>> createDefaultHierarchyDeserializers() { ParameterizedTypeHandlerMap<JsonDeserializer<?>> map = new ParameterizedTypeHandlerMap<JsonDeserializer<?>>(); map.registerForTypeHierarchy(Enum.class, wrapDeserializer(ENUM_TYPE_ADAPTER), true); map.registerForTypeHierarchy(InetAddress.class, wrapDeserializer(INET_ADDRESS_ADAPTER), true); map.registerForTypeHierarchy(Collection.class, wrapDeserializer(COLLECTION_TYPE_ADAPTER), true); map.registerForTypeHierarchy(Map.class, wrapDeserializer(MAP_TYPE_ADAPTER), true); map.makeUnmodifiable(); return map; } @SuppressWarnings("unchecked") private static ParameterizedTypeHandlerMap<InstanceCreator<?>> createDefaultInstanceCreators() { ParameterizedTypeHandlerMap<InstanceCreator<?>> map = new ParameterizedTypeHandlerMap<InstanceCreator<?>>(); DefaultConstructorAllocator allocator = new DefaultConstructorAllocator( 50); // Map Instance Creators map.registerForTypeHierarchy(Map.class, new DefaultConstructorCreator<Map>(LinkedHashMap.class, allocator), true); // Add Collection type instance creators DefaultConstructorCreator<List> listCreator = new DefaultConstructorCreator<List>( ArrayList.class, allocator); DefaultConstructorCreator<Queue> queueCreator = new DefaultConstructorCreator<Queue>( LinkedList.class, allocator); DefaultConstructorCreator<Set> setCreator = new DefaultConstructorCreator<Set>( HashSet.class, allocator); DefaultConstructorCreator<SortedSet> sortedSetCreator = new DefaultConstructorCreator<SortedSet>( TreeSet.class, allocator); map.registerForTypeHierarchy(Collection.class, listCreator, true); map.registerForTypeHierarchy(Queue.class, queueCreator, true); map.registerForTypeHierarchy(Set.class, setCreator, true); map.registerForTypeHierarchy(SortedSet.class, sortedSetCreator, true); map.makeUnmodifiable(); return map; } @SuppressWarnings("unchecked") private static JsonDeserializer<?> wrapDeserializer( JsonDeserializer<?> deserializer) { return new JsonDeserializerExceptionWrapper(deserializer); } static ParameterizedTypeHandlerMap<JsonSerializer<?>> getDefaultSerializers() { return getDefaultSerializers(false, LongSerializationPolicy.DEFAULT); } static ParameterizedTypeHandlerMap<JsonSerializer<?>> getAllDefaultSerializers() { ParameterizedTypeHandlerMap<JsonSerializer<?>> defaultSerializers = getDefaultSerializers( false, LongSerializationPolicy.DEFAULT); defaultSerializers.register(DEFAULT_HIERARCHY_SERIALIZERS); return defaultSerializers; } static ParameterizedTypeHandlerMap<JsonDeserializer<?>> getAllDefaultDeserializers() { ParameterizedTypeHandlerMap<JsonDeserializer<?>> defaultDeserializers = getDefaultDeserializers() .copyOf(); defaultDeserializers.register(DEFAULT_HIERARCHY_DESERIALIZERS); return defaultDeserializers; } static ParameterizedTypeHandlerMap<JsonSerializer<?>> getDefaultSerializers( boolean serializeSpecialFloatingPointValues, LongSerializationPolicy longSerializationPolicy) { ParameterizedTypeHandlerMap<JsonSerializer<?>> serializers = new ParameterizedTypeHandlerMap<JsonSerializer<?>>(); // Double primitive DefaultTypeAdapters.DoubleSerializer doubleSerializer = new DefaultTypeAdapters.DoubleSerializer( serializeSpecialFloatingPointValues); serializers.registerIfAbsent(Double.class, doubleSerializer); serializers.registerIfAbsent(double.class, doubleSerializer); // Float primitive DefaultTypeAdapters.FloatSerializer floatSerializer = new DefaultTypeAdapters.FloatSerializer( serializeSpecialFloatingPointValues); serializers.registerIfAbsent(Float.class, floatSerializer); serializers.registerIfAbsent(float.class, floatSerializer); // Long primitive DefaultTypeAdapters.LongSerializer longSerializer = new DefaultTypeAdapters.LongSerializer( longSerializationPolicy); serializers.registerIfAbsent(Long.class, longSerializer); serializers.registerIfAbsent(long.class, longSerializer); serializers.registerIfAbsent(DEFAULT_SERIALIZERS); return serializers; } static ParameterizedTypeHandlerMap<JsonDeserializer<?>> getDefaultDeserializers() { return DEFAULT_DESERIALIZERS; } static ParameterizedTypeHandlerMap<InstanceCreator<?>> getDefaultInstanceCreators() { return DEFAULT_INSTANCE_CREATORS; } /** * This type adapter supports three subclasses of date: Date, Timestamp, and * java.sql.Date. */ static final class DefaultDateTypeAdapter implements JsonSerializer<Date>, JsonDeserializer<Date> { private final DateFormat enUsFormat; private final DateFormat localFormat; private final DateFormat iso8601Format; DefaultDateTypeAdapter() { this(DateFormat.getDateTimeInstance(DateFormat.DEFAULT, DateFormat.DEFAULT, Locale.US), DateFormat.getDateTimeInstance(DateFormat.DEFAULT, DateFormat.DEFAULT)); } DefaultDateTypeAdapter(String datePattern) { this(new SimpleDateFormat(datePattern, Locale.US), new SimpleDateFormat(datePattern)); } DefaultDateTypeAdapter(int style) { this(DateFormat.getDateInstance(style, Locale.US), DateFormat .getDateInstance(style)); } public DefaultDateTypeAdapter(int dateStyle, int timeStyle) { this(DateFormat .getDateTimeInstance(dateStyle, timeStyle, Locale.US), DateFormat.getDateTimeInstance(dateStyle, timeStyle)); } DefaultDateTypeAdapter(DateFormat enUsFormat, DateFormat localFormat) { this.enUsFormat = enUsFormat; this.localFormat = localFormat; this.iso8601Format = new SimpleDateFormat( "yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.US); this.iso8601Format.setTimeZone(TimeZone.getTimeZone("UTC")); } // These methods need to be synchronized since JDK DateFormat classes // are not thread-safe // See issue 162 public JsonElement serialize(Date src, Type typeOfSrc, JsonSerializationContext context) { synchronized (localFormat) { String dateFormatAsString = enUsFormat.format(src); return new JsonPrimitive(dateFormatAsString); } } public Date deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { if (!(json instanceof JsonPrimitive)) { throw new JsonParseException( "The date should be a string value"); } Date date = deserializeToDate(json); if (typeOfT == Date.class) { return date; } else if (typeOfT == Timestamp.class) { return new Timestamp(date.getTime()); } else if (typeOfT == java.sql.Date.class) { return new java.sql.Date(date.getTime()); } else { throw new IllegalArgumentException(getClass() + " cannot deserialize to " + typeOfT); } } private Date deserializeToDate(JsonElement json) { synchronized (localFormat) { try { return localFormat.parse(json.getAsString()); } catch (ParseException ignored) { } try { return enUsFormat.parse(json.getAsString()); } catch (ParseException ignored) { } try { return iso8601Format.parse(json.getAsString()); } catch (ParseException e) { throw new JsonSyntaxException(json.getAsString(), e); } } } @Override public String toString() { StringBuilder sb = new StringBuilder(); sb.append(DefaultDateTypeAdapter.class.getSimpleName()); sb.append('(').append(localFormat.getClass().getSimpleName()) .append(')'); return sb.toString(); } } static final class DefaultJavaSqlDateTypeAdapter implements JsonSerializer<java.sql.Date>, JsonDeserializer<java.sql.Date> { private final DateFormat format; DefaultJavaSqlDateTypeAdapter() { this.format = new SimpleDateFormat("MMM d, yyyy"); } public JsonElement serialize(java.sql.Date src, Type typeOfSrc, JsonSerializationContext context) { synchronized (format) { String dateFormatAsString = format.format(src); return new JsonPrimitive(dateFormatAsString); } } public java.sql.Date deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { if (!(json instanceof JsonPrimitive)) { throw new JsonParseException( "The date should be a string value"); } try { synchronized (format) { Date date = format.parse(json.getAsString()); return new java.sql.Date(date.getTime()); } } catch (ParseException e) { throw new JsonSyntaxException(e); } } } static final class DefaultTimestampDeserializer implements JsonDeserializer<Timestamp> { public Timestamp deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { Date date = context.deserialize(json, Date.class); return new Timestamp(date.getTime()); } } static final class DefaultTimeTypeAdapter implements JsonSerializer<Time>, JsonDeserializer<Time> { private final DateFormat format; DefaultTimeTypeAdapter() { this.format = new SimpleDateFormat("hh:mm:ss a"); } public JsonElement serialize(Time src, Type typeOfSrc, JsonSerializationContext context) { synchronized (format) { String dateFormatAsString = format.format(src); return new JsonPrimitive(dateFormatAsString); } } public Time deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { if (!(json instanceof JsonPrimitive)) { throw new JsonParseException( "The date should be a string value"); } try { synchronized (format) { Date date = format.parse(json.getAsString()); return new Time(date.getTime()); } } catch (ParseException e) { throw new JsonSyntaxException(e); } } } private static final class GregorianCalendarTypeAdapter implements JsonSerializer<GregorianCalendar>, JsonDeserializer<GregorianCalendar> { private static final String YEAR = "year"; private static final String MONTH = "month"; private static final String DAY_OF_MONTH = "dayOfMonth"; private static final String HOUR_OF_DAY = "hourOfDay"; private static final String MINUTE = "minute"; private static final String SECOND = "second"; public JsonElement serialize(GregorianCalendar src, Type typeOfSrc, JsonSerializationContext context) { JsonObject obj = new JsonObject(); obj.addProperty(YEAR, src.get(Calendar.YEAR)); obj.addProperty(MONTH, src.get(Calendar.MONTH)); obj.addProperty(DAY_OF_MONTH, src.get(Calendar.DAY_OF_MONTH)); obj.addProperty(HOUR_OF_DAY, src.get(Calendar.HOUR_OF_DAY)); obj.addProperty(MINUTE, src.get(Calendar.MINUTE)); obj.addProperty(SECOND, src.get(Calendar.SECOND)); return obj; } public GregorianCalendar deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { JsonObject obj = json.getAsJsonObject(); int year = obj.get(YEAR).getAsInt(); int month = obj.get(MONTH).getAsInt(); int dayOfMonth = obj.get(DAY_OF_MONTH).getAsInt(); int hourOfDay = obj.get(HOUR_OF_DAY).getAsInt(); int minute = obj.get(MINUTE).getAsInt(); int second = obj.get(SECOND).getAsInt(); return new GregorianCalendar(year, month, dayOfMonth, hourOfDay, minute, second); } @Override public String toString() { return GregorianCalendarTypeAdapter.class.getSimpleName(); } } static final class DefaultInetAddressAdapter implements JsonDeserializer<InetAddress>, JsonSerializer<InetAddress> { public InetAddress deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { try { return InetAddress.getByName(json.getAsString()); } catch (UnknownHostException e) { throw new JsonParseException(e); } } public JsonElement serialize(InetAddress src, Type typeOfSrc, JsonSerializationContext context) { return new JsonPrimitive(src.getHostAddress()); } } @SuppressWarnings("unchecked") private static final class EnumTypeAdapter<T extends Enum<T>> implements JsonSerializer<T>, JsonDeserializer<T> { public JsonElement serialize(T src, Type typeOfSrc, JsonSerializationContext context) { return new JsonPrimitive(src.name()); } @SuppressWarnings("cast") public T deserialize(JsonElement json, Type classOfT, JsonDeserializationContext context) throws JsonParseException { return (T) Enum.valueOf((Class<T>) classOfT, json.getAsString()); } @Override public String toString() { return EnumTypeAdapter.class.getSimpleName(); } } private static final class BitSetTypeAdapter implements JsonSerializer<BitSet>, JsonDeserializer<BitSet> { public JsonElement serialize(BitSet src, Type typeOfSrc, JsonSerializationContext context) { JsonArray array = new JsonArray(); for (int i = 0; i < src.length(); i++) { int value = (src.get(i)) ? 1 : 0; array.add(new JsonPrimitive(value)); } return array; } public BitSet deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { if (!json.isJsonArray()) { throw new JsonParseException("Expected an array of bits."); } BitSet result = new BitSet(); JsonArray array = json.getAsJsonArray(); for (int i = 0; i < array.size(); i++) { JsonElement element = array.get(i); if (element.getAsBoolean()) { result.set(i); } } return result; } @Override public String toString() { return BitSetTypeAdapter.class.getSimpleName(); } } private static final class UrlTypeAdapter implements JsonSerializer<URL>, JsonDeserializer<URL> { public JsonElement serialize(URL src, Type typeOfSrc, JsonSerializationContext context) { return new JsonPrimitive(src.toExternalForm()); } public URL deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { try { return new URL(json.getAsString()); } catch (MalformedURLException e) { throw new JsonSyntaxException(e); } } @Override public String toString() { return UrlTypeAdapter.class.getSimpleName(); } } private static final class UriTypeAdapter implements JsonSerializer<URI>, JsonDeserializer<URI> { public JsonElement serialize(URI src, Type typeOfSrc, JsonSerializationContext context) { return new JsonPrimitive(src.toASCIIString()); } public URI deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { try { return new URI(json.getAsString()); } catch (URISyntaxException e) { throw new JsonSyntaxException(e); } } @Override public String toString() { return UriTypeAdapter.class.getSimpleName(); } } private static final class UuidTypeAdapter implements JsonSerializer<UUID>, JsonDeserializer<UUID> { public JsonElement serialize(UUID src, Type typeOfSrc, JsonSerializationContext context) { return new JsonPrimitive(src.toString()); } public UUID deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { return UUID.fromString(json.getAsString()); } @Override public String toString() { return UuidTypeAdapter.class.getSimpleName(); } } private static final class LocaleTypeAdapter implements JsonSerializer<Locale>, JsonDeserializer<Locale> { public JsonElement serialize(Locale src, Type typeOfSrc, JsonSerializationContext context) { return new JsonPrimitive(src.toString()); } public Locale deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { String locale = json.getAsString(); StringTokenizer tokenizer = new StringTokenizer(locale, "_"); String language = null; String country = null; String variant = null; if (tokenizer.hasMoreElements()) { language = tokenizer.nextToken(); } if (tokenizer.hasMoreElements()) { country = tokenizer.nextToken(); } if (tokenizer.hasMoreElements()) { variant = tokenizer.nextToken(); } if (country == null && variant == null) { return new Locale(language); } else if (variant == null) { return new Locale(language, country); } else { return new Locale(language, country, variant); } } @Override public String toString() { return LocaleTypeAdapter.class.getSimpleName(); } } @SuppressWarnings("unchecked") private static final class CollectionTypeAdapter implements JsonSerializer<Collection>, JsonDeserializer<Collection> { public JsonElement serialize(Collection src, Type typeOfSrc, JsonSerializationContext context) { if (src == null) { return JsonNull.INSTANCE; } JsonArray array = new JsonArray(); Type childGenericType = null; if (typeOfSrc instanceof ParameterizedType) { Class<?> rawTypeOfSrc = $Gson$Types.getRawType(typeOfSrc); childGenericType = $Gson$Types.getCollectionElementType( typeOfSrc, rawTypeOfSrc); } for (Object child : src) { if (child == null) { array.add(JsonNull.INSTANCE); } else { Type childType = (childGenericType == null || childGenericType == Object.class) ? child .getClass() : childGenericType; JsonElement element = context.serialize(child, childType, false, false); array.add(element); } } return array; } public Collection deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { if (json.isJsonNull()) { return null; } // Use ObjectConstructor to create instance instead of hard-coding a // specific type. // This handles cases where users are using their own subclass of // Collection. Collection collection = constructCollectionType(typeOfT, context); Type childType = $Gson$Types.getCollectionElementType(typeOfT, $Gson$Types.getRawType(typeOfT)); for (JsonElement childElement : json.getAsJsonArray()) { if (childElement == null || childElement.isJsonNull()) { collection.add(null); } else { Object value = context.deserialize(childElement, childType); collection.add(value); } } return collection; } private Collection constructCollectionType(Type collectionType, JsonDeserializationContext context) { return context.construct(collectionType); } } private static final class BigDecimalTypeAdapter implements JsonSerializer<BigDecimal>, JsonDeserializer<BigDecimal> { public JsonElement serialize(BigDecimal src, Type typeOfSrc, JsonSerializationContext context) { return new JsonPrimitive(src); } public BigDecimal deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { try { return json.getAsBigDecimal(); } catch (NumberFormatException e) { throw new JsonSyntaxException(e); } catch (UnsupportedOperationException e) { throw new JsonSyntaxException(e); } catch (IllegalStateException e) { throw new JsonSyntaxException(e); } } @Override public String toString() { return BigDecimalTypeAdapter.class.getSimpleName(); } } private static final class BigIntegerTypeAdapter implements JsonSerializer<BigInteger>, JsonDeserializer<BigInteger> { public JsonElement serialize(BigInteger src, Type typeOfSrc, JsonSerializationContext context) { return new JsonPrimitive(src); } public BigInteger deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { try { return json.getAsBigInteger(); } catch (NumberFormatException e) { throw new JsonSyntaxException(e); } catch (UnsupportedOperationException e) { throw new JsonSyntaxException(e); } catch (IllegalStateException e) { throw new JsonSyntaxException(e); } } @Override public String toString() { return BigIntegerTypeAdapter.class.getSimpleName(); } } private static final class NumberTypeAdapter implements JsonSerializer<Number>, JsonDeserializer<Number> { public JsonElement serialize(Number src, Type typeOfSrc, JsonSerializationContext context) { return new JsonPrimitive(src); } public Number deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { try { return json.getAsNumber(); } catch (NumberFormatException e) { throw new JsonSyntaxException(e); } catch (UnsupportedOperationException e) { throw new JsonSyntaxException(e); } catch (IllegalStateException e) { throw new JsonSyntaxException(e); } } @Override public String toString() { return NumberTypeAdapter.class.getSimpleName(); } } private static final class LongSerializer implements JsonSerializer<Long> { private final LongSerializationPolicy longSerializationPolicy; private LongSerializer(LongSerializationPolicy longSerializationPolicy) { this.longSerializationPolicy = longSerializationPolicy; } public JsonElement serialize(Long src, Type typeOfSrc, JsonSerializationContext context) { return longSerializationPolicy.serialize(src); } @Override public String toString() { return LongSerializer.class.getSimpleName(); } } private static final class LongDeserializer implements JsonDeserializer<Long> { public Long deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { try { return json.getAsLong(); } catch (NumberFormatException e) { throw new JsonSyntaxException(e); } catch (UnsupportedOperationException e) { throw new JsonSyntaxException(e); } catch (IllegalStateException e) { throw new JsonSyntaxException(e); } } @Override public String toString() { return LongDeserializer.class.getSimpleName(); } } private static final class IntegerTypeAdapter implements JsonSerializer<Integer>, JsonDeserializer<Integer> { public JsonElement serialize(Integer src, Type typeOfSrc, JsonSerializationContext context) { return new JsonPrimitive(src); } public Integer deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { try { return json.getAsInt(); } catch (NumberFormatException e) { throw new JsonSyntaxException(e); } catch (UnsupportedOperationException e) { throw new JsonSyntaxException(e); } catch (IllegalStateException e) { throw new JsonSyntaxException(e); } } @Override public String toString() { return IntegerTypeAdapter.class.getSimpleName(); } } private static final class ShortTypeAdapter implements JsonSerializer<Short>, JsonDeserializer<Short> { public JsonElement serialize(Short src, Type typeOfSrc, JsonSerializationContext context) { return new JsonPrimitive(src); } public Short deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { try { return json.getAsShort(); } catch (NumberFormatException e) { throw new JsonSyntaxException(e); } catch (UnsupportedOperationException e) { throw new JsonSyntaxException(e); } catch (IllegalStateException e) { throw new JsonSyntaxException(e); } } @Override public String toString() { return ShortTypeAdapter.class.getSimpleName(); } } private static final class ByteTypeAdapter implements JsonSerializer<Byte>, JsonDeserializer<Byte> { public JsonElement serialize(Byte src, Type typeOfSrc, JsonSerializationContext context) { return new JsonPrimitive(src); } public Byte deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { try { return json.getAsByte(); } catch (NumberFormatException e) { throw new JsonSyntaxException(e); } catch (UnsupportedOperationException e) { throw new JsonSyntaxException(e); } catch (IllegalStateException e) { throw new JsonSyntaxException(e); } } @Override public String toString() { return ByteTypeAdapter.class.getSimpleName(); } } static final class FloatSerializer implements JsonSerializer<Float> { private final boolean serializeSpecialFloatingPointValues; FloatSerializer(boolean serializeSpecialDoubleValues) { this.serializeSpecialFloatingPointValues = serializeSpecialDoubleValues; } public JsonElement serialize(Float src, Type typeOfSrc, JsonSerializationContext context) { if (!serializeSpecialFloatingPointValues) { if (Float.isNaN(src) || Float.isInfinite(src)) { throw new IllegalArgumentException( src + " is not a valid float value as per JSON specification. To override this" + " behavior, use GsonBuilder.serializeSpecialFloatingPointValues() method."); } } return new JsonPrimitive(src); } } private static final class FloatDeserializer implements JsonDeserializer<Float> { public Float deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { try { return json.getAsFloat(); } catch (NumberFormatException e) { throw new JsonSyntaxException(e); } catch (UnsupportedOperationException e) { throw new JsonSyntaxException(e); } catch (IllegalStateException e) { throw new JsonSyntaxException(e); } } @Override public String toString() { return FloatDeserializer.class.getSimpleName(); } } static final class DoubleSerializer implements JsonSerializer<Double> { private final boolean serializeSpecialFloatingPointValues; DoubleSerializer(boolean serializeSpecialDoubleValues) { this.serializeSpecialFloatingPointValues = serializeSpecialDoubleValues; } public JsonElement serialize(Double src, Type typeOfSrc, JsonSerializationContext context) { if (!serializeSpecialFloatingPointValues) { if (Double.isNaN(src) || Double.isInfinite(src)) { throw new IllegalArgumentException( src + " is not a valid double value as per JSON specification. To override this" + " behavior, use GsonBuilder.serializeSpecialDoubleValues() method."); } } return new JsonPrimitive(src); } } private static final class DoubleDeserializer implements JsonDeserializer<Double> { public Double deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { try { return json.getAsDouble(); } catch (NumberFormatException e) { throw new JsonSyntaxException(e); } catch (UnsupportedOperationException e) { throw new JsonSyntaxException(e); } catch (IllegalStateException e) { throw new JsonSyntaxException(e); } } @Override public String toString() { return DoubleDeserializer.class.getSimpleName(); } } private static final class CharacterTypeAdapter implements JsonSerializer<Character>, JsonDeserializer<Character> { public JsonElement serialize(Character src, Type typeOfSrc, JsonSerializationContext context) { return new JsonPrimitive(src); } public Character deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { return json.getAsCharacter(); } @Override public String toString() { return CharacterTypeAdapter.class.getSimpleName(); } } private static final class StringTypeAdapter implements JsonSerializer<String>, JsonDeserializer<String> { public JsonElement serialize(String src, Type typeOfSrc, JsonSerializationContext context) { return new JsonPrimitive(src); } public String deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { return json.getAsString(); } @Override public String toString() { return StringTypeAdapter.class.getSimpleName(); } } private static final class StringBuilderTypeAdapter implements JsonSerializer<StringBuilder>, JsonDeserializer<StringBuilder> { public JsonElement serialize(StringBuilder src, Type typeOfSrc, JsonSerializationContext context) { return new JsonPrimitive(src.toString()); } public StringBuilder deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { return new StringBuilder(json.getAsString()); } @Override public String toString() { return StringBuilderTypeAdapter.class.getSimpleName(); } } private static final class StringBufferTypeAdapter implements JsonSerializer<StringBuffer>, JsonDeserializer<StringBuffer> { public JsonElement serialize(StringBuffer src, Type typeOfSrc, JsonSerializationContext context) { return new JsonPrimitive(src.toString()); } public StringBuffer deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { return new StringBuffer(json.getAsString()); } @Override public String toString() { return StringBufferTypeAdapter.class.getSimpleName(); } } private static final class BooleanTypeAdapter implements JsonSerializer<Boolean>, JsonDeserializer<Boolean> { public JsonElement serialize(Boolean src, Type typeOfSrc, JsonSerializationContext context) { return new JsonPrimitive(src); } public Boolean deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { try { return json.getAsBoolean(); } catch (UnsupportedOperationException e) { throw new JsonSyntaxException(e); } catch (IllegalStateException e) { throw new JsonSyntaxException(e); } } @Override public String toString() { return BooleanTypeAdapter.class.getSimpleName(); } } @SuppressWarnings("unchecked") private static final class DefaultConstructorCreator<T> implements InstanceCreator<T> { private final Class<? extends T> defaultInstance; private final DefaultConstructorAllocator allocator; public DefaultConstructorCreator(Class<? extends T> defaultInstance, DefaultConstructorAllocator allocator) { this.defaultInstance = defaultInstance; this.allocator = allocator; } public T createInstance(Type type) { Class<?> rawType = $Gson$Types.getRawType(type); try { T specificInstance = (T) allocator.newInstance(rawType); return (specificInstance == null) ? allocator .newInstance(defaultInstance) : specificInstance; } catch (Exception e) { throw new JsonIOException(e); } } @Override public String toString() { return DefaultConstructorCreator.class.getSimpleName(); } } }