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