Adapter for Object.class
This commit is contained in:
parent
9fb39c89ea
commit
3aeb70e030
@ -28,12 +28,12 @@ import java.util.Map;
|
||||
abstract class BaseMapTypeAdapter
|
||||
implements JsonSerializer<Map<?, ?>>, JsonDeserializer<Map<?, ?>> {
|
||||
|
||||
protected static final JsonElement serialize(JsonSerializationContext context,
|
||||
protected static JsonElement serialize(JsonSerializationContext context,
|
||||
Object src, Type srcType) {
|
||||
return context.serialize(src, srcType, false, false);
|
||||
}
|
||||
|
||||
protected static final Map<Object, Object> constructMapType(
|
||||
protected static Map<Object, Object> constructMapType(
|
||||
Type mapType, JsonDeserializationContext context) {
|
||||
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.BigIntegerTypeAdapter;
|
||||
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.ObjectTypeAdapter;
|
||||
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.TypeAdapters;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
@ -34,7 +35,6 @@ import com.google.gson.stream.MalformedJsonException;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Reader;
|
||||
import java.io.StringReader;
|
||||
import java.io.StringWriter;
|
||||
import java.io.Writer;
|
||||
import java.lang.reflect.Field;
|
||||
@ -246,10 +246,11 @@ public final class Gson {
|
||||
.typeAdapter(BigDecimal.class, new BigDecimalTypeAdapter())
|
||||
.typeAdapter(BigInteger.class, new BigIntegerTypeAdapter())
|
||||
.factory(excludedTypeFactory)
|
||||
.factory(GsonCompatibleMapTypeAdapter.FACTORY)
|
||||
.factory(new GsonToMiniGsonTypeAdapter(serializers, deserializers, serializeNulls))
|
||||
.factory(CollectionTypeAdapter.FACTORY)
|
||||
.factory(StringToValueMapTypeAdapter.FACTORY)
|
||||
.factory(ArrayTypeAdapter.FACTORY)
|
||||
.factory(ObjectTypeAdapter.FACTORY)
|
||||
.factory(reflectiveTypeAdapterFactory);
|
||||
|
||||
this.miniGson = builder.build();
|
||||
|
@ -68,7 +68,7 @@ final class GsonToMiniGsonTypeAdapter implements TypeAdapter.Factory {
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
public JsonSerializationContext createSerializationContext(final MiniGson miniGson) {
|
||||
return new JsonSerializationContext() {
|
||||
@Override
|
||||
@ -85,6 +85,18 @@ final class GsonToMiniGsonTypeAdapter implements TypeAdapter.Factory {
|
||||
TypeToken typeToken = TypeToken.get(typeOfT);
|
||||
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);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
/**
|
||||
* TODO: remove this from the public API
|
||||
*/
|
||||
@SuppressWarnings("unchecked") @Deprecated
|
||||
public <T> T construct(Type type) {
|
||||
Object instance = objectConstructor.construct(type);
|
||||
return (T) instance;
|
||||
|
@ -56,12 +56,12 @@ public final class CollectionTypeAdapter<E> extends TypeAdapter<Collection<E>> {
|
||||
} else {
|
||||
constructorType = rawType;
|
||||
}
|
||||
// TODO: Queue=LinkedList, SortedSet=TreeSet
|
||||
|
||||
Constructor<?> constructor;
|
||||
Constructor<?> constructor = null;
|
||||
try {
|
||||
constructor = constructorType.getConstructor();
|
||||
} catch (NoSuchMethodException e) {
|
||||
return null;
|
||||
} catch (NoSuchMethodException ignored) {
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked") // create() doesn't define a type parameter
|
||||
@ -86,6 +86,9 @@ public final class CollectionTypeAdapter<E> extends TypeAdapter<Collection<E>> {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (constructor == null) {
|
||||
throw new UnsupportedOperationException("TODO: use unsafeAllocator.newInstance");
|
||||
}
|
||||
Collection<E> collection = Reflection.newInstance(constructor);
|
||||
reader.beginArray();
|
||||
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(StringToValueMapTypeAdapter.FACTORY);
|
||||
factories.add(ArrayTypeAdapter.FACTORY);
|
||||
factories.add(ObjectTypeAdapter.FACTORY);
|
||||
factories.add(ReflectiveTypeAdapter.FACTORY);
|
||||
}
|
||||
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 boolean serializeField(Class<?> declaringClazz, Field f, Type declaredType) {
|
||||
return true;
|
||||
return !f.isSynthetic();
|
||||
}
|
||||
public boolean deserializeField(Class<?> declaringClazz, Field f, Type declaredType) {
|
||||
return true;
|
||||
return !f.isSynthetic();
|
||||
}
|
||||
|
||||
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