1
16
17 package com.google.gson.internal.bind;
18
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;
29
30
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();
37 }
38 @Override public void flush() throws IOException {
39 throw new AssertionError();
40 }
41 @Override public void close() throws IOException {
42 throw new AssertionError();
43 }
44 };
45
46 private static final JsonPrimitive SENTINEL_CLOSED = new JsonPrimitive("closed");
47
48
49 private final List<JsonElement> stack = new ArrayList<JsonElement>();
50
51
52 private String pendingName;
53
54
55 private JsonElement product = JsonNull.INSTANCE;
56
57 public JsonTreeWriter() {
58 super(UNWRITABLE_WRITER);
59 }
60
61
64 public JsonElement get() {
65 if (!stack.isEmpty()) {
66 throw new IllegalStateException("Expected one JSON element but was " + stack);
67 }
68 return product;
69 }
70
71 private JsonElement peek() {
72 return stack.get(stack.size() - 1);
73 }
74
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);
80 }
81 pendingName = null;
82 } else if (stack.isEmpty()) {
83 product = value;
84 } else {
85 JsonElement element = peek();
86 if (element instanceof JsonArray) {
87 ((JsonArray) element).add(value);
88 } else {
89 throw new IllegalStateException();
90 }
91 }
92 }
93
94 @Override public JsonWriter beginArray() throws IOException {
95 JsonArray array = new JsonArray();
96 put(array);
97 stack.add(array);
98 return this;
99 }
100
101 @Override public JsonWriter endArray() throws IOException {
102 if (stack.isEmpty() || pendingName != null) {
103 throw new IllegalStateException();
104 }
105 JsonElement element = peek();
106 if (element instanceof JsonArray) {
107 stack.remove(stack.size() - 1);
108 return this;
109 }
110 throw new IllegalStateException();
111 }
112
113 @Override public JsonWriter beginObject() throws IOException {
114 JsonObject object = new JsonObject();
115 put(object);
116 stack.add(object);
117 return this;
118 }
119
120 @Override public JsonWriter endObject() throws IOException {
121 if (stack.isEmpty() || pendingName != null) {
122 throw new IllegalStateException();
123 }
124 JsonElement element = peek();
125 if (element instanceof JsonObject) {
126 stack.remove(stack.size() - 1);
127 return this;
128 }
129 throw new IllegalStateException();
130 }
131
132 @Override public JsonWriter name(String name) throws IOException {
133 if (stack.isEmpty() || pendingName != null) {
134 throw new IllegalStateException();
135 }
136 JsonElement element = peek();
137 if (element instanceof JsonObject) {
138 pendingName = name;
139 return this;
140 }
141 throw new IllegalStateException();
142 }
143
144 @Override public JsonWriter value(String value) throws IOException {
145 if (value == null) {
146 return nullValue();
147 }
148 put(new JsonPrimitive(value));
149 return this;
150 }
151
152 @Override public JsonWriter nullValue() throws IOException {
153 put(JsonNull.INSTANCE);
154 return this;
155 }
156
157 @Override public JsonWriter value(boolean value) throws IOException {
158 put(new JsonPrimitive(value));
159 return this;
160 }
161
162 @Override public JsonWriter value(Boolean value) throws IOException {
163 if (value == null) {
164 return nullValue();
165 }
166 put(new JsonPrimitive(value));
167 return this;
168 }
169
170 @Override public JsonWriter value(double value) throws IOException {
171 if (!isLenient() && (Double.isNaN(value) || Double.isInfinite(value))) {
172 throw new IllegalArgumentException("JSON forbids NaN and infinities: " + value);
173 }
174 put(new JsonPrimitive(value));
175 return this;
176 }
177
178 @Override public JsonWriter value(long value) throws IOException {
179 put(new JsonPrimitive(value));
180 return this;
181 }
182
183 @Override public JsonWriter value(Number value) throws IOException {
184 if (value == null) {
185 return nullValue();
186 }
187
188 if (!isLenient()) {
189 double d = value.doubleValue();
190 if (Double.isNaN(d) || Double.isInfinite(d)) {
191 throw new IllegalArgumentException("JSON forbids NaN and infinities: " + value);
192 }
193 }
194
195 put(new JsonPrimitive(value));
196 return this;
197 }
198
199 @Override public void flush() throws IOException {
200 }
201
202 @Override public void close() throws IOException {
203 if (!stack.isEmpty()) {
204 throw new IOException("Incomplete document");
205 }
206 stack.add(SENTINEL_CLOSED);
207 }
208 }
209