Use more specific type for map serialization if possible.
This commit is contained in:
parent
50b4e3f4b9
commit
2fb8c92812
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* 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 java.lang.reflect.Type;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Captures all the common/shared logic between the old, ({@link MapTypeAdapter}, and
|
||||
* the new, {@link MapAsArrayTypeAdapter}, map type adapters.
|
||||
*
|
||||
* @author Joel Leitch
|
||||
*/
|
||||
abstract class BaseMapTypeAdapter
|
||||
implements JsonSerializer<Map<?, ?>>, JsonDeserializer<Map<?, ?>> {
|
||||
|
||||
protected static final JsonElement serialize(JsonSerializationContext context,
|
||||
Object src, Type srcType) {
|
||||
JsonSerializationContextDefault contextImpl = (JsonSerializationContextDefault) context;
|
||||
return contextImpl.serialize(src, srcType, false);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
protected static final Map<Object, Object> constructMapType(
|
||||
Type mapType, JsonDeserializationContext context) {
|
||||
JsonDeserializationContextDefault contextImpl = (JsonDeserializationContextDefault) context;
|
||||
ObjectConstructor objectConstructor = contextImpl.getObjectConstructor();
|
||||
return (Map<Object, Object>) objectConstructor.construct(mapType);
|
||||
}
|
||||
|
||||
}
|
|
@ -46,16 +46,20 @@ final class JsonSerializationContextDefault implements JsonSerializationContext
|
|||
if (src == null) {
|
||||
return JsonNull.createJsonNull();
|
||||
}
|
||||
return serialize(src, src.getClass());
|
||||
return serialize(src, src.getClass(), false);
|
||||
}
|
||||
|
||||
public JsonElement serialize(Object src, Type typeOfSrc) {
|
||||
return serialize(src, typeOfSrc, true);
|
||||
}
|
||||
|
||||
JsonElement serialize(Object src, Type typeOfSrc, boolean preserveType) {
|
||||
if (src == null) {
|
||||
return JsonNull.createJsonNull();
|
||||
}
|
||||
JsonSerializationVisitor visitor = new JsonSerializationVisitor(
|
||||
objectNavigator, fieldNamingPolicy, serializeNulls, serializers, this, ancestors);
|
||||
objectNavigator.accept(new ObjectTypePair(src, typeOfSrc, true), visitor);
|
||||
objectNavigator.accept(new ObjectTypePair(src, typeOfSrc, preserveType), visitor);
|
||||
return visitor.getJsonElement();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -90,6 +90,7 @@ import java.util.Map;
|
|||
* object.
|
||||
*/
|
||||
final class MapAsArrayTypeAdapter
|
||||
extends BaseMapTypeAdapter
|
||||
implements JsonSerializer<Map<?, ?>>, JsonDeserializer<Map<?, ?>> {
|
||||
|
||||
public Map<?, ?> deserialize(JsonElement json, Type typeOfT,
|
||||
|
@ -122,10 +123,10 @@ final class MapAsArrayTypeAdapter
|
|||
boolean serializeAsArray = false;
|
||||
List<JsonElement> keysAndValues = new ArrayList<JsonElement>();
|
||||
for (Map.Entry<?, ?> entry : src.entrySet()) {
|
||||
JsonElement key = context.serialize(entry.getKey(), keyAndValueType[0]);
|
||||
JsonElement key = serialize(context, entry.getKey(), keyAndValueType[0]);
|
||||
serializeAsArray |= key.isJsonObject() || key.isJsonArray();
|
||||
keysAndValues.add(key);
|
||||
keysAndValues.add(context.serialize(entry.getValue(), keyAndValueType[1]));
|
||||
keysAndValues.add(serialize(context, entry.getValue(), keyAndValueType[1]));
|
||||
}
|
||||
|
||||
if (serializeAsArray) {
|
||||
|
@ -146,13 +147,6 @@ final class MapAsArrayTypeAdapter
|
|||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private Map<Object, Object> constructMapType(Type mapType, JsonDeserializationContext context) {
|
||||
JsonDeserializationContextDefault contextImpl = (JsonDeserializationContextDefault) context;
|
||||
ObjectConstructor objectConstructor = contextImpl.getObjectConstructor();
|
||||
return (Map<Object, Object>) objectConstructor.construct(mapType);
|
||||
}
|
||||
|
||||
private Type[] typeToTypeArguments(Type typeOfT) {
|
||||
if (typeOfT instanceof ParameterizedType) {
|
||||
|
|
|
@ -31,8 +31,8 @@ import java.util.Set;
|
|||
* @author Joel Leitch
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
final class MapTypeAdapter implements JsonSerializer<Map<?, ?>>,
|
||||
JsonDeserializer<Map<?, ?>> {
|
||||
final class MapTypeAdapter extends BaseMapTypeAdapter {
|
||||
|
||||
public JsonElement serialize(Map src, Type typeOfSrc, JsonSerializationContext context) {
|
||||
JsonObject map = new JsonObject();
|
||||
Type childGenericType = null;
|
||||
|
@ -50,7 +50,7 @@ final class MapTypeAdapter implements JsonSerializer<Map<?, ?>>,
|
|||
} else {
|
||||
Type childType = (childGenericType == null)
|
||||
? value.getClass() : childGenericType;
|
||||
valueElement = context.serialize(value, childType);
|
||||
valueElement = serialize(context, value, childType);
|
||||
}
|
||||
map.add(String.valueOf(entry.getKey()), valueElement);
|
||||
}
|
||||
|
@ -71,12 +71,6 @@ final class MapTypeAdapter implements JsonSerializer<Map<?, ?>>,
|
|||
return map;
|
||||
}
|
||||
|
||||
private Map constructMapType(Type mapType, JsonDeserializationContext context) {
|
||||
JsonDeserializationContextDefault contextImpl = (JsonDeserializationContextDefault) context;
|
||||
ObjectConstructor objectConstructor = contextImpl.getObjectConstructor();
|
||||
return (Map) objectConstructor.construct(mapType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return MapTypeAdapter.class.getSimpleName();
|
||||
|
|
|
@ -19,6 +19,10 @@ package com.google.gson.functional;
|
|||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import com.google.gson.InstanceCreator;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonSerializationContext;
|
||||
import com.google.gson.JsonSerializer;
|
||||
import com.google.gson.common.TestTypes;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
@ -325,4 +329,71 @@ public class MapTest extends TestCase {
|
|||
assertEquals("{\"a\":12,\"c\":{}}",
|
||||
new GsonBuilder().create().toJson(map));
|
||||
}
|
||||
|
||||
public final void testInterfaceTypeMap() {
|
||||
MapClass element = new MapClass();
|
||||
TestTypes.Sub subType = new TestTypes.Sub();
|
||||
element.addBase("Test", subType);
|
||||
element.addSub("Test", subType);
|
||||
|
||||
String subTypeJson = new Gson().toJson(subType);
|
||||
String expected = "{\"bases\":{\"Test\":" + subTypeJson + "},"
|
||||
+ "\"subs\":{\"Test\":" + subTypeJson + "}}";
|
||||
|
||||
Gson gsonWithComplexKeys = new GsonBuilder()
|
||||
.enableComplexMapKeySerialization()
|
||||
.create();
|
||||
String json = gsonWithComplexKeys.toJson(element);
|
||||
assertEquals(expected, json);
|
||||
|
||||
Gson gson = new Gson();
|
||||
json = gson.toJson(element);
|
||||
assertEquals(expected, json);
|
||||
}
|
||||
|
||||
public final void testInterfaceTypeMapWithSerializer() {
|
||||
MapClass element = new MapClass();
|
||||
TestTypes.Sub subType = new TestTypes.Sub();
|
||||
element.addBase("Test", subType);
|
||||
element.addSub("Test", subType);
|
||||
|
||||
Gson tempGson = new Gson();
|
||||
String subTypeJson = tempGson.toJson(subType);
|
||||
final JsonElement baseTypeJson = tempGson.toJsonTree(subType, TestTypes.Base.class);
|
||||
String expected = "{\"bases\":{\"Test\":" + baseTypeJson.toString() + "},"
|
||||
+ "\"subs\":{\"Test\":" + subTypeJson + "}}";
|
||||
|
||||
JsonSerializer<TestTypes.Base> baseTypeAdapter = new JsonSerializer<TestTypes.Base>() {
|
||||
public JsonElement serialize(TestTypes.Base src, Type typeOfSrc,
|
||||
JsonSerializationContext context) {
|
||||
return baseTypeJson;
|
||||
}
|
||||
};
|
||||
|
||||
Gson gson = new GsonBuilder()
|
||||
.enableComplexMapKeySerialization()
|
||||
.registerTypeAdapter(TestTypes.Base.class, baseTypeAdapter)
|
||||
.create();
|
||||
String json = gson.toJson(element);
|
||||
assertEquals(expected, json);
|
||||
|
||||
gson = new GsonBuilder()
|
||||
.registerTypeAdapter(TestTypes.Base.class, baseTypeAdapter)
|
||||
.create();
|
||||
json = gson.toJson(element);
|
||||
assertEquals(expected, json);
|
||||
}
|
||||
|
||||
static final class MapClass {
|
||||
private final Map<String, TestTypes.Base> bases = new HashMap<String, TestTypes.Base>();
|
||||
private final Map<String, TestTypes.Sub> subs = new HashMap<String, TestTypes.Sub>();
|
||||
|
||||
public final void addBase(final String name, final TestTypes.Base value) {
|
||||
bases.put(name, value);
|
||||
}
|
||||
|
||||
public final void addSub(final String name, final TestTypes.Sub value) {
|
||||
subs.put(name, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,6 +26,7 @@ import com.google.gson.common.TestTypes.CrazyLongTypeAdapter;
|
|||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.io.StringReader;
|
||||
import java.math.BigDecimal;
|
||||
import java.math.BigInteger;
|
||||
|
@ -345,6 +346,16 @@ public class PrimitiveTest extends TestCase {
|
|||
} catch (JsonParseException expected) { }
|
||||
}
|
||||
|
||||
public void testMoreSpecificSerialization() {
|
||||
Gson gson = new Gson();
|
||||
String expected = "This is a string";
|
||||
String expectedJson = gson.toJson(expected);
|
||||
|
||||
Serializable serializableString = expected;
|
||||
String actualJson = gson.toJson(serializableString, Serializable.class);
|
||||
assertFalse(expectedJson.equals(actualJson));
|
||||
}
|
||||
|
||||
public void testOverridingDefaultPrimitiveSerialization() {
|
||||
CrazyLongTypeAdapter typeAdapter = new CrazyLongTypeAdapter();
|
||||
gson = new GsonBuilder()
|
||||
|
|
Loading…
Reference in New Issue