comparison lib/org.json_2.0/src/org/json/JSONObject.java @ 0:db87c1b7eb6d

initial
author dwinter
date Wed, 03 Nov 2010 12:18:46 +0100
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:db87c1b7eb6d
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.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 }