root / org.gvsig.toolbox / trunk / org.gvsig.toolbox / org.gvsig.toolbox.algorithm / src / main / java / org / json / JSONWriter.java @ 59
History | View | Annotate | Download (10 KB)
1 |
package org.json; |
---|---|
2 |
|
3 |
import java.io.IOException; |
4 |
import java.io.Writer; |
5 |
|
6 |
/*
|
7 |
Copyright (c) 2006 JSON.org
|
8 |
|
9 |
Permission is hereby granted, free of charge, to any person obtaining a copy
|
10 |
of this software and associated documentation files (the "Software"), to deal
|
11 |
in the Software without restriction, including without limitation the rights
|
12 |
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
13 |
copies of the Software, and to permit persons to whom the Software is
|
14 |
furnished to do so, subject to the following conditions:
|
15 |
|
16 |
The above copyright notice and this permission notice shall be included in all
|
17 |
copies or substantial portions of the Software.
|
18 |
|
19 |
The Software shall be used for Good, not Evil.
|
20 |
|
21 |
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
22 |
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
23 |
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
24 |
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
25 |
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
26 |
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
27 |
SOFTWARE.
|
28 |
*/
|
29 |
|
30 |
/**
|
31 |
* JSONWriter provides a quick and convenient way of producing JSON text. The texts produced strictly conform to JSON syntax
|
32 |
* rules. No whitespace is added, so the results are ready for transmission or storage. Each instance of JSONWriter can produce
|
33 |
* one JSON text.
|
34 |
* <p>
|
35 |
* A JSONWriter instance provides a <code>value</code> method for appending values to the text, and a <code>key</code> method
|
36 |
* for adding keys before values in objects. There are <code>array</code> and <code>endArray</code> methods that make and
|
37 |
* bound array values, and <code>object</code> and <code>endObject</code> methods which make and bound object values. All of
|
38 |
* these methods return the JSONWriter instance, permitting a cascade style. For example,
|
39 |
*
|
40 |
* <pre>
|
41 |
* new JSONWriter(myWriter).object().key("JSON").value("Hello, World!").endObject();
|
42 |
* </pre>
|
43 |
*
|
44 |
* which writes
|
45 |
*
|
46 |
* <pre>
|
47 |
* {"JSON":"Hello, World!"}
|
48 |
* </pre>
|
49 |
*
|
50 |
* <p>
|
51 |
* The first method called must be <code>array</code> or <code>object</code>. There are no methods for adding commas or
|
52 |
* colons. JSONWriter adds them for you. Objects and arrays can be nested up to 20 levels deep.
|
53 |
* <p>
|
54 |
* This can sometimes be easier than using a JSONObject to build a string.
|
55 |
*
|
56 |
* @author JSON.org
|
57 |
* @version 2
|
58 |
*/
|
59 |
public class JSONWriter { |
60 |
private static final int maxdepth = 20; |
61 |
|
62 |
/**
|
63 |
* The comma flag determines if a comma should be output before the next value.
|
64 |
*/
|
65 |
private boolean comma; |
66 |
|
67 |
/**
|
68 |
* The current mode. Values: 'a' (array), 'd' (done), 'i' (initial), 'k' (key), 'o' (object).
|
69 |
*/
|
70 |
protected char mode; |
71 |
|
72 |
/**
|
73 |
* The object/array stack.
|
74 |
*/
|
75 |
private final char stack[]; |
76 |
|
77 |
/**
|
78 |
* The stack top index. A value of 0 indicates that the stack is empty.
|
79 |
*/
|
80 |
private int top; |
81 |
|
82 |
/**
|
83 |
* The writer that will receive the output.
|
84 |
*/
|
85 |
protected Writer writer; |
86 |
|
87 |
|
88 |
/**
|
89 |
* Make a fresh JSONWriter. It can be used to build one JSON text.
|
90 |
*/
|
91 |
public JSONWriter(final Writer w) { |
92 |
this.comma = false; |
93 |
this.mode = 'i'; |
94 |
this.stack = new char[maxdepth]; |
95 |
this.top = 0; |
96 |
this.writer = w;
|
97 |
} |
98 |
|
99 |
|
100 |
/**
|
101 |
* Append a value.
|
102 |
*
|
103 |
* @param s
|
104 |
* A string value.
|
105 |
* @return this
|
106 |
* @throws JSONException
|
107 |
* If the value is out of sequence.
|
108 |
*/
|
109 |
private JSONWriter append(final String s) throws JSONException { |
110 |
if (s == null) { |
111 |
throw new JSONException("Null pointer"); |
112 |
} |
113 |
if (this.mode == 'o' || this.mode == 'a') { |
114 |
try {
|
115 |
if (this.comma && this.mode == 'a') { |
116 |
this.writer.write(','); |
117 |
} |
118 |
this.writer.write(s);
|
119 |
} |
120 |
catch (final IOException e) { |
121 |
throw new JSONException(e); |
122 |
} |
123 |
if (this.mode == 'o') { |
124 |
this.mode = 'k'; |
125 |
} |
126 |
this.comma = true; |
127 |
return this; |
128 |
} |
129 |
throw new JSONException("Value out of sequence."); |
130 |
} |
131 |
|
132 |
|
133 |
/**
|
134 |
* Begin appending a new array. All values until the balancing <code>endArray</code> will be appended to this array. The
|
135 |
* <code>endArray</code> method must be called to mark the array's end.
|
136 |
*
|
137 |
* @return this
|
138 |
* @throws JSONException
|
139 |
* If the nesting is too deep, or if the object is started in the wrong place (for example as a key or after
|
140 |
* the end of the outermost array or object).
|
141 |
*/
|
142 |
public JSONWriter array() throws JSONException { |
143 |
if (this.mode == 'i' || this.mode == 'o' || this.mode == 'a') { |
144 |
this.push('a'); |
145 |
this.append("["); |
146 |
this.comma = false; |
147 |
return this; |
148 |
} |
149 |
throw new JSONException("Misplaced array."); |
150 |
} |
151 |
|
152 |
|
153 |
/**
|
154 |
* End something.
|
155 |
*
|
156 |
* @param m
|
157 |
* Mode
|
158 |
* @param c
|
159 |
* Closing character
|
160 |
* @return this
|
161 |
* @throws JSONException
|
162 |
* If unbalanced.
|
163 |
*/
|
164 |
private JSONWriter end(final char m, |
165 |
final char c) throws JSONException { |
166 |
if (this.mode != m) { |
167 |
throw new JSONException(m == 'o' ? "Misplaced endObject." : "Misplaced endArray."); |
168 |
} |
169 |
this.pop(m);
|
170 |
try {
|
171 |
this.writer.write(c);
|
172 |
} |
173 |
catch (final IOException e) { |
174 |
throw new JSONException(e); |
175 |
} |
176 |
this.comma = true; |
177 |
return this; |
178 |
} |
179 |
|
180 |
|
181 |
/**
|
182 |
* End an array. This method most be called to balance calls to <code>array</code>.
|
183 |
*
|
184 |
* @return this
|
185 |
* @throws JSONException
|
186 |
* If incorrectly nested.
|
187 |
*/
|
188 |
public JSONWriter endArray() throws JSONException { |
189 |
return this.end('a', ']'); |
190 |
} |
191 |
|
192 |
|
193 |
/**
|
194 |
* End an object. This method most be called to balance calls to <code>object</code>.
|
195 |
*
|
196 |
* @return this
|
197 |
* @throws JSONException
|
198 |
* If incorrectly nested.
|
199 |
*/
|
200 |
public JSONWriter endObject() throws JSONException { |
201 |
return this.end('k', '}'); |
202 |
} |
203 |
|
204 |
|
205 |
/**
|
206 |
* Append a key. The key will be associated with the next value. In an object, every value must be preceded by a key.
|
207 |
*
|
208 |
* @param s
|
209 |
* A key string.
|
210 |
* @return this
|
211 |
* @throws JSONException
|
212 |
* If the key is out of place. For example, keys do not belong in arrays or if the key is null.
|
213 |
*/
|
214 |
public JSONWriter key(final String s) throws JSONException { |
215 |
if (s == null) { |
216 |
throw new JSONException("Null key."); |
217 |
} |
218 |
if (this.mode == 'k') { |
219 |
try {
|
220 |
if (this.comma) { |
221 |
this.writer.write(','); |
222 |
} |
223 |
this.writer.write(JSONObject.quote(s));
|
224 |
this.writer.write(':'); |
225 |
this.comma = false; |
226 |
this.mode = 'o'; |
227 |
return this; |
228 |
} |
229 |
catch (final IOException e) { |
230 |
throw new JSONException(e); |
231 |
} |
232 |
} |
233 |
throw new JSONException("Misplaced key."); |
234 |
} |
235 |
|
236 |
|
237 |
/**
|
238 |
* Begin appending a new object. All keys and values until the balancing <code>endObject</code> will be appended to this
|
239 |
* object. The <code>endObject</code> method must be called to mark the object's end.
|
240 |
*
|
241 |
* @return this
|
242 |
* @throws JSONException
|
243 |
* If the nesting is too deep, or if the object is started in the wrong place (for example as a key or after
|
244 |
* the end of the outermost array or object).
|
245 |
*/
|
246 |
public JSONWriter object() throws JSONException { |
247 |
if (this.mode == 'i') { |
248 |
this.mode = 'o'; |
249 |
} |
250 |
if (this.mode == 'o' || this.mode == 'a') { |
251 |
this.append("{"); |
252 |
this.push('k'); |
253 |
this.comma = false; |
254 |
return this; |
255 |
} |
256 |
throw new JSONException("Misplaced object."); |
257 |
|
258 |
} |
259 |
|
260 |
|
261 |
/**
|
262 |
* Pop an array or object scope.
|
263 |
*
|
264 |
* @param c
|
265 |
* The scope to close.
|
266 |
* @throws JSONException
|
267 |
* If nesting is wrong.
|
268 |
*/
|
269 |
private void pop(final char c) throws JSONException { |
270 |
if (this.top <= 0 || this.stack[this.top - 1] != c) { |
271 |
throw new JSONException("Nesting error."); |
272 |
} |
273 |
this.top -= 1; |
274 |
this.mode = this.top == 0 ? 'd' : this.stack[this.top - 1]; |
275 |
} |
276 |
|
277 |
|
278 |
/**
|
279 |
* Push an array or object scope.
|
280 |
*
|
281 |
* @param c
|
282 |
* The scope to open.
|
283 |
* @throws JSONException
|
284 |
* If nesting is too deep.
|
285 |
*/
|
286 |
private void push(final char c) throws JSONException { |
287 |
if (this.top >= maxdepth) { |
288 |
throw new JSONException("Nesting too deep."); |
289 |
} |
290 |
this.stack[this.top] = c; |
291 |
this.mode = c;
|
292 |
this.top += 1; |
293 |
} |
294 |
|
295 |
|
296 |
/**
|
297 |
* Append either the value <code>true</code> or the value <code>false</code>.
|
298 |
*
|
299 |
* @param b
|
300 |
* A boolean.
|
301 |
* @return this
|
302 |
* @throws JSONException
|
303 |
*/
|
304 |
public JSONWriter value(final boolean b) throws JSONException { |
305 |
return this.append(b ? "true" : "false"); |
306 |
} |
307 |
|
308 |
|
309 |
/**
|
310 |
* Append a double value.
|
311 |
*
|
312 |
* @param d
|
313 |
* A double.
|
314 |
* @return this
|
315 |
* @throws JSONException
|
316 |
* If the number is not finite.
|
317 |
*/
|
318 |
public JSONWriter value(final double d) throws JSONException { |
319 |
return this.value(new Double(d)); |
320 |
} |
321 |
|
322 |
|
323 |
/**
|
324 |
* Append a long value.
|
325 |
*
|
326 |
* @param l
|
327 |
* A long.
|
328 |
* @return this
|
329 |
* @throws JSONException
|
330 |
*/
|
331 |
public JSONWriter value(final long l) throws JSONException { |
332 |
return this.append(Long.toString(l)); |
333 |
} |
334 |
|
335 |
|
336 |
/**
|
337 |
* Append an object value.
|
338 |
*
|
339 |
* @param o
|
340 |
* The object to append. It can be null, or a Boolean, Number, String, JSONObject, or JSONArray, or an object
|
341 |
* with a toJSONString() method.
|
342 |
* @return this
|
343 |
* @throws JSONException
|
344 |
* If the value is out of sequence.
|
345 |
*/
|
346 |
public JSONWriter value(final Object o) throws JSONException { |
347 |
return this.append(JSONObject.valueToString(o)); |
348 |
} |
349 |
} |