Add a type adapter for JsonElement, so it serializes just like everything else.

Fixes issue 362.
This commit is contained in:
Jesse Wilson 2011-10-02 16:59:56 +00:00
parent 3a3870591e
commit 65df3b97ba
4 changed files with 151 additions and 76 deletions

View File

@ -248,6 +248,7 @@ 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(new CollectionTypeAdapterFactory(constructorConstructor)) .factory(new CollectionTypeAdapterFactory(constructorConstructor))
.factory(TypeAdapters.JSON_ELEMENT_FACTORY)
.factory(ObjectTypeAdapter.FACTORY); .factory(ObjectTypeAdapter.FACTORY);
for (TypeAdapter.Factory factory : typeAdapterFactories) { for (TypeAdapter.Factory factory : typeAdapterFactories) {

View File

@ -16,27 +16,23 @@
package com.google.gson.internal; package com.google.gson.internal;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement; import com.google.gson.JsonElement;
import com.google.gson.JsonIOException; import com.google.gson.JsonIOException;
import com.google.gson.JsonNull; import com.google.gson.JsonNull;
import com.google.gson.JsonObject;
import com.google.gson.JsonParseException; import com.google.gson.JsonParseException;
import com.google.gson.JsonPrimitive;
import com.google.gson.JsonSyntaxException; import com.google.gson.JsonSyntaxException;
import com.google.gson.internal.bind.TypeAdapters;
import com.google.gson.stream.JsonReader; import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonWriter; import com.google.gson.stream.JsonWriter;
import com.google.gson.stream.MalformedJsonException; import com.google.gson.stream.MalformedJsonException;
import java.io.EOFException; import java.io.EOFException;
import java.io.IOException; import java.io.IOException;
import java.io.Writer; import java.io.Writer;
import java.util.Map;
/** /**
* Reads and writes GSON parse trees over streams. * Reads and writes GSON parse trees over streams.
*/ */
public final class Streams { public final class Streams {
/** /**
* Takes a reader in any state and returns the next value as a JsonElement. * Takes a reader in any state and returns the next value as a JsonElement.
*/ */
@ -45,7 +41,7 @@ public final class Streams {
try { try {
reader.peek(); reader.peek();
isEmpty = false; isEmpty = false;
return parseRecursive(reader); return TypeAdapters.JSON_ELEMENT.read(reader);
} catch (EOFException e) { } catch (EOFException e) {
/* /*
* For compatibility with JSON 1.5 and earlier, we return a JsonNull for * For compatibility with JSON 1.5 and earlier, we return a JsonNull for
@ -64,79 +60,11 @@ public final class Streams {
} }
} }
private static JsonElement parseRecursive(JsonReader reader) throws IOException {
switch (reader.peek()) {
case STRING:
return new JsonPrimitive(reader.nextString());
case NUMBER:
String number = reader.nextString();
return new JsonPrimitive(new LazilyParsedNumber(number));
case BOOLEAN:
return new JsonPrimitive(reader.nextBoolean());
case NULL:
reader.nextNull();
return JsonNull.INSTANCE;
case BEGIN_ARRAY:
JsonArray array = new JsonArray();
reader.beginArray();
while (reader.hasNext()) {
array.add(parseRecursive(reader));
}
reader.endArray();
return array;
case BEGIN_OBJECT:
JsonObject object = new JsonObject();
reader.beginObject();
while (reader.hasNext()) {
object.add(reader.nextName(), parseRecursive(reader));
}
reader.endObject();
return object;
case END_DOCUMENT:
case NAME:
case END_OBJECT:
case END_ARRAY:
default:
throw new IllegalArgumentException();
}
}
/** /**
* Writes the JSON element to the writer, recursively. * Writes the JSON element to the writer, recursively.
*/ */
public static void write(JsonElement element, JsonWriter writer) public static void write(JsonElement element, JsonWriter writer) throws IOException {
throws IOException { TypeAdapters.JSON_ELEMENT.write(writer, element);
if (element == null || element.isJsonNull()) {
writer.nullValue();
} else if (element.isJsonPrimitive()) {
JsonPrimitive primitive = element.getAsJsonPrimitive();
if (primitive.isNumber()) {
writer.value(primitive.getAsNumber());
} else if (primitive.isBoolean()) {
writer.value(primitive.getAsBoolean());
} else {
writer.value(primitive.getAsString());
}
} else if (element.isJsonArray()) {
writer.beginArray();
for (JsonElement e : element.getAsJsonArray()) {
write(e, writer);
}
writer.endArray();
} else if (element.isJsonObject()) {
writer.beginObject();
for (Map.Entry<String, JsonElement> e : element.getAsJsonObject().entrySet()) {
JsonElement value = e.getValue();
writer.name(e.getKey());
write(value, writer);
}
writer.endObject();
} else {
throw new IllegalArgumentException("Couldn't write " + element.getClass());
}
} }
public static Writer writerForAppendable(Appendable appendable) { public static Writer writerForAppendable(Appendable appendable) {
@ -183,4 +111,5 @@ public final class Streams {
} }
} }
} }
} }

View File

@ -16,7 +16,12 @@
package com.google.gson.internal.bind; package com.google.gson.internal.bind;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonIOException; import com.google.gson.JsonIOException;
import com.google.gson.JsonNull;
import com.google.gson.JsonObject;
import com.google.gson.JsonPrimitive;
import com.google.gson.JsonSyntaxException; import com.google.gson.JsonSyntaxException;
import com.google.gson.internal.LazilyParsedNumber; import com.google.gson.internal.LazilyParsedNumber;
import com.google.gson.reflect.TypeToken; import com.google.gson.reflect.TypeToken;
@ -34,6 +39,7 @@ import java.util.Calendar;
import java.util.Date; import java.util.Date;
import java.util.GregorianCalendar; import java.util.GregorianCalendar;
import java.util.Locale; import java.util.Locale;
import java.util.Map;
import java.util.StringTokenizer; import java.util.StringTokenizer;
import java.util.UUID; import java.util.UUID;
@ -526,6 +532,81 @@ public final class TypeAdapters {
public static final TypeAdapter.Factory LOCALE_FACTORY = newFactory(Locale.class, LOCALE); public static final TypeAdapter.Factory LOCALE_FACTORY = newFactory(Locale.class, LOCALE);
public static final TypeAdapter<JsonElement> JSON_ELEMENT = new TypeAdapter<JsonElement>() {
@Override public JsonElement read(JsonReader reader) throws IOException {
switch (reader.peek()) {
case STRING:
return new JsonPrimitive(reader.nextString());
case NUMBER:
String number = reader.nextString();
return new JsonPrimitive(new LazilyParsedNumber(number));
case BOOLEAN:
return new JsonPrimitive(reader.nextBoolean());
case NULL:
reader.nextNull();
return JsonNull.INSTANCE;
case BEGIN_ARRAY:
JsonArray array = new JsonArray();
reader.beginArray();
while (reader.hasNext()) {
array.add(read(reader));
}
reader.endArray();
return array;
case BEGIN_OBJECT:
JsonObject object = new JsonObject();
reader.beginObject();
while (reader.hasNext()) {
object.add(reader.nextName(), read(reader));
}
reader.endObject();
return object;
case END_DOCUMENT:
case NAME:
case END_OBJECT:
case END_ARRAY:
default:
throw new IllegalArgumentException();
}
}
@Override public void write(JsonWriter writer, JsonElement value) throws IOException {
if (value == null || value.isJsonNull()) {
writer.nullValue();
} else if (value.isJsonPrimitive()) {
JsonPrimitive primitive = value.getAsJsonPrimitive();
if (primitive.isNumber()) {
writer.value(primitive.getAsNumber());
} else if (primitive.isBoolean()) {
writer.value(primitive.getAsBoolean());
} else {
writer.value(primitive.getAsString());
}
} else if (value.isJsonArray()) {
writer.beginArray();
for (JsonElement e : value.getAsJsonArray()) {
write(writer, e);
}
writer.endArray();
} else if (value.isJsonObject()) {
writer.beginObject();
for (Map.Entry<String, JsonElement> e : value.getAsJsonObject().entrySet()) {
writer.name(e.getKey());
write(writer, e.getValue());
}
writer.endObject();
} else {
throw new IllegalArgumentException("Couldn't write " + value.getClass());
}
}
};
public static final TypeAdapter.Factory JSON_ELEMENT_FACTORY
= newFactory(JsonElement.class, JSON_ELEMENT);
private static final class EnumTypeAdapter<T extends Enum<T>> extends TypeAdapter<T> { private static final class EnumTypeAdapter<T extends Enum<T>> extends TypeAdapter<T> {
private final Class<T> classOfT; private final Class<T> classOfT;

View File

@ -17,10 +17,14 @@ package com.google.gson.functional;
import com.google.gson.Gson; import com.google.gson.Gson;
import com.google.gson.GsonBuilder; import com.google.gson.GsonBuilder;
import com.google.gson.JsonArray;
import com.google.gson.JsonDeserializationContext; import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer; import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement; import com.google.gson.JsonElement;
import com.google.gson.JsonNull;
import com.google.gson.JsonObject;
import com.google.gson.JsonParseException; import com.google.gson.JsonParseException;
import com.google.gson.JsonPrimitive;
import com.google.gson.reflect.TypeToken; import com.google.gson.reflect.TypeToken;
import java.lang.reflect.Type; import java.lang.reflect.Type;
import java.math.BigDecimal; import java.math.BigDecimal;
@ -459,6 +463,66 @@ public class DefaultTypeAdaptersTest extends TestCase {
} }
} }
public void testJsonPrimitiveSerialization() {
assertEquals("5", gson.toJson(new JsonPrimitive(5), JsonElement.class));
assertEquals("true", gson.toJson(new JsonPrimitive(true), JsonElement.class));
assertEquals("\"foo\"", gson.toJson(new JsonPrimitive("foo"), JsonElement.class));
assertEquals("\"a\"", gson.toJson(new JsonPrimitive('a'), JsonElement.class));
}
public void testJsonPrimitiveDeserialization() {
assertEquals(new JsonPrimitive(5), gson.fromJson("5", JsonElement.class));
assertEquals(new JsonPrimitive(true), gson.fromJson("true", JsonElement.class));
assertEquals(new JsonPrimitive("foo"), gson.fromJson("\"foo\"", JsonElement.class));
assertEquals(new JsonPrimitive('a'), gson.fromJson("\"a\"", JsonElement.class));
}
public void testJsonNullSerialization() {
assertEquals("null", gson.toJson(JsonNull.INSTANCE, JsonElement.class));
}
public void testNullJsonElementSerialization() {
assertEquals("null", gson.toJson(null, JsonElement.class));
}
public void testJsonArraySerialization() {
JsonArray array = new JsonArray();
array.add(new JsonPrimitive(1));
array.add(new JsonPrimitive(2));
array.add(new JsonPrimitive(3));
assertEquals("[1,2,3]", gson.toJson(array, JsonElement.class));
}
public void testJsonArrayDeerialization() {
JsonArray array = new JsonArray();
array.add(new JsonPrimitive(1));
array.add(new JsonPrimitive(2));
array.add(new JsonPrimitive(3));
assertEquals(array, gson.fromJson("[1,2,3]", JsonElement.class));
}
public void testJsonObjectSerialization() {
JsonObject object = new JsonObject();
object.add("foo", new JsonPrimitive(1));
object.add("bar", new JsonPrimitive(2));
assertEquals("{\"foo\":1,\"bar\":2}", gson.toJson(object, JsonElement.class));
}
public void testJsonObjectDeerialization() {
JsonObject object = new JsonObject();
object.add("foo", new JsonPrimitive(1));
object.add("bar", new JsonPrimitive(2));
assertEquals(object, gson.fromJson("{\"foo\":1,\"bar\":2}", JsonElement.class));
}
public void testJsonNullDeerialization() {
assertEquals(JsonNull.INSTANCE, gson.fromJson("null", JsonElement.class));
}
public void testNullJsonElementDeserialization() {
assertEquals(JsonNull.INSTANCE, gson.fromJson("null", JsonElement.class));
}
private static class ClassWithBigDecimal { private static class ClassWithBigDecimal {
BigDecimal value; BigDecimal value;
ClassWithBigDecimal(String value) { ClassWithBigDecimal(String value) {