4 Copyright (c) 2002 JSON.org
6 Permission is hereby granted, free of charge, to any person obtaining a copy
7 of this software and associated documentation files (the "Software"), to deal
8 in the Software without restriction, including without limitation the rights
9 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 copies of the Software, and to permit persons to whom the Software is
11 furnished to do so, subject to the following conditions:
13 The above copyright notice and this permission notice shall be included in all
14 copies or substantial portions of the Software.
16 The Software shall be used for Good, not Evil.
18 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
27 import java.io.IOException;
28 import java.io.StringWriter;
29 import java.io.Writer;
30 import java.lang.reflect.Field;
31 import java.lang.reflect.Method;
32 import java.lang.reflect.Modifier;
33 import java.math.BigDecimal;
34 import java.math.BigInteger;
35 import java.util.Collection;
36 import java.util.Enumeration;
37 import java.util.HashMap;
38 import java.util.Iterator;
39 import java.util.Locale;
41 import java.util.Map.Entry;
42 import java.util.ResourceBundle;
46 * A JSONObject is an unordered collection of name/value pairs. Its external
47 * form is a string wrapped in curly braces with colons between the names and
48 * values, and commas between the values and names. The internal form is an
49 * object having <code>get</code> and <code>opt</code> methods for accessing
50 * the values by name, and <code>put</code> methods for adding or replacing
51 * values by name. The values can be any of these types: <code>Boolean</code>,
52 * <code>JSONArray</code>, <code>JSONObject</code>, <code>Number</code>,
53 * <code>String</code>, or the <code>JSONObject.NULL</code> object. A
54 * JSONObject constructor can be used to convert an external form JSON text
55 * into an internal form whose values can be retrieved with the
56 * <code>get</code> and <code>opt</code> methods, or to convert values into a
57 * JSON text using the <code>put</code> and <code>toString</code> methods. A
58 * <code>get</code> method returns a value if one can be found, and throws an
59 * exception if one cannot be found. An <code>opt</code> method returns a
60 * default value instead of throwing an exception, and so is useful for
61 * obtaining optional values.
63 * The generic <code>get()</code> and <code>opt()</code> methods return an
64 * object, which you can cast or query for type. There are also typed
65 * <code>get</code> and <code>opt</code> methods that do type checking and type
66 * coercion for you. The opt methods differ from the get methods in that they
67 * do not throw. Instead, they return a specified value, such as null.
69 * The <code>put</code> methods add or replace values in an object. For
73 * myString = new JSONObject()
74 * .put("JSON", "Hello, World!").toString();
77 * produces the string <code>{"JSON": "Hello, World"}</code>.
79 * The texts produced by the <code>toString</code> methods strictly conform to
80 * the JSON syntax rules. The constructors are more forgiving in the texts they
83 * <li>An extra <code>,</code> <small>(comma)</small> may appear just
84 * before the closing brace.</li>
85 * <li>Strings may be quoted with <code>'</code> <small>(single
86 * quote)</small>.</li>
87 * <li>Strings do not need to be quoted at all if they do not begin with a
88 * quote or single quote, and if they do not contain leading or trailing
89 * spaces, and if they do not contain any of these characters:
90 * <code>{ } [ ] / \ : , #</code> and if they do not look like numbers and
91 * if they are not the reserved words <code>true</code>, <code>false</code>,
92 * or <code>null</code>.</li>
98 public class JSONObject {
100 * JSONObject.NULL is equivalent to the value that JavaScript calls null,
101 * whilst Java's null is equivalent to the value that JavaScript calls
104 private static final class Null {
107 * There is only intended to be a single instance of the NULL object,
108 * so the clone method returns itself.
113 protected final Object clone() {
118 * A Null object is equal to the null value and to itself.
121 * An object to test for nullness.
122 * @return true if the object parameter is the JSONObject.NULL object or
126 public boolean equals(Object object) {
127 return object == null || object == this;
131 * Get the "null" string value.
133 * @return The string "null".
135 public String toString() {
141 * The map where the JSONObject's properties are kept.
143 private final Map<String, Object> map;
146 * It is sometimes more convenient and less ambiguous to have a
147 * <code>NULL</code> object than to use Java's <code>null</code> value.
148 * <code>JSONObject.NULL.equals(null)</code> returns <code>true</code>.
149 * <code>JSONObject.NULL.toString()</code> returns <code>"null"</code>.
151 public static final Object NULL = new Null();
154 * Construct an empty JSONObject.
156 public JSONObject() {
157 this.map = new HashMap<String, Object>();
161 * Construct a JSONObject from a subset of another JSONObject. An array of
162 * strings is used to identify the keys that should be copied. Missing keys
168 * An array of strings.
170 public JSONObject(JSONObject jo, String[] names) {
172 for (int i = 0; i < names.length; i += 1) {
174 this.putOnce(names[i], jo.opt(names[i]));
175 } catch (Exception ignore) {
181 * Construct a JSONObject from a JSONTokener.
184 * A JSONTokener object containing the source string.
185 * @throws JSONException
186 * If there is a syntax error in the source string or a
189 public JSONObject(JSONTokener x) throws JSONException {
194 if (x.nextClean() != '{') {
195 throw x.syntaxError("A JSONObject text must begin with '{'");
201 throw x.syntaxError("A JSONObject text must end with '}'");
206 key = x.nextValue().toString();
209 // The key is followed by ':'.
213 throw x.syntaxError("Expected a ':' after a key");
215 this.putOnce(key, x.nextValue());
217 // Pairs are separated by ','.
219 switch (x.nextClean()) {
222 if (x.nextClean() == '}') {
230 throw x.syntaxError("Expected a ',' or '}'");
236 * Construct a JSONObject from a Map.
239 * A map object that can be used to initialize the contents of
242 public JSONObject(Map<?, ?> map) {
243 this.map = new HashMap<String, Object>();
245 for (final Entry<?, ?> e : map.entrySet()) {
246 final Object value = e.getValue();
248 this.map.put(String.valueOf(e.getKey()), wrap(value));
255 * Construct a JSONObject from an Object using bean getters. It reflects on
256 * all of the public methods of the object. For each of the methods with no
257 * parameters and a name starting with <code>"get"</code> or
258 * <code>"is"</code> followed by an uppercase letter, the method is invoked,
259 * and a key and the value returned from the getter method are put into the
262 * The key is formed by removing the <code>"get"</code> or <code>"is"</code>
263 * prefix. If the second remaining character is not upper case, then the
264 * first character is converted to lower case.
266 * For example, if an object has a method named <code>"getName"</code>, and
267 * if the result of calling <code>object.getName()</code> is
268 * <code>"Larry Fine"</code>, then the JSONObject will contain
269 * <code>"name": "Larry Fine"</code>.
272 * An object that has getter methods that should be used to make
275 public JSONObject(Object bean) {
277 this.populateMap(bean);
281 * Construct a JSONObject from an Object, using reflection to find the
282 * public members. The resulting JSONObject's keys will be the strings from
283 * the names array, and the values will be the field values associated with
284 * those keys in the object. If a key is not found or not visible, then it
285 * will not be copied into the new JSONObject.
288 * An object that has fields that should be used to make a
291 * An array of strings, the names of the fields to be obtained
294 public JSONObject(Object object, String names[]) {
296 Class<?> c = object.getClass();
297 for (int i = 0; i < names.length; i += 1) {
298 String name = names[i];
300 this.putOpt(name, c.getField(name).get(object));
301 } catch (Exception ignore) {
307 * Construct a JSONObject from a source JSON text string. This is the most
308 * commonly used JSONObject constructor.
311 * A string beginning with <code>{</code> <small>(left
312 * brace)</small> and ending with <code>}</code>
313 * <small>(right brace)</small>.
314 * @exception JSONException
315 * If there is a syntax error in the source string or a
318 public JSONObject(String source) throws JSONException {
319 this(new JSONTokener(source));
323 * Construct a JSONObject from a ResourceBundle.
326 * The ResourceBundle base name.
328 * The Locale to load the ResourceBundle for.
329 * @throws JSONException
330 * If any JSONExceptions are detected.
332 public JSONObject(String baseName, Locale locale) throws JSONException {
334 ResourceBundle bundle = ResourceBundle.getBundle(baseName, locale,
335 Thread.currentThread().getContextClassLoader());
337 // Iterate through the keys in the bundle.
339 Enumeration<String> keys = bundle.getKeys();
340 while (keys.hasMoreElements()) {
341 Object key = keys.nextElement();
344 // Go through the path, ensuring that there is a nested JSONObject for each
345 // segment except the last. Add the value using the last segment's name into
346 // the deepest nested JSONObject.
348 String[] path = ((String) key).split("\\.");
349 int last = path.length - 1;
350 JSONObject target = this;
351 for (int i = 0; i < last; i += 1) {
352 String segment = path[i];
353 JSONObject nextTarget = target.optJSONObject(segment);
354 if (nextTarget == null) {
355 nextTarget = new JSONObject();
356 target.put(segment, nextTarget);
360 target.put(path[last], bundle.getString((String) key));
366 * Accumulate values under a key. It is similar to the put method except
367 * that if there is already an object stored under the key then a JSONArray
368 * is stored under the key to hold all of the accumulated values. If there
369 * is already a JSONArray, then the new value is appended to it. In
370 * contrast, the put method replaces the previous value.
372 * If only one value is accumulated that is not a JSONArray, then the result
373 * will be the same as using put. But if multiple values are accumulated,
374 * then the result will be like append.
379 * An object to be accumulated under the key.
381 * @throws JSONException
382 * If the value is an invalid number or if the key is null.
384 public JSONObject accumulate(String key, Object value) throws JSONException {
386 Object object = this.opt(key);
387 if (object == null) {
389 value instanceof JSONArray ? new JSONArray().put(value)
391 } else if (object instanceof JSONArray) {
392 ((JSONArray) object).put(value);
394 this.put(key, new JSONArray().put(object).put(value));
400 * Append values to the array under a key. If the key does not exist in the
401 * JSONObject, then the key is put in the JSONObject with its value being a
402 * JSONArray containing the value parameter. If the key was already
403 * associated with a JSONArray, then the value parameter is appended to it.
408 * An object to be accumulated under the key.
410 * @throws JSONException
411 * If the key is null or if the current value associated with
412 * the key is not a JSONArray.
414 public JSONObject append(String key, Object value) throws JSONException {
416 Object object = this.opt(key);
417 if (object == null) {
418 this.put(key, new JSONArray().put(value));
419 } else if (object instanceof JSONArray) {
420 this.put(key, ((JSONArray) object).put(value));
422 throw new JSONException("JSONObject[" + key
423 + "] is not a JSONArray.");
429 * Produce a string from a double. The string "null" will be returned if the
430 * number is not finite.
436 public static String doubleToString(double d) {
437 if (Double.isInfinite(d) || Double.isNaN(d)) {
441 // Shave off trailing zeros and decimal point, if possible.
443 String string = Double.toString(d);
444 if (string.indexOf('.') > 0 && string.indexOf('e') < 0
445 && string.indexOf('E') < 0) {
446 while (string.endsWith("0")) {
447 string = string.substring(0, string.length() - 1);
449 if (string.endsWith(".")) {
450 string = string.substring(0, string.length() - 1);
457 * Get the value object associated with a key.
461 * @return The object associated with the key.
462 * @throws JSONException
463 * if the key is not found.
465 public Object get(String key) throws JSONException {
467 throw new JSONException("Null key.");
469 Object object = this.opt(key);
470 if (object == null) {
471 throw new JSONException("JSONObject[" + quote(key) + "] not found.");
477 * Get the enum value associated with a key.
480 * The type of enum to retrieve.
483 * @return The enum value associated with the key
484 * @throws JSONException
485 * if the key is not found or if the value cannot be converted
488 public <E extends Enum<E>> E getEnum(Class<E> clazz, String key) throws JSONException {
489 E val = optEnum(clazz, key);
491 // JSONException should really take a throwable argument.
492 // If it did, I would re-implement this with the Enum.valueOf
493 // method and place any thrown exception in the JSONException
494 throw new JSONException("JSONObject[" + quote(key)
495 + "] is not an enum of type " + quote(clazz.getSimpleName())
502 * Get the boolean value associated with a key.
507 * @throws JSONException
508 * if the value is not a Boolean or the String "true" or
511 public boolean getBoolean(String key) throws JSONException {
512 Object object = this.get(key);
513 if (object.equals(Boolean.FALSE)
514 || (object instanceof String && ((String) object)
515 .equalsIgnoreCase("false"))) {
517 } else if (object.equals(Boolean.TRUE)
518 || (object instanceof String && ((String) object)
519 .equalsIgnoreCase("true"))) {
522 throw new JSONException("JSONObject[" + quote(key)
523 + "] is not a Boolean.");
527 * Get the BigInteger value associated with a key.
531 * @return The numeric value.
532 * @throws JSONException
533 * if the key is not found or if the value cannot
534 * be converted to BigInteger.
536 public BigInteger getBigInteger(String key) throws JSONException {
537 Object object = this.get(key);
539 return new BigInteger(object.toString());
540 } catch (Exception e) {
541 throw new JSONException("JSONObject[" + quote(key)
542 + "] could not be converted to BigInteger.");
547 * Get the BigDecimal value associated with a key.
551 * @return The numeric value.
552 * @throws JSONException
553 * if the key is not found or if the value
554 * cannot be converted to BigDecimal.
556 public BigDecimal getBigDecimal(String key) throws JSONException {
557 Object object = this.get(key);
559 return new BigDecimal(object.toString());
560 } catch (Exception e) {
561 throw new JSONException("JSONObject[" + quote(key)
562 + "] could not be converted to BigDecimal.");
567 * Get the double value associated with a key.
571 * @return The numeric value.
572 * @throws JSONException
573 * if the key is not found or if the value is not a Number
574 * object and cannot be converted to a number.
576 public double getDouble(String key) throws JSONException {
577 Object object = this.get(key);
579 return object instanceof Number ? ((Number) object).doubleValue()
580 : Double.parseDouble((String) object);
581 } catch (Exception e) {
582 throw new JSONException("JSONObject[" + quote(key)
583 + "] is not a number.");
588 * Get the int value associated with a key.
592 * @return The integer value.
593 * @throws JSONException
594 * if the key is not found or if the value cannot be converted
597 public int getInt(String key) throws JSONException {
598 Object object = this.get(key);
600 return object instanceof Number ? ((Number) object).intValue()
601 : Integer.parseInt((String) object);
602 } catch (Exception e) {
603 throw new JSONException("JSONObject[" + quote(key)
604 + "] is not an int.");
609 * Get the JSONArray value associated with a key.
613 * @return A JSONArray which is the value.
614 * @throws JSONException
615 * if the key is not found or if the value is not a JSONArray.
617 public JSONArray getJSONArray(String key) throws JSONException {
618 Object object = this.get(key);
619 if (object instanceof JSONArray) {
620 return (JSONArray) object;
622 throw new JSONException("JSONObject[" + quote(key)
623 + "] is not a JSONArray.");
627 * Get the JSONObject value associated with a key.
631 * @return A JSONObject which is the value.
632 * @throws JSONException
633 * if the key is not found or if the value is not a JSONObject.
635 public JSONObject getJSONObject(String key) throws JSONException {
636 Object object = this.get(key);
637 if (object instanceof JSONObject) {
638 return (JSONObject) object;
640 throw new JSONException("JSONObject[" + quote(key)
641 + "] is not a JSONObject.");
645 * Get the long value associated with a key.
649 * @return The long value.
650 * @throws JSONException
651 * if the key is not found or if the value cannot be converted
654 public long getLong(String key) throws JSONException {
655 Object object = this.get(key);
657 return object instanceof Number ? ((Number) object).longValue()
658 : Long.parseLong((String) object);
659 } catch (Exception e) {
660 throw new JSONException("JSONObject[" + quote(key)
661 + "] is not a long.");
666 * Get an array of field names from a JSONObject.
668 * @return An array of field names, or null if there are no names.
670 public static String[] getNames(JSONObject jo) {
671 int length = jo.length();
675 Iterator<String> iterator = jo.keys();
676 String[] names = new String[length];
678 while (iterator.hasNext()) {
679 names[i] = iterator.next();
686 * Get an array of field names from an Object.
688 * @return An array of field names, or null if there are no names.
690 public static String[] getNames(Object object) {
691 if (object == null) {
694 Class<?> klass = object.getClass();
695 Field[] fields = klass.getFields();
696 int length = fields.length;
700 String[] names = new String[length];
701 for (int i = 0; i < length; i += 1) {
702 names[i] = fields[i].getName();
708 * Get the string associated with a key.
712 * @return A string which is the value.
713 * @throws JSONException
714 * if there is no string value for the key.
716 public String getString(String key) throws JSONException {
717 Object object = this.get(key);
718 if (object instanceof String) {
719 return (String) object;
721 throw new JSONException("JSONObject[" + quote(key) + "] not a string.");
725 * Determine if the JSONObject contains a specific key.
729 * @return true if the key exists in the JSONObject.
731 public boolean has(String key) {
732 return this.map.containsKey(key);
736 * Increment a property of a JSONObject. If there is no such property,
737 * create one with a value of 1. If there is such a property, and if it is
738 * an Integer, Long, Double, or Float, then add one to it.
743 * @throws JSONException
744 * If there is already a property with this name that is not an
745 * Integer, Long, Double, or Float.
747 public JSONObject increment(String key) throws JSONException {
748 Object value = this.opt(key);
751 } else if (value instanceof BigInteger) {
752 this.put(key, ((BigInteger)value).add(BigInteger.ONE));
753 } else if (value instanceof BigDecimal) {
754 this.put(key, ((BigDecimal)value).add(BigDecimal.ONE));
755 } else if (value instanceof Integer) {
756 this.put(key, (Integer) value + 1);
757 } else if (value instanceof Long) {
758 this.put(key, (Long) value + 1);
759 } else if (value instanceof Double) {
760 this.put(key, (Double) value + 1);
761 } else if (value instanceof Float) {
762 this.put(key, (Float) value + 1);
764 throw new JSONException("Unable to increment [" + quote(key) + "].");
770 * Determine if the value associated with the key is null or if there is no
775 * @return true if there is no value associated with the key or if the value
776 * is the JSONObject.NULL object.
778 public boolean isNull(String key) {
779 return JSONObject.NULL.equals(this.opt(key));
783 * Get an enumeration of the keys of the JSONObject.
785 * @return An iterator of the keys.
787 public Iterator<String> keys() {
788 return this.keySet().iterator();
792 * Get a set of keys of the JSONObject.
796 public Set<String> keySet() {
797 return this.map.keySet();
801 * Get the number of keys stored in the JSONObject.
803 * @return The number of keys in the JSONObject.
805 public int length() {
806 return this.map.size();
810 * Produce a JSONArray containing the names of the elements of this
813 * @return A JSONArray containing the key strings, or null if the JSONObject
816 public JSONArray names() {
817 JSONArray ja = new JSONArray();
818 Iterator<String> keys = this.keys();
819 while (keys.hasNext()) {
822 return ja.length() == 0 ? null : ja;
826 * Produce a string from a Number.
831 * @throws JSONException
832 * If n is a non-finite number.
834 public static String numberToString(Number number) throws JSONException {
835 if (number == null) {
836 throw new JSONException("Null pointer");
838 testValidity(number);
840 // Shave off trailing zeros and decimal point, if possible.
842 String string = number.toString();
843 if (string.indexOf('.') > 0 && string.indexOf('e') < 0
844 && string.indexOf('E') < 0) {
845 while (string.endsWith("0")) {
846 string = string.substring(0, string.length() - 1);
848 if (string.endsWith(".")) {
849 string = string.substring(0, string.length() - 1);
856 * Get an optional value associated with a key.
860 * @return An object which is the value, or null if there is no value.
862 public Object opt(String key) {
863 return key == null ? null : this.map.get(key);
867 * Get the enum value associated with a key.
870 * The type of enum to retrieve.
873 * @return The enum value associated with the key or null if not found
875 public <E extends Enum<E>> E optEnum(Class<E> clazz, String key) {
876 return this.optEnum(clazz, key, null);
880 * Get the enum value associated with a key.
883 * The type of enum to retrieve.
886 * @param defaultValue
887 * The default in case the value is not found
888 * @return The enum value associated with the key or defaultValue
889 * if the value is not found or cannot be assigned to clazz
891 public <E extends Enum<E>> E optEnum(Class<E> clazz, String key, E defaultValue) {
893 Object val = this.opt(key);
894 if (NULL.equals(val)) {
897 if (clazz.isAssignableFrom(val.getClass())) {
898 // we just checked it!
899 @SuppressWarnings("unchecked")
903 return Enum.valueOf(clazz, val.toString());
904 } catch (IllegalArgumentException e) {
906 } catch (NullPointerException e) {
912 * Get an optional boolean associated with a key. It returns false if there
913 * is no such key, or if the value is not Boolean.TRUE or the String "true".
919 public boolean optBoolean(String key) {
920 return this.optBoolean(key, false);
924 * Get an optional boolean associated with a key. It returns the
925 * defaultValue if there is no such key, or if it is not a Boolean or the
926 * String "true" or "false" (case insensitive).
930 * @param defaultValue
934 public boolean optBoolean(String key, boolean defaultValue) {
936 return this.getBoolean(key);
937 } catch (Exception e) {
943 * Get an optional double associated with a key, or NaN if there is no such
944 * key or if its value is not a number. If the value is a string, an attempt
945 * will be made to evaluate it as a number.
948 * A string which is the key.
949 * @return An object which is the value.
951 public double optDouble(String key) {
952 return this.optDouble(key, Double.NaN);
956 * Get an optional BigInteger associated with a key, or the defaultValue if
957 * there is no such key or if its value is not a number. If the value is a
958 * string, an attempt will be made to evaluate it as a number.
962 * @param defaultValue
964 * @return An object which is the value.
966 public BigInteger optBigInteger(String key, BigInteger defaultValue) {
968 return this.getBigInteger(key);
969 } catch (Exception e) {
975 * Get an optional BigDecimal associated with a key, or the defaultValue if
976 * there is no such key or if its value is not a number. If the value is a
977 * string, an attempt will be made to evaluate it as a number.
981 * @param defaultValue
983 * @return An object which is the value.
985 public BigDecimal optBigDecimal(String key, BigDecimal defaultValue) {
987 return this.getBigDecimal(key);
988 } catch (Exception e) {
994 * Get an optional double associated with a key, or the defaultValue if
995 * there is no such key or if its value is not a number. If the value is a
996 * string, an attempt will be made to evaluate it as a number.
1000 * @param defaultValue
1002 * @return An object which is the value.
1004 public double optDouble(String key, double defaultValue) {
1006 return this.getDouble(key);
1007 } catch (Exception e) {
1008 return defaultValue;
1013 * Get an optional int value associated with a key, or zero if there is no
1014 * such key or if the value is not a number. If the value is a string, an
1015 * attempt will be made to evaluate it as a number.
1019 * @return An object which is the value.
1021 public int optInt(String key) {
1022 return this.optInt(key, 0);
1026 * Get an optional int value associated with a key, or the default if there
1027 * is no such key or if the value is not a number. If the value is a string,
1028 * an attempt will be made to evaluate it as a number.
1032 * @param defaultValue
1034 * @return An object which is the value.
1036 public int optInt(String key, int defaultValue) {
1038 return this.getInt(key);
1039 } catch (Exception e) {
1040 return defaultValue;
1045 * Get an optional JSONArray associated with a key. It returns null if there
1046 * is no such key, or if its value is not a JSONArray.
1050 * @return A JSONArray which is the value.
1052 public JSONArray optJSONArray(String key) {
1053 Object o = this.opt(key);
1054 return o instanceof JSONArray ? (JSONArray) o : null;
1058 * Get an optional JSONObject associated with a key. It returns null if
1059 * there is no such key, or if its value is not a JSONObject.
1063 * @return A JSONObject which is the value.
1065 public JSONObject optJSONObject(String key) {
1066 Object object = this.opt(key);
1067 return object instanceof JSONObject ? (JSONObject) object : null;
1071 * Get an optional long value associated with a key, or zero if there is no
1072 * such key or if the value is not a number. If the value is a string, an
1073 * attempt will be made to evaluate it as a number.
1077 * @return An object which is the value.
1079 public long optLong(String key) {
1080 return this.optLong(key, 0);
1084 * Get an optional long value associated with a key, or the default if there
1085 * is no such key or if the value is not a number. If the value is a string,
1086 * an attempt will be made to evaluate it as a number.
1090 * @param defaultValue
1092 * @return An object which is the value.
1094 public long optLong(String key, long defaultValue) {
1096 return this.getLong(key);
1097 } catch (Exception e) {
1098 return defaultValue;
1103 * Get an optional string associated with a key. It returns an empty string
1104 * if there is no such key. If the value is not a string and is not null,
1105 * then it is converted to a string.
1109 * @return A string which is the value.
1111 public String optString(String key) {
1112 return this.optString(key, "");
1116 * Get an optional string associated with a key. It returns the defaultValue
1117 * if there is no such key.
1121 * @param defaultValue
1123 * @return A string which is the value.
1125 public String optString(String key, String defaultValue) {
1126 Object object = this.opt(key);
1127 return NULL.equals(object) ? defaultValue : object.toString();
1130 private void populateMap(Object bean) {
1131 Class<?> klass = bean.getClass();
1133 // If klass is a System class then set includeSuperClass to false.
1135 boolean includeSuperClass = klass.getClassLoader() != null;
1137 Method[] methods = includeSuperClass ? klass.getMethods() : klass
1138 .getDeclaredMethods();
1139 for (int i = 0; i < methods.length; i += 1) {
1141 Method method = methods[i];
1142 if (Modifier.isPublic(method.getModifiers())) {
1143 String name = method.getName();
1145 if (name.startsWith("get")) {
1146 if ("getClass".equals(name)
1147 || "getDeclaringClass".equals(name)) {
1150 key = name.substring(3);
1152 } else if (name.startsWith("is")) {
1153 key = name.substring(2);
1155 if (key.length() > 0
1156 && Character.isUpperCase(key.charAt(0))
1157 && method.getParameterTypes().length == 0) {
1158 if (key.length() == 1) {
1159 key = key.toLowerCase();
1160 } else if (!Character.isUpperCase(key.charAt(1))) {
1161 key = key.substring(0, 1).toLowerCase()
1165 Object result = method.invoke(bean, (Object[]) null);
1166 if (result != null) {
1167 this.map.put(key, wrap(result));
1171 } catch (Exception ignore) {
1177 * Put a key/boolean pair in the JSONObject.
1182 * A boolean which is the value.
1184 * @throws JSONException
1185 * If the key is null.
1187 public JSONObject put(String key, boolean value) throws JSONException {
1188 this.put(key, value ? Boolean.TRUE : Boolean.FALSE);
1193 * Put a key/value pair in the JSONObject, where the value will be a
1194 * JSONArray which is produced from a Collection.
1199 * A Collection value.
1201 * @throws JSONException
1203 public JSONObject put(String key, Collection<?> value) throws JSONException {
1204 this.put(key, new JSONArray(value));
1209 * Put a key/double pair in the JSONObject.
1214 * A double which is the value.
1216 * @throws JSONException
1217 * If the key is null or if the number is invalid.
1219 public JSONObject put(String key, double value) throws JSONException {
1220 this.put(key, new Double(value));
1225 * Put a key/int pair in the JSONObject.
1230 * An int which is the value.
1232 * @throws JSONException
1233 * If the key is null.
1235 public JSONObject put(String key, int value) throws JSONException {
1236 this.put(key, new Integer(value));
1241 * Put a key/long pair in the JSONObject.
1246 * A long which is the value.
1248 * @throws JSONException
1249 * If the key is null.
1251 public JSONObject put(String key, long value) throws JSONException {
1252 this.put(key, new Long(value));
1257 * Put a key/value pair in the JSONObject, where the value will be a
1258 * JSONObject which is produced from a Map.
1265 * @throws JSONException
1267 public JSONObject put(String key, Map<?, ?> value) throws JSONException {
1268 this.put(key, new JSONObject(value));
1273 * Put a key/value pair in the JSONObject. If the value is null, then the
1274 * key will be removed from the JSONObject if it is present.
1279 * An object which is the value. It should be of one of these
1280 * types: Boolean, Double, Integer, JSONArray, JSONObject, Long,
1281 * String, or the JSONObject.NULL object.
1283 * @throws JSONException
1284 * If the value is non-finite number or if the key is null.
1286 public JSONObject put(String key, Object value) throws JSONException {
1288 throw new NullPointerException("Null key.");
1290 if (value != null) {
1291 testValidity(value);
1292 this.map.put(key, value);
1300 * Put a key/value pair in the JSONObject, but only if the key and the value
1301 * are both non-null, and only if there is not already a member with that
1305 * @param value object
1307 * @throws JSONException
1308 * if the key is a duplicate
1310 public JSONObject putOnce(String key, Object value) throws JSONException {
1311 if (key != null && value != null) {
1312 if (this.opt(key) != null) {
1313 throw new JSONException("Duplicate key \"" + key + "\"");
1315 this.put(key, value);
1321 * Put a key/value pair in the JSONObject, but only if the key and the value
1322 * are both non-null.
1327 * An object which is the value. It should be of one of these
1328 * types: Boolean, Double, Integer, JSONArray, JSONObject, Long,
1329 * String, or the JSONObject.NULL object.
1331 * @throws JSONException
1332 * If the value is a non-finite number.
1334 public JSONObject putOpt(String key, Object value) throws JSONException {
1335 if (key != null && value != null) {
1336 this.put(key, value);
1342 * Produce a string in double quotes with backslash sequences in all the
1343 * right places. A backslash will be inserted within </, producing <\/,
1344 * allowing JSON text to be delivered in HTML. In JSON text, a string cannot
1345 * contain a control character or an unescaped quote or backslash.
1349 * @return A String correctly formatted for insertion in a JSON text.
1351 public static String quote(String string) {
1352 StringWriter sw = new StringWriter();
1353 synchronized (sw.getBuffer()) {
1355 return quote(string, sw).toString();
1356 } catch (IOException ignored) {
1357 // will never happen - we are writing to a string writer
1363 public static Writer quote(String string, Writer w) throws IOException {
1364 if (string == null || string.length() == 0) {
1373 int len = string.length();
1376 for (i = 0; i < len; i += 1) {
1378 c = string.charAt(i);
1407 if (c < ' ' || (c >= '\u0080' && c < '\u00a0')
1408 || (c >= '\u2000' && c < '\u2100')) {
1410 hhhh = Integer.toHexString(c);
1411 w.write("0000", 0, 4 - hhhh.length());
1423 * Remove a name and its value, if present.
1426 * The name to be removed.
1427 * @return The value that was associated with the name, or null if there was
1430 public Object remove(String key) {
1431 return this.map.remove(key);
1435 * Determine if two JSONObjects are similar.
1436 * They must contain the same set of names which must be associated with
1439 * @param other The other JSONObject
1440 * @return true if they are equal
1442 public boolean similar(Object other) {
1444 if (!(other instanceof JSONObject)) {
1447 Set<String> set = this.keySet();
1448 if (!set.equals(((JSONObject)other).keySet())) {
1451 Iterator<String> iterator = set.iterator();
1452 while (iterator.hasNext()) {
1453 String name = iterator.next();
1454 Object valueThis = this.get(name);
1455 Object valueOther = ((JSONObject)other).get(name);
1456 if (valueThis instanceof JSONObject) {
1457 if (!((JSONObject)valueThis).similar(valueOther)) {
1460 } else if (valueThis instanceof JSONArray) {
1461 if (!((JSONArray)valueThis).similar(valueOther)) {
1464 } else if (!valueThis.equals(valueOther)) {
1469 } catch (Throwable exception) {
1475 * Try to convert a string into a number, boolean, or null. If the string
1476 * can't be converted, return the string.
1480 * @return A simple JSON value.
1482 public static Object stringToValue(String string) {
1483 if (string.equals("")) {
1486 if (string.equalsIgnoreCase("true")) {
1487 return Boolean.TRUE;
1489 if (string.equalsIgnoreCase("false")) {
1490 return Boolean.FALSE;
1492 if (string.equalsIgnoreCase("null")) {
1493 return JSONObject.NULL;
1497 * If it might be a number, try converting it. If a number cannot be
1498 * produced, then the value will just be a string.
1501 char initial = string.charAt(0);
1502 if ((initial >= '0' && initial <= '9') || initial == '-') {
1504 if (string.indexOf('.') > -1 || string.indexOf('e') > -1
1505 || string.indexOf('E') > -1
1506 || "-0".equals(string)) {
1507 Double d = Double.valueOf(string);
1508 if (!d.isInfinite() && !d.isNaN()) {
1512 Long myLong = new Long(string);
1513 if (string.equals(myLong.toString())) {
1514 if (myLong.longValue() == myLong.intValue()) {
1515 return Integer.valueOf(myLong.intValue());
1520 } catch (Exception ignore) {
1527 * Throw an exception if the object is a NaN or infinite number.
1530 * The object to test.
1531 * @throws JSONException
1532 * If o is a non-finite number.
1534 public static void testValidity(Object o) throws JSONException {
1536 if (o instanceof Double) {
1537 if (((Double) o).isInfinite() || ((Double) o).isNaN()) {
1538 throw new JSONException(
1539 "JSON does not allow non-finite numbers.");
1541 } else if (o instanceof Float) {
1542 if (((Float) o).isInfinite() || ((Float) o).isNaN()) {
1543 throw new JSONException(
1544 "JSON does not allow non-finite numbers.");
1551 * Produce a JSONArray containing the values of the members of this
1555 * A JSONArray containing a list of key strings. This determines
1556 * the sequence of the values in the result.
1557 * @return A JSONArray of values.
1558 * @throws JSONException
1559 * If any of the values are non-finite numbers.
1561 public JSONArray toJSONArray(JSONArray names) throws JSONException {
1562 if (names == null || names.length() == 0) {
1565 JSONArray ja = new JSONArray();
1566 for (int i = 0; i < names.length(); i += 1) {
1567 ja.put(this.opt(names.getString(i)));
1573 * Make a JSON text of this JSONObject. For compactness, no whitespace is
1574 * added. If this would not result in a syntactically correct JSON text,
1575 * then null will be returned instead.
1577 * Warning: This method assumes that the data structure is acyclical.
1579 * @return a printable, displayable, portable, transmittable representation
1580 * of the object, beginning with <code>{</code> <small>(left
1581 * brace)</small> and ending with <code>}</code> <small>(right
1584 public String toString() {
1586 return this.toString(0);
1587 } catch (Exception e) {
1593 * Make a prettyprinted JSON text of this JSONObject.
1595 * Warning: This method assumes that the data structure is acyclical.
1597 * @param indentFactor
1598 * The number of spaces to add to each level of indentation.
1599 * @return a printable, displayable, portable, transmittable representation
1600 * of the object, beginning with <code>{</code> <small>(left
1601 * brace)</small> and ending with <code>}</code> <small>(right
1603 * @throws JSONException
1604 * If the object contains an invalid number.
1606 public String toString(int indentFactor) throws JSONException {
1607 StringWriter w = new StringWriter();
1608 synchronized (w.getBuffer()) {
1609 return this.write(w, indentFactor, 0).toString();
1614 * Make a JSON text of an Object value. If the object has an
1615 * value.toJSONString() method, then that method will be used to produce the
1616 * JSON text. The method is required to produce a strictly conforming text.
1617 * If the object does not contain a toJSONString method (which is the most
1618 * common case), then a text will be produced by other means. If the value
1619 * is an array or Collection, then a JSONArray will be made from it and its
1620 * toJSONString method will be called. If the value is a MAP, then a
1621 * JSONObject will be made from it and its toJSONString method will be
1622 * called. Otherwise, the value's toString method will be called, and the
1623 * result will be quoted.
1626 * Warning: This method assumes that the data structure is acyclical.
1629 * The value to be serialized.
1630 * @return a printable, displayable, transmittable representation of the
1631 * object, beginning with <code>{</code> <small>(left
1632 * brace)</small> and ending with <code>}</code> <small>(right
1634 * @throws JSONException
1635 * If the value is or contains an invalid number.
1637 public static String valueToString(Object value) throws JSONException {
1638 if (value == null || value.equals(null)) {
1641 if (value instanceof JSONString) {
1644 object = ((JSONString) value).toJSONString();
1645 } catch (Exception e) {
1646 throw new JSONException(e);
1648 if (object instanceof String) {
1649 return (String) object;
1651 throw new JSONException("Bad value from toJSONString: " + object);
1653 if (value instanceof Number) {
1654 return numberToString((Number) value);
1656 if (value instanceof Boolean || value instanceof JSONObject
1657 || value instanceof JSONArray) {
1658 return value.toString();
1660 if (value instanceof Map) {
1661 Map<?, ?> map = (Map<?, ?>) value;
1662 return new JSONObject(map).toString();
1664 if (value instanceof Collection) {
1665 Collection<?> coll = (Collection<?>) value;
1666 return new JSONArray(coll).toString();
1668 if (value.getClass().isArray()) {
1669 return new JSONArray(value).toString();
1671 return quote(value.toString());
1675 * Wrap an object, if necessary. If the object is null, return the NULL
1676 * object. If it is an array or collection, wrap it in a JSONArray. If it is
1677 * a map, wrap it in a JSONObject. If it is a standard property (Double,
1678 * String, et al) then it is already wrapped. Otherwise, if it comes from
1679 * one of the java packages, turn it into a string. And if it doesn't, try
1680 * to wrap it in a JSONObject. If the wrapping fails, then null is returned.
1683 * The object to wrap
1684 * @return The wrapped value
1686 public static Object wrap(Object object) {
1688 if (object == null) {
1691 if (object instanceof JSONObject || object instanceof JSONArray
1692 || NULL.equals(object) || object instanceof JSONString
1693 || object instanceof Byte || object instanceof Character
1694 || object instanceof Short || object instanceof Integer
1695 || object instanceof Long || object instanceof Boolean
1696 || object instanceof Float || object instanceof Double
1697 || object instanceof String || object instanceof BigInteger
1698 || object instanceof BigDecimal) {
1702 if (object instanceof Collection) {
1703 Collection<?> coll = (Collection<?>) object;
1704 return new JSONArray(coll);
1706 if (object.getClass().isArray()) {
1707 return new JSONArray(object);
1709 if (object instanceof Map) {
1710 Map<?, ?> map = (Map<?, ?>) object;
1711 return new JSONObject(map);
1713 Package objectPackage = object.getClass().getPackage();
1714 String objectPackageName = objectPackage != null ? objectPackage
1716 if (objectPackageName.startsWith("java.")
1717 || objectPackageName.startsWith("javax.")
1718 || object.getClass().getClassLoader() == null) {
1719 return object.toString();
1721 return new JSONObject(object);
1722 } catch (Exception exception) {
1728 * Write the contents of the JSONObject as JSON text to a writer. For
1729 * compactness, no whitespace is added.
1731 * Warning: This method assumes that the data structure is acyclical.
1733 * @return The writer.
1734 * @throws JSONException
1736 public Writer write(Writer writer) throws JSONException {
1737 return this.write(writer, 0, 0);
1740 static final Writer writeValue(Writer writer, Object value,
1741 int indentFactor, int indent) throws JSONException, IOException {
1742 if (value == null || value.equals(null)) {
1743 writer.write("null");
1744 } else if (value instanceof JSONObject) {
1745 ((JSONObject) value).write(writer, indentFactor, indent);
1746 } else if (value instanceof JSONArray) {
1747 ((JSONArray) value).write(writer, indentFactor, indent);
1748 } else if (value instanceof Map) {
1749 Map<?, ?> map = (Map<?, ?>) value;
1750 new JSONObject(map).write(writer, indentFactor, indent);
1751 } else if (value instanceof Collection) {
1752 Collection<?> coll = (Collection<?>) value;
1753 new JSONArray(coll).write(writer, indentFactor, indent);
1754 } else if (value.getClass().isArray()) {
1755 new JSONArray(value).write(writer, indentFactor, indent);
1756 } else if (value instanceof Number) {
1757 writer.write(numberToString((Number) value));
1758 } else if (value instanceof Boolean) {
1759 writer.write(value.toString());
1760 } else if (value instanceof JSONString) {
1763 o = ((JSONString) value).toJSONString();
1764 } catch (Exception e) {
1765 throw new JSONException(e);
1767 writer.write(o != null ? o.toString() : quote(value.toString()));
1769 quote(value.toString(), writer);
1774 static final void indent(Writer writer, int indent) throws IOException {
1775 for (int i = 0; i < indent; i += 1) {
1781 * Write the contents of the JSONObject as JSON text to a writer. For
1782 * compactness, no whitespace is added.
1784 * Warning: This method assumes that the data structure is acyclical.
1787 * Writes the serialized JSON
1788 * @param indentFactor
1789 * The number of spaces to add to each level of indentation.
1791 * The indention of the top level.
1792 * @return The writer.
1793 * @throws JSONException
1795 public Writer write(Writer writer, int indentFactor, int indent)
1796 throws JSONException {
1798 boolean commanate = false;
1799 final int length = this.length();
1800 Iterator<String> keys = this.keys();
1804 Object key = keys.next();
1805 writer.write(quote(key.toString()));
1807 if (indentFactor > 0) {
1810 writeValue(writer, this.map.get(key), indentFactor, indent);
1811 } else if (length != 0) {
1812 final int newindent = indent + indentFactor;
1813 while (keys.hasNext()) {
1814 Object key = keys.next();
1818 if (indentFactor > 0) {
1821 indent(writer, newindent);
1822 writer.write(quote(key.toString()));
1824 if (indentFactor > 0) {
1827 writeValue(writer, this.map.get(key), indentFactor, newindent);
1830 if (indentFactor > 0) {
1833 indent(writer, indent);
1837 } catch (IOException exception) {
1838 throw new JSONException(exception);
1843 * Returns a java.util.Map containing all of the entrys in this object.
1844 * If an entry in the object is a JSONArray or JSONObject it will also
1847 * Warning: This method assumes that the data structure is acyclical.
1849 * @return a java.util.Map containing the entrys of this object
1851 public Map<String, Object> toMap() {
1852 Map<String, Object> results = new HashMap<String, Object>();
1853 for (Entry<String, Object> entry : this.map.entrySet()) {
1855 if (entry.getValue() == null || NULL.equals(entry.getValue())) {
1857 } else if (entry.getValue() instanceof JSONObject) {
1858 value = ((JSONObject) entry.getValue()).toMap();
1859 } else if (entry.getValue() instanceof JSONArray) {
1860 value = ((JSONArray) entry.getValue()).toList();
1862 value = entry.getValue();
1864 results.put(entry.getKey(), value);