1package com.google.polo.json;
2
3/*
4Copyright (c) 2002 JSON.org
5
6Permission is hereby granted, free of charge, to any person obtaining a copy
7of this software and associated documentation files (the "Software"), to deal
8in the Software without restriction, including without limitation the rights
9to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10copies of the Software, and to permit persons to whom the Software is
11furnished to do so, subject to the following conditions:
12
13The above copyright notice and this permission notice shall be included in all
14copies or substantial portions of the Software.
15
16The Software shall be used for Good, not Evil.
17
18THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24SOFTWARE.
25*/
26
27import java.io.IOException;
28import java.io.Writer;
29import java.lang.reflect.Field;
30import java.lang.reflect.Modifier;
31import java.lang.reflect.Method;
32import java.util.Collection;
33import java.util.HashMap;
34import java.util.Iterator;
35import java.util.Map;
36import java.util.TreeSet;
37
38/**
39 * A JSONObject is an unordered collection of name/value pairs. Its
40 * external form is a string wrapped in curly braces with colons between the
41 * names and values, and commas between the values and names. The internal form
42 * is an object having <code>get</code> and <code>opt</code> methods for
43 * accessing the values by name, and <code>put</code> methods for adding or
44 * replacing values by name. The values can be any of these types:
45 * <code>Boolean</code>, <code>JSONArray</code>, <code>JSONObject</code>,
46 * <code>Number</code>, <code>String</code>, or the <code>JSONObject.NULL</code>
47 * object. A JSONObject constructor can be used to convert an external form
48 * JSON text into an internal form whose values can be retrieved with the
49 * <code>get</code> and <code>opt</code> methods, or to convert values into a
50 * JSON text using the <code>put</code> and <code>toString</code> methods.
51 * A <code>get</code> method returns a value if one can be found, and throws an
52 * exception if one cannot be found. An <code>opt</code> method returns a
53 * default value instead of throwing an exception, and so is useful for
54 * obtaining optional values.
55 * <p>
56 * The generic <code>get()</code> and <code>opt()</code> methods return an
57 * object, which you can cast or query for type. There are also typed
58 * <code>get</code> and <code>opt</code> methods that do type checking and type
59 * coercion for you.
60 * <p>
61 * The <code>put</code> methods adds values to an object. For example, <pre>
62 *     myString = new JSONObject().put("JSON", "Hello, World!").toString();</pre>
63 * produces the string <code>{"JSON": "Hello, World"}</code>.
64 * <p>
65 * The texts produced by the <code>toString</code> methods strictly conform to
66 * the JSON syntax rules.
67 * The constructors are more forgiving in the texts they will accept:
68 * <ul>
69 * <li>An extra <code>,</code>&nbsp;<small>(comma)</small> may appear just
70 *     before the closing brace.</li>
71 * <li>Strings may be quoted with <code>'</code>&nbsp;<small>(single
72 *     quote)</small>.</li>
73 * <li>Strings do not need to be quoted at all if they do not begin with a quote
74 *     or single quote, and if they do not contain leading or trailing spaces,
75 *     and if they do not contain any of these characters:
76 *     <code>{ } [ ] / \ : , = ; #</code> and if they do not look like numbers
77 *     and if they are not the reserved words <code>true</code>,
78 *     <code>false</code>, or <code>null</code>.</li>
79 * <li>Keys can be followed by <code>=</code> or <code>=></code> as well as
80 *     by <code>:</code>.</li>
81 * <li>Values can be followed by <code>;</code> <small>(semicolon)</small> as
82 *     well as by <code>,</code> <small>(comma)</small>.</li>
83 * <li>Numbers may have the <code>0-</code> <small>(octal)</small> or
84 *     <code>0x-</code> <small>(hex)</small> prefix.</li>
85 * </ul>
86 * @author JSON.org
87 * @version 2009-03-06
88 */
89public class JSONObject {
90
91    /**
92     * JSONObject.NULL is equivalent to the value that JavaScript calls null,
93     * whilst Java's null is equivalent to the value that JavaScript calls
94     * undefined.
95     */
96     private static final class Null {
97
98        /**
99         * There is only intended to be a single instance of the NULL object,
100         * so the clone method returns itself.
101         * @return     NULL.
102         */
103        protected final Object clone() {
104            return this;
105        }
106
107
108        /**
109         * A Null object is equal to the null value and to itself.
110         * @param object    An object to test for nullness.
111         * @return true if the object parameter is the JSONObject.NULL object
112         *  or null.
113         */
114        public boolean equals(Object object) {
115            return object == null || object == this;
116        }
117
118
119        /**
120         * Get the "null" string value.
121         * @return The string "null".
122         */
123        public String toString() {
124            return "null";
125        }
126    }
127
128
129    /**
130     * The map where the JSONObject's properties are kept.
131     */
132    private Map map;
133
134
135    /**
136     * It is sometimes more convenient and less ambiguous to have a
137     * <code>NULL</code> object than to use Java's <code>null</code> value.
138     * <code>JSONObject.NULL.equals(null)</code> returns <code>true</code>.
139     * <code>JSONObject.NULL.toString()</code> returns <code>"null"</code>.
140     */
141    public static final Object NULL = new Null();
142
143
144    /**
145     * Construct an empty JSONObject.
146     */
147    public JSONObject() {
148        this.map = new HashMap();
149    }
150
151
152    /**
153     * Construct a JSONObject from a subset of another JSONObject.
154     * An array of strings is used to identify the keys that should be copied.
155     * Missing keys are ignored.
156     * @param jo A JSONObject.
157     * @param names An array of strings.
158     * @exception JSONException If a value is a non-finite number or if a name is duplicated.
159     */
160    public JSONObject(JSONObject jo, String[] names) throws JSONException {
161        this();
162        for (int i = 0; i < names.length; i += 1) {
163            putOnce(names[i], jo.opt(names[i]));
164        }
165    }
166
167
168    /**
169     * Construct a JSONObject from a JSONTokener.
170     * @param x A JSONTokener object containing the source string.
171     * @throws JSONException If there is a syntax error in the source string
172     *  or a duplicated key.
173     */
174    public JSONObject(JSONTokener x) throws JSONException {
175        this();
176        char c;
177        String key;
178
179        if (x.nextClean() != '{') {
180            throw x.syntaxError("A JSONObject text must begin with '{'");
181        }
182        for (;;) {
183            c = x.nextClean();
184            switch (c) {
185            case 0:
186                throw x.syntaxError("A JSONObject text must end with '}'");
187            case '}':
188                return;
189            default:
190                x.back();
191                key = x.nextValue().toString();
192            }
193
194            /*
195             * The key is followed by ':'. We will also tolerate '=' or '=>'.
196             */
197
198            c = x.nextClean();
199            if (c == '=') {
200                if (x.next() != '>') {
201                    x.back();
202                }
203            } else if (c != ':') {
204                throw x.syntaxError("Expected a ':' after a key");
205            }
206            putOnce(key, x.nextValue());
207
208            /*
209             * Pairs are separated by ','. We will also tolerate ';'.
210             */
211
212            switch (x.nextClean()) {
213            case ';':
214            case ',':
215                if (x.nextClean() == '}') {
216                    return;
217                }
218                x.back();
219                break;
220            case '}':
221                return;
222            default:
223                throw x.syntaxError("Expected a ',' or '}'");
224            }
225        }
226    }
227
228
229    /**
230     * Construct a JSONObject from a Map.
231     *
232     * @param map A map object that can be used to initialize the contents of
233     *  the JSONObject.
234     */
235    public JSONObject(Map map) {
236        this.map = (map == null) ? new HashMap() : map;
237    }
238
239
240    /**
241     * Construct a JSONObject from a Map.
242     *
243     * Note: Use this constructor when the map contains <key,bean>.
244     *
245     * @param map - A map with Key-Bean data.
246     * @param includeSuperClass - Tell whether to include the super class properties.
247     */
248    public JSONObject(Map map, boolean includeSuperClass) {
249        this.map = new HashMap();
250        if (map != null) {
251            Iterator i = map.entrySet().iterator();
252            while (i.hasNext()) {
253                Map.Entry e = (Map.Entry)i.next();
254                if (isStandardProperty(e.getValue().getClass())) {
255                    this.map.put(e.getKey(), e.getValue());
256                } else {
257                    this.map.put(e.getKey(), new JSONObject(e.getValue(),
258                            includeSuperClass));
259                }
260            }
261        }
262    }
263
264
265    /**
266     * Construct a JSONObject from an Object using bean getters.
267     * It reflects on all of the public methods of the object.
268     * For each of the methods with no parameters and a name starting
269     * with <code>"get"</code> or <code>"is"</code> followed by an uppercase letter,
270     * the method is invoked, and a key and the value returned from the getter method
271     * are put into the new JSONObject.
272     *
273     * The key is formed by removing the <code>"get"</code> or <code>"is"</code> prefix.
274     * If the second remaining character is not upper case, then the first
275     * character is converted to lower case.
276     *
277     * For example, if an object has a method named <code>"getName"</code>, and
278     * if the result of calling <code>object.getName()</code> is <code>"Larry Fine"</code>,
279     * then the JSONObject will contain <code>"name": "Larry Fine"</code>.
280     *
281     * @param bean An object that has getter methods that should be used
282     * to make a JSONObject.
283     */
284    public JSONObject(Object bean) {
285        this();
286        populateInternalMap(bean, false);
287    }
288
289
290    /**
291     * Construct a JSONObject from an Object using bean getters.
292     * It reflects on all of the public methods of the object.
293     * For each of the methods with no parameters and a name starting
294     * with <code>"get"</code> or <code>"is"</code> followed by an uppercase letter,
295     * the method is invoked, and a key and the value returned from the getter method
296     * are put into the new JSONObject.
297     *
298     * The key is formed by removing the <code>"get"</code> or <code>"is"</code> prefix.
299     * If the second remaining character is not upper case, then the first
300     * character is converted to lower case.
301     *
302     * @param bean An object that has getter methods that should be used
303     * to make a JSONObject.
304     * @param includeSuperClass If true, include the super class properties.
305     */
306    public JSONObject(Object bean, boolean includeSuperClass) {
307        this();
308        populateInternalMap(bean, includeSuperClass);
309    }
310
311    private void populateInternalMap(Object bean, boolean includeSuperClass){
312        Class klass = bean.getClass();
313
314        /* If klass.getSuperClass is System class then force includeSuperClass to false. */
315
316        if (klass.getClassLoader() == null) {
317            includeSuperClass = false;
318        }
319
320        Method[] methods = (includeSuperClass) ?
321                klass.getMethods() : klass.getDeclaredMethods();
322        for (int i = 0; i < methods.length; i += 1) {
323            try {
324                Method method = methods[i];
325                if (Modifier.isPublic(method.getModifiers())) {
326                    String name = method.getName();
327                    String key = "";
328                    if (name.startsWith("get")) {
329                        key = name.substring(3);
330                    } else if (name.startsWith("is")) {
331                        key = name.substring(2);
332                    }
333                    if (key.length() > 0 &&
334                            Character.isUpperCase(key.charAt(0)) &&
335                            method.getParameterTypes().length == 0) {
336                        if (key.length() == 1) {
337                            key = key.toLowerCase();
338                        } else if (!Character.isUpperCase(key.charAt(1))) {
339                            key = key.substring(0, 1).toLowerCase() +
340                                key.substring(1);
341                        }
342
343                        Object result = method.invoke(bean, (Object[])null);
344                        if (result == null) {
345                            map.put(key, NULL);
346                        } else if (result.getClass().isArray()) {
347                            map.put(key, new JSONArray(result, includeSuperClass));
348                        } else if (result instanceof Collection) { // List or Set
349                            map.put(key, new JSONArray((Collection)result, includeSuperClass));
350                        } else if (result instanceof Map) {
351                            map.put(key, new JSONObject((Map)result, includeSuperClass));
352                        } else if (isStandardProperty(result.getClass())) { // Primitives, String and Wrapper
353                            map.put(key, result);
354                        } else {
355                            if (result.getClass().getPackage().getName().startsWith("java") ||
356                                    result.getClass().getClassLoader() == null) {
357                                map.put(key, result.toString());
358                            } else { // User defined Objects
359                                map.put(key, new JSONObject(result, includeSuperClass));
360                            }
361                        }
362                    }
363                }
364            } catch (Exception e) {
365                throw new RuntimeException(e);
366            }
367        }
368    }
369
370
371    static boolean isStandardProperty(Class clazz) {
372        return clazz.isPrimitive()                  ||
373            clazz.isAssignableFrom(Byte.class)      ||
374            clazz.isAssignableFrom(Short.class)     ||
375            clazz.isAssignableFrom(Integer.class)   ||
376            clazz.isAssignableFrom(Long.class)      ||
377            clazz.isAssignableFrom(Float.class)     ||
378            clazz.isAssignableFrom(Double.class)    ||
379            clazz.isAssignableFrom(Character.class) ||
380            clazz.isAssignableFrom(String.class)    ||
381            clazz.isAssignableFrom(Boolean.class);
382    }
383
384
385    /**
386     * Construct a JSONObject from an Object, using reflection to find the
387     * public members. The resulting JSONObject's keys will be the strings
388     * from the names array, and the values will be the field values associated
389     * with those keys in the object. If a key is not found or not visible,
390     * then it will not be copied into the new JSONObject.
391     * @param object An object that has fields that should be used to make a
392     * JSONObject.
393     * @param names An array of strings, the names of the fields to be obtained
394     * from the object.
395     */
396    public JSONObject(Object object, String names[]) {
397        this();
398        Class c = object.getClass();
399        for (int i = 0; i < names.length; i += 1) {
400            String name = names[i];
401            try {
402                putOpt(name, c.getField(name).get(object));
403            } catch (Exception e) {
404                /* forget about it */
405            }
406        }
407    }
408
409
410    /**
411     * Construct a JSONObject from a source JSON text string.
412     * This is the most commonly used JSONObject constructor.
413     * @param source    A string beginning
414     *  with <code>{</code>&nbsp;<small>(left brace)</small> and ending
415     *  with <code>}</code>&nbsp;<small>(right brace)</small>.
416     * @exception JSONException If there is a syntax error in the source
417     *  string or a duplicated key.
418     */
419    public JSONObject(String source) throws JSONException {
420        this(new JSONTokener(source));
421    }
422
423
424    /**
425     * Accumulate values under a key. It is similar to the put method except
426     * that if there is already an object stored under the key then a
427     * JSONArray is stored under the key to hold all of the accumulated values.
428     * If there is already a JSONArray, then the new value is appended to it.
429     * In contrast, the put method replaces the previous value.
430     * @param key   A key string.
431     * @param value An object to be accumulated under the key.
432     * @return this.
433     * @throws JSONException If the value is an invalid number
434     *  or if the key is null.
435     */
436    public JSONObject accumulate(String key, Object value)
437            throws JSONException {
438        testValidity(value);
439        Object o = opt(key);
440        if (o == null) {
441            put(key, value instanceof JSONArray ?
442                    new JSONArray().put(value) :
443                    value);
444        } else if (o instanceof JSONArray) {
445            ((JSONArray)o).put(value);
446        } else {
447            put(key, new JSONArray().put(o).put(value));
448        }
449        return this;
450    }
451
452
453    /**
454     * Append values to the array under a key. If the key does not exist in the
455     * JSONObject, then the key is put in the JSONObject with its value being a
456     * JSONArray containing the value parameter. If the key was already
457     * associated with a JSONArray, then the value parameter is appended to it.
458     * @param key   A key string.
459     * @param value An object to be accumulated under the key.
460     * @return this.
461     * @throws JSONException If the key is null or if the current value
462     *  associated with the key is not a JSONArray.
463     */
464    public JSONObject append(String key, Object value)
465            throws JSONException {
466        testValidity(value);
467        Object o = opt(key);
468        if (o == null) {
469            put(key, new JSONArray().put(value));
470        } else if (o instanceof JSONArray) {
471            put(key, ((JSONArray)o).put(value));
472        } else {
473            throw new JSONException("JSONObject[" + key +
474                    "] is not a JSONArray.");
475        }
476        return this;
477    }
478
479
480    /**
481     * Produce a string from a double. The string "null" will be returned if
482     * the number is not finite.
483     * @param  d A double.
484     * @return A String.
485     */
486    static public String doubleToString(double d) {
487        if (Double.isInfinite(d) || Double.isNaN(d)) {
488            return "null";
489        }
490
491// Shave off trailing zeros and decimal point, if possible.
492
493        String s = Double.toString(d);
494        if (s.indexOf('.') > 0 && s.indexOf('e') < 0 && s.indexOf('E') < 0) {
495            while (s.endsWith("0")) {
496                s = s.substring(0, s.length() - 1);
497            }
498            if (s.endsWith(".")) {
499                s = s.substring(0, s.length() - 1);
500            }
501        }
502        return s;
503    }
504
505
506    /**
507     * Get the value object associated with a key.
508     *
509     * @param key   A key string.
510     * @return      The object associated with the key.
511     * @throws   JSONException if the key is not found.
512     */
513    public Object get(String key) throws JSONException {
514        Object o = opt(key);
515        if (o == null) {
516            throw new JSONException("JSONObject[" + quote(key) +
517                    "] not found.");
518        }
519        return o;
520    }
521
522
523    /**
524     * Get the boolean value associated with a key.
525     *
526     * @param key   A key string.
527     * @return      The truth.
528     * @throws   JSONException
529     *  if the value is not a Boolean or the String "true" or "false".
530     */
531    public boolean getBoolean(String key) throws JSONException {
532        Object o = get(key);
533        if (o.equals(Boolean.FALSE) ||
534                (o instanceof String &&
535                ((String)o).equalsIgnoreCase("false"))) {
536            return false;
537        } else if (o.equals(Boolean.TRUE) ||
538                (o instanceof String &&
539                ((String)o).equalsIgnoreCase("true"))) {
540            return true;
541        }
542        throw new JSONException("JSONObject[" + quote(key) +
543                "] is not a Boolean.");
544    }
545
546
547    /**
548     * Get the double value associated with a key.
549     * @param key   A key string.
550     * @return      The numeric value.
551     * @throws JSONException if the key is not found or
552     *  if the value is not a Number object and cannot be converted to a number.
553     */
554    public double getDouble(String key) throws JSONException {
555        Object o = get(key);
556        try {
557            return o instanceof Number ?
558                ((Number)o).doubleValue() :
559                Double.valueOf((String)o).doubleValue();
560        } catch (Exception e) {
561            throw new JSONException("JSONObject[" + quote(key) +
562                "] is not a number.");
563        }
564    }
565
566
567    /**
568     * Get the int value associated with a key. If the number value is too
569     * large for an int, it will be clipped.
570     *
571     * @param key   A key string.
572     * @return      The integer value.
573     * @throws   JSONException if the key is not found or if the value cannot
574     *  be converted to an integer.
575     */
576    public int getInt(String key) throws JSONException {
577        Object o = get(key);
578        return o instanceof Number ?
579                ((Number)o).intValue() : (int)getDouble(key);
580    }
581
582
583    /**
584     * Get the JSONArray value associated with a key.
585     *
586     * @param key   A key string.
587     * @return      A JSONArray which is the value.
588     * @throws   JSONException if the key is not found or
589     *  if the value is not a JSONArray.
590     */
591    public JSONArray getJSONArray(String key) throws JSONException {
592        Object o = get(key);
593        if (o instanceof JSONArray) {
594            return (JSONArray)o;
595        }
596        throw new JSONException("JSONObject[" + quote(key) +
597                "] is not a JSONArray.");
598    }
599
600
601    /**
602     * Get the JSONObject value associated with a key.
603     *
604     * @param key   A key string.
605     * @return      A JSONObject which is the value.
606     * @throws   JSONException if the key is not found or
607     *  if the value is not a JSONObject.
608     */
609    public JSONObject getJSONObject(String key) throws JSONException {
610        Object o = get(key);
611        if (o instanceof JSONObject) {
612            return (JSONObject)o;
613        }
614        throw new JSONException("JSONObject[" + quote(key) +
615                "] is not a JSONObject.");
616    }
617
618
619    /**
620     * Get the long value associated with a key. If the number value is too
621     * long for a long, it will be clipped.
622     *
623     * @param key   A key string.
624     * @return      The long value.
625     * @throws   JSONException if the key is not found or if the value cannot
626     *  be converted to a long.
627     */
628    public long getLong(String key) throws JSONException {
629        Object o = get(key);
630        return o instanceof Number ?
631                ((Number)o).longValue() : (long)getDouble(key);
632    }
633
634
635    /**
636     * Get an array of field names from a JSONObject.
637     *
638     * @return An array of field names, or null if there are no names.
639     */
640    public static String[] getNames(JSONObject jo) {
641        int length = jo.length();
642        if (length == 0) {
643            return null;
644        }
645        Iterator i = jo.keys();
646        String[] names = new String[length];
647        int j = 0;
648        while (i.hasNext()) {
649            names[j] = (String)i.next();
650            j += 1;
651        }
652        return names;
653    }
654
655
656    /**
657     * Get an array of field names from an Object.
658     *
659     * @return An array of field names, or null if there are no names.
660     */
661    public static String[] getNames(Object object) {
662        if (object == null) {
663            return null;
664        }
665        Class klass = object.getClass();
666        Field[] fields = klass.getFields();
667        int length = fields.length;
668        if (length == 0) {
669            return null;
670        }
671        String[] names = new String[length];
672        for (int i = 0; i < length; i += 1) {
673            names[i] = fields[i].getName();
674        }
675        return names;
676    }
677
678
679    /**
680     * Get the string associated with a key.
681     *
682     * @param key   A key string.
683     * @return      A string which is the value.
684     * @throws   JSONException if the key is not found.
685     */
686    public String getString(String key) throws JSONException {
687        return get(key).toString();
688    }
689
690
691    /**
692     * Determine if the JSONObject contains a specific key.
693     * @param key   A key string.
694     * @return      true if the key exists in the JSONObject.
695     */
696    public boolean has(String key) {
697        return this.map.containsKey(key);
698    }
699
700
701    /**
702     * Determine if the value associated with the key is null or if there is
703     *  no value.
704     * @param key   A key string.
705     * @return      true if there is no value associated with the key or if
706     *  the value is the JSONObject.NULL object.
707     */
708    public boolean isNull(String key) {
709        return JSONObject.NULL.equals(opt(key));
710    }
711
712
713    /**
714     * Get an enumeration of the keys of the JSONObject.
715     *
716     * @return An iterator of the keys.
717     */
718    public Iterator keys() {
719        return this.map.keySet().iterator();
720    }
721
722
723    /**
724     * Get the number of keys stored in the JSONObject.
725     *
726     * @return The number of keys in the JSONObject.
727     */
728    public int length() {
729        return this.map.size();
730    }
731
732
733    /**
734     * Produce a JSONArray containing the names of the elements of this
735     * JSONObject.
736     * @return A JSONArray containing the key strings, or null if the JSONObject
737     * is empty.
738     */
739    public JSONArray names() {
740        JSONArray ja = new JSONArray();
741        Iterator  keys = keys();
742        while (keys.hasNext()) {
743            ja.put(keys.next());
744        }
745        return ja.length() == 0 ? null : ja;
746    }
747
748    /**
749     * Produce a string from a Number.
750     * @param  n A Number
751     * @return A String.
752     * @throws JSONException If n is a non-finite number.
753     */
754    static public String numberToString(Number n)
755            throws JSONException {
756        if (n == null) {
757            throw new JSONException("Null pointer");
758        }
759        testValidity(n);
760
761// Shave off trailing zeros and decimal point, if possible.
762
763        String s = n.toString();
764        if (s.indexOf('.') > 0 && s.indexOf('e') < 0 && s.indexOf('E') < 0) {
765            while (s.endsWith("0")) {
766                s = s.substring(0, s.length() - 1);
767            }
768            if (s.endsWith(".")) {
769                s = s.substring(0, s.length() - 1);
770            }
771        }
772        return s;
773    }
774
775
776    /**
777     * Get an optional value associated with a key.
778     * @param key   A key string.
779     * @return      An object which is the value, or null if there is no value.
780     */
781    public Object opt(String key) {
782        return key == null ? null : this.map.get(key);
783    }
784
785
786    /**
787     * Get an optional boolean associated with a key.
788     * It returns false if there is no such key, or if the value is not
789     * Boolean.TRUE or the String "true".
790     *
791     * @param key   A key string.
792     * @return      The truth.
793     */
794    public boolean optBoolean(String key) {
795        return optBoolean(key, false);
796    }
797
798
799    /**
800     * Get an optional boolean associated with a key.
801     * It returns the defaultValue if there is no such key, or if it is not
802     * a Boolean or the String "true" or "false" (case insensitive).
803     *
804     * @param key              A key string.
805     * @param defaultValue     The default.
806     * @return      The truth.
807     */
808    public boolean optBoolean(String key, boolean defaultValue) {
809        try {
810            return getBoolean(key);
811        } catch (Exception e) {
812            return defaultValue;
813        }
814    }
815
816
817    /**
818     * Put a key/value pair in the JSONObject, where the value will be a
819     * JSONArray which is produced from a Collection.
820     * @param key   A key string.
821     * @param value A Collection value.
822     * @return      this.
823     * @throws JSONException
824     */
825    public JSONObject put(String key, Collection value) throws JSONException {
826        put(key, new JSONArray(value));
827        return this;
828    }
829
830
831    /**
832     * Get an optional double associated with a key,
833     * or NaN if there is no such key or if its value is not a number.
834     * If the value is a string, an attempt will be made to evaluate it as
835     * a number.
836     *
837     * @param key   A string which is the key.
838     * @return      An object which is the value.
839     */
840    public double optDouble(String key) {
841        return optDouble(key, Double.NaN);
842    }
843
844
845    /**
846     * Get an optional double associated with a key, or the
847     * defaultValue if there is no such key or if its value is not a number.
848     * If the value is a string, an attempt will be made to evaluate it as
849     * a number.
850     *
851     * @param key   A key string.
852     * @param defaultValue     The default.
853     * @return      An object which is the value.
854     */
855    public double optDouble(String key, double defaultValue) {
856        try {
857            Object o = opt(key);
858            return o instanceof Number ? ((Number)o).doubleValue() :
859                new Double((String)o).doubleValue();
860        } catch (Exception e) {
861            return defaultValue;
862        }
863    }
864
865
866    /**
867     * Get an optional int value associated with a key,
868     * or zero if there is no such key or if the value is not a number.
869     * If the value is a string, an attempt will be made to evaluate it as
870     * a number.
871     *
872     * @param key   A key string.
873     * @return      An object which is the value.
874     */
875    public int optInt(String key) {
876        return optInt(key, 0);
877    }
878
879
880    /**
881     * Get an optional int value associated with a key,
882     * or the default if there is no such key or if the value is not a number.
883     * If the value is a string, an attempt will be made to evaluate it as
884     * a number.
885     *
886     * @param key   A key string.
887     * @param defaultValue     The default.
888     * @return      An object which is the value.
889     */
890    public int optInt(String key, int defaultValue) {
891        try {
892            return getInt(key);
893        } catch (Exception e) {
894            return defaultValue;
895        }
896    }
897
898
899    /**
900     * Get an optional JSONArray associated with a key.
901     * It returns null if there is no such key, or if its value is not a
902     * JSONArray.
903     *
904     * @param key   A key string.
905     * @return      A JSONArray which is the value.
906     */
907    public JSONArray optJSONArray(String key) {
908        Object o = opt(key);
909        return o instanceof JSONArray ? (JSONArray)o : null;
910    }
911
912
913    /**
914     * Get an optional JSONObject associated with a key.
915     * It returns null if there is no such key, or if its value is not a
916     * JSONObject.
917     *
918     * @param key   A key string.
919     * @return      A JSONObject which is the value.
920     */
921    public JSONObject optJSONObject(String key) {
922        Object o = opt(key);
923        return o instanceof JSONObject ? (JSONObject)o : null;
924    }
925
926
927    /**
928     * Get an optional long value associated with a key,
929     * or zero if there is no such key or if the value is not a number.
930     * If the value is a string, an attempt will be made to evaluate it as
931     * a number.
932     *
933     * @param key   A key string.
934     * @return      An object which is the value.
935     */
936    public long optLong(String key) {
937        return optLong(key, 0);
938    }
939
940
941    /**
942     * Get an optional long value associated with a key,
943     * or the default if there is no such key or if the value is not a number.
944     * If the value is a string, an attempt will be made to evaluate it as
945     * a number.
946     *
947     * @param key   A key string.
948     * @param defaultValue     The default.
949     * @return      An object which is the value.
950     */
951    public long optLong(String key, long defaultValue) {
952        try {
953            return getLong(key);
954        } catch (Exception e) {
955            return defaultValue;
956        }
957    }
958
959
960    /**
961     * Get an optional string associated with a key.
962     * It returns an empty string if there is no such key. If the value is not
963     * a string and is not null, then it is coverted to a string.
964     *
965     * @param key   A key string.
966     * @return      A string which is the value.
967     */
968    public String optString(String key) {
969        return optString(key, "");
970    }
971
972
973    /**
974     * Get an optional string associated with a key.
975     * It returns the defaultValue if there is no such key.
976     *
977     * @param key   A key string.
978     * @param defaultValue     The default.
979     * @return      A string which is the value.
980     */
981    public String optString(String key, String defaultValue) {
982        Object o = opt(key);
983        return o != null ? o.toString() : defaultValue;
984    }
985
986
987    /**
988     * Put a key/boolean pair in the JSONObject.
989     *
990     * @param key   A key string.
991     * @param value A boolean which is the value.
992     * @return this.
993     * @throws JSONException If the key is null.
994     */
995    public JSONObject put(String key, boolean value) throws JSONException {
996        put(key, value ? Boolean.TRUE : Boolean.FALSE);
997        return this;
998    }
999
1000
1001    /**
1002     * Put a key/double pair in the JSONObject.
1003     *
1004     * @param key   A key string.
1005     * @param value A double which is the value.
1006     * @return this.
1007     * @throws JSONException If the key is null or if the number is invalid.
1008     */
1009    public JSONObject put(String key, double value) throws JSONException {
1010        put(key, new Double(value));
1011        return this;
1012    }
1013
1014
1015    /**
1016     * Put a key/int pair in the JSONObject.
1017     *
1018     * @param key   A key string.
1019     * @param value An int which is the value.
1020     * @return this.
1021     * @throws JSONException If the key is null.
1022     */
1023    public JSONObject put(String key, int value) throws JSONException {
1024        put(key, new Integer(value));
1025        return this;
1026    }
1027
1028
1029    /**
1030     * Put a key/long pair in the JSONObject.
1031     *
1032     * @param key   A key string.
1033     * @param value A long which is the value.
1034     * @return this.
1035     * @throws JSONException If the key is null.
1036     */
1037    public JSONObject put(String key, long value) throws JSONException {
1038        put(key, new Long(value));
1039        return this;
1040    }
1041
1042
1043    /**
1044     * Put a key/value pair in the JSONObject, where the value will be a
1045     * JSONObject which is produced from a Map.
1046     * @param key   A key string.
1047     * @param value A Map value.
1048     * @return      this.
1049     * @throws JSONException
1050     */
1051    public JSONObject put(String key, Map value) throws JSONException {
1052        put(key, new JSONObject(value));
1053        return this;
1054    }
1055
1056
1057    /**
1058     * Put a key/value pair in the JSONObject. If the value is null,
1059     * then the key will be removed from the JSONObject if it is present.
1060     * @param key   A key string.
1061     * @param value An object which is the value. It should be of one of these
1062     *  types: Boolean, Double, Integer, JSONArray, JSONObject, Long, String,
1063     *  or the JSONObject.NULL object.
1064     * @return this.
1065     * @throws JSONException If the value is non-finite number
1066     *  or if the key is null.
1067     */
1068    public JSONObject put(String key, Object value) throws JSONException {
1069        if (key == null) {
1070            throw new JSONException("Null key.");
1071        }
1072        if (value != null) {
1073            testValidity(value);
1074            this.map.put(key, value);
1075        } else {
1076            remove(key);
1077        }
1078        return this;
1079    }
1080
1081
1082    /**
1083     * Put a key/value pair in the JSONObject, but only if the key and the
1084     * value are both non-null, and only if there is not already a member
1085     * with that name.
1086     * @param key
1087     * @param value
1088     * @return his.
1089     * @throws JSONException if the key is a duplicate
1090     */
1091    public JSONObject putOnce(String key, Object value) throws JSONException {
1092        if (key != null && value != null) {
1093            if (opt(key) != null) {
1094                throw new JSONException("Duplicate key \"" + key + "\"");
1095            }
1096            put(key, value);
1097        }
1098        return this;
1099    }
1100
1101
1102    /**
1103     * Put a key/value pair in the JSONObject, but only if the
1104     * key and the value are both non-null.
1105     * @param key   A key string.
1106     * @param value An object which is the value. It should be of one of these
1107     *  types: Boolean, Double, Integer, JSONArray, JSONObject, Long, String,
1108     *  or the JSONObject.NULL object.
1109     * @return this.
1110     * @throws JSONException If the value is a non-finite number.
1111     */
1112    public JSONObject putOpt(String key, Object value) throws JSONException {
1113        if (key != null && value != null) {
1114            put(key, value);
1115        }
1116        return this;
1117    }
1118
1119
1120    /**
1121     * Produce a string in double quotes with backslash sequences in all the
1122     * right places. A backslash will be inserted within </, allowing JSON
1123     * text to be delivered in HTML. In JSON text, a string cannot contain a
1124     * control character or an unescaped quote or backslash.
1125     * @param string A String
1126     * @return  A String correctly formatted for insertion in a JSON text.
1127     */
1128    public static String quote(String string) {
1129        if (string == null || string.length() == 0) {
1130            return "\"\"";
1131        }
1132
1133        char         b;
1134        char         c = 0;
1135        int          i;
1136        int          len = string.length();
1137        StringBuffer sb = new StringBuffer(len + 4);
1138        String       t;
1139
1140        sb.append('"');
1141        for (i = 0; i < len; i += 1) {
1142            b = c;
1143            c = string.charAt(i);
1144            switch (c) {
1145            case '\\':
1146            case '"':
1147                sb.append('\\');
1148                sb.append(c);
1149                break;
1150            case '/':
1151                if (b == '<') {
1152                    sb.append('\\');
1153                }
1154                sb.append(c);
1155                break;
1156            case '\b':
1157                sb.append("\\b");
1158                break;
1159            case '\t':
1160                sb.append("\\t");
1161                break;
1162            case '\n':
1163                sb.append("\\n");
1164                break;
1165            case '\f':
1166                sb.append("\\f");
1167                break;
1168            case '\r':
1169                sb.append("\\r");
1170                break;
1171            default:
1172                if (c < ' ' || (c >= '\u0080' && c < '\u00a0') ||
1173                               (c >= '\u2000' && c < '\u2100')) {
1174                    t = "000" + Integer.toHexString(c);
1175                    sb.append("\\u" + t.substring(t.length() - 4));
1176                } else {
1177                    sb.append(c);
1178                }
1179            }
1180        }
1181        sb.append('"');
1182        return sb.toString();
1183    }
1184
1185    /**
1186     * Remove a name and its value, if present.
1187     * @param key The name to be removed.
1188     * @return The value that was associated with the name,
1189     * or null if there was no value.
1190     */
1191    public Object remove(String key) {
1192        return this.map.remove(key);
1193    }
1194
1195    /**
1196     * Get an enumeration of the keys of the JSONObject.
1197     * The keys will be sorted alphabetically.
1198     *
1199     * @return An iterator of the keys.
1200     */
1201    public Iterator sortedKeys() {
1202      return new TreeSet(this.map.keySet()).iterator();
1203    }
1204
1205    /**
1206     * Try to convert a string into a number, boolean, or null. If the string
1207     * can't be converted, return the string.
1208     * @param s A String.
1209     * @return A simple JSON value.
1210     */
1211    static public Object stringToValue(String s) {
1212        if (s.equals("")) {
1213            return s;
1214        }
1215        if (s.equalsIgnoreCase("true")) {
1216            return Boolean.TRUE;
1217        }
1218        if (s.equalsIgnoreCase("false")) {
1219            return Boolean.FALSE;
1220        }
1221        if (s.equalsIgnoreCase("null")) {
1222            return JSONObject.NULL;
1223        }
1224
1225        /*
1226         * If it might be a number, try converting it. We support the 0- and 0x-
1227         * conventions. If a number cannot be produced, then the value will just
1228         * be a string. Note that the 0-, 0x-, plus, and implied string
1229         * conventions are non-standard. A JSON parser is free to accept
1230         * non-JSON forms as long as it accepts all correct JSON forms.
1231         */
1232
1233        char b = s.charAt(0);
1234        if ((b >= '0' && b <= '9') || b == '.' || b == '-' || b == '+') {
1235            if (b == '0') {
1236                if (s.length() > 2 &&
1237                        (s.charAt(1) == 'x' || s.charAt(1) == 'X')) {
1238                    try {
1239                        return new Integer(Integer.parseInt(s.substring(2),
1240                                16));
1241                    } catch (Exception e) {
1242                        /* Ignore the error */
1243                    }
1244                } else {
1245                    try {
1246                        return new Integer(Integer.parseInt(s, 8));
1247                    } catch (Exception e) {
1248                        /* Ignore the error */
1249                    }
1250                }
1251            }
1252            try {
1253                if (s.indexOf('.') > -1 || s.indexOf('e') > -1 || s.indexOf('E') > -1) {
1254                    return Double.valueOf(s);
1255                } else {
1256                    Long myLong = new Long(s);
1257                    if (myLong.longValue() == myLong.intValue()) {
1258                        return new Integer(myLong.intValue());
1259                    } else {
1260                        return myLong;
1261                    }
1262                }
1263            }  catch (Exception f) {
1264                /* Ignore the error */
1265            }
1266        }
1267        return s;
1268    }
1269
1270
1271    /**
1272     * Throw an exception if the object is an NaN or infinite number.
1273     * @param o The object to test.
1274     * @throws JSONException If o is a non-finite number.
1275     */
1276    static void testValidity(Object o) throws JSONException {
1277        if (o != null) {
1278            if (o instanceof Double) {
1279                if (((Double)o).isInfinite() || ((Double)o).isNaN()) {
1280                    throw new JSONException(
1281                        "JSON does not allow non-finite numbers.");
1282                }
1283            } else if (o instanceof Float) {
1284                if (((Float)o).isInfinite() || ((Float)o).isNaN()) {
1285                    throw new JSONException(
1286                        "JSON does not allow non-finite numbers.");
1287                }
1288            }
1289        }
1290    }
1291
1292
1293    /**
1294     * Produce a JSONArray containing the values of the members of this
1295     * JSONObject.
1296     * @param names A JSONArray containing a list of key strings. This
1297     * determines the sequence of the values in the result.
1298     * @return A JSONArray of values.
1299     * @throws JSONException If any of the values are non-finite numbers.
1300     */
1301    public JSONArray toJSONArray(JSONArray names) throws JSONException {
1302        if (names == null || names.length() == 0) {
1303            return null;
1304        }
1305        JSONArray ja = new JSONArray();
1306        for (int i = 0; i < names.length(); i += 1) {
1307            ja.put(this.opt(names.getString(i)));
1308        }
1309        return ja;
1310    }
1311
1312    /**
1313     * Make a JSON text of this JSONObject. For compactness, no whitespace
1314     * is added. If this would not result in a syntactically correct JSON text,
1315     * then null will be returned instead.
1316     * <p>
1317     * Warning: This method assumes that the data structure is acyclical.
1318     *
1319     * @return a printable, displayable, portable, transmittable
1320     *  representation of the object, beginning
1321     *  with <code>{</code>&nbsp;<small>(left brace)</small> and ending
1322     *  with <code>}</code>&nbsp;<small>(right brace)</small>.
1323     */
1324    public String toString() {
1325        try {
1326            Iterator     keys = keys();
1327            StringBuffer sb = new StringBuffer("{");
1328
1329            while (keys.hasNext()) {
1330                if (sb.length() > 1) {
1331                    sb.append(',');
1332                }
1333                Object o = keys.next();
1334                sb.append(quote(o.toString()));
1335                sb.append(':');
1336                sb.append(valueToString(this.map.get(o)));
1337            }
1338            sb.append('}');
1339            return sb.toString();
1340        } catch (Exception e) {
1341            return null;
1342        }
1343    }
1344
1345
1346    /**
1347     * Make a prettyprinted JSON text of this JSONObject.
1348     * <p>
1349     * Warning: This method assumes that the data structure is acyclical.
1350     * @param indentFactor The number of spaces to add to each level of
1351     *  indentation.
1352     * @return a printable, displayable, portable, transmittable
1353     *  representation of the object, beginning
1354     *  with <code>{</code>&nbsp;<small>(left brace)</small> and ending
1355     *  with <code>}</code>&nbsp;<small>(right brace)</small>.
1356     * @throws JSONException If the object contains an invalid number.
1357     */
1358    public String toString(int indentFactor) throws JSONException {
1359        return toString(indentFactor, 0);
1360    }
1361
1362
1363    /**
1364     * Make a prettyprinted JSON text of this JSONObject.
1365     * <p>
1366     * Warning: This method assumes that the data structure is acyclical.
1367     * @param indentFactor The number of spaces to add to each level of
1368     *  indentation.
1369     * @param indent The indentation of the top level.
1370     * @return a printable, displayable, transmittable
1371     *  representation of the object, beginning
1372     *  with <code>{</code>&nbsp;<small>(left brace)</small> and ending
1373     *  with <code>}</code>&nbsp;<small>(right brace)</small>.
1374     * @throws JSONException If the object contains an invalid number.
1375     */
1376    String toString(int indentFactor, int indent) throws JSONException {
1377        int j;
1378        int n = length();
1379        if (n == 0) {
1380            return "{}";
1381        }
1382        Iterator     keys = sortedKeys();
1383        StringBuffer sb = new StringBuffer("{");
1384        int          newindent = indent + indentFactor;
1385        Object       o;
1386        if (n == 1) {
1387            o = keys.next();
1388            sb.append(quote(o.toString()));
1389            sb.append(": ");
1390            sb.append(valueToString(this.map.get(o), indentFactor,
1391                    indent));
1392        } else {
1393            while (keys.hasNext()) {
1394                o = keys.next();
1395                if (sb.length() > 1) {
1396                    sb.append(",\n");
1397                } else {
1398                    sb.append('\n');
1399                }
1400                for (j = 0; j < newindent; j += 1) {
1401                    sb.append(' ');
1402                }
1403                sb.append(quote(o.toString()));
1404                sb.append(": ");
1405                sb.append(valueToString(this.map.get(o), indentFactor,
1406                        newindent));
1407            }
1408            if (sb.length() > 1) {
1409                sb.append('\n');
1410                for (j = 0; j < indent; j += 1) {
1411                    sb.append(' ');
1412                }
1413            }
1414        }
1415        sb.append('}');
1416        return sb.toString();
1417    }
1418
1419
1420    /**
1421     * Make a JSON text of an Object value. If the object has an
1422     * value.toJSONString() method, then that method will be used to produce
1423     * the JSON text. The method is required to produce a strictly
1424     * conforming text. If the object does not contain a toJSONString
1425     * method (which is the most common case), then a text will be
1426     * produced by other means. If the value is an array or Collection,
1427     * then a JSONArray will be made from it and its toJSONString method
1428     * will be called. If the value is a MAP, then a JSONObject will be made
1429     * from it and its toJSONString method will be called. Otherwise, the
1430     * value's toString method will be called, and the result will be quoted.
1431     *
1432     * <p>
1433     * Warning: This method assumes that the data structure is acyclical.
1434     * @param value The value to be serialized.
1435     * @return a printable, displayable, transmittable
1436     *  representation of the object, beginning
1437     *  with <code>{</code>&nbsp;<small>(left brace)</small> and ending
1438     *  with <code>}</code>&nbsp;<small>(right brace)</small>.
1439     * @throws JSONException If the value is or contains an invalid number.
1440     */
1441    static String valueToString(Object value) throws JSONException {
1442        if (value == null || value.equals(null)) {
1443            return "null";
1444        }
1445        if (value instanceof JSONString) {
1446            Object o;
1447            try {
1448                o = ((JSONString)value).toJSONString();
1449            } catch (Exception e) {
1450                throw new JSONException(e);
1451            }
1452            if (o instanceof String) {
1453                return (String)o;
1454            }
1455            throw new JSONException("Bad value from toJSONString: " + o);
1456        }
1457        if (value instanceof Number) {
1458            return numberToString((Number) value);
1459        }
1460        if (value instanceof Boolean || value instanceof JSONObject ||
1461                value instanceof JSONArray) {
1462            return value.toString();
1463        }
1464        if (value instanceof Map) {
1465            return new JSONObject((Map)value).toString();
1466        }
1467        if (value instanceof Collection) {
1468            return new JSONArray((Collection)value).toString();
1469        }
1470        if (value.getClass().isArray()) {
1471            return new JSONArray(value).toString();
1472        }
1473        return quote(value.toString());
1474    }
1475
1476
1477    /**
1478     * Make a prettyprinted JSON text of an object value.
1479     * <p>
1480     * Warning: This method assumes that the data structure is acyclical.
1481     * @param value The value to be serialized.
1482     * @param indentFactor The number of spaces to add to each level of
1483     *  indentation.
1484     * @param indent The indentation of the top level.
1485     * @return a printable, displayable, transmittable
1486     *  representation of the object, beginning
1487     *  with <code>{</code>&nbsp;<small>(left brace)</small> and ending
1488     *  with <code>}</code>&nbsp;<small>(right brace)</small>.
1489     * @throws JSONException If the object contains an invalid number.
1490     */
1491     static String valueToString(Object value, int indentFactor, int indent)
1492            throws JSONException {
1493        if (value == null || value.equals(null)) {
1494            return "null";
1495        }
1496        try {
1497            if (value instanceof JSONString) {
1498                Object o = ((JSONString)value).toJSONString();
1499                if (o instanceof String) {
1500                    return (String)o;
1501                }
1502            }
1503        } catch (Exception e) {
1504            /* forget about it */
1505        }
1506        if (value instanceof Number) {
1507            return numberToString((Number) value);
1508        }
1509        if (value instanceof Boolean) {
1510            return value.toString();
1511        }
1512        if (value instanceof JSONObject) {
1513            return ((JSONObject)value).toString(indentFactor, indent);
1514        }
1515        if (value instanceof JSONArray) {
1516            return ((JSONArray)value).toString(indentFactor, indent);
1517        }
1518        if (value instanceof Map) {
1519            return new JSONObject((Map)value).toString(indentFactor, indent);
1520        }
1521        if (value instanceof Collection) {
1522            return new JSONArray((Collection)value).toString(indentFactor, indent);
1523        }
1524        if (value.getClass().isArray()) {
1525            return new JSONArray(value).toString(indentFactor, indent);
1526        }
1527        return quote(value.toString());
1528    }
1529
1530
1531     /**
1532      * Write the contents of the JSONObject as JSON text to a writer.
1533      * For compactness, no whitespace is added.
1534      * <p>
1535      * Warning: This method assumes that the data structure is acyclical.
1536      *
1537      * @return The writer.
1538      * @throws JSONException
1539      */
1540     public Writer write(Writer writer) throws JSONException {
1541        try {
1542            boolean  b = false;
1543            Iterator keys = keys();
1544            writer.write('{');
1545
1546            while (keys.hasNext()) {
1547                if (b) {
1548                    writer.write(',');
1549                }
1550                Object k = keys.next();
1551                writer.write(quote(k.toString()));
1552                writer.write(':');
1553                Object v = this.map.get(k);
1554                if (v instanceof JSONObject) {
1555                    ((JSONObject)v).write(writer);
1556                } else if (v instanceof JSONArray) {
1557                    ((JSONArray)v).write(writer);
1558                } else {
1559                    writer.write(valueToString(v));
1560                }
1561                b = true;
1562            }
1563            writer.write('}');
1564            return writer;
1565        } catch (IOException e) {
1566            throw new JSONException(e);
1567        }
1568     }
1569}