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