Adapter for Object.class
This commit is contained in:
parent
9fb39c89ea
commit
3aeb70e030
@ -28,12 +28,12 @@ import java.util.Map;
|
|||||||
abstract class BaseMapTypeAdapter
|
abstract class BaseMapTypeAdapter
|
||||||
implements JsonSerializer<Map<?, ?>>, JsonDeserializer<Map<?, ?>> {
|
implements JsonSerializer<Map<?, ?>>, JsonDeserializer<Map<?, ?>> {
|
||||||
|
|
||||||
protected static final JsonElement serialize(JsonSerializationContext context,
|
protected static JsonElement serialize(JsonSerializationContext context,
|
||||||
Object src, Type srcType) {
|
Object src, Type srcType) {
|
||||||
return context.serialize(src, srcType, false, false);
|
return context.serialize(src, srcType, false, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static final Map<Object, Object> constructMapType(
|
protected static Map<Object, Object> constructMapType(
|
||||||
Type mapType, JsonDeserializationContext context) {
|
Type mapType, JsonDeserializationContext context) {
|
||||||
return context.construct(mapType);
|
return context.construct(mapType);
|
||||||
}
|
}
|
||||||
|
@ -21,9 +21,10 @@ import com.google.gson.internal.bind.ArrayTypeAdapter;
|
|||||||
import com.google.gson.internal.bind.BigDecimalTypeAdapter;
|
import com.google.gson.internal.bind.BigDecimalTypeAdapter;
|
||||||
import com.google.gson.internal.bind.BigIntegerTypeAdapter;
|
import com.google.gson.internal.bind.BigIntegerTypeAdapter;
|
||||||
import com.google.gson.internal.bind.CollectionTypeAdapter;
|
import com.google.gson.internal.bind.CollectionTypeAdapter;
|
||||||
|
import com.google.gson.internal.bind.GsonCompatibleMapTypeAdapter;
|
||||||
import com.google.gson.internal.bind.MiniGson;
|
import com.google.gson.internal.bind.MiniGson;
|
||||||
|
import com.google.gson.internal.bind.ObjectTypeAdapter;
|
||||||
import com.google.gson.internal.bind.ReflectiveTypeAdapter;
|
import com.google.gson.internal.bind.ReflectiveTypeAdapter;
|
||||||
import com.google.gson.internal.bind.StringToValueMapTypeAdapter;
|
|
||||||
import com.google.gson.internal.bind.TypeAdapter;
|
import com.google.gson.internal.bind.TypeAdapter;
|
||||||
import com.google.gson.internal.bind.TypeAdapters;
|
import com.google.gson.internal.bind.TypeAdapters;
|
||||||
import com.google.gson.reflect.TypeToken;
|
import com.google.gson.reflect.TypeToken;
|
||||||
@ -34,7 +35,6 @@ import com.google.gson.stream.MalformedJsonException;
|
|||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.Reader;
|
import java.io.Reader;
|
||||||
import java.io.StringReader;
|
|
||||||
import java.io.StringWriter;
|
import java.io.StringWriter;
|
||||||
import java.io.Writer;
|
import java.io.Writer;
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
@ -246,10 +246,11 @@ public final class Gson {
|
|||||||
.typeAdapter(BigDecimal.class, new BigDecimalTypeAdapter())
|
.typeAdapter(BigDecimal.class, new BigDecimalTypeAdapter())
|
||||||
.typeAdapter(BigInteger.class, new BigIntegerTypeAdapter())
|
.typeAdapter(BigInteger.class, new BigIntegerTypeAdapter())
|
||||||
.factory(excludedTypeFactory)
|
.factory(excludedTypeFactory)
|
||||||
|
.factory(GsonCompatibleMapTypeAdapter.FACTORY)
|
||||||
.factory(new GsonToMiniGsonTypeAdapter(serializers, deserializers, serializeNulls))
|
.factory(new GsonToMiniGsonTypeAdapter(serializers, deserializers, serializeNulls))
|
||||||
.factory(CollectionTypeAdapter.FACTORY)
|
.factory(CollectionTypeAdapter.FACTORY)
|
||||||
.factory(StringToValueMapTypeAdapter.FACTORY)
|
|
||||||
.factory(ArrayTypeAdapter.FACTORY)
|
.factory(ArrayTypeAdapter.FACTORY)
|
||||||
|
.factory(ObjectTypeAdapter.FACTORY)
|
||||||
.factory(reflectiveTypeAdapterFactory);
|
.factory(reflectiveTypeAdapterFactory);
|
||||||
|
|
||||||
this.miniGson = builder.build();
|
this.miniGson = builder.build();
|
||||||
|
@ -85,6 +85,18 @@ final class GsonToMiniGsonTypeAdapter implements TypeAdapter.Factory {
|
|||||||
TypeToken typeToken = TypeToken.get(typeOfT);
|
TypeToken typeToken = TypeToken.get(typeOfT);
|
||||||
return (T) miniGson.getAdapter(typeToken).fromJsonElement(json);
|
return (T) miniGson.getAdapter(typeToken).fromJsonElement(json);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override public <T> T construct(Type type) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public Object constructArray(Type type, int length) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public <T> T deserializeDefault(JsonElement json, Type typeOfT) throws JsonParseException {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -46,7 +46,10 @@ public class JsonDeserializationContext {
|
|||||||
this(null, null, null, null);
|
this(null, null, null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
/**
|
||||||
|
* TODO: remove this from the public API
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unchecked") @Deprecated
|
||||||
public <T> T construct(Type type) {
|
public <T> T construct(Type type) {
|
||||||
Object instance = objectConstructor.construct(type);
|
Object instance = objectConstructor.construct(type);
|
||||||
return (T) instance;
|
return (T) instance;
|
||||||
|
@ -56,12 +56,12 @@ public final class CollectionTypeAdapter<E> extends TypeAdapter<Collection<E>> {
|
|||||||
} else {
|
} else {
|
||||||
constructorType = rawType;
|
constructorType = rawType;
|
||||||
}
|
}
|
||||||
|
// TODO: Queue=LinkedList, SortedSet=TreeSet
|
||||||
|
|
||||||
Constructor<?> constructor;
|
Constructor<?> constructor = null;
|
||||||
try {
|
try {
|
||||||
constructor = constructorType.getConstructor();
|
constructor = constructorType.getConstructor();
|
||||||
} catch (NoSuchMethodException e) {
|
} catch (NoSuchMethodException ignored) {
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked") // create() doesn't define a type parameter
|
@SuppressWarnings("unchecked") // create() doesn't define a type parameter
|
||||||
@ -86,6 +86,9 @@ public final class CollectionTypeAdapter<E> extends TypeAdapter<Collection<E>> {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (constructor == null) {
|
||||||
|
throw new UnsupportedOperationException("TODO: use unsafeAllocator.newInstance");
|
||||||
|
}
|
||||||
Collection<E> collection = Reflection.newInstance(constructor);
|
Collection<E> collection = Reflection.newInstance(constructor);
|
||||||
reader.beginArray();
|
reader.beginArray();
|
||||||
while (reader.hasNext()) {
|
while (reader.hasNext()) {
|
||||||
|
@ -0,0 +1,104 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2011 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.internal.bind;
|
||||||
|
|
||||||
|
import com.google.gson.internal.$Gson$Types;
|
||||||
|
import com.google.gson.reflect.TypeToken;
|
||||||
|
import com.google.gson.stream.JsonReader;
|
||||||
|
import com.google.gson.stream.JsonToken;
|
||||||
|
import com.google.gson.stream.JsonWriter;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.lang.reflect.Constructor;
|
||||||
|
import java.lang.reflect.ParameterizedType;
|
||||||
|
import java.lang.reflect.Type;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adapt a map whose keys are any type.
|
||||||
|
*/
|
||||||
|
public final class GsonCompatibleMapTypeAdapter<V> extends TypeAdapter<Map<String, V>> {
|
||||||
|
public static final Factory FACTORY = new Factory() {
|
||||||
|
public <T> TypeAdapter<T> create(MiniGson context, TypeToken<T> typeToken) {
|
||||||
|
Type type = typeToken.getType();
|
||||||
|
|
||||||
|
Class<? super T> rawType = typeToken.getRawType();
|
||||||
|
if (!Map.class.isAssignableFrom(rawType)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
Type childGenericType = Object.class;
|
||||||
|
if (type instanceof ParameterizedType) {
|
||||||
|
Class<?> rawTypeOfSrc = $Gson$Types.getRawType(type);
|
||||||
|
childGenericType = $Gson$Types.getMapKeyAndValueTypes(type, rawTypeOfSrc)[1];
|
||||||
|
}
|
||||||
|
TypeAdapter valueAdapter = context.getAdapter(TypeToken.get(childGenericType));
|
||||||
|
|
||||||
|
Constructor<?> constructor;
|
||||||
|
try {
|
||||||
|
Class<?> constructorType = (rawType == Map.class) ? LinkedHashMap.class : rawType;
|
||||||
|
constructor = constructorType.getConstructor();
|
||||||
|
} catch (NoSuchMethodException e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked") // we don't define a type parameter for the key or value types
|
||||||
|
TypeAdapter<T> result = new GsonCompatibleMapTypeAdapter(valueAdapter, constructor);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
private final TypeAdapter<V> valueTypeAdapter;
|
||||||
|
private final Constructor<? extends Map<String, V>> constructor;
|
||||||
|
|
||||||
|
public GsonCompatibleMapTypeAdapter(TypeAdapter<V> valueTypeAdapter,
|
||||||
|
Constructor<? extends Map<String, V>> constructor) {
|
||||||
|
this.valueTypeAdapter = valueTypeAdapter;
|
||||||
|
this.constructor = constructor;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<String, V> read(JsonReader reader) throws IOException {
|
||||||
|
if (reader.peek() == JsonToken.NULL) {
|
||||||
|
reader.nextNull(); // TODO: does this belong here?
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, V> map = Reflection.newInstance(constructor);
|
||||||
|
reader.beginObject();
|
||||||
|
while (reader.hasNext()) {
|
||||||
|
String key = reader.nextName();
|
||||||
|
V value = valueTypeAdapter.read(reader);
|
||||||
|
map.put(key, value);
|
||||||
|
}
|
||||||
|
reader.endObject();
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void write(JsonWriter writer, Map<String, V> map) throws IOException {
|
||||||
|
if (map == null) {
|
||||||
|
writer.nullValue(); // TODO: better policy here?
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
writer.beginObject();
|
||||||
|
for (Map.Entry<String, V> entry : map.entrySet()) {
|
||||||
|
writer.name(entry.getKey());
|
||||||
|
valueTypeAdapter.write(writer, entry.getValue());
|
||||||
|
}
|
||||||
|
writer.endObject();
|
||||||
|
}
|
||||||
|
}
|
@ -62,6 +62,7 @@ public final class MiniGson {
|
|||||||
factories.add(CollectionTypeAdapter.FACTORY);
|
factories.add(CollectionTypeAdapter.FACTORY);
|
||||||
factories.add(StringToValueMapTypeAdapter.FACTORY);
|
factories.add(StringToValueMapTypeAdapter.FACTORY);
|
||||||
factories.add(ArrayTypeAdapter.FACTORY);
|
factories.add(ArrayTypeAdapter.FACTORY);
|
||||||
|
factories.add(ObjectTypeAdapter.FACTORY);
|
||||||
factories.add(ReflectiveTypeAdapter.FACTORY);
|
factories.add(ReflectiveTypeAdapter.FACTORY);
|
||||||
}
|
}
|
||||||
this.factories = Collections.unmodifiableList(factories);
|
this.factories = Collections.unmodifiableList(factories);
|
||||||
|
@ -0,0 +1,104 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2011 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.internal.bind;
|
||||||
|
|
||||||
|
import com.google.gson.reflect.TypeToken;
|
||||||
|
import com.google.gson.stream.JsonReader;
|
||||||
|
import com.google.gson.stream.JsonToken;
|
||||||
|
import com.google.gson.stream.JsonWriter;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adapts types whose static type is only 'Object'. Uses getClass() on
|
||||||
|
* serialization and a primitive/Map/List on deserialization.
|
||||||
|
*/
|
||||||
|
public final class ObjectTypeAdapter extends TypeAdapter<Object> {
|
||||||
|
public static final Factory FACTORY = new Factory() {
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
@Override public <T> TypeAdapter<T> create(MiniGson context, TypeToken<T> type) {
|
||||||
|
if (type.getRawType() == Object.class) {
|
||||||
|
return (TypeAdapter<T>) new ObjectTypeAdapter(context);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
private final MiniGson miniGson;
|
||||||
|
|
||||||
|
private ObjectTypeAdapter(MiniGson miniGson) {
|
||||||
|
this.miniGson = miniGson;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public Object read(JsonReader reader) throws IOException {
|
||||||
|
JsonToken token = reader.peek();
|
||||||
|
switch (token) {
|
||||||
|
case BEGIN_ARRAY:
|
||||||
|
List<Object> list = new ArrayList<Object>();
|
||||||
|
reader.beginArray();
|
||||||
|
while (reader.hasNext()) {
|
||||||
|
list.add(read(reader));
|
||||||
|
}
|
||||||
|
reader.endArray();
|
||||||
|
return list;
|
||||||
|
|
||||||
|
case BEGIN_OBJECT:
|
||||||
|
Map<String, Object> map = new LinkedHashMap<String, Object>();
|
||||||
|
reader.beginObject();
|
||||||
|
while (reader.hasNext()) {
|
||||||
|
map.put(reader.nextName(), read(reader));
|
||||||
|
}
|
||||||
|
reader.endObject();
|
||||||
|
return map;
|
||||||
|
|
||||||
|
case STRING:
|
||||||
|
return reader.nextString();
|
||||||
|
|
||||||
|
case NUMBER:
|
||||||
|
return reader.nextDouble();
|
||||||
|
|
||||||
|
case BOOLEAN:
|
||||||
|
return reader.nextBoolean();
|
||||||
|
|
||||||
|
case NULL:
|
||||||
|
reader.nextNull();
|
||||||
|
return null;
|
||||||
|
|
||||||
|
}
|
||||||
|
throw new IllegalStateException();
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
@Override public void write(JsonWriter writer, Object value) throws IOException {
|
||||||
|
if (value == null) {
|
||||||
|
writer.nullValue(); // TODO: better policy here?
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
TypeAdapter<Object> typeAdapter = (TypeAdapter<Object>) miniGson.getAdapter(value.getClass());
|
||||||
|
if (typeAdapter instanceof ObjectTypeAdapter) {
|
||||||
|
writer.beginObject();
|
||||||
|
writer.endObject();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
typeAdapter.write(writer, value);
|
||||||
|
}
|
||||||
|
}
|
@ -135,10 +135,10 @@ public final class ReflectiveTypeAdapter<T> extends TypeAdapter<T> {
|
|||||||
|
|
||||||
public static class FactoryImpl implements Factory {
|
public static class FactoryImpl implements Factory {
|
||||||
public boolean serializeField(Class<?> declaringClazz, Field f, Type declaredType) {
|
public boolean serializeField(Class<?> declaringClazz, Field f, Type declaredType) {
|
||||||
return true;
|
return !f.isSynthetic();
|
||||||
}
|
}
|
||||||
public boolean deserializeField(Class<?> declaringClazz, Field f, Type declaredType) {
|
public boolean deserializeField(Class<?> declaringClazz, Field f, Type declaredType) {
|
||||||
return true;
|
return !f.isSynthetic();
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getFieldName(Class<?> declaringClazz, Field f, Type declaredType) {
|
public String getFieldName(Class<?> declaringClazz, Field f, Type declaredType) {
|
||||||
|
@ -0,0 +1,46 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2011 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 com.google.gson.internal.bind.MiniGson;
|
||||||
|
import com.google.gson.internal.bind.TypeAdapter;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Map;
|
||||||
|
import junit.framework.TestCase;
|
||||||
|
|
||||||
|
public final class ObjectTypeAdapterTest extends TestCase {
|
||||||
|
private final MiniGson gson = new MiniGson.Builder().build();
|
||||||
|
private final TypeAdapter<Object> adapter = gson.getAdapter(Object.class);
|
||||||
|
|
||||||
|
public void testDeserialize() throws Exception {
|
||||||
|
Map<?, ?> map = (Map) adapter.fromJson("{a: 5, b: [1, 2, null]}");
|
||||||
|
assertEquals(5.0, map.get("a"));
|
||||||
|
assertEquals(Arrays.asList(1.0, 2.0, null), map.get("b"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testSerialize() throws Exception {
|
||||||
|
Object object = new Object() {
|
||||||
|
Object a = 5;
|
||||||
|
Object b = Arrays.asList(1, 2, null);
|
||||||
|
};
|
||||||
|
assertEquals("{'a':5,'b':[1,2,null]}", adapter.toJson(object).replace("\"", "'"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testSerializeObject() throws Exception {
|
||||||
|
assertEquals("{}", adapter.toJson(new Object()));
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user