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