2 * Copyright (C) 2011 Google Inc.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 package com
.google
.gson
.internal
.bind
;
19 import com
.google
.gson
.JsonArray
;
20 import com
.google
.gson
.JsonElement
;
21 import com
.google
.gson
.JsonNull
;
22 import com
.google
.gson
.JsonObject
;
23 import com
.google
.gson
.JsonPrimitive
;
24 import com
.google
.gson
.stream
.JsonWriter
;
25 import java
.io
.IOException
;
26 import java
.io
.Writer
;
27 import java
.util
.ArrayList
;
28 import java
.util
.List
;
31 * This writer creates a JsonElement.
33 public final class JsonTreeWriter
extends JsonWriter
{
34 private static final Writer UNWRITABLE_WRITER
= new Writer() {
35 @Override public void write(char[] buffer
, int offset
, int counter
) {
36 throw new AssertionError();
38 @Override public void flush() throws IOException
{
39 throw new AssertionError();
41 @Override public void close() throws IOException
{
42 throw new AssertionError();
45 /** Added to the top of the stack when this writer is closed to cause following ops to fail. */
46 private static final JsonPrimitive SENTINEL_CLOSED
= new JsonPrimitive("closed");
48 /** The JsonElements and JsonArrays under modification, outermost to innermost. */
49 private final List
<JsonElement
> stack
= new ArrayList
<JsonElement
>();
51 /** The name for the next JSON object value. If non-null, the top of the stack is a JsonObject. */
52 private String pendingName
;
54 /** the JSON element constructed by this writer. */
55 private JsonElement product
= JsonNull
.INSTANCE
; // TODO: is this really what we want?;
57 public JsonTreeWriter() {
58 super(UNWRITABLE_WRITER
);
62 * Returns the top level object produced by this writer.
64 public JsonElement
get() {
65 if (!stack
.isEmpty()) {
66 throw new IllegalStateException("Expected one JSON element but was " + stack
);
71 private JsonElement
peek() {
72 return stack
.get(stack
.size() - 1);
75 private void put(JsonElement value
) {
76 if (pendingName
!= null) {
77 if (!value
.isJsonNull() || getSerializeNulls()) {
78 JsonObject object
= (JsonObject
) peek();
79 object
.add(pendingName
, value
);
82 } else if (stack
.isEmpty()) {
85 JsonElement element
= peek();
86 if (element
instanceof JsonArray
) {
87 ((JsonArray
) element
).add(value
);
89 throw new IllegalStateException();
94 @Override public JsonWriter
beginArray() throws IOException
{
95 JsonArray array
= new JsonArray();
101 @Override public JsonWriter
endArray() throws IOException
{
102 if (stack
.isEmpty() || pendingName
!= null) {
103 throw new IllegalStateException();
105 JsonElement element
= peek();
106 if (element
instanceof JsonArray
) {
107 stack
.remove(stack
.size() - 1);
110 throw new IllegalStateException();
113 @Override public JsonWriter
beginObject() throws IOException
{
114 JsonObject object
= new JsonObject();
120 @Override public JsonWriter
endObject() throws IOException
{
121 if (stack
.isEmpty() || pendingName
!= null) {
122 throw new IllegalStateException();
124 JsonElement element
= peek();
125 if (element
instanceof JsonObject
) {
126 stack
.remove(stack
.size() - 1);
129 throw new IllegalStateException();
132 @Override public JsonWriter
name(String name
) throws IOException
{
133 if (stack
.isEmpty() || pendingName
!= null) {
134 throw new IllegalStateException();
136 JsonElement element
= peek();
137 if (element
instanceof JsonObject
) {
141 throw new IllegalStateException();
144 @Override public JsonWriter
value(String value
) throws IOException
{
148 put(new JsonPrimitive(value
));
152 @Override public JsonWriter
nullValue() throws IOException
{
153 put(JsonNull
.INSTANCE
);
157 @Override public JsonWriter
value(boolean value
) throws IOException
{
158 put(new JsonPrimitive(value
));
162 @Override public JsonWriter
value(double value
) throws IOException
{
163 if (!isLenient() && (Double
.isNaN(value
) || Double
.isInfinite(value
))) {
164 throw new IllegalArgumentException("JSON forbids NaN and infinities: " + value
);
166 put(new JsonPrimitive(value
));
170 @Override public JsonWriter
value(long value
) throws IOException
{
171 put(new JsonPrimitive(value
));
175 @Override public JsonWriter
value(Number value
) throws IOException
{
181 double d
= value
.doubleValue();
182 if (Double
.isNaN(d
) || Double
.isInfinite(d
)) {
183 throw new IllegalArgumentException("JSON forbids NaN and infinities: " + value
);
187 put(new JsonPrimitive(value
));
191 @Override public void flush() throws IOException
{
194 @Override public void close() throws IOException
{
195 if (!stack
.isEmpty()) {
196 throw new IOException("Incomplete document");
198 stack
.add(SENTINEL_CLOSED
);