]>
Commit | Line | Data |
---|---|---|
1 | /* | |
2 | * Copyright (C) 2011 Google Inc. | |
3 | * | |
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 | |
7 | * | |
8 | * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | * | |
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. | |
15 | */ | |
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 | /** | |
31 | * This writer creates a JsonElement. | |
32 | */ | |
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 | /** 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"); | |
47 | ||
48 | /** The JsonElements and JsonArrays under modification, outermost to innermost. */ | |
49 | private final List<JsonElement> stack = new ArrayList<JsonElement>(); | |
50 | ||
51 | /** The name for the next JSON object value. If non-null, the top of the stack is a JsonObject. */ | |
52 | private String pendingName; | |
53 | ||
54 | /** the JSON element constructed by this writer. */ | |
55 | private JsonElement product = JsonNull.INSTANCE; // TODO: is this really what we want?; | |
56 | ||
57 | public JsonTreeWriter() { | |
58 | super(UNWRITABLE_WRITER); | |
59 | } | |
60 | ||
61 | /** | |
62 | * Returns the top level object produced by this writer. | |
63 | */ | |
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(double value) throws IOException { | |
163 | if (!isLenient() && (Double.isNaN(value) || Double.isInfinite(value))) { | |
164 | throw new IllegalArgumentException("JSON forbids NaN and infinities: " + value); | |
165 | } | |
166 | put(new JsonPrimitive(value)); | |
167 | return this; | |
168 | } | |
169 | ||
170 | @Override public JsonWriter value(long value) throws IOException { | |
171 | put(new JsonPrimitive(value)); | |
172 | return this; | |
173 | } | |
174 | ||
175 | @Override public JsonWriter value(Number value) throws IOException { | |
176 | if (value == null) { | |
177 | return nullValue(); | |
178 | } | |
179 | ||
180 | if (!isLenient()) { | |
181 | double d = value.doubleValue(); | |
182 | if (Double.isNaN(d) || Double.isInfinite(d)) { | |
183 | throw new IllegalArgumentException("JSON forbids NaN and infinities: " + value); | |
184 | } | |
185 | } | |
186 | ||
187 | put(new JsonPrimitive(value)); | |
188 | return this; | |
189 | } | |
190 | ||
191 | @Override public void flush() throws IOException { | |
192 | } | |
193 | ||
194 | @Override public void close() throws IOException { | |
195 | if (!stack.isEmpty()) { | |
196 | throw new IOException("Incomplete document"); | |
197 | } | |
198 | stack.add(SENTINEL_CLOSED); | |
199 | } | |
200 | } |