Statistics
| Branch: | Tag: | Revision:

root / src / org / json / JSONWriter.java @ 4bf05cad

History | View | Annotate | Download (10 kB)

1 14ad7326 pastith
package org.json;
2 14ad7326 pastith
3 14ad7326 pastith
import java.io.IOException;
4 14ad7326 pastith
import java.io.Writer;
5 14ad7326 pastith
6 14ad7326 pastith
/*
7 14ad7326 pastith
Copyright (c) 2006 JSON.org
8 14ad7326 pastith

9 14ad7326 pastith
Permission is hereby granted, free of charge, to any person obtaining a copy
10 14ad7326 pastith
of this software and associated documentation files (the "Software"), to deal
11 14ad7326 pastith
in the Software without restriction, including without limitation the rights
12 14ad7326 pastith
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 14ad7326 pastith
copies of the Software, and to permit persons to whom the Software is
14 14ad7326 pastith
furnished to do so, subject to the following conditions:
15 14ad7326 pastith

16 14ad7326 pastith
The above copyright notice and this permission notice shall be included in all
17 14ad7326 pastith
copies or substantial portions of the Software.
18 14ad7326 pastith

19 14ad7326 pastith
The Software shall be used for Good, not Evil.
20 14ad7326 pastith

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