source: main/trunk/model-sites-dev/cambridge-museum/collect/waikato-independent/pre-import/EditableDatabaseTable/src/org/json/JSONObject.java@ 34493

Last change on this file since 34493 was 34493, checked in by davidb, 4 years ago

Base project for providing jquery/jquery-ui controlled interface to editing a database table

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