Adopt JsonElementWriter in GSON.

Add setSerializeNulls() to JsonWriter, so nulls can be skipped from serialization. This does not yet impact JsonElementWriter.

One change in behavior: if the only value is skipped, we now emit "null" rather than "".
This commit is contained in:
Jesse Wilson 2011-09-30 07:08:44 +00:00
parent 364de80611
commit bb7f0b6bb0
7 changed files with 140 additions and 51 deletions

View File

@ -54,8 +54,16 @@ GSON 1.x sometimes sets subclass fields when an InstanceCreator returns a subcla
GSON 2.x sets fields of the requested type only GSON 2.x sets fields of the requested type only
com.google.gson.functional.InstanceCreatorTest.testInstanceCreatorReturnsSubTypeForField com.google.gson.functional.InstanceCreatorTest.testInstanceCreatorReturnsSubTypeForField
GSON 1.x applies different rules for versioning for classes vs fields. So, if you deserialize a GSON 1.x applies different rules for versioning for classes vs fields. So, if you deserialize a
JSON into a field that is supposed to be skipped, the field is set to null (or default value). JSON into a field that is supposed to be skipped, the field is set to null (or default value).
However, if you deserialize it to a top-level class, a default instance is returned. However, if you deserialize it to a top-level class, a default instance is returned.
GSON 2.x returns null for the top-level class. GSON 2.x returns null for the top-level class.
com.google.gson.functional.VersioningTest.testIgnoreLaterVersionClassDeserialization com.google.gson.functional.VersioningTest.testIgnoreLaterVersionClassDeserialization
GSON 1.x creates the empty string "" if the only element is skipped
GSON 2.x writes "null" if the only element is skipped
com.google.gson.functional.ObjectTest.testAnonymousLocalClassesSerialization
com.google.gson.functional.FieldExclusionTest.testInnerClassExclusion
com.google.gson.functional.VersioningTest.testIgnoreLaterVersionClassSerialization

View File

@ -443,7 +443,7 @@ public final class Gson {
*/ */
public String toJson(Object src, Type typeOfSrc) { public String toJson(Object src, Type typeOfSrc) {
StringWriter writer = new StringWriter(); StringWriter writer = new StringWriter();
toJson(toJsonTree(src, typeOfSrc), writer); toJson(src, typeOfSrc, writer);
return writer.toString(); return writer.toString();
} }
@ -486,8 +486,12 @@ public final class Gson {
* @since 1.2 * @since 1.2
*/ */
public void toJson(Object src, Type typeOfSrc, Appendable writer) throws JsonIOException { public void toJson(Object src, Type typeOfSrc, Appendable writer) throws JsonIOException {
JsonElement jsonElement = toJsonTree(src, typeOfSrc); try {
toJson(jsonElement, writer); JsonWriter jsonWriter = newJsonWriter(Streams.writerForAppendable(writer));
toJson(src, typeOfSrc, jsonWriter);
} catch (IOException e) {
throw new JsonIOException(e);
}
} }
/** /**
@ -496,7 +500,22 @@ public final class Gson {
* @throws JsonIOException if there was a problem writing to the writer * @throws JsonIOException if there was a problem writing to the writer
*/ */
public void toJson(Object src, Type typeOfSrc, JsonWriter writer) throws JsonIOException { public void toJson(Object src, Type typeOfSrc, JsonWriter writer) throws JsonIOException {
toJson(toJsonTree(src, typeOfSrc), writer); TypeAdapter<?> adapter = miniGson.getAdapter(TypeToken.get(typeOfSrc));
boolean oldLenient = writer.isLenient();
writer.setLenient(true);
boolean oldHtmlSafe = writer.isHtmlSafe();
writer.setHtmlSafe(htmlSafe);
boolean oldSerializeNulls = writer.getSerializeNulls();
writer.setSerializeNulls(serializeNulls);
try {
((TypeAdapter<Object>) adapter).write(writer, src);
} catch (IOException e) {
throw new JsonIOException(e);
} finally {
writer.setLenient(oldLenient);
writer.setHtmlSafe(oldHtmlSafe);
writer.setSerializeNulls(oldSerializeNulls);
}
} }
/** /**
@ -522,19 +541,29 @@ public final class Gson {
*/ */
public void toJson(JsonElement jsonElement, Appendable writer) throws JsonIOException { public void toJson(JsonElement jsonElement, Appendable writer) throws JsonIOException {
try { try {
if (generateNonExecutableJson) { JsonWriter jsonWriter = newJsonWriter(Streams.writerForAppendable(writer));
writer.append(JSON_NON_EXECUTABLE_PREFIX);
}
JsonWriter jsonWriter = new JsonWriter(Streams.writerForAppendable(writer));
if (prettyPrinting) {
jsonWriter.setIndent(" ");
}
toJson(jsonElement, jsonWriter); toJson(jsonElement, jsonWriter);
} catch (IOException e) { } catch (IOException e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
} }
/**
* Returns a new JSON writer configured for this GSON and with the non-execute
* prefix if that is configured.
*/
private JsonWriter newJsonWriter(Writer writer) throws IOException {
if (generateNonExecutableJson) {
writer.write(JSON_NON_EXECUTABLE_PREFIX);
}
JsonWriter jsonWriter = new JsonWriter(writer);
if (prettyPrinting) {
jsonWriter.setIndent(" ");
}
jsonWriter.setSerializeNulls(serializeNulls);
return jsonWriter;
}
/** /**
* Writes the JSON for {@code jsonElement} to {@code writer}. * Writes the JSON for {@code jsonElement} to {@code writer}.
* @throws JsonIOException if there was a problem writing to the writer * @throws JsonIOException if there was a problem writing to the writer
@ -544,6 +573,8 @@ public final class Gson {
writer.setLenient(true); writer.setLenient(true);
boolean oldHtmlSafe = writer.isHtmlSafe(); boolean oldHtmlSafe = writer.isHtmlSafe();
writer.setHtmlSafe(htmlSafe); writer.setHtmlSafe(htmlSafe);
boolean oldSerializeNulls = writer.getSerializeNulls();
writer.setSerializeNulls(serializeNulls);
try { try {
Streams.write(jsonElement, serializeNulls, writer); Streams.write(jsonElement, serializeNulls, writer);
} catch (IOException e) { } catch (IOException e) {
@ -551,6 +582,7 @@ public final class Gson {
} finally { } finally {
writer.setLenient(oldLenient); writer.setLenient(oldLenient);
writer.setHtmlSafe(oldHtmlSafe); writer.setHtmlSafe(oldHtmlSafe);
writer.setSerializeNulls(oldSerializeNulls);
} }
} }

View File

@ -145,6 +145,10 @@ public class JsonWriter implements Closeable {
private boolean htmlSafe; private boolean htmlSafe;
private String deferredName;
private boolean serializeNulls = true;
/** /**
* Creates a new instance that writes a JSON-encoded stream to {@code out}. * Creates a new instance that writes a JSON-encoded stream to {@code out}.
* For best performance, ensure {@link Writer} is buffered; wrapping in * For best performance, ensure {@link Writer} is buffered; wrapping in
@ -217,6 +221,22 @@ public class JsonWriter implements Closeable {
return htmlSafe; return htmlSafe;
} }
/**
* Sets whether object members are serialized when their value is null.
* This has no impact on array elements. The default is true.
*/
public final void setSerializeNulls(boolean serializeNulls) {
this.serializeNulls = serializeNulls;
}
/**
* Returns true if object members are serialized when their value is null.
* This has no impact on array elements. The default is true.
*/
public final boolean getSerializeNulls() {
return serializeNulls;
}
/** /**
* Begins encoding a new array. Each call to this method must be paired with * Begins encoding a new array. Each call to this method must be paired with
* a call to {@link #endArray}. * a call to {@link #endArray}.
@ -224,6 +244,7 @@ public class JsonWriter implements Closeable {
* @return this writer. * @return this writer.
*/ */
public JsonWriter beginArray() throws IOException { public JsonWriter beginArray() throws IOException {
writeDeferredName();
return open(JsonScope.EMPTY_ARRAY, "["); return open(JsonScope.EMPTY_ARRAY, "[");
} }
@ -243,6 +264,7 @@ public class JsonWriter implements Closeable {
* @return this writer. * @return this writer.
*/ */
public JsonWriter beginObject() throws IOException { public JsonWriter beginObject() throws IOException {
writeDeferredName();
return open(JsonScope.EMPTY_OBJECT, "{"); return open(JsonScope.EMPTY_OBJECT, "{");
} }
@ -276,6 +298,9 @@ public class JsonWriter implements Closeable {
if (context != nonempty && context != empty) { if (context != nonempty && context != empty) {
throw new IllegalStateException("Nesting problem: " + stack); throw new IllegalStateException("Nesting problem: " + stack);
} }
if (deferredName != null) {
throw new IllegalStateException("Dangling name: " + deferredName);
}
stack.remove(stack.size() - 1); stack.remove(stack.size() - 1);
if (context == nonempty) { if (context == nonempty) {
@ -309,11 +334,21 @@ public class JsonWriter implements Closeable {
if (name == null) { if (name == null) {
throw new NullPointerException("name == null"); throw new NullPointerException("name == null");
} }
beforeName(); if (deferredName != null) {
string(name); throw new IllegalStateException();
}
deferredName = name;
return this; return this;
} }
private void writeDeferredName() throws IOException {
if (deferredName != null) {
beforeName();
string(deferredName);
deferredName = null;
}
}
/** /**
* Encodes {@code value}. * Encodes {@code value}.
* *
@ -324,6 +359,7 @@ public class JsonWriter implements Closeable {
if (value == null) { if (value == null) {
return nullValue(); return nullValue();
} }
writeDeferredName();
beforeValue(false); beforeValue(false);
string(value); string(value);
return this; return this;
@ -335,6 +371,14 @@ public class JsonWriter implements Closeable {
* @return this writer. * @return this writer.
*/ */
public JsonWriter nullValue() throws IOException { public JsonWriter nullValue() throws IOException {
if (deferredName != null) {
if (serializeNulls) {
writeDeferredName();
} else {
deferredName = null;
return this; // skip the name and the value
}
}
beforeValue(false); beforeValue(false);
out.write("null"); out.write("null");
return this; return this;
@ -346,6 +390,7 @@ public class JsonWriter implements Closeable {
* @return this writer. * @return this writer.
*/ */
public JsonWriter value(boolean value) throws IOException { public JsonWriter value(boolean value) throws IOException {
writeDeferredName();
beforeValue(false); beforeValue(false);
out.write(value ? "true" : "false"); out.write(value ? "true" : "false");
return this; return this;
@ -362,6 +407,7 @@ public class JsonWriter implements Closeable {
if (Double.isNaN(value) || Double.isInfinite(value)) { if (Double.isNaN(value) || Double.isInfinite(value)) {
throw new IllegalArgumentException("Numeric values must be finite, but was " + value); throw new IllegalArgumentException("Numeric values must be finite, but was " + value);
} }
writeDeferredName();
beforeValue(false); beforeValue(false);
out.append(Double.toString(value)); out.append(Double.toString(value));
return this; return this;
@ -373,6 +419,7 @@ public class JsonWriter implements Closeable {
* @return this writer. * @return this writer.
*/ */
public JsonWriter value(long value) throws IOException { public JsonWriter value(long value) throws IOException {
writeDeferredName();
beforeValue(false); beforeValue(false);
out.write(Long.toString(value)); out.write(Long.toString(value));
return this; return this;
@ -390,6 +437,7 @@ public class JsonWriter implements Closeable {
return nullValue(); return nullValue();
} }
writeDeferredName();
String string = value.toString(); String string = value.toString();
if (!lenient if (!lenient
&& (string.equals("-Infinity") || string.equals("Infinity") || string.equals("NaN"))) { && (string.equals("-Infinity") || string.equals("Infinity") || string.equals("NaN"))) {

View File

@ -32,59 +32,59 @@ public class FieldExclusionTest extends TestCase {
private static final String VALUE = "blah_1234"; private static final String VALUE = "blah_1234";
private Outer outer; private Outer outer;
@Override @Override
protected void setUp() throws Exception { protected void setUp() throws Exception {
super.setUp(); super.setUp();
outer = new Outer(); outer = new Outer();
} }
public void testDefaultInnerClassExclusion() throws Exception { public void testDefaultInnerClassExclusion() throws Exception {
Gson gson = new Gson(); Gson gson = new Gson();
Outer.Inner target = outer.new Inner(VALUE); Outer.Inner target = outer.new Inner(VALUE);
String result = gson.toJson(target); String result = gson.toJson(target);
assertEquals(target.toJson(), result); assertEquals(target.toJson(), result);
gson = new GsonBuilder().create(); gson = new GsonBuilder().create();
target = outer.new Inner(VALUE); target = outer.new Inner(VALUE);
result = gson.toJson(target); result = gson.toJson(target);
assertEquals(target.toJson(), result); assertEquals(target.toJson(), result);
} }
public void testInnerClassExclusion() throws Exception { public void testInnerClassExclusion() throws Exception {
Gson gson = new GsonBuilder().disableInnerClassSerialization().create(); Gson gson = new GsonBuilder().disableInnerClassSerialization().create();
Outer.Inner target = outer.new Inner(VALUE); Outer.Inner target = outer.new Inner(VALUE);
String result = gson.toJson(target); String result = gson.toJson(target);
assertEquals("", result); assertEquals("null", result);
} }
public void testDefaultNestedStaticClassIncluded() throws Exception { public void testDefaultNestedStaticClassIncluded() throws Exception {
Gson gson = new Gson(); Gson gson = new Gson();
Outer.Inner target = outer.new Inner(VALUE); Outer.Inner target = outer.new Inner(VALUE);
String result = gson.toJson(target); String result = gson.toJson(target);
assertEquals(target.toJson(), result); assertEquals(target.toJson(), result);
gson = new GsonBuilder().create(); gson = new GsonBuilder().create();
target = outer.new Inner(VALUE); target = outer.new Inner(VALUE);
result = gson.toJson(target); result = gson.toJson(target);
assertEquals(target.toJson(), result); assertEquals(target.toJson(), result);
} }
private static class Outer { private static class Outer {
private class Inner extends NestedClass { private class Inner extends NestedClass {
public Inner(String value) { public Inner(String value) {
super(value); super(value);
} }
} }
} }
private static class NestedClass { private static class NestedClass {
private final String value; private final String value;
public NestedClass(String value) { public NestedClass(String value) {
this.value = value; this.value = value;
} }
public String toJson() { public String toJson() {
return "{\"value\":\"" + value + "\"}"; return "{\"value\":\"" + value + "\"}";
} }

View File

@ -61,7 +61,7 @@ public class ObjectTest extends TestCase {
assertEquals(10, target.intValue); assertEquals(10, target.intValue);
assertEquals(20, target.longValue); assertEquals(20, target.longValue);
} }
public void testJsonInMixedQuotesDeserialization() { public void testJsonInMixedQuotesDeserialization() {
String json = "{\"stringValue\":'no message','intValue':10,'longValue':20}"; String json = "{\"stringValue\":'no message','intValue':10,'longValue':20}";
BagOfPrimitives target = gson.fromJson(json, BagOfPrimitives.class); BagOfPrimitives target = gson.fromJson(json, BagOfPrimitives.class);
@ -69,7 +69,7 @@ public class ObjectTest extends TestCase {
assertEquals(10, target.intValue); assertEquals(10, target.intValue);
assertEquals(20, target.longValue); assertEquals(20, target.longValue);
} }
public void testBagOfPrimitivesSerialization() throws Exception { public void testBagOfPrimitivesSerialization() throws Exception {
BagOfPrimitives target = new BagOfPrimitives(10, 20, false, "stringValue"); BagOfPrimitives target = new BagOfPrimitives(10, 20, false, "stringValue");
assertEquals(target.getExpectedJson(), gson.toJson(target)); assertEquals(target.getExpectedJson(), gson.toJson(target));
@ -201,7 +201,7 @@ public class ObjectTest extends TestCase {
String stringValue = "someStringValueInArray"; String stringValue = "someStringValueInArray";
String classWithObjectsJson = gson.toJson(classWithObjects); String classWithObjectsJson = gson.toJson(classWithObjects);
String bagOfPrimitivesJson = gson.toJson(bagOfPrimitives); String bagOfPrimitivesJson = gson.toJson(bagOfPrimitives);
ClassWithArray classWithArray = new ClassWithArray( ClassWithArray classWithArray = new ClassWithArray(
new Object[] { stringValue, classWithObjects, bagOfPrimitives }); new Object[] { stringValue, classWithObjects, bagOfPrimitives });
String json = gson.toJson(classWithArray); String json = gson.toJson(classWithArray);
@ -267,7 +267,7 @@ public class ObjectTest extends TestCase {
} }
public void testAnonymousLocalClassesSerialization() throws Exception { public void testAnonymousLocalClassesSerialization() throws Exception {
assertEquals("", gson.toJson(new ClassWithNoFields() { assertEquals("null", gson.toJson(new ClassWithNoFields() {
// empty anonymous class // empty anonymous class
})); }));
} }
@ -278,7 +278,7 @@ public class ObjectTest extends TestCase {
} }
/** /**
* Tests that a class field with type Object can be serialized properly. * Tests that a class field with type Object can be serialized properly.
* See issue 54 * See issue 54
*/ */
public void testClassWithObjectFieldSerialization() { public void testClassWithObjectFieldSerialization() {
@ -292,28 +292,28 @@ public class ObjectTest extends TestCase {
@SuppressWarnings("unused") @SuppressWarnings("unused")
Object member; Object member;
} }
public void testInnerClassSerialization() { public void testInnerClassSerialization() {
Parent p = new Parent(); Parent p = new Parent();
Parent.Child c = p.new Child(); Parent.Child c = p.new Child();
String json = gson.toJson(c); String json = gson.toJson(c);
assertTrue(json.contains("value2")); assertTrue(json.contains("value2"));
assertFalse(json.contains("value1")); assertFalse(json.contains("value1"));
} }
public void testInnerClassDeserialization() { public void testInnerClassDeserialization() {
final Parent p = new Parent(); final Parent p = new Parent();
Gson gson = new GsonBuilder().registerTypeAdapter( Gson gson = new GsonBuilder().registerTypeAdapter(
Parent.Child.class, new InstanceCreator<Parent.Child>() { Parent.Child.class, new InstanceCreator<Parent.Child>() {
public Parent.Child createInstance(Type type) { public Parent.Child createInstance(Type type) {
return p.new Child(); return p.new Child();
} }
}).create(); }).create();
String json = "{'value2':3}"; String json = "{'value2':3}";
Parent.Child c = gson.fromJson(json, Parent.Child.class); Parent.Child c = gson.fromJson(json, Parent.Child.class);
assertEquals(3, c.value2); assertEquals(3, c.value2);
} }
private static class Parent { private static class Parent {
@SuppressWarnings("unused") @SuppressWarnings("unused")
int value1 = 1; int value1 = 1;
@ -365,7 +365,7 @@ public class ObjectTest extends TestCase {
a = 10; a = 10;
} }
} }
/** /**
* In response to Issue 41 http://code.google.com/p/google-gson/issues/detail?id=41 * In response to Issue 41 http://code.google.com/p/google-gson/issues/detail?id=41
*/ */
@ -376,16 +376,16 @@ public class ObjectTest extends TestCase {
assertTrue(bag.booleanValue); assertTrue(bag.booleanValue);
assertEquals("bar", bag.stringValue); assertEquals("bar", bag.stringValue);
} }
public void testStringFieldWithNumberValueDeserialization() { public void testStringFieldWithNumberValueDeserialization() {
String json = "{\"stringValue\":1}"; String json = "{\"stringValue\":1}";
BagOfPrimitives bag = gson.fromJson(json, BagOfPrimitives.class); BagOfPrimitives bag = gson.fromJson(json, BagOfPrimitives.class);
assertEquals("1", bag.stringValue); assertEquals("1", bag.stringValue);
json = "{\"stringValue\":1.5E+6}"; json = "{\"stringValue\":1.5E+6}";
bag = gson.fromJson(json, BagOfPrimitives.class); bag = gson.fromJson(json, BagOfPrimitives.class);
assertEquals("1.5E+6", bag.stringValue); assertEquals("1.5E+6", bag.stringValue);
json = "{\"stringValue\":true}"; json = "{\"stringValue\":true}";
bag = gson.fromJson(json, BagOfPrimitives.class); bag = gson.fromJson(json, BagOfPrimitives.class);
assertEquals("true", bag.stringValue); assertEquals("true", bag.stringValue);
@ -419,7 +419,7 @@ public class ObjectTest extends TestCase {
String b = ""; String b = "";
String c = ""; String c = "";
} }
public void testJsonObjectSerialization() { public void testJsonObjectSerialization() {
Gson gson = new GsonBuilder().serializeNulls().create(); Gson gson = new GsonBuilder().serializeNulls().create();
JsonObject obj = new JsonObject(); JsonObject obj = new JsonObject();

View File

@ -48,12 +48,12 @@ public class VersioningTest extends TestCase {
Gson gson = builder.setVersion(1.29).create(); Gson gson = builder.setVersion(1.29).create();
String json = gson.toJson(target); String json = gson.toJson(target);
assertTrue(json.contains("\"a\":" + A)); assertTrue(json.contains("\"a\":" + A));
gson = builder.setVersion(1.3).create(); gson = builder.setVersion(1.3).create();
json = gson.toJson(target); json = gson.toJson(target);
assertFalse(json.contains("\"a\":" + A)); assertFalse(json.contains("\"a\":" + A));
} }
public void testVersionedUntilDeserialization() { public void testVersionedUntilDeserialization() {
Gson gson = builder.setVersion(1.3).create(); Gson gson = builder.setVersion(1.3).create();
String json = "{\"a\":3,\"b\":4,\"c\":5}"; String json = "{\"a\":3,\"b\":4,\"c\":5}";
@ -82,7 +82,7 @@ public class VersioningTest extends TestCase {
public void testIgnoreLaterVersionClassSerialization() { public void testIgnoreLaterVersionClassSerialization() {
Gson gson = builder.setVersion(1.0).create(); Gson gson = builder.setVersion(1.0).create();
assertEquals("", gson.toJson(new Version1_2())); assertEquals("null", gson.toJson(new Version1_2()));
} }
public void testIgnoreLaterVersionClassDeserialization() { public void testIgnoreLaterVersionClassDeserialization() {
@ -117,11 +117,11 @@ public class VersioningTest extends TestCase {
SinceUntilMixing target = new SinceUntilMixing(); SinceUntilMixing target = new SinceUntilMixing();
String json = gson.toJson(target); String json = gson.toJson(target);
assertFalse(json.contains("\"b\":" + B)); assertFalse(json.contains("\"b\":" + B));
gson = builder.setVersion(1.2).create(); gson = builder.setVersion(1.2).create();
json = gson.toJson(target); json = gson.toJson(target);
assertTrue(json.contains("\"b\":" + B)); assertTrue(json.contains("\"b\":" + B));
gson = builder.setVersion(1.3).create(); gson = builder.setVersion(1.3).create();
json = gson.toJson(target); json = gson.toJson(target);
assertFalse(json.contains("\"b\":" + B)); assertFalse(json.contains("\"b\":" + B));
@ -133,12 +133,12 @@ public class VersioningTest extends TestCase {
SinceUntilMixing result = gson.fromJson(json, SinceUntilMixing.class); SinceUntilMixing result = gson.fromJson(json, SinceUntilMixing.class);
assertEquals(5, result.a); assertEquals(5, result.a);
assertEquals(B, result.b); assertEquals(B, result.b);
gson = builder.setVersion(1.2).create(); gson = builder.setVersion(1.2).create();
result = gson.fromJson(json, SinceUntilMixing.class); result = gson.fromJson(json, SinceUntilMixing.class);
assertEquals(5, result.a); assertEquals(5, result.a);
assertEquals(6, result.b); assertEquals(6, result.b);
gson = builder.setVersion(1.3).create(); gson = builder.setVersion(1.3).create();
result = gson.fromJson(json, SinceUntilMixing.class); result = gson.fromJson(json, SinceUntilMixing.class);
assertEquals(5, result.a); assertEquals(5, result.a);
@ -158,10 +158,10 @@ public class VersioningTest extends TestCase {
private static class Version1_2 extends Version1_1 { private static class Version1_2 extends Version1_1 {
int d = D; int d = D;
} }
private static class SinceUntilMixing { private static class SinceUntilMixing {
int a = A; int a = A;
@Since(1.1) @Since(1.1)
@Until(1.3) @Until(1.3)
int b = B; int b = B;

View File

@ -24,6 +24,7 @@ public final class JsonElementWriterTest extends TestCase {
// TODO: more tests // TODO: more tests
// TODO: close support // TODO: close support
// TODO: figure out what should be returned by an empty writer // TODO: figure out what should be returned by an empty writer
// TODO: test when serialize nulls is false
public void testArray() throws IOException { public void testArray() throws IOException {
JsonElementWriter writer = new JsonElementWriter(); JsonElementWriter writer = new JsonElementWriter();