Enable serialization of nulls within Maps.

This commit is contained in:
Joel Leitch 2008-11-30 23:01:14 +00:00
parent a82c400dc8
commit b90228dcc0
10 changed files with 93 additions and 23 deletions

View File

@ -31,7 +31,6 @@ 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;
@ -374,7 +373,7 @@ final class DefaultTypeAdapters {
public JsonElement serialize(Collection src, Type typeOfSrc, JsonSerializationContext context) {
if (src == null) {
return JsonNull.INSTANCE;
return JsonNull.createJsonNull();
}
JsonArray array = new JsonArray();
Type childGenericType = null;
@ -432,13 +431,19 @@ final class DefaultTypeAdapters {
if (typeOfSrc instanceof ParameterizedType) {
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();
Type childType = (childGenericType == null) ?
childType = value.getClass() : childGenericType;
JsonElement valueElement = context.serialize(value, childType);
map.add(entry.getKey().toString(), valueElement);
JsonElement valueElement;
if (value == null) {
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;
}

View File

@ -61,7 +61,7 @@ final class JsonArrayDeserializationVisitor<T> extends JsonDeserializationVisito
JsonElement jsonChild = jsonArray.get(i);
Object child;
if (jsonChild == null) {
if (jsonChild == null || jsonChild.isJsonNull()) {
child = null;
} else if (jsonChild instanceof JsonObject) {
child = visitChildAsObject(arrayTypeInfo.getComponentRawType(), jsonChild);

View File

@ -17,7 +17,7 @@
package com.google.gson;
/**
* A class representing a Json null value.
* A class representing a Json {@code null} value.
*
* @author Inderjeet Singh
* @author Joel Leitch
@ -25,7 +25,19 @@ package com.google.gson;
*/
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
protected void toString(StringBuilder sb) {
@ -46,5 +58,9 @@ public final class JsonNull extends JsonElement {
@Override
public boolean equals(Object other) {
return other instanceof JsonNull;
}
}
public static JsonNull createJsonNull() {
return INSTANCE;
}
}

View File

@ -115,7 +115,7 @@ public final class JsonObject extends JsonElement {
public JsonElement get(String memberName) {
if (members.containsKey(memberName)) {
JsonElement member = members.get(memberName);
return member == null ? JsonNull.INSTANCE : member;
return member == null ? JsonNull.createJsonNull() : member;
} else {
return null;
}

View File

@ -93,7 +93,7 @@ final class JsonObjectDeserializationVisitor<T> extends JsonDeserializationVisit
JsonElement child = json.getAsJsonObject().get(fName);
if (child == null) {
return true;
} else if (JsonNull.INSTANCE.equals(child)) {
} else if (child.isJsonNull()) {
TypeInfo typeInfo = new TypeInfo(actualTypeOfField);
if (!typeInfo.isPrimitive()) {
f.set(parent, null);

View File

@ -53,7 +53,7 @@ final class JsonParser implements JsonParserConstants {
final private JsonNull JsonNull() throws ParseException {
Token t;
t = jj_consume_token(NULL);
{if (true) return JsonNull.INSTANCE;}
{if (true) return JsonNull.createJsonNull();}
throw new Error("Missing return statement in function");
}
@ -159,7 +159,7 @@ final class JsonParser implements JsonParserConstants {
o = JsonBoolean();
break;
case NULL:
jj_consume_token(NULL);
o = JsonNull();
break;
default:
jj_la1[6] = jj_gen;

View File

@ -67,7 +67,7 @@ final class JsonSerializationVisitor implements ObjectNavigator.Visitor {
public void visitArrayField(Field f, Type typeOfF, Object obj) {
if (isFieldNull(f, obj)) {
if (serializeNulls) {
addChildAsElement(f, JsonNull.INSTANCE);
addChildAsElement(f, JsonNull.createJsonNull());
}
} else {
Object array = getFieldValue(f, obj);
@ -78,7 +78,7 @@ final class JsonSerializationVisitor implements ObjectNavigator.Visitor {
public void visitObjectField(Field f, Type typeOfF, Object obj) {
if (isFieldNull(f, obj)) {
if (serializeNulls) {
addChildAsElement(f, JsonNull.INSTANCE);
addChildAsElement(f, JsonNull.createJsonNull());
}
} else {
Object fieldValue = getFieldValue(f, obj);
@ -127,7 +127,7 @@ final class JsonSerializationVisitor implements ObjectNavigator.Visitor {
JsonSerializer serializer = serializers.getHandlerFor(objType);
if (serializer != null) {
if (obj == null) {
assignToRoot(JsonNull.INSTANCE);
assignToRoot(JsonNull.createJsonNull());
} else {
assignToRoot(serializer.serialize(obj, objType, context));
}
@ -143,7 +143,7 @@ final class JsonSerializationVisitor implements ObjectNavigator.Visitor {
Object obj = f.get(parent);
if (obj == null) {
if (serializeNulls) {
addChildAsElement(f, JsonNull.INSTANCE);
addChildAsElement(f, JsonNull.createJsonNull());
}
return true;
}

View File

@ -47,7 +47,7 @@ final class JsonTreeNavigator {
}
}
visitor.endArray(array);
} else if (element.isJsonObject()){
} else if (element.isJsonObject()) {
JsonObject object = element.getAsJsonObject();
visitor.startObject(object);
boolean isFirst = true;

View File

@ -78,7 +78,7 @@ private JsonNull JsonNull() :
Token t;
}
{
t = <NULL> { return JsonNull.INSTANCE; }
t = <NULL> { return JsonNull.createJsonNull(); }
}
private void Members(JsonObject o) :
@ -133,7 +133,7 @@ private JsonElement JsonValue() :
o=JsonObject() |
o=JsonArray() |
o=JsonBoolean() |
"null" )
o=JsonNull() )
{ return o; }
}

View File

@ -75,6 +75,55 @@ public class MapTest extends TestCase {
String json = gson.toJson(map, typeOfMap);
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() {
MyParameterizedMap<String, String> map = new MyParameterizedMap<String, String>();