diff --git a/gson/src/main/java/com/google/gson/internal/bind/JsonElementWriter.java b/gson/src/main/java/com/google/gson/internal/bind/JsonElementWriter.java new file mode 100644 index 00000000..a6ea3641 --- /dev/null +++ b/gson/src/main/java/com/google/gson/internal/bind/JsonElementWriter.java @@ -0,0 +1,166 @@ +/* + * 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.internal.bind; + +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonNull; +import com.google.gson.JsonObject; +import com.google.gson.JsonPrimitive; +import com.google.gson.stream.JsonWriter; +import java.io.IOException; +import java.io.Writer; +import java.util.ArrayList; +import java.util.List; + +/** + * This writer writes a JsonElement. + */ +public final class JsonElementWriter extends JsonWriter { + private static final Writer UNWRITABLE_WRITER = new Writer() { + @Override public void write(char[] buffer, int offset, int counter) { + throw new AssertionError(); + } + @Override public void flush() throws IOException { + throw new AssertionError(); + } + @Override public void close() throws IOException { + throw new AssertionError(); + } + }; + + private final List stack = new ArrayList(); + private String pendingName; + + public JsonElementWriter() { + super(UNWRITABLE_WRITER); + } + + public JsonElement get() { + if (stack.size() != 1) { + throw new IllegalStateException(); + } + return stack.get(0); + } + + private JsonElement peek() { + return stack.get(stack.size() - 1); + } + + private void put(JsonElement value) { + if (pendingName != null) { + JsonObject object = (JsonObject) peek(); + object.add(pendingName, value); + pendingName = null; + } else if (stack.isEmpty()) { + stack.add(value); + } else { + JsonElement element = peek(); + if (element instanceof JsonArray) { + ((JsonArray) element).add(value); + } else { + throw new IllegalStateException(); + } + } + } + + @Override public JsonWriter beginArray() throws IOException { + JsonArray array = new JsonArray(); + put(array); + stack.add(array); + return this; + } + + @Override public JsonWriter endArray() throws IOException { + if (stack.isEmpty() || pendingName != null) { + throw new IllegalStateException(); + } + JsonElement element = peek(); + if (element instanceof JsonArray) { + stack.remove(stack.size() - 1); + return this; + } + throw new IllegalStateException(); + } + + @Override public JsonWriter beginObject() throws IOException { + JsonObject object = new JsonObject(); + put(object); + stack.add(object); + return this; + } + + @Override public JsonWriter endObject() throws IOException { + if (stack.isEmpty() || pendingName != null) { + throw new IllegalStateException(); + } + JsonElement element = peek(); + if (element instanceof JsonObject) { + stack.remove(stack.size() - 1); + return this; + } + throw new IllegalStateException(); + } + + @Override public JsonWriter name(String name) throws IOException { + if (stack.isEmpty() || pendingName != null) { + throw new IllegalStateException(); + } + JsonElement element = peek(); + if (element instanceof JsonObject) { + pendingName = name; + return this; + } + throw new IllegalStateException(); + } + + @Override public JsonWriter value(String value) throws IOException { + put(new JsonPrimitive(value)); + return this; + } + + @Override public JsonWriter nullValue() throws IOException { + put(JsonNull.INSTANCE); + return this; + } + + @Override public JsonWriter value(boolean value) throws IOException { + put(new JsonPrimitive(value)); + return this; + } + + @Override public JsonWriter value(double value) throws IOException { + put(new JsonPrimitive(value)); + return this; + } + + @Override public JsonWriter value(long value) throws IOException { + put(new JsonPrimitive(value)); + return this; + } + + @Override public JsonWriter value(Number value) throws IOException { + put(new JsonPrimitive(value)); + return this; + } + + @Override public void flush() throws IOException { + } + + @Override public void close() throws IOException { + } +} diff --git a/gson/src/main/java/com/google/gson/stream/JsonWriter.java b/gson/src/main/java/com/google/gson/stream/JsonWriter.java index 0e3691ce..49d16d11 100644 --- a/gson/src/main/java/com/google/gson/stream/JsonWriter.java +++ b/gson/src/main/java/com/google/gson/stream/JsonWriter.java @@ -120,7 +120,7 @@ import java.util.List; * @author Jesse Wilson * @since 1.6 */ -public final class JsonWriter implements Closeable { +public class JsonWriter implements Closeable { /** The output data, containing at most one top-level array or object. */ private final Writer out; @@ -165,7 +165,7 @@ public final class JsonWriter implements Closeable { * * @param indent a string containing only whitespace. */ - public void setIndent(String indent) { + public final void setIndent(String indent) { if (indent.length() == 0) { this.indent = null; this.separator = ":"; @@ -187,7 +187,7 @@ public final class JsonWriter implements Closeable { * Double#isInfinite() infinities}. * */ - public void setLenient(boolean lenient) { + public final void setLenient(boolean lenient) { this.lenient = lenient; } @@ -205,7 +205,7 @@ public final class JsonWriter implements Closeable { * setting, your XML/HTML encoder should replace these characters with the * corresponding escape sequences. */ - public void setHtmlSafe(boolean htmlSafe) { + public final void setHtmlSafe(boolean htmlSafe) { this.htmlSafe = htmlSafe; } @@ -213,7 +213,7 @@ public final class JsonWriter implements Closeable { * Returns true if this writer writes JSON that's safe for inclusion in HTML * and XML documents. */ - public boolean isHtmlSafe() { + public final boolean isHtmlSafe() { return htmlSafe; } diff --git a/gson/src/test/java/com/google/gson/internal/bind/JsonElementWriterTest.java b/gson/src/test/java/com/google/gson/internal/bind/JsonElementWriterTest.java new file mode 100644 index 00000000..2ba05589 --- /dev/null +++ b/gson/src/test/java/com/google/gson/internal/bind/JsonElementWriterTest.java @@ -0,0 +1,74 @@ +/* + * 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.internal.bind; + +import java.io.IOException; +import junit.framework.TestCase; + +public final class JsonElementWriterTest extends TestCase { + + // TODO: more tests + // TODO: close support + + public void testArray() throws IOException { + JsonElementWriter writer = new JsonElementWriter(); + writer.beginArray(); + writer.value(1); + writer.value(2); + writer.value(3); + writer.endArray(); + assertEquals("[1,2,3]", writer.get().toString()); + } + + public void testNestedArray() throws IOException { + JsonElementWriter writer = new JsonElementWriter(); + writer.beginArray(); + writer.beginArray(); + writer.endArray(); + writer.beginArray(); + writer.beginArray(); + writer.endArray(); + writer.endArray(); + writer.endArray(); + assertEquals("[[],[[]]]", writer.get().toString()); + } + + public void testObject() throws IOException { + JsonElementWriter writer = new JsonElementWriter(); + writer.beginObject(); + writer.name("A").value(1); + writer.name("B").value(2); + writer.endObject(); + assertEquals("{\"A\":1,\"B\":2}", writer.get().toString()); + } + + public void testNestedObject() throws IOException { + JsonElementWriter writer = new JsonElementWriter(); + writer.beginObject(); + writer.name("A"); + writer.beginObject(); + writer.name("B"); + writer.beginObject(); + writer.endObject(); + writer.endObject(); + writer.name("C"); + writer.beginObject(); + writer.endObject(); + writer.endObject(); + assertEquals("{\"A\":{\"B\":{}},\"C\":{}}", writer.get().toString()); + } +}