6a8362805b32c1a6749dfbe649b8d388b16f30dc
[unical.git] / gson / com / google / gson / internal / bind / JsonTreeReader.java
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.JsonReader;
25 import com.google.gson.stream.JsonToken;
26 import java.io.IOException;
27 import java.io.Reader;
28 import java.util.ArrayList;
29 import java.util.Iterator;
30 import java.util.List;
31 import java.util.Map;
32
33 /**
34 * This reader walks the elements of a JsonElement as if it was coming from a
35 * character stream.
36 *
37 * @author Jesse Wilson
38 */
39 public final class JsonTreeReader extends JsonReader {
40 private static final Reader UNREADABLE_READER = new Reader() {
41 @Override public int read(char[] buffer, int offset, int count) throws IOException {
42 throw new AssertionError();
43 }
44 @Override public void close() throws IOException {
45 throw new AssertionError();
46 }
47 };
48 private static final Object SENTINEL_CLOSED = new Object();
49
50 private final List<Object> stack = new ArrayList<Object>();
51
52 public JsonTreeReader(JsonElement element) {
53 super(UNREADABLE_READER);
54 stack.add(element);
55 }
56
57 @Override public void beginArray() throws IOException {
58 expect(JsonToken.BEGIN_ARRAY);
59 JsonArray array = (JsonArray) peekStack();
60 stack.add(array.iterator());
61 }
62
63 @Override public void endArray() throws IOException {
64 expect(JsonToken.END_ARRAY);
65 popStack(); // empty iterator
66 popStack(); // array
67 }
68
69 @Override public void beginObject() throws IOException {
70 expect(JsonToken.BEGIN_OBJECT);
71 JsonObject object = (JsonObject) peekStack();
72 stack.add(object.entrySet().iterator());
73 }
74
75 @Override public void endObject() throws IOException {
76 expect(JsonToken.END_OBJECT);
77 popStack(); // empty iterator
78 popStack(); // object
79 }
80
81 @Override public boolean hasNext() throws IOException {
82 JsonToken token = peek();
83 return token != JsonToken.END_OBJECT && token != JsonToken.END_ARRAY;
84 }
85
86 @Override public JsonToken peek() throws IOException {
87 if (stack.isEmpty()) {
88 return JsonToken.END_DOCUMENT;
89 }
90
91 Object o = peekStack();
92 if (o instanceof Iterator) {
93 boolean isObject = stack.get(stack.size() - 2) instanceof JsonObject;
94 Iterator<?> iterator = (Iterator<?>) o;
95 if (iterator.hasNext()) {
96 if (isObject) {
97 return JsonToken.NAME;
98 } else {
99 stack.add(iterator.next());
100 return peek();
101 }
102 } else {
103 return isObject ? JsonToken.END_OBJECT : JsonToken.END_ARRAY;
104 }
105 } else if (o instanceof JsonObject) {
106 return JsonToken.BEGIN_OBJECT;
107 } else if (o instanceof JsonArray) {
108 return JsonToken.BEGIN_ARRAY;
109 } else if (o instanceof JsonPrimitive) {
110 JsonPrimitive primitive = (JsonPrimitive) o;
111 if (primitive.isString()) {
112 return JsonToken.STRING;
113 } else if (primitive.isBoolean()) {
114 return JsonToken.BOOLEAN;
115 } else if (primitive.isNumber()) {
116 return JsonToken.NUMBER;
117 } else {
118 throw new AssertionError();
119 }
120 } else if (o instanceof JsonNull) {
121 return JsonToken.NULL;
122 } else if (o == SENTINEL_CLOSED) {
123 throw new IllegalStateException("JsonReader is closed");
124 } else {
125 throw new AssertionError();
126 }
127 }
128
129 private Object peekStack() {
130 return stack.get(stack.size() - 1);
131 }
132
133 private Object popStack() {
134 return stack.remove(stack.size() - 1);
135 }
136
137 private void expect(JsonToken expected) throws IOException {
138 if (peek() != expected) {
139 throw new IllegalStateException("Expected " + expected + " but was " + peek());
140 }
141 }
142
143 @Override public String nextName() throws IOException {
144 expect(JsonToken.NAME);
145 Iterator<?> i = (Iterator<?>) peekStack();
146 Map.Entry<?, ?> entry = (Map.Entry<?, ?>) i.next();
147 stack.add(entry.getValue());
148 return (String) entry.getKey();
149 }
150
151 @Override public String nextString() throws IOException {
152 JsonToken token = peek();
153 if (token != JsonToken.STRING && token != JsonToken.NUMBER) {
154 throw new IllegalStateException("Expected " + JsonToken.STRING + " but was " + token);
155 }
156 return ((JsonPrimitive) popStack()).getAsString();
157 }
158
159 @Override public boolean nextBoolean() throws IOException {
160 expect(JsonToken.BOOLEAN);
161 return ((JsonPrimitive) popStack()).getAsBoolean();
162 }
163
164 @Override public void nextNull() throws IOException {
165 expect(JsonToken.NULL);
166 popStack();
167 }
168
169 @Override public double nextDouble() throws IOException {
170 JsonToken token = peek();
171 if (token != JsonToken.NUMBER && token != JsonToken.STRING) {
172 throw new IllegalStateException("Expected " + JsonToken.NUMBER + " but was " + token);
173 }
174 double result = ((JsonPrimitive) peekStack()).getAsDouble();
175 if (!isLenient() && (Double.isNaN(result) || Double.isInfinite(result))) {
176 throw new NumberFormatException("JSON forbids NaN and infinities: " + result);
177 }
178 popStack();
179 return result;
180 }
181
182 @Override public long nextLong() throws IOException {
183 JsonToken token = peek();
184 if (token != JsonToken.NUMBER && token != JsonToken.STRING) {
185 throw new IllegalStateException("Expected " + JsonToken.NUMBER + " but was " + token);
186 }
187 long result = ((JsonPrimitive) peekStack()).getAsLong();
188 popStack();
189 return result;
190 }
191
192 @Override public int nextInt() throws IOException {
193 JsonToken token = peek();
194 if (token != JsonToken.NUMBER && token != JsonToken.STRING) {
195 throw new IllegalStateException("Expected " + JsonToken.NUMBER + " but was " + token);
196 }
197 int result = ((JsonPrimitive) peekStack()).getAsInt();
198 popStack();
199 return result;
200 }
201
202 @Override public void close() throws IOException {
203 stack.clear();
204 stack.add(SENTINEL_CLOSED);
205 }
206
207 @Override public void skipValue() throws IOException {
208 if (peek() == JsonToken.NAME) {
209 nextName();
210 } else {
211 popStack();
212 }
213 }
214
215 @Override public String toString() {
216 return getClass().getSimpleName();
217 }
218
219 public void promoteNameToValue() throws IOException {
220 expect(JsonToken.NAME);
221 Iterator<?> i = (Iterator<?>) peekStack();
222 Map.Entry<?, ?> entry = (Map.Entry<?, ?>) i.next();
223 stack.add(entry.getValue());
224 stack.add(new JsonPrimitive((String)entry.getKey()));
225 }
226 }
This page took 0.028499 seconds and 3 git commands to generate.