1 package org.json;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27 import java.text.ParseException;
28 import java.util.HashMap;
29 import java.util.Iterator;
30 import java.util.Map;
31 import java.util.NoSuchElementException;
32
33 /**
34 * A JSONObject is an unordered collection of name/value pairs. Its external
35 * form is a string wrapped in curly braces with colons between the names and
36 * values, and commas between the values and names. The internal form is an
37 * object having get() and opt() methods for accessing the values by name, and
38 * put() methods for adding or replacing values by name. The values can be any
39 * of these types: Boolean, JSONArray, JSONObject, Number, String, or the
40 * JSONObject.NULL object.
41 * <p>
42 * The constructor can convert an external form string into an internal form
43 * Java object. The toString() method creates an external form string.
44 * <p>
45 * A get() method returns a value if one can be found, and throws an exception
46 * if one cannot be found. An opt() method returns a default value instead of
47 * throwing an exception, and so is useful for obtaining optional values.
48 * <p>
49 * The generic get() and opt() methods return an object, which you can cast or
50 * query for type. There are also typed get() and opt() methods that do type
51 * checking and type coersion for you.
52 * <p>
53 * The texts produced by the toString() methods are very strict. The
54 * constructors are more forgiving in the texts they will accept:
55 * <ul>
56 * <li>An extra <code>,</code> <small>(comma)</small> may appear just
57 * before the closing brace.</li>
58 * <li>Strings may be quoted with <code>'</code> <small>(single quote)</small>.</li>
59 * <li>Strings do not need to be quoted at all if they do not begin with a
60 * quote or single quote, and if they do not contain leading or trailing spaces,
61 * and if they do not contain any of these characters:
62 * <code>{ } [ ] / \ : , = ; #</code> and if they do not look like numbers and
63 * if they are not the reserved words <code>true</code>, <code>false</code>,
64 * or <code>null</code>.</li>
65 * <li>Keys can be followed by <code>=</code> or <code>=></code> as well as
66 * by <code>:</code></li>
67 * <li>Values can be followed by <code>;</code> as well as by <code>,</code></li>
68 * <li>Numbers may have the <code>0-</code> <small>(octal)</small> or
69 * <code>0x-</code> <small>(hex)</small> prefix.</li>
70 * <li>Line comments can begin with <code>#</code></li>
71 * </ul>
72 *
73 * @author JSON.org
74 * @version 1
75 */
76 public class JSONObject {
77
78 /**
79 * JSONObject.NULL is equivalent to the value that JavaScript calls null,
80 * whilst Java's null is equivalent to the value that JavaScript calls
81 * undefined.
82 */
83 private static final class Null {
84
85 /**
86 * Make a Null object.
87 */
88 private Null() {
89 }
90
91 /**
92 * There is only intended to be a single instance of the NULL object, so
93 * the clone method returns itself.
94 *
95 * @return NULL.
96 */
97 protected final Object clone() {
98 return this;
99 }
100
101 /**
102 * A Null object is equal to the null value and to itself.
103 *
104 * @param object
105 * An object to test for nullness.
106 * @return true if the object parameter is the JSONObject.NULL object or
107 * null.
108 */
109 public boolean equals(Object object) {
110 return object == null || object == this;
111 }
112
113 /**
114 * Get the "null" string value.
115 *
116 * @return The string "null".
117 */
118 public String toString() {
119 return "null";
120 }
121 }
122
123 /**
124 * The hash map where the JSONObject's properties are kept.
125 */
126 private HashMap myHashMap;
127
128 /**
129 * It is sometimes more convenient and less ambiguous to have a NULL object
130 * than to use Java's null value. JSONObject.NULL.equals(null) returns true.
131 * JSONObject.NULL.toString() returns "null".
132 */
133 public static final Object NULL = new Null();
134
135 /**
136 * Construct an empty JSONObject.
137 */
138 public JSONObject() {
139 myHashMap = new HashMap();
140 }
141
142 /**
143 * Construct a JSONObject from a JSONTokener.
144 *
145 * @throws ParseException
146 * if there is a syntax error in the source string.
147 * @param x
148 * A JSONTokener object containing the source string.
149 */
150 @SuppressWarnings("unchecked")
151 public JSONObject(JSONTokener x) throws ParseException {
152 this();
153 char c;
154 String key;
155
156 if (x.nextClean() != '{') {
157 throw x.syntaxError("A JSONObject must begin with '{'");
158 }
159 while (true) {
160 c = x.nextClean();
161 switch (c) {
162 case 0:
163 throw x.syntaxError("A JSONObject must end with '}'");
164 case '}':
165 return;
166 default:
167 x.back();
168 key = x.nextValue().toString();
169 }
170
171
172
173
174
175 c = x.nextClean();
176 if (c == '=') {
177 if (x.next() != '>') {
178 x.back();
179 }
180 } else if (c != ':') {
181 throw x.syntaxError("Expected a ':' after a key");
182 }
183 myHashMap.put(key, x.nextValue());
184
185
186
187
188
189 switch (x.nextClean()) {
190 case ';':
191 case ',':
192 if (x.nextClean() == '}') {
193 return;
194 }
195 x.back();
196 break;
197 case '}':
198 return;
199 default:
200 throw x.syntaxError("Expected a ',' or '}'");
201 }
202 }
203 }
204
205 /**
206 * Construct a JSONObject from a string.
207 *
208 * @exception ParseException
209 * The string must be properly formatted.
210 * @param string
211 * A string beginning with <code>{</code> <small>(left
212 * brace)</small> and ending with <code>}</code> <small>(right
213 * brace)</small>.
214 */
215 public JSONObject(String string) throws ParseException {
216 this(new JSONTokener(string));
217 }
218
219 /**
220 * Construct a JSONObject from a Map.
221 *
222 * @param map
223 * A map object that can be used to initialize the contents of
224 * the JSONObject.
225 */
226 @SuppressWarnings("unchecked")
227 public JSONObject(Map map) {
228 myHashMap = new HashMap(map);
229 }
230
231 /**
232 * Accumulate values under a key. It is similar to the put method except
233 * that if there is already an object stored under the key then a JSONArray
234 * is stored under the key to hold all of the accumulated values. If there
235 * is already a JSONArray, then the new value is appended to it. In
236 * contrast, the put method replaces the previous value.
237 *
238 * @throws NullPointerException
239 * if the key is null
240 * @param key
241 * A key string.
242 * @param value
243 * An object to be accumulated under the key.
244 * @return this.
245 */
246 public JSONObject accumulate(String key, Object value)
247 throws NullPointerException {
248 JSONArray a;
249 Object o = opt(key);
250 if (o == null) {
251 put(key, value);
252 } else if (o instanceof JSONArray) {
253 a = (JSONArray) o;
254 a.put(value);
255 } else {
256 a = new JSONArray();
257 a.put(o);
258 a.put(value);
259 put(key, a);
260 }
261 return this;
262 }
263
264 /**
265 * Get the value object associated with a key.
266 *
267 * @exception NoSuchElementException
268 * if the key is not found.
269 *
270 * @param key
271 * A key string.
272 * @return The object associated with the key.
273 */
274 public Object get(String key) throws NoSuchElementException {
275 Object o = opt(key);
276 if (o == null) {
277 throw new NoSuchElementException("JSONObject[" + quote(key)
278 + "] not found.");
279 }
280 return o;
281 }
282
283 /**
284 * Get the boolean value associated with a key.
285 *
286 * @exception NoSuchElementException
287 * if the key is not found.
288 * @exception ClassCastException
289 * if the value is not a Boolean or the String "true" or
290 * "false".
291 *
292 * @param key
293 * A key string.
294 * @return The truth.
295 */
296 public boolean getBoolean(String key) throws ClassCastException,
297 NoSuchElementException {
298 Object o = get(key);
299 if (o.equals(Boolean.FALSE)
300 || (o instanceof String && ((String) o)
301 .equalsIgnoreCase("false"))) {
302 return false;
303 } else if (o.equals(Boolean.TRUE)
304 || (o instanceof String && ((String) o)
305 .equalsIgnoreCase("true"))) {
306 return true;
307 }
308 throw new ClassCastException("JSONObject[" + quote(key)
309 + "] is not a Boolean.");
310 }
311
312 /**
313 * Get the double value associated with a key.
314 *
315 * @exception NoSuchElementException
316 * if the key is not found or if the value is a Number
317 * object.
318 * @exception NumberFormatException
319 * if the value cannot be converted to a number.
320 * @param key
321 * A key string.
322 * @return The numeric value.
323 */
324 public double getDouble(String key) throws NoSuchElementException,
325 NumberFormatException {
326 Object o = get(key);
327 if (o instanceof Number) {
328 return ((Number) o).doubleValue();
329 }
330 if (o instanceof String) {
331 return new Double((String) o).doubleValue();
332 }
333 throw new NumberFormatException("JSONObject[" + quote(key)
334 + "] is not a number.");
335 }
336
337 /**
338 * Get the HashMap the holds that contents of the JSONObject.
339 *
340 * @return The getHashMap.
341 */
342 HashMap getHashMap() {
343 return myHashMap;
344 }
345
346 /**
347 * Get the int value associated with a key.
348 *
349 * @exception NoSuchElementException
350 * if the key is not found
351 * @exception NumberFormatException
352 * if the value cannot be converted to a number.
353 *
354 * @param key
355 * A key string.
356 * @return The integer value.
357 */
358 public int getInt(String key) throws NoSuchElementException,
359 NumberFormatException {
360 Object o = get(key);
361 return o instanceof Number ? ((Number) o).intValue()
362 : (int) getDouble(key);
363 }
364
365 /**
366 * Get the JSONArray value associated with a key.
367 *
368 * @exception NoSuchElementException
369 * if the key is not found or if the value is not a
370 * JSONArray.
371 *
372 * @param key
373 * A key string.
374 * @return A JSONArray which is the value.
375 */
376 public JSONArray getJSONArray(String key) throws NoSuchElementException {
377 Object o = get(key);
378 if (o instanceof JSONArray) {
379 return (JSONArray) o;
380 }
381 throw new NoSuchElementException("JSONObject[" + quote(key)
382 + "] is not a JSONArray.");
383 }
384
385 /**
386 * Get the JSONObject value associated with a key.
387 *
388 * @exception NoSuchElementException
389 * if the key is not found or if the value is not a
390 * JSONObject.
391 *
392 * @param key
393 * A key string.
394 * @return A JSONObject which is the value.
395 */
396 public JSONObject getJSONObject(String key) throws NoSuchElementException {
397 Object o = get(key);
398 if (o instanceof JSONObject) {
399 return (JSONObject) o;
400 }
401 throw new NoSuchElementException("JSONObject[" + quote(key)
402 + "] is not a JSONObject.");
403 }
404
405 /**
406 * Get the string associated with a key.
407 *
408 * @exception NoSuchElementException
409 * if the key is not found.
410 *
411 * @param key
412 * A key string.
413 * @return A string which is the value.
414 */
415 public String getString(String key) throws NoSuchElementException {
416 return get(key).toString();
417 }
418
419 /**
420 * Determine if the JSONObject contains a specific key.
421 *
422 * @param key
423 * A key string.
424 * @return true if the key exists in the JSONObject.
425 */
426 public boolean has(String key) {
427 return myHashMap.containsKey(key);
428 }
429
430 /**
431 * Determine if the value associated with the key is null or if there is no
432 * value.
433 *
434 * @param key
435 * A key string.
436 * @return true if there is no value associated with the key or if the value
437 * is the JSONObject.NULL object.
438 */
439 public boolean isNull(String key) {
440 return JSONObject.NULL.equals(opt(key));
441 }
442
443 /**
444 * Get an enumeration of the keys of the JSONObject.
445 *
446 * @return An iterator of the keys.
447 */
448 public Iterator keys() {
449 return myHashMap.keySet().iterator();
450 }
451
452 /**
453 * Get the number of keys stored in the JSONObject.
454 *
455 * @return The number of keys in the JSONObject.
456 */
457 public int length() {
458 return myHashMap.size();
459 }
460
461 /**
462 * Produce a JSONArray containing the names of the elements of this
463 * JSONObject.
464 *
465 * @return A JSONArray containing the key strings, or null if the JSONObject
466 * is empty.
467 */
468 public JSONArray names() {
469 JSONArray ja = new JSONArray();
470 Iterator keys = keys();
471 while (keys.hasNext()) {
472 ja.put(keys.next());
473 }
474 return ja.length() == 0 ? null : ja;
475 }
476
477 /**
478 * Produce a string from a number.
479 *
480 * @exception ArithmeticException
481 * JSON can only serialize finite numbers.
482 * @param n
483 * A Number
484 * @return A String.
485 */
486 static public String numberToString(Number n) throws ArithmeticException {
487 if ((n instanceof Float && (((Float) n).isInfinite() || ((Float) n)
488 .isNaN()))
489 || (n instanceof Double && (((Double) n).isInfinite() || ((Double) n)
490 .isNaN()))) {
491 throw new ArithmeticException(
492 "JSON can only serialize finite numbers.");
493 }
494
495
496
497 String s = n.toString().toLowerCase();
498 if (s.indexOf('e') < 0 && s.indexOf('.') > 0) {
499 while (s.endsWith("0")) {
500 s = s.substring(0, s.length() - 1);
501 }
502 if (s.endsWith(".")) {
503 s = s.substring(0, s.length() - 1);
504 }
505 }
506 return s;
507 }
508
509 /**
510 * Get an optional value associated with a key.
511 *
512 * @exception NullPointerException
513 * The key must not be null.
514 * @param key
515 * A key string.
516 * @return An object which is the value, or null if there is no value.
517 */
518 public Object opt(String key) throws NullPointerException {
519 if (key == null) {
520 throw new NullPointerException("Null key");
521 }
522 return myHashMap.get(key);
523 }
524
525 /**
526 * Get an optional boolean associated with a key. It returns false if there
527 * is no such key, or if the value is not Boolean.TRUE or the String "true".
528 *
529 * @param key
530 * A key string.
531 * @return The truth.
532 */
533 public boolean optBoolean(String key) {
534 return optBoolean(key, false);
535 }
536
537 /**
538 * Get an optional boolean associated with a key. It returns the
539 * defaultValue if there is no such key, or if it is not a Boolean or the
540 * String "true" or "false" (case insensitive).
541 *
542 * @param key
543 * A key string.
544 * @param defaultValue
545 * The default.
546 * @return The truth.
547 */
548 public boolean optBoolean(String key, boolean defaultValue) {
549 Object o = opt(key);
550 if (o != null) {
551 if (o.equals(Boolean.FALSE)
552 || (o instanceof String && ((String) o)
553 .equalsIgnoreCase("false"))) {
554 return false;
555 } else if (o.equals(Boolean.TRUE)
556 || (o instanceof String && ((String) o)
557 .equalsIgnoreCase("true"))) {
558 return true;
559 }
560 }
561 return defaultValue;
562 }
563
564 /**
565 * Get an optional double associated with a key, or NaN if there is no such
566 * key or if its value is not a number. If the value is a string, an attempt
567 * will be made to evaluate it as a number.
568 *
569 * @param key
570 * A string which is the key.
571 * @return An object which is the value.
572 */
573 public double optDouble(String key) {
574 return optDouble(key, Double.NaN);
575 }
576
577 /**
578 * Get an optional double associated with a key, or the defaultValue if
579 * there is no such key or if its value is not a number. If the value is a
580 * string, an attempt will be made to evaluate it as a number.
581 *
582 * @param key
583 * A key string.
584 * @param defaultValue
585 * The default.
586 * @return An object which is the value.
587 */
588 public double optDouble(String key, double defaultValue) {
589 Object o = opt(key);
590 if (o != null) {
591 if (o instanceof Number) {
592 return ((Number) o).doubleValue();
593 }
594 try {
595 return new Double((String) o).doubleValue();
596 } catch (Exception e) {
597 }
598 }
599 return defaultValue;
600 }
601
602 /**
603 * Get an optional int value associated with a key, or zero if there is no
604 * such key or if the value is not a number. If the value is a string, an
605 * attempt will be made to evaluate it as a number.
606 *
607 * @param key
608 * A key string.
609 * @return An object which is the value.
610 */
611 public int optInt(String key) {
612 return optInt(key, 0);
613 }
614
615 /**
616 * Get an optional int value associated with a key, or the default if there
617 * is no such key or if the value is not a number. If the value is a string,
618 * an attempt will be made to evaluate it as a number.
619 *
620 * @param key
621 * A key string.
622 * @param defaultValue
623 * The default.
624 * @return An object which is the value.
625 */
626 public int optInt(String key, int defaultValue) {
627 Object o = opt(key);
628 if (o != null) {
629 if (o instanceof Number) {
630 return ((Number) o).intValue();
631 }
632 try {
633 return Integer.parseInt((String) o);
634 } catch (Exception e) {
635 }
636 }
637 return defaultValue;
638 }
639
640 /**
641 * Get an optional JSONArray associated with a key. It returns null if there
642 * is no such key, or if its value is not a JSONArray.
643 *
644 * @param key
645 * A key string.
646 * @return A JSONArray which is the value.
647 */
648 public JSONArray optJSONArray(String key) {
649 Object o = opt(key);
650 return o instanceof JSONArray ? (JSONArray) o : null;
651 }
652
653 /**
654 * Get an optional JSONObject associated with a key. It returns null if
655 * there is no such key, or if its value is not a JSONObject.
656 *
657 * @param key
658 * A key string.
659 * @return A JSONObject which is the value.
660 */
661 public JSONObject optJSONObject(String key) {
662 Object o = opt(key);
663 return o instanceof JSONObject ? (JSONObject) o : null;
664 }
665
666 /**
667 * Get an optional string associated with a key. It returns an empty string
668 * if there is no such key. If the value is not a string and is not null,
669 * then it is coverted to a string.
670 *
671 * @param key
672 * A key string.
673 * @return A string which is the value.
674 */
675 public String optString(String key) {
676 return optString(key, "");
677 }
678
679 /**
680 * Get an optional string associated with a key. It returns the defaultValue
681 * if there is no such key.
682 *
683 * @param key
684 * A key string.
685 * @param defaultValue
686 * The default.
687 * @return A string which is the value.
688 */
689 public String optString(String key, String defaultValue) {
690 Object o = opt(key);
691 return o != null ? o.toString() : defaultValue;
692 }
693
694 /**
695 * Put a key/boolean pair in the JSONObject.
696 *
697 * @param key
698 * A key string.
699 * @param value
700 * A boolean which is the value.
701 * @return this.
702 */
703 public JSONObject put(String key, boolean value) {
704 put(key, Boolean.valueOf(value));
705 return this;
706 }
707
708 /**
709 * Put a key/double pair in the JSONObject.
710 *
711 * @param key
712 * A key string.
713 * @param value
714 * A double which is the value.
715 * @return this.
716 */
717 public JSONObject put(String key, double value) {
718 put(key, new Double(value));
719 return this;
720 }
721
722 /**
723 * Put a key/int pair in the JSONObject.
724 *
725 * @param key
726 * A key string.
727 * @param value
728 * An int which is the value.
729 * @return this.
730 */
731 public JSONObject put(String key, int value) {
732 put(key, new Integer(value));
733 return this;
734 }
735
736 /**
737 * Put a key/value pair in the JSONObject. If the value is null, then the
738 * key will be removed from the JSONObject if it is present.
739 *
740 * @exception NullPointerException
741 * The key must be non-null.
742 * @param key
743 * A key string.
744 * @param value
745 * An object which is the value. It should be of one of these
746 * types: Boolean, Double, Integer, JSONArray, JSONObject,
747 * String, or the JSONObject.NULL object.
748 * @return this.
749 */
750 @SuppressWarnings("unchecked")
751 public JSONObject put(String key, Object value) throws NullPointerException {
752 if (key == null) {
753 throw new NullPointerException("Null key.");
754 }
755 if (value != null) {
756 myHashMap.put(key, value);
757 } else {
758 remove(key);
759 }
760 return this;
761 }
762
763 /**
764 * Put a key/value pair in the JSONObject, but only if the value is
765 * non-null.
766 *
767 * @exception NullPointerException
768 * The key must be non-null.
769 * @param key
770 * A key string.
771 * @param value
772 * An object which is the value. It should be of one of these
773 * types: Boolean, Double, Integer, JSONArray, JSONObject,
774 * String, or the JSONObject.NULL object.
775 * @return this.
776 */
777 public JSONObject putOpt(String key, Object value)
778 throws NullPointerException {
779 if (value != null) {
780 put(key, value);
781 }
782 return this;
783 }
784
785 /**
786 * Produce a string in double quotes with backslash sequences in all the
787 * right places.
788 *
789 * @param string
790 * A String
791 * @return A String correctly formatted for insertion in a JSON message.
792 */
793 public static String quote(String string) {
794 if (string == null || string.length() == 0) {
795 return "\"\"";
796 }
797
798 char b;
799 char c = 0;
800 int i;
801 int len = string.length();
802 StringBuffer sb = new StringBuffer(len + 4);
803 String t;
804
805 sb.append('"');
806 for (i = 0; i < len; i += 1) {
807 b = c;
808 c = string.charAt(i);
809 switch (c) {
810 case '\\':
811 case '"':
812 sb.append('\\');
813 sb.append(c);
814 break;
815 case '/':
816 if (b == '<') {
817 sb.append('\\');
818 }
819 sb.append(c);
820 break;
821 case '\b':
822 sb.append("\\b");
823 break;
824 case '\t':
825 sb.append("\\t");
826 break;
827 case '\n':
828 sb.append("\\n");
829 break;
830 case '\f':
831 sb.append("\\f");
832 break;
833 case '\r':
834 sb.append("\\r");
835 break;
836 default:
837 if (c < ' ') {
838 t = "000" + Integer.toHexString(c);
839 sb.append("\\u" + t.substring(t.length() - 4));
840 } else {
841 sb.append(c);
842 }
843 }
844 }
845 sb.append('"');
846 return sb.toString();
847 }
848
849 /**
850 * Remove a name and its value, if present.
851 *
852 * @param key
853 * The name to be removed.
854 * @return The value that was associated with the name, or null if there was
855 * no value.
856 */
857 public Object remove(String key) {
858 return myHashMap.remove(key);
859 }
860
861 /**
862 * Produce a JSONArray containing the values of the members of this
863 * JSONObject.
864 *
865 * @param names
866 * A JSONArray containing a list of key strings. This determines
867 * the sequence of the values in the result.
868 * @return A JSONArray of values.
869 */
870 public JSONArray toJSONArray(JSONArray names) {
871 if (names == null || names.length() == 0) {
872 return null;
873 }
874 JSONArray ja = new JSONArray();
875 for (int i = 0; i < names.length(); i += 1) {
876 ja.put(this.opt(names.getString(i)));
877 }
878 return ja;
879 }
880
881 /**
882 * Make an JSON external form string of this JSONObject. For compactness, no
883 * unnecessary whitespace is added.
884 * <p>
885 * Warning: This method assumes that the data structure is acyclical.
886 *
887 * @return a printable, displayable, portable, transmittable representation
888 * of the object, beginning with <code>{</code> <small>(left
889 * brace)</small> and ending with <code>}</code> <small>(right
890 * brace)</small>.
891 */
892 public String toString() {
893 Iterator keys = keys();
894 StringBuffer sb = new StringBuffer("{");
895
896 while (keys.hasNext()) {
897 if (sb.length() > 1) {
898 sb.append(',');
899 }
900 Object o = keys.next();
901 sb.append(quote(o.toString()));
902 sb.append(':');
903 sb.append(valueToString(myHashMap.get(o)));
904 }
905 sb.append('}');
906 return sb.toString();
907 }
908
909 /**
910 * Make a prettyprinted JSON external form string of this JSONObject.
911 * <p>
912 * Warning: This method assumes that the data structure is acyclical.
913 *
914 * @param indentFactor
915 * The number of spaces to add to each level of indentation.
916 * @return a printable, displayable, portable, transmittable representation
917 * of the object, beginning with <code>{</code> <small>(left
918 * brace)</small> and ending with <code>}</code> <small>(right
919 * brace)</small>.
920 */
921 public String toString(int indentFactor) {
922 return toString(indentFactor, 0);
923 }
924
925 /**
926 * Make a prettyprinted JSON string of this JSONObject.
927 * <p>
928 * Warning: This method assumes that the data structure is acyclical.
929 *
930 * @param indentFactor
931 * The number of spaces to add to each level of indentation.
932 * @param indent
933 * The indentation of the top level.
934 * @return a printable, displayable, transmittable representation of the
935 * object, beginning with <code>{</code> <small>(left
936 * brace)</small> and ending with <code>}</code> <small>(right
937 * brace)</small>.
938 */
939 String toString(int indentFactor, int indent) {
940 int i;
941 int n = length();
942 if (n == 0) {
943 return "{}";
944 }
945 Iterator keys = keys();
946 StringBuffer sb = new StringBuffer("{");
947 int newindent = indent + indentFactor;
948 Object o;
949 if (n == 1) {
950 o = keys.next();
951 sb.append(quote(o.toString()));
952 sb.append(": ");
953 sb.append(valueToString(myHashMap.get(o), indentFactor, indent));
954 } else {
955 while (keys.hasNext()) {
956 o = keys.next();
957 if (sb.length() > 1) {
958 sb.append(",\n");
959 } else {
960 sb.append('\n');
961 }
962 for (i = 0; i < newindent; i += 1) {
963 sb.append(' ');
964 }
965 sb.append(quote(o.toString()));
966 sb.append(": ");
967 sb.append(valueToString(myHashMap.get(o), indentFactor,
968 newindent));
969 }
970 if (sb.length() > 1) {
971 sb.append('\n');
972 for (i = 0; i < indent; i += 1) {
973 sb.append(' ');
974 }
975 }
976 }
977 sb.append('}');
978 return sb.toString();
979 }
980
981 /**
982 * Make JSON string of an object value.
983 * <p>
984 * Warning: This method assumes that the data structure is acyclical.
985 *
986 * @param value
987 * The value to be serialized.
988 * @return a printable, displayable, transmittable representation of the
989 * object, beginning with <code>{</code> <small>(left
990 * brace)</small> and ending with <code>}</code> <small>(right
991 * brace)</small>.
992 */
993 static String valueToString(Object value) throws ArithmeticException {
994 if (value == null || value.equals(null)) {
995 return "null";
996 }
997 if (value instanceof Number) {
998 return numberToString((Number) value);
999 }
1000 if (value instanceof Boolean || value instanceof JSONObject
1001 || value instanceof JSONArray) {
1002 return value.toString();
1003 }
1004 return quote(value.toString());
1005 }
1006
1007 /**
1008 * Make a prettyprinted JSON string of an object value.
1009 * <p>
1010 * Warning: This method assumes that the data structure is acyclical.
1011 *
1012 * @param value
1013 * The value to be serialized.
1014 * @param indentFactor
1015 * The number of spaces to add to each level of indentation.
1016 * @param indent
1017 * The indentation of the top level.
1018 * @return a printable, displayable, transmittable representation of the
1019 * object, beginning with <code>{</code> <small>(left
1020 * brace)</small> and ending with <code>}</code> <small>(right
1021 * brace)</small>.
1022 */
1023 static String valueToString(Object value, int indentFactor, int indent)
1024 throws ArithmeticException {
1025 if (value == null || value.equals(null)) {
1026 return "null";
1027 }
1028 if (value instanceof Number) {
1029 return numberToString((Number) value);
1030 }
1031 if (value instanceof Boolean) {
1032 return value.toString();
1033 }
1034 if (value instanceof JSONObject) {
1035 return (((JSONObject) value).toString(indentFactor, indent));
1036 }
1037 if (value instanceof JSONArray) {
1038 return (((JSONArray) value).toString(indentFactor, indent));
1039 }
1040 return quote(value.toString());
1041 }
1042 }