| /* |
| * 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.google.gson; |
| |
| 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.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.Locale; |
| import java.util.Map; |
| import java.util.Properties; |
| import java.util.Set; |
| import java.util.SortedSet; |
| import java.util.StringTokenizer; |
| import java.util.TimeZone; |
| import java.util.TreeSet; |
| import java.util.UUID; |
| |
| /** |
| * 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("rawtypes") |
| 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 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 PropertiesCreator PROPERTIES_CREATOR = new PropertiesCreator(); |
| private static final TreeSetCreator TREE_SET_CREATOR = new TreeSetCreator(); |
| private static final HashSetCreator HASH_SET_CREATOR = new HashSetCreator(); |
| private static final GregorianCalendarTypeAdapter GREGORIAN_CALENDAR_TYPE_ADAPTER = |
| new GregorianCalendarTypeAdapter(); |
| |
| // 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); |
| map.register(URI.class, URI_TYPE_ADAPTER); |
| map.register(UUID.class, UUUID_TYPE_ADAPTER); |
| map.register(Locale.class, LOCALE_TYPE_ADAPTER); |
| map.register(Date.class, DATE_TYPE_ADAPTER); |
| map.register(java.sql.Date.class, JAVA_SQL_DATE_TYPE_ADAPTER); |
| map.register(Timestamp.class, DATE_TYPE_ADAPTER); |
| map.register(Time.class, TIME_TYPE_ADAPTER); |
| map.register(Calendar.class, GREGORIAN_CALENDAR_TYPE_ADAPTER); |
| map.register(GregorianCalendar.class, GREGORIAN_CALENDAR_TYPE_ADAPTER); |
| map.register(BigDecimal.class, BIG_DECIMAL_TYPE_ADAPTER); |
| map.register(BigInteger.class, BIG_INTEGER_TYPE_ADAPTER); |
| |
| // Add primitive serializers |
| map.register(Boolean.class, BOOLEAN_TYPE_ADAPTER); |
| map.register(boolean.class, BOOLEAN_TYPE_ADAPTER); |
| map.register(Byte.class, BYTE_TYPE_ADAPTER); |
| map.register(byte.class, BYTE_TYPE_ADAPTER); |
| map.register(Character.class, CHARACTER_TYPE_ADAPTER); |
| map.register(char.class, CHARACTER_TYPE_ADAPTER); |
| map.register(Integer.class, INTEGER_TYPE_ADAPTER); |
| map.register(int.class, INTEGER_TYPE_ADAPTER); |
| map.register(Number.class, NUMBER_TYPE_ADAPTER); |
| map.register(Short.class, SHORT_TYPE_ADAPTER); |
| map.register(short.class, SHORT_TYPE_ADAPTER); |
| map.register(String.class, STRING_TYPE_ADAPTER); |
| map.register(StringBuilder.class, STRING_BUILDER_TYPE_ADAPTER); |
| map.register(StringBuffer.class, STRING_BUFFER_TYPE_ADAPTER); |
| |
| map.makeUnmodifiable(); |
| return map; |
| } |
| |
| private static ParameterizedTypeHandlerMap<JsonSerializer<?>> createDefaultHierarchySerializers() { |
| ParameterizedTypeHandlerMap<JsonSerializer<?>> map = |
| new ParameterizedTypeHandlerMap<JsonSerializer<?>>(); |
| map.registerForTypeHierarchy(Enum.class, ENUM_TYPE_ADAPTER); |
| map.registerForTypeHierarchy(InetAddress.class, INET_ADDRESS_ADAPTER); |
| map.registerForTypeHierarchy(Collection.class, COLLECTION_TYPE_ADAPTER); |
| map.registerForTypeHierarchy(Map.class, MAP_TYPE_ADAPTER); |
| map.makeUnmodifiable(); |
| return map; |
| } |
| |
| private static ParameterizedTypeHandlerMap<JsonDeserializer<?>> createDefaultDeserializers() { |
| ParameterizedTypeHandlerMap<JsonDeserializer<?>> map = |
| new ParameterizedTypeHandlerMap<JsonDeserializer<?>>(); |
| map.register(URL.class, wrapDeserializer(URL_TYPE_ADAPTER)); |
| map.register(URI.class, wrapDeserializer(URI_TYPE_ADAPTER)); |
| map.register(UUID.class, wrapDeserializer(UUUID_TYPE_ADAPTER)); |
| map.register(Locale.class, wrapDeserializer(LOCALE_TYPE_ADAPTER)); |
| map.register(Date.class, wrapDeserializer(DATE_TYPE_ADAPTER)); |
| map.register(java.sql.Date.class, wrapDeserializer(JAVA_SQL_DATE_TYPE_ADAPTER)); |
| map.register(Timestamp.class, wrapDeserializer(TIMESTAMP_DESERIALIZER)); |
| map.register(Time.class, wrapDeserializer(TIME_TYPE_ADAPTER)); |
| map.register(Calendar.class, GREGORIAN_CALENDAR_TYPE_ADAPTER); |
| map.register(GregorianCalendar.class, GREGORIAN_CALENDAR_TYPE_ADAPTER); |
| map.register(BigDecimal.class, wrapDeserializer(BIG_DECIMAL_TYPE_ADAPTER)); |
| map.register(BigInteger.class, wrapDeserializer(BIG_INTEGER_TYPE_ADAPTER)); |
| |
| // Add primitive deserializers |
| map.register(Boolean.class, wrapDeserializer(BOOLEAN_TYPE_ADAPTER)); |
| map.register(boolean.class, wrapDeserializer(BOOLEAN_TYPE_ADAPTER)); |
| map.register(Byte.class, wrapDeserializer(BYTE_TYPE_ADAPTER)); |
| map.register(byte.class, wrapDeserializer(BYTE_TYPE_ADAPTER)); |
| map.register(Character.class, wrapDeserializer(CHARACTER_TYPE_ADAPTER)); |
| map.register(char.class, wrapDeserializer(CHARACTER_TYPE_ADAPTER)); |
| map.register(Double.class, wrapDeserializer(DOUBLE_TYPE_ADAPTER)); |
| map.register(double.class, wrapDeserializer(DOUBLE_TYPE_ADAPTER)); |
| map.register(Float.class, wrapDeserializer(FLOAT_TYPE_ADAPTER)); |
| map.register(float.class, wrapDeserializer(FLOAT_TYPE_ADAPTER)); |
| map.register(Integer.class, wrapDeserializer(INTEGER_TYPE_ADAPTER)); |
| map.register(int.class, wrapDeserializer(INTEGER_TYPE_ADAPTER)); |
| map.register(Long.class, wrapDeserializer(LONG_DESERIALIZER)); |
| map.register(long.class, wrapDeserializer(LONG_DESERIALIZER)); |
| map.register(Number.class, wrapDeserializer(NUMBER_TYPE_ADAPTER)); |
| map.register(Short.class, wrapDeserializer(SHORT_TYPE_ADAPTER)); |
| map.register(short.class, wrapDeserializer(SHORT_TYPE_ADAPTER)); |
| map.register(String.class, wrapDeserializer(STRING_TYPE_ADAPTER)); |
| map.register(StringBuilder.class, wrapDeserializer(STRING_BUILDER_TYPE_ADAPTER)); |
| map.register(StringBuffer.class, wrapDeserializer(STRING_BUFFER_TYPE_ADAPTER)); |
| |
| map.makeUnmodifiable(); |
| return map; |
| } |
| |
| private static ParameterizedTypeHandlerMap<JsonDeserializer<?>> createDefaultHierarchyDeserializers() { |
| ParameterizedTypeHandlerMap<JsonDeserializer<?>> map = |
| new ParameterizedTypeHandlerMap<JsonDeserializer<?>>(); |
| map.registerForTypeHierarchy(Enum.class, wrapDeserializer(ENUM_TYPE_ADAPTER)); |
| map.registerForTypeHierarchy(InetAddress.class, wrapDeserializer(INET_ADDRESS_ADAPTER)); |
| map.registerForTypeHierarchy(Collection.class, wrapDeserializer(COLLECTION_TYPE_ADAPTER)); |
| map.registerForTypeHierarchy(Map.class, wrapDeserializer(MAP_TYPE_ADAPTER)); |
| map.makeUnmodifiable(); |
| return map; |
| } |
| |
| private static ParameterizedTypeHandlerMap<InstanceCreator<?>> createDefaultInstanceCreators() { |
| ParameterizedTypeHandlerMap<InstanceCreator<?>> map = |
| new ParameterizedTypeHandlerMap<InstanceCreator<?>>(); |
| map.registerForTypeHierarchy(Map.class, MAP_TYPE_ADAPTER); |
| |
| // Add Collection type instance creators |
| map.registerForTypeHierarchy(Collection.class, COLLECTION_TYPE_ADAPTER); |
| |
| map.registerForTypeHierarchy(Set.class, HASH_SET_CREATOR); |
| map.registerForTypeHierarchy(SortedSet.class, TREE_SET_CREATOR); |
| map.register(Properties.class, PROPERTIES_CREATOR); |
| map.makeUnmodifiable(); |
| return map; |
| } |
| |
| @SuppressWarnings({"unchecked", "rawtypes"}) |
| 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; |
| } |
| |
| static 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)); |
| } |
| |
| public 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"); |
| } |
| 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 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 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 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 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 class DefaultInetAddressAdapter |
| implements JsonDeserializer<InetAddress>, JsonSerializer<InetAddress> { |
| |
| public InetAddress deserialize(JsonElement json, Type typeOfT, |
| JsonDeserializationContext context) throws JsonParseException { |
| try { |
| return InetAddress.getByName(json.getAsString()); |
| } catch (UnknownHostException e) { |
| throw new JsonParseException(e); |
| } |
| } |
| |
| public JsonElement serialize(InetAddress src, Type typeOfSrc, |
| JsonSerializationContext context) { |
| return new JsonPrimitive(src.getHostAddress()); |
| } |
| } |
| |
| @SuppressWarnings("unchecked") |
| private static class EnumTypeAdapter<T extends Enum<T>> |
| 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 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 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 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 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", "rawtypes"}) |
| private static class CollectionTypeAdapter implements JsonSerializer<Collection>, |
| JsonDeserializer<Collection>, InstanceCreator<Collection> { |
| public JsonElement serialize(Collection src, Type typeOfSrc, JsonSerializationContext context) { |
| if (src == null) { |
| return JsonNull.createJsonNull(); |
| } |
| JsonArray array = new JsonArray(); |
| Type childGenericType = null; |
| if (typeOfSrc instanceof ParameterizedType) { |
| Class<?> rawTypeOfSrc = Types.getRawType(typeOfSrc); |
| childGenericType = Types.getCollectionElementType(typeOfSrc, rawTypeOfSrc); |
| } |
| for (Object child : src) { |
| if (child == null) { |
| array.add(JsonNull.createJsonNull()); |
| } else { |
| Type childType = (childGenericType == null || childGenericType == Object.class) |
| ? child.getClass() : childGenericType; |
| JsonElement element = context.serialize(child, childType); |
| 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 = Types.getCollectionElementType(typeOfT, 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) { |
| JsonDeserializationContextDefault contextImpl = (JsonDeserializationContextDefault) context; |
| ObjectConstructor objectConstructor = contextImpl.getObjectConstructor(); |
| return (Collection) objectConstructor.construct(collectionType); |
| } |
| |
| public Collection createInstance(Type type) { |
| return new LinkedList(); |
| } |
| } |
| |
| private static class PropertiesCreator implements InstanceCreator<Properties> { |
| public Properties createInstance(Type type) { |
| return new Properties(); |
| } |
| } |
| |
| @SuppressWarnings({"unchecked", "rawtypes"}) |
| static class MapTypeAdapter implements JsonSerializer<Map>, JsonDeserializer<Map>, |
| InstanceCreator<Map> { |
| |
| public JsonElement serialize(Map src, Type typeOfSrc, JsonSerializationContext context) { |
| JsonObject map = new JsonObject(); |
| Type childGenericType = null; |
| if (typeOfSrc instanceof ParameterizedType) { |
| Class<?> rawTypeOfSrc = Types.getRawType(typeOfSrc); |
| childGenericType = Types.getMapKeyAndValueTypes(typeOfSrc, rawTypeOfSrc)[1]; |
| } |
| |
| for (Map.Entry entry : (Set<Map.Entry>) src.entrySet()) { |
| Object value = entry.getValue(); |
| |
| JsonElement valueElement; |
| if (value == null) { |
| valueElement = JsonNull.createJsonNull(); |
| } else { |
| Type childType = (childGenericType == null) |
| ? value.getClass() : childGenericType; |
| valueElement = context.serialize(value, childType); |
| } |
| map.add(String.valueOf(entry.getKey()), valueElement); |
| } |
| return map; |
| } |
| |
| public Map deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) |
| throws JsonParseException { |
| // Use ObjectConstructor to create instance instead of hard-coding a specific type. |
| // This handles cases where users are using their own subclass of Map. |
| Map<Object, Object> map = constructMapType(typeOfT, context); |
| Type[] keyAndValueTypes = Types.getMapKeyAndValueTypes(typeOfT, Types.getRawType(typeOfT)); |
| for (Map.Entry<String, JsonElement> entry : json.getAsJsonObject().entrySet()) { |
| Object key = context.deserialize(new JsonPrimitive(entry.getKey()), keyAndValueTypes[0]); |
| Object value = context.deserialize(entry.getValue(), keyAndValueTypes[1]); |
| map.put(key, value); |
| } |
| return map; |
| } |
| |
| private Map constructMapType(Type mapType, JsonDeserializationContext context) { |
| JsonDeserializationContextDefault contextImpl = (JsonDeserializationContextDefault) context; |
| ObjectConstructor objectConstructor = contextImpl.getObjectConstructor(); |
| return (Map) objectConstructor.construct(mapType); |
| } |
| |
| public Map createInstance(Type type) { |
| return new LinkedHashMap(); |
| } |
| |
| @Override |
| public String toString() { |
| return MapTypeAdapter.class.getSimpleName(); |
| } |
| } |
| |
| private static class BigDecimalTypeAdapter |
| implements JsonSerializer<BigDecimal>, JsonDeserializer<BigDecimal> { |
| public JsonElement serialize(BigDecimal src, Type typeOfSrc, JsonSerializationContext context) { |
| return new JsonPrimitive(src); |
| } |
| |
| public BigDecimal deserialize(JsonElement json, Type typeOfT, |
| JsonDeserializationContext context) throws JsonParseException { |
| return json.getAsBigDecimal(); |
| } |
| |
| @Override |
| public String toString() { |
| return BigDecimalTypeAdapter.class.getSimpleName(); |
| } |
| } |
| |
| private static 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 { |
| return json.getAsBigInteger(); |
| } |
| |
| @Override |
| public String toString() { |
| return BigIntegerTypeAdapter.class.getSimpleName(); |
| } |
| } |
| |
| private static 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 { |
| return json.getAsNumber(); |
| } |
| |
| @Override |
| public String toString() { |
| return NumberTypeAdapter.class.getSimpleName(); |
| } |
| } |
| |
| private static 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 class LongDeserializer implements JsonDeserializer<Long> { |
| public Long deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) |
| throws JsonParseException { |
| return json.getAsLong(); |
| } |
| |
| @Override |
| public String toString() { |
| return LongDeserializer.class.getSimpleName(); |
| } |
| } |
| |
| private static 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 { |
| return json.getAsInt(); |
| } |
| |
| @Override |
| public String toString() { |
| return IntegerTypeAdapter.class.getSimpleName(); |
| } |
| } |
| |
| private static 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 { |
| return json.getAsShort(); |
| } |
| |
| @Override |
| public String toString() { |
| return ShortTypeAdapter.class.getSimpleName(); |
| } |
| } |
| |
| private static class ByteTypeAdapter implements JsonSerializer<Byte>, JsonDeserializer<Byte> { |
| public JsonElement serialize(Byte src, Type typeOfSrc, JsonSerializationContext context) { |
| return new JsonPrimitive(src); |
| } |
| |
| public Byte deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) |
| throws JsonParseException { |
| return json.getAsByte(); |
| } |
| |
| @Override |
| public String toString() { |
| return ByteTypeAdapter.class.getSimpleName(); |
| } |
| } |
| |
| static 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 class FloatDeserializer implements JsonDeserializer<Float> { |
| public Float deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) |
| throws JsonParseException { |
| return json.getAsFloat(); |
| } |
| |
| @Override |
| public String toString() { |
| return FloatDeserializer.class.getSimpleName(); |
| } |
| } |
| |
| static 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 class DoubleDeserializer implements JsonDeserializer<Double> { |
| public Double deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) |
| throws JsonParseException { |
| return json.getAsDouble(); |
| } |
| |
| @Override |
| public String toString() { |
| return DoubleDeserializer.class.getSimpleName(); |
| } |
| } |
| |
| private static 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 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 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 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 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 { |
| return json.getAsBoolean(); |
| } |
| |
| @Override |
| public String toString() { |
| return BooleanTypeAdapter.class.getSimpleName(); |
| } |
| } |
| |
| private static class TreeSetCreator implements InstanceCreator<TreeSet<?>> { |
| public TreeSet<?> createInstance(Type type) { |
| return new TreeSet<Object>(); |
| } |
| @Override |
| public String toString() { |
| return TreeSetCreator.class.getSimpleName(); |
| } |
| } |
| |
| private static class HashSetCreator implements InstanceCreator<HashSet<?>> { |
| public HashSet<?> createInstance(Type type) { |
| return new HashSet<Object>(); |
| } |
| @Override |
| public String toString() { |
| return HashSetCreator.class.getSimpleName(); |
| } |
| } |
| } |