Enable serialization of nulls within Maps.
This commit is contained in:
parent
a82c400dc8
commit
b90228dcc0
|
@ -31,7 +31,6 @@ import java.text.ParseException;
|
||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -374,7 +373,7 @@ final class DefaultTypeAdapters {
|
||||||
|
|
||||||
public JsonElement serialize(Collection src, Type typeOfSrc, JsonSerializationContext context) {
|
public JsonElement serialize(Collection src, Type typeOfSrc, JsonSerializationContext context) {
|
||||||
if (src == null) {
|
if (src == null) {
|
||||||
return JsonNull.INSTANCE;
|
return JsonNull.createJsonNull();
|
||||||
}
|
}
|
||||||
JsonArray array = new JsonArray();
|
JsonArray array = new JsonArray();
|
||||||
Type childGenericType = null;
|
Type childGenericType = null;
|
||||||
|
@ -432,13 +431,19 @@ final class DefaultTypeAdapters {
|
||||||
if (typeOfSrc instanceof ParameterizedType) {
|
if (typeOfSrc instanceof ParameterizedType) {
|
||||||
childGenericType = new TypeInfoMap(typeOfSrc).getValueType();
|
childGenericType = new TypeInfoMap(typeOfSrc).getValueType();
|
||||||
}
|
}
|
||||||
for (Iterator iterator = src.entrySet().iterator(); iterator.hasNext(); ) {
|
|
||||||
Map.Entry entry = (Map.Entry) iterator.next();
|
for (Map.Entry entry : (Set<Map.Entry>) src.entrySet()) {
|
||||||
Object value = entry.getValue();
|
Object value = entry.getValue();
|
||||||
Type childType = (childGenericType == null) ?
|
|
||||||
childType = value.getClass() : childGenericType;
|
JsonElement valueElement;
|
||||||
JsonElement valueElement = context.serialize(value, childType);
|
if (value == null) {
|
||||||
map.add(entry.getKey().toString(), valueElement);
|
valueElement = JsonNull.createJsonNull();
|
||||||
|
} else {
|
||||||
|
Type childType = (childGenericType == null) ?
|
||||||
|
childType = value.getClass() : childGenericType;
|
||||||
|
valueElement = context.serialize(value, childType);
|
||||||
|
}
|
||||||
|
map.add(String.valueOf(entry.getKey()), valueElement);
|
||||||
}
|
}
|
||||||
return map;
|
return map;
|
||||||
}
|
}
|
||||||
|
|
|
@ -61,7 +61,7 @@ final class JsonArrayDeserializationVisitor<T> extends JsonDeserializationVisito
|
||||||
JsonElement jsonChild = jsonArray.get(i);
|
JsonElement jsonChild = jsonArray.get(i);
|
||||||
Object child;
|
Object child;
|
||||||
|
|
||||||
if (jsonChild == null) {
|
if (jsonChild == null || jsonChild.isJsonNull()) {
|
||||||
child = null;
|
child = null;
|
||||||
} else if (jsonChild instanceof JsonObject) {
|
} else if (jsonChild instanceof JsonObject) {
|
||||||
child = visitChildAsObject(arrayTypeInfo.getComponentRawType(), jsonChild);
|
child = visitChildAsObject(arrayTypeInfo.getComponentRawType(), jsonChild);
|
||||||
|
|
|
@ -17,7 +17,7 @@
|
||||||
package com.google.gson;
|
package com.google.gson;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A class representing a Json null value.
|
* A class representing a Json {@code null} value.
|
||||||
*
|
*
|
||||||
* @author Inderjeet Singh
|
* @author Inderjeet Singh
|
||||||
* @author Joel Leitch
|
* @author Joel Leitch
|
||||||
|
@ -25,7 +25,19 @@ package com.google.gson;
|
||||||
*/
|
*/
|
||||||
public final class JsonNull extends JsonElement {
|
public final class JsonNull extends JsonElement {
|
||||||
|
|
||||||
static final JsonNull INSTANCE = new JsonNull();
|
private static final JsonNull INSTANCE = new JsonNull(true);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated use the creation method, {@link #createJsonNull()}, instead.
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
|
public JsonNull() {
|
||||||
|
// Do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
private JsonNull(boolean placeholder) {
|
||||||
|
// Prevent instantiation
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void toString(StringBuilder sb) {
|
protected void toString(StringBuilder sb) {
|
||||||
|
@ -46,5 +58,9 @@ public final class JsonNull extends JsonElement {
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object other) {
|
public boolean equals(Object other) {
|
||||||
return other instanceof JsonNull;
|
return other instanceof JsonNull;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static JsonNull createJsonNull() {
|
||||||
|
return INSTANCE;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -115,7 +115,7 @@ public final class JsonObject extends JsonElement {
|
||||||
public JsonElement get(String memberName) {
|
public JsonElement get(String memberName) {
|
||||||
if (members.containsKey(memberName)) {
|
if (members.containsKey(memberName)) {
|
||||||
JsonElement member = members.get(memberName);
|
JsonElement member = members.get(memberName);
|
||||||
return member == null ? JsonNull.INSTANCE : member;
|
return member == null ? JsonNull.createJsonNull() : member;
|
||||||
} else {
|
} else {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -93,7 +93,7 @@ final class JsonObjectDeserializationVisitor<T> extends JsonDeserializationVisit
|
||||||
JsonElement child = json.getAsJsonObject().get(fName);
|
JsonElement child = json.getAsJsonObject().get(fName);
|
||||||
if (child == null) {
|
if (child == null) {
|
||||||
return true;
|
return true;
|
||||||
} else if (JsonNull.INSTANCE.equals(child)) {
|
} else if (child.isJsonNull()) {
|
||||||
TypeInfo typeInfo = new TypeInfo(actualTypeOfField);
|
TypeInfo typeInfo = new TypeInfo(actualTypeOfField);
|
||||||
if (!typeInfo.isPrimitive()) {
|
if (!typeInfo.isPrimitive()) {
|
||||||
f.set(parent, null);
|
f.set(parent, null);
|
||||||
|
|
|
@ -53,7 +53,7 @@ final class JsonParser implements JsonParserConstants {
|
||||||
final private JsonNull JsonNull() throws ParseException {
|
final private JsonNull JsonNull() throws ParseException {
|
||||||
Token t;
|
Token t;
|
||||||
t = jj_consume_token(NULL);
|
t = jj_consume_token(NULL);
|
||||||
{if (true) return JsonNull.INSTANCE;}
|
{if (true) return JsonNull.createJsonNull();}
|
||||||
throw new Error("Missing return statement in function");
|
throw new Error("Missing return statement in function");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -159,7 +159,7 @@ final class JsonParser implements JsonParserConstants {
|
||||||
o = JsonBoolean();
|
o = JsonBoolean();
|
||||||
break;
|
break;
|
||||||
case NULL:
|
case NULL:
|
||||||
jj_consume_token(NULL);
|
o = JsonNull();
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
jj_la1[6] = jj_gen;
|
jj_la1[6] = jj_gen;
|
||||||
|
|
|
@ -67,7 +67,7 @@ final class JsonSerializationVisitor implements ObjectNavigator.Visitor {
|
||||||
public void visitArrayField(Field f, Type typeOfF, Object obj) {
|
public void visitArrayField(Field f, Type typeOfF, Object obj) {
|
||||||
if (isFieldNull(f, obj)) {
|
if (isFieldNull(f, obj)) {
|
||||||
if (serializeNulls) {
|
if (serializeNulls) {
|
||||||
addChildAsElement(f, JsonNull.INSTANCE);
|
addChildAsElement(f, JsonNull.createJsonNull());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Object array = getFieldValue(f, obj);
|
Object array = getFieldValue(f, obj);
|
||||||
|
@ -78,7 +78,7 @@ final class JsonSerializationVisitor implements ObjectNavigator.Visitor {
|
||||||
public void visitObjectField(Field f, Type typeOfF, Object obj) {
|
public void visitObjectField(Field f, Type typeOfF, Object obj) {
|
||||||
if (isFieldNull(f, obj)) {
|
if (isFieldNull(f, obj)) {
|
||||||
if (serializeNulls) {
|
if (serializeNulls) {
|
||||||
addChildAsElement(f, JsonNull.INSTANCE);
|
addChildAsElement(f, JsonNull.createJsonNull());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Object fieldValue = getFieldValue(f, obj);
|
Object fieldValue = getFieldValue(f, obj);
|
||||||
|
@ -127,7 +127,7 @@ final class JsonSerializationVisitor implements ObjectNavigator.Visitor {
|
||||||
JsonSerializer serializer = serializers.getHandlerFor(objType);
|
JsonSerializer serializer = serializers.getHandlerFor(objType);
|
||||||
if (serializer != null) {
|
if (serializer != null) {
|
||||||
if (obj == null) {
|
if (obj == null) {
|
||||||
assignToRoot(JsonNull.INSTANCE);
|
assignToRoot(JsonNull.createJsonNull());
|
||||||
} else {
|
} else {
|
||||||
assignToRoot(serializer.serialize(obj, objType, context));
|
assignToRoot(serializer.serialize(obj, objType, context));
|
||||||
}
|
}
|
||||||
|
@ -143,7 +143,7 @@ final class JsonSerializationVisitor implements ObjectNavigator.Visitor {
|
||||||
Object obj = f.get(parent);
|
Object obj = f.get(parent);
|
||||||
if (obj == null) {
|
if (obj == null) {
|
||||||
if (serializeNulls) {
|
if (serializeNulls) {
|
||||||
addChildAsElement(f, JsonNull.INSTANCE);
|
addChildAsElement(f, JsonNull.createJsonNull());
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,7 +47,7 @@ final class JsonTreeNavigator {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
visitor.endArray(array);
|
visitor.endArray(array);
|
||||||
} else if (element.isJsonObject()){
|
} else if (element.isJsonObject()) {
|
||||||
JsonObject object = element.getAsJsonObject();
|
JsonObject object = element.getAsJsonObject();
|
||||||
visitor.startObject(object);
|
visitor.startObject(object);
|
||||||
boolean isFirst = true;
|
boolean isFirst = true;
|
||||||
|
|
|
@ -78,7 +78,7 @@ private JsonNull JsonNull() :
|
||||||
Token t;
|
Token t;
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
t = <NULL> { return JsonNull.INSTANCE; }
|
t = <NULL> { return JsonNull.createJsonNull(); }
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Members(JsonObject o) :
|
private void Members(JsonObject o) :
|
||||||
|
@ -133,7 +133,7 @@ private JsonElement JsonValue() :
|
||||||
o=JsonObject() |
|
o=JsonObject() |
|
||||||
o=JsonArray() |
|
o=JsonArray() |
|
||||||
o=JsonBoolean() |
|
o=JsonBoolean() |
|
||||||
"null" )
|
o=JsonNull() )
|
||||||
{ return o; }
|
{ return o; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -75,6 +75,55 @@ public class MapTest extends TestCase {
|
||||||
String json = gson.toJson(map, typeOfMap);
|
String json = gson.toJson(map, typeOfMap);
|
||||||
assertEquals("{}", json);
|
assertEquals("{}", json);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testMapDeserializationEmpty() {
|
||||||
|
Type typeOfMap = new TypeToken<Map<String, Integer>>() {}.getType();
|
||||||
|
Map<String, Integer> map = gson.fromJson("{}", typeOfMap);
|
||||||
|
assertTrue(map.isEmpty());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testMapSerializationWithNullValue() {
|
||||||
|
Map<String, Integer> map = new LinkedHashMap<String, Integer>();
|
||||||
|
map.put("abc", null);
|
||||||
|
Type typeOfMap = new TypeToken<Map<String, Integer>>() {}.getType();
|
||||||
|
String json = gson.toJson(map, typeOfMap);
|
||||||
|
|
||||||
|
// Maps are represented as JSON objects, so ignoring null field
|
||||||
|
assertEquals("{}", json);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testMapDeserializationWithNullValue() {
|
||||||
|
Type typeOfMap = new TypeToken<Map<String, Integer>>() {}.getType();
|
||||||
|
Map<String, Integer> map = gson.fromJson("{\"abc\":null}", typeOfMap);
|
||||||
|
assertEquals(1, map.size());
|
||||||
|
assertNull(map.get("abc"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testMapSerializationWithNullValueButSerializeNulls() {
|
||||||
|
gson = new GsonBuilder().serializeNulls().create();
|
||||||
|
Map<String, Integer> map = new LinkedHashMap<String, Integer>();
|
||||||
|
map.put("abc", null);
|
||||||
|
Type typeOfMap = new TypeToken<Map<String, Integer>>() {}.getType();
|
||||||
|
String json = gson.toJson(map, typeOfMap);
|
||||||
|
|
||||||
|
assertEquals("{\"abc\":null}", json);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testMapSerializationWithNullKey() {
|
||||||
|
Map<String, Integer> map = new LinkedHashMap<String, Integer>();
|
||||||
|
map.put(null, 123);
|
||||||
|
Type typeOfMap = new TypeToken<Map<String, Integer>>() {}.getType();
|
||||||
|
String json = gson.toJson(map, typeOfMap);
|
||||||
|
|
||||||
|
assertEquals("{\"null\":123}", json);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testMapDeserializationWithNullKey() {
|
||||||
|
Type typeOfMap = new TypeToken<Map<String, Integer>>() {}.getType();
|
||||||
|
Map<String, Integer> map = gson.fromJson("{\"null\":123}", typeOfMap);
|
||||||
|
assertEquals(1, map.size());
|
||||||
|
assertNull(map.get(null));
|
||||||
|
}
|
||||||
|
|
||||||
public void testParameterizedMapSubclassSerialization() {
|
public void testParameterizedMapSubclassSerialization() {
|
||||||
MyParameterizedMap<String, String> map = new MyParameterizedMap<String, String>();
|
MyParameterizedMap<String, String> map = new MyParameterizedMap<String, String>();
|
||||||
|
|
Loading…
Reference in New Issue
Block a user