Statistics
| Revision:

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(&quot;JSON&quot;).value(&quot;Hello, World!&quot;).endObject();
42
 * </pre>
43
 *
44
 * which writes
45
 *
46
 * <pre>
47
 * {&quot;JSON&quot;:&quot;Hello, World!&quot;}
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
}