416 lines
16 KiB
Java
416 lines
16 KiB
Java
/*
|
|
* 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.InvocationTargetException;
|
|
import java.lang.reflect.Method;
|
|
import java.lang.reflect.Type;
|
|
import java.math.BigDecimal;
|
|
import java.math.BigInteger;
|
|
import java.net.MalformedURLException;
|
|
import java.net.URI;
|
|
import java.net.URISyntaxException;
|
|
import java.net.URL;
|
|
import java.text.DateFormat;
|
|
import java.text.ParseException;
|
|
import java.text.SimpleDateFormat;
|
|
import java.util.Collection;
|
|
import java.util.Date;
|
|
import java.util.Iterator;
|
|
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.TreeSet;
|
|
|
|
/**
|
|
* 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(DateFormat.DEFAULT);
|
|
@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 LocaleTypeAdapter LOCALE_TYPE_ADAPTER = new LocaleTypeAdapter();
|
|
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 BooleanCreator BOOLEAN_CREATOR = new BooleanCreator();
|
|
private static final ByteCreator BYTE_CREATOR = new ByteCreator();
|
|
private static final CharacterCreator CHARACTER_CREATOR = new CharacterCreator();
|
|
private static final DoubleCreator DOUBLE_CREATOR = new DoubleCreator();
|
|
private static final FloatCreator FLOAT_CREATOR = new FloatCreator();
|
|
private static final IntegerCreator INTEGER_CREATOR = new IntegerCreator();
|
|
private static final LongCreator LONG_CREATOR = new LongCreator();
|
|
private static final ShortCreator SHORT_CREATOR = new ShortCreator();
|
|
private static final LinkedListCreator LINKED_LIST_CREATOR = new LinkedListCreator();
|
|
private static final TreeSetCreator TREE_SET_CREATOR = new TreeSetCreator();
|
|
|
|
// 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.
|
|
static final ParameterizedTypeHandlerMap<JsonSerializer<?>> DEFAULT_SERIALIZERS =
|
|
getDefaultSerializers();
|
|
static final ParameterizedTypeHandlerMap<JsonDeserializer<?>> DEFAULT_DESERIALIZERS =
|
|
getDefaultDeserializers();
|
|
static final ParameterizedTypeHandlerMap<InstanceCreator<?>> DEFAULT_INSTANCE_CREATORS =
|
|
getDefaultInstanceCreators();
|
|
|
|
private static ParameterizedTypeHandlerMap<JsonSerializer<?>> getDefaultSerializers() {
|
|
ParameterizedTypeHandlerMap<JsonSerializer<?>> map =
|
|
new ParameterizedTypeHandlerMap<JsonSerializer<?>>();
|
|
|
|
map.register(Enum.class, wrapSerializer(ENUM_TYPE_ADAPTER));
|
|
map.register(URL.class, wrapSerializer(URL_TYPE_ADAPTER));
|
|
map.register(URI.class, wrapSerializer(URI_TYPE_ADAPTER));
|
|
map.register(Locale.class, wrapSerializer(LOCALE_TYPE_ADAPTER));
|
|
map.register(Map.class, wrapSerializer(MAP_TYPE_ADAPTER));
|
|
map.register(Date.class, wrapSerializer(DATE_TYPE_ADAPTER));
|
|
map.register(BigDecimal.class, wrapSerializer(BIG_DECIMAL_TYPE_ADAPTER));
|
|
map.register(BigInteger.class, wrapSerializer(BIG_INTEGER_TYPE_ADAPTER));
|
|
map.makeUnmodifiable();
|
|
return map;
|
|
}
|
|
|
|
private static ParameterizedTypeHandlerMap<JsonDeserializer<?>> getDefaultDeserializers() {
|
|
ParameterizedTypeHandlerMap<JsonDeserializer<?>> map =
|
|
new ParameterizedTypeHandlerMap<JsonDeserializer<?>>();
|
|
map.register(Enum.class, wrapDeserializer(ENUM_TYPE_ADAPTER));
|
|
map.register(URL.class, wrapDeserializer(URL_TYPE_ADAPTER));
|
|
map.register(URI.class, wrapDeserializer(URI_TYPE_ADAPTER));
|
|
map.register(Locale.class, wrapDeserializer(LOCALE_TYPE_ADAPTER));
|
|
map.register(Map.class, wrapDeserializer(MAP_TYPE_ADAPTER));
|
|
map.register(Date.class, wrapDeserializer(DATE_TYPE_ADAPTER));
|
|
map.register(BigDecimal.class, wrapDeserializer(BIG_DECIMAL_TYPE_ADAPTER));
|
|
map.register(BigInteger.class, wrapDeserializer(BIG_INTEGER_TYPE_ADAPTER));
|
|
map.makeUnmodifiable();
|
|
return map;
|
|
}
|
|
|
|
private static ParameterizedTypeHandlerMap<InstanceCreator<?>> getDefaultInstanceCreators() {
|
|
ParameterizedTypeHandlerMap<InstanceCreator<?>> map =
|
|
new ParameterizedTypeHandlerMap<InstanceCreator<?>>();
|
|
map.register(Enum.class, ENUM_TYPE_ADAPTER);
|
|
map.register(URL.class, URL_TYPE_ADAPTER);
|
|
map.register(Locale.class, LOCALE_TYPE_ADAPTER);
|
|
map.register(Map.class, MAP_TYPE_ADAPTER);
|
|
map.register(BigDecimal.class, BIG_DECIMAL_TYPE_ADAPTER);
|
|
map.register(BigInteger.class, BIG_INTEGER_TYPE_ADAPTER);
|
|
|
|
// Add primitive instance creators
|
|
map.register(Boolean.class, BOOLEAN_CREATOR);
|
|
map.register(boolean.class, BOOLEAN_CREATOR);
|
|
map.register(Byte.class, BYTE_CREATOR);
|
|
map.register(byte.class, BYTE_CREATOR);
|
|
map.register(Character.class, CHARACTER_CREATOR);
|
|
map.register(char.class, CHARACTER_CREATOR);
|
|
map.register(Double.class, DOUBLE_CREATOR);
|
|
map.register(double.class, DOUBLE_CREATOR);
|
|
map.register(Float.class, FLOAT_CREATOR);
|
|
map.register(float.class, FLOAT_CREATOR);
|
|
map.register(Integer.class, INTEGER_CREATOR);
|
|
map.register(int.class, INTEGER_CREATOR);
|
|
map.register(Long.class, LONG_CREATOR);
|
|
map.register(long.class, LONG_CREATOR);
|
|
map.register(Short.class, SHORT_CREATOR);
|
|
map.register(short.class, SHORT_CREATOR);
|
|
|
|
map.register(Collection.class, LINKED_LIST_CREATOR);
|
|
map.register(List.class, LINKED_LIST_CREATOR);
|
|
map.register(Queue.class, LINKED_LIST_CREATOR);
|
|
|
|
map.register(Set.class, TREE_SET_CREATOR);
|
|
map.register(SortedSet.class, TREE_SET_CREATOR);
|
|
map.makeUnmodifiable();
|
|
return map;
|
|
}
|
|
|
|
@SuppressWarnings("unchecked")
|
|
private static JsonSerializer<?> wrapSerializer(JsonSerializer<?> serializer) {
|
|
return new JsonSerializerExceptionWrapper(serializer);
|
|
}
|
|
|
|
@SuppressWarnings("unchecked")
|
|
private static JsonDeserializer<?> wrapDeserializer(JsonDeserializer<?> deserializer) {
|
|
return new JsonDeserializerExceptionWrapper(deserializer);
|
|
}
|
|
|
|
static class DefaultDateTypeAdapter implements JsonSerializer<Date>, JsonDeserializer<Date> {
|
|
|
|
private final DateFormat format;
|
|
|
|
public DefaultDateTypeAdapter(String datePattern) {
|
|
this.format = new SimpleDateFormat(datePattern);
|
|
}
|
|
|
|
public DefaultDateTypeAdapter(int style) {
|
|
this.format = DateFormat.getDateInstance(style);
|
|
}
|
|
|
|
public JsonElement serialize(Date src, Type typeOfSrc, JsonSerializationContext context) {
|
|
String dateFormatAsString = format.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");
|
|
}
|
|
|
|
try {
|
|
return format.parse(json.getAsString());
|
|
} catch (ParseException e) {
|
|
throw new JsonParseException(e);
|
|
}
|
|
}
|
|
}
|
|
|
|
@SuppressWarnings("unchecked")
|
|
private static class EnumTypeAdapter<T extends Enum<T>> implements JsonSerializer<T>,
|
|
JsonDeserializer<T>, InstanceCreator<Enum<?>> {
|
|
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());
|
|
}
|
|
public Enum<?> createInstance(Type type) {
|
|
Class<Enum<?>> enumClass = (Class<Enum<?>>) type;
|
|
try {
|
|
Method valuesMethod = enumClass.getMethod("values");
|
|
Enum<?>[] enums = (Enum<?>[]) valuesMethod.invoke(null);
|
|
return enums[0];
|
|
} catch (NoSuchMethodException e) {
|
|
throw new RuntimeException(e);
|
|
} catch (IllegalAccessException e) {
|
|
throw new RuntimeException(e);
|
|
} catch (InvocationTargetException e) {
|
|
throw new RuntimeException(e);
|
|
}
|
|
}
|
|
}
|
|
|
|
private static class UrlTypeAdapter implements JsonSerializer<URL>, JsonDeserializer<URL>,
|
|
InstanceCreator<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 JsonParseException(e);
|
|
}
|
|
}
|
|
public URL createInstance(Type type) {
|
|
try {
|
|
return new URL("http://google.com/");
|
|
} catch (MalformedURLException e) {
|
|
throw new RuntimeException(e);
|
|
}
|
|
}
|
|
}
|
|
|
|
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 JsonParseException(e);
|
|
}
|
|
}
|
|
}
|
|
|
|
private static class LocaleTypeAdapter implements JsonSerializer<Locale>,
|
|
JsonDeserializer<Locale>, InstanceCreator<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);
|
|
}
|
|
}
|
|
public Locale createInstance(Type type) {
|
|
return new Locale("en_US");
|
|
}
|
|
}
|
|
|
|
@SuppressWarnings("unchecked")
|
|
static class MapTypeAdapter implements JsonSerializer<Map>, JsonDeserializer<Map>,
|
|
InstanceCreator<Map> {
|
|
public JsonElement serialize(Map src, Type typeOfSrc, JsonSerializationContext context) {
|
|
JsonObject map = new JsonObject();
|
|
Type childType = new TypeInfoMap(typeOfSrc).getValueType();
|
|
for (Iterator iterator = src.entrySet().iterator(); iterator.hasNext(); ) {
|
|
Map.Entry entry = (Map.Entry) iterator.next();
|
|
JsonElement valueElement = context.serialize(entry.getValue(), childType);
|
|
map.add(entry.getKey().toString(), valueElement);
|
|
}
|
|
return map;
|
|
}
|
|
public Map deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
|
|
throws JsonParseException {
|
|
// Using linked hash map to preserve order in which elements are entered
|
|
Map<String, Object> map = new LinkedHashMap<String, Object>();
|
|
Type childType = new TypeInfoMap(typeOfT).getValueType();
|
|
for (Map.Entry<String, JsonElement> entry : json.getAsJsonObject().entrySet()) {
|
|
Object value = context.deserialize(entry.getValue(), childType);
|
|
map.put(entry.getKey(), value);
|
|
}
|
|
return map;
|
|
}
|
|
public Map createInstance(Type type) {
|
|
return new LinkedHashMap();
|
|
}
|
|
}
|
|
|
|
private static class BigDecimalTypeAdapter implements JsonSerializer<BigDecimal>,
|
|
JsonDeserializer<BigDecimal>, InstanceCreator<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();
|
|
}
|
|
|
|
public BigDecimal createInstance(Type type) {
|
|
return new BigDecimal(0);
|
|
}
|
|
}
|
|
|
|
private static class BigIntegerTypeAdapter implements JsonSerializer<BigInteger>,
|
|
JsonDeserializer<BigInteger>, InstanceCreator<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();
|
|
}
|
|
|
|
public BigInteger createInstance(Type type) {
|
|
return new BigInteger("0");
|
|
}
|
|
}
|
|
|
|
private static class LongCreator implements InstanceCreator<Long> {
|
|
public Long createInstance(Type type) {
|
|
return new Long(0L);
|
|
}
|
|
}
|
|
|
|
private static class IntegerCreator implements InstanceCreator<Integer> {
|
|
public Integer createInstance(Type type) {
|
|
return new Integer(0);
|
|
}
|
|
}
|
|
|
|
private static class ShortCreator implements InstanceCreator<Short> {
|
|
public Short createInstance(Type type) {
|
|
return new Short((short) 0);
|
|
}
|
|
}
|
|
|
|
private static class ByteCreator implements InstanceCreator<Byte> {
|
|
public Byte createInstance(Type type) {
|
|
return new Byte((byte) 0);
|
|
}
|
|
}
|
|
|
|
private static class FloatCreator implements InstanceCreator<Float> {
|
|
public Float createInstance(Type type) {
|
|
return new Float(0F);
|
|
}
|
|
}
|
|
|
|
private static class DoubleCreator implements InstanceCreator<Double> {
|
|
public Double createInstance(Type type) {
|
|
return new Double(0D);
|
|
}
|
|
}
|
|
|
|
private static class CharacterCreator implements InstanceCreator<Character> {
|
|
public Character createInstance(Type type) {
|
|
return new Character((char) 0);
|
|
}
|
|
}
|
|
|
|
private static class BooleanCreator implements InstanceCreator<Boolean> {
|
|
public Boolean createInstance(Type type) {
|
|
return new Boolean(false);
|
|
}
|
|
}
|
|
|
|
private static class LinkedListCreator implements InstanceCreator<LinkedList<?>> {
|
|
public LinkedList<?> createInstance(Type type) {
|
|
return new LinkedList<Object>();
|
|
}
|
|
}
|
|
|
|
private static class TreeSetCreator implements InstanceCreator<TreeSet<?>> {
|
|
public TreeSet<?> createInstance(Type type) {
|
|
return new TreeSet<Object>();
|
|
}
|
|
}
|
|
}
|