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