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