3 import java.io.Closeable;
7 * Note: This file has been adapted for SwingJS by Bob Hanson hansonr@stolaf.edu
9 Copyright (c) 2002 JSON.org
11 Permission is hereby granted, free of charge, to any person obtaining a copy
12 of this software and associated documentation files (the "Software"), to deal
13 in the Software without restriction, including without limitation the rights
14 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15 copies of the Software, and to permit persons to whom the Software is
16 furnished to do so, subject to the following conditions:
18 The above copyright notice and this permission notice shall be included in all
19 copies or substantial portions of the Software.
21 The Software shall be used for Good, not Evil.
23 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
32 import java.io.IOException;
33 import java.io.StringWriter;
34 import java.io.Writer;
35 import java.lang.reflect.Field;
36 import java.lang.reflect.InvocationTargetException;
37 import java.lang.reflect.Method;
38 import java.lang.reflect.Modifier;
39 import java.math.BigDecimal;
40 import java.math.BigInteger;
41 import java.util.Collection;
42 import java.util.Enumeration;
43 import java.util.HashMap;
44 import java.util.Iterator;
45 import java.util.Locale;
47 import java.util.Map.Entry;
48 import java.util.ResourceBundle;
52 * A JSONObject is an unordered collection of name/value pairs. Its external
53 * form is a string wrapped in curly braces with colons between the names and
54 * values, and commas between the values and names. The internal form is an
55 * object having <code>get</code> and <code>opt</code> methods for accessing the
56 * values by name, and <code>put</code> methods for adding or replacing values
57 * by name. The values can be any of these types: <code>Boolean</code>,
58 * <code>JSONArray</code>, <code>JSONObject</code>, <code>Number</code>,
59 * <code>String</code>, or the <code>JSONObject.NULL</code> object. A JSONObject
60 * constructor can be used to convert an external form JSON text into an
61 * internal form whose values can be retrieved with the <code>get</code> and
62 * <code>opt</code> methods, or to convert values into a JSON text using the
63 * <code>put</code> and <code>toString</code> methods. A <code>get</code> method
64 * returns a value if one can be found, and throws an exception if one cannot be
65 * found. An <code>opt</code> method returns a default value instead of throwing
66 * an exception, and so is useful for obtaining optional values.
68 * The generic <code>get()</code> and <code>opt()</code> methods return an
69 * object, which you can cast or query for type. There are also typed
70 * <code>get</code> and <code>opt</code> methods that do type checking and type
71 * coercion for you. The opt methods differ from the get methods in that they do
72 * not throw. Instead, they return a specified value, such as null.
74 * The <code>put</code> methods add or replace values in an object. For example,
77 * myString = new JSONObject().put("JSON", "Hello, World!").toString();
80 * produces the string <code>{"JSON": "Hello, World"}</code>.
82 * The texts produced by the <code>toString</code> methods strictly conform to
83 * the JSON syntax rules. The constructors are more forgiving in the texts they
86 * <li>An extra <code>,</code> <small>(comma)</small> may appear just
87 * before the closing brace.</li>
88 * <li>Strings may be quoted with <code>'</code> <small>(single
89 * quote)</small>.</li>
90 * <li>Strings do not need to be quoted at all if they do not begin with a quote
91 * or single quote, and if they do not contain leading or trailing spaces, and
92 * if they do not contain any of these characters:
93 * <code>{ } [ ] / \ : , #</code> and if they do not look like numbers and if
94 * they are not the reserved words <code>true</code>, <code>false</code>, or
95 * <code>null</code>.</li>
101 public class JSONObject {
103 * JSONObject.NULL is equivalent to the value that JavaScript calls null, whilst
104 * Java's null is equivalent to the value that JavaScript calls undefined.
106 private static final class Null {
109 * There is only intended to be a single instance of the NULL object, so the
110 * clone method returns itself.
115 protected final Object clone() {
120 * A Null object is equal to the null value and to itself.
122 * @param object An object to test for nullness.
123 * @return true if the object parameter is the JSONObject.NULL object or null.
126 public boolean equals(Object object) {
127 return object == null || object == this;
131 * A Null object is equal to the null value and to itself.
133 * @return always returns 0.
136 public int hashCode() {
141 * Get the "null" string value.
143 * @return The string "null".
146 public String toString() {
152 * The map where the JSONObject's properties are kept.
154 private final Map<String, Object> map;
157 * It is sometimes more convenient and less ambiguous to have a
158 * <code>NULL</code> object than to use Java's <code>null</code> value.
159 * <code>JSONObject.NULL.equals(null)</code> returns <code>true</code>.
160 * <code>JSONObject.NULL.toString()</code> returns <code>"null"</code>.
162 public static final Object NULL = new Null();
165 * Construct an empty JSONObject.
167 public JSONObject() {
168 // HashMap is used on purpose to ensure that elements are unordered by
169 // the specification.
170 // JSON tends to be a portable transfer format to allows the container
171 // implementations to rearrange their items for a faster element
172 // retrieval based on associative access.
173 // Therefore, an implementation mustn't rely on the order of the item.
174 this.map = new HashMap<String, Object>();
178 * Construct a JSONObject from a subset of another JSONObject. An array of
179 * strings is used to identify the keys that should be copied. Missing keys are
182 * @param jo A JSONObject.
183 * @param names An array of strings.
185 public JSONObject(JSONObject jo, String[] names) {
187 for (int i = 0; i < names.length; i += 1) {
189 this.putOnce(names[i], jo.opt(names[i]));
190 } catch (Exception ignore) {
196 * Construct a JSONObject from a JSONTokener.
198 * @param x A JSONTokener object containing the source string.
199 * @throws JSONException If there is a syntax error in the source string or a
202 public JSONObject(JSONTokener x) throws JSONException {
207 if (x.nextClean() != '{') {
208 throw x.syntaxError("A JSONObject text must begin with '{'");
214 throw x.syntaxError("A JSONObject text must end with '}'");
219 key = x.nextValue().toString();
222 // The key is followed by ':'.
226 throw x.syntaxError("Expected a ':' after a key");
229 // Use syntaxError(..) to include error location
232 // Check if key exists
233 if (this.opt(key) != null) {
234 // key already exists
235 throw x.syntaxError("Duplicate key \"" + key + "\"");
237 // Only add value if non-null
238 Object value = x.nextValue();
240 this.put(key, value);
244 // Pairs are separated by ','.
246 switch (x.nextClean()) {
249 if (x.nextClean() == '}') {
257 throw x.syntaxError("Expected a ',' or '}'");
263 * Construct a JSONObject from a Map.
265 * @param m A map object that can be used to initialize the contents of the
267 * @throws JSONException If a value in the map is non-finite number.
268 * @throws NullPointerException If a key in the map is <code>null</code>
270 public JSONObject(Map<?, ?> m) {
272 this.map = new HashMap<String, Object>();
274 this.map = new HashMap<String, Object>(m.size());
275 for (final Entry<?, ?> e : m.entrySet()) {
276 if (e.getKey() == null) {
277 throw new NullPointerException("Null key.");
279 final Object value = e.getValue();
281 this.map.put(String.valueOf(e.getKey()), wrap(value));
288 * Construct a JSONObject from an Object using bean getters. It reflects on all
289 * of the public methods of the object. For each of the methods with no
290 * parameters and a name starting with <code>"get"</code> or <code>"is"</code>
291 * followed by an uppercase letter, the method is invoked, and a key and the
292 * value returned from the getter method are put into the new JSONObject.
294 * The key is formed by removing the <code>"get"</code> or <code>"is"</code>
295 * prefix. If the second remaining character is not upper case, then the first
296 * character is converted to lower case.
298 * Methods that are <code>static</code>, return <code>void</code>, have
299 * parameters, or are "bridge" methods, are ignored.
301 * For example, if an object has a method named <code>"getName"</code>, and if
302 * the result of calling <code>object.getName()</code> is
303 * <code>"Larry Fine"</code>, then the JSONObject will contain
304 * <code>"name": "Larry Fine"</code>.
306 * The {@link JSONPropertyName} annotation can be used on a bean getter to
307 * override key name used in the JSONObject. For example, using the object above
308 * with the <code>getName</code> method, if we annotated it with:
311 * @JSONPropertyName("FullName")
312 * public String getName() {
317 * The resulting JSON object would contain <code>"FullName": "Larry Fine"</code>
319 * Similarly, the {@link JSONPropertyName} annotation can be used on non-
320 * <code>get</code> and <code>is</code> methods. We can also override key name
321 * used in the JSONObject as seen below even though the field would normally be
325 * @JSONPropertyName("FullName")
326 * public String fullName() {
331 * The resulting JSON object would contain <code>"FullName": "Larry Fine"</code>
333 * The {@link JSONPropertyIgnore} annotation can be used to force the bean
334 * property to not be serialized into JSON. If both {@link JSONPropertyIgnore}
335 * and {@link JSONPropertyName} are defined on the same method, a depth
336 * comparison is performed and the one closest to the concrete class being
337 * serialized is used. If both annotations are at the same level, then the
338 * {@link JSONPropertyIgnore} annotation takes precedent and the field is not
339 * serialized. For example, the following declaration would prevent the
340 * <code>getName</code> method from being serialized:
343 * @JSONPropertyName("FullName")
344 * @JSONPropertyIgnore
345 * public String getName() {
351 * @param bean An object that has getter methods that should be used to make a
354 public JSONObject(Object bean) {
356 this.populateMap(bean);
360 * Construct a JSONObject from an Object, using reflection to find the public
361 * members. The resulting JSONObject's keys will be the strings from the names
362 * array, and the values will be the field values associated with those keys in
363 * the object. If a key is not found or not visible, then it will not be copied
364 * into the new JSONObject.
366 * @param object An object that has fields that should be used to make a
368 * @param names An array of strings, the names of the fields to be obtained
371 public JSONObject(Object object, String names[]) {
373 Class<?> c = object.getClass();
374 for (int i = 0; i < names.length; i += 1) {
375 String name = names[i];
377 this.putOpt(name, c.getField(name).get(object));
378 } catch (Exception ignore) {
384 * Construct a JSONObject from a source JSON text string. This is the most
385 * commonly used JSONObject constructor.
387 * @param source A string beginning with <code>{</code> <small>(left
388 * brace)</small> and ending with <code>}</code>
389 * <small>(right brace)</small>.
390 * @exception JSONException If there is a syntax error in the source string or a
393 public JSONObject(String source) throws JSONException {
394 this(new JSONTokener(source));
398 * Construct a JSONObject from a ResourceBundle.
400 * @param baseName The ResourceBundle base name.
401 * @param locale The Locale to load the ResourceBundle for.
402 * @throws JSONException If any JSONExceptions are detected.
404 public JSONObject(String baseName, Locale locale) throws JSONException {
406 ResourceBundle bundle = ResourceBundle.getBundle(baseName, locale,
407 Thread.currentThread().getContextClassLoader());
409 // Iterate through the keys in the bundle.
411 Enumeration<String> keys = bundle.getKeys();
412 while (keys.hasMoreElements()) {
413 Object key = keys.nextElement();
416 // Go through the path, ensuring that there is a nested JSONObject for each
417 // segment except the last. Add the value using the last segment's name into
418 // the deepest nested JSONObject.
420 String[] path = ((String) key).split("\\.");
421 int last = path.length - 1;
422 JSONObject target = this;
423 for (int i = 0; i < last; i += 1) {
424 String segment = path[i];
425 JSONObject nextTarget = target.optJSONObject(segment);
426 if (nextTarget == null) {
427 nextTarget = new JSONObject();
428 target.put(segment, nextTarget);
432 target.put(path[last], bundle.getString((String) key));
438 * Constructor to specify an initial capacity of the internal map. Useful for
439 * library internal calls where we know, or at least can best guess, how big
440 * this JSONObject will be.
442 * @param initialCapacity initial capacity of the internal map.
444 protected JSONObject(int initialCapacity) {
445 this.map = new HashMap<String, Object>(initialCapacity);
449 * Accumulate values under a key. It is similar to the put method except that if
450 * there is already an object stored under the key then a JSONArray is stored
451 * under the key to hold all of the accumulated values. If there is already a
452 * JSONArray, then the new value is appended to it. In contrast, the put method
453 * replaces the previous value.
455 * If only one value is accumulated that is not a JSONArray, then the result
456 * will be the same as using put. But if multiple values are accumulated, then
457 * the result will be like append.
459 * @param key A key string.
460 * @param value An object to be accumulated under the key.
462 * @throws JSONException If the value is non-finite number.
463 * @throws NullPointerException If the key is <code>null</code>.
465 public JSONObject accumulate(String key, Object value) throws JSONException {
467 Object object = this.opt(key);
468 if (object == null) {
469 this.put(key, value instanceof JSONArray ? new JSONArray().put(value) : value);
470 } else if (object instanceof JSONArray) {
471 ((JSONArray) object).put(value);
473 this.put(key, new JSONArray().put(object).put(value));
479 * Append values to the array under a key. If the key does not exist in the
480 * JSONObject, then the key is put in the JSONObject with its value being a
481 * JSONArray containing the value parameter. If the key was already associated
482 * with a JSONArray, then the value parameter is appended to it.
484 * @param key A key string.
485 * @param value An object to be accumulated under the key.
487 * @throws JSONException If the value is non-finite number or if the
488 * current value associated with the key is not a
490 * @throws NullPointerException If the key is <code>null</code>.
492 public JSONObject append(String key, Object value) throws JSONException {
494 Object object = this.opt(key);
495 if (object == null) {
496 this.put(key, new JSONArray().put(value));
497 } else if (object instanceof JSONArray) {
498 this.put(key, ((JSONArray) object).put(value));
500 throw new JSONException("JSONObject[" + key + "] is not a JSONArray.");
506 * Produce a string from a double. The string "null" will be returned if the
507 * number is not finite.
512 public static String doubleToString(double d) {
513 if (Double.isInfinite(d) || Double.isNaN(d)) {
517 // Shave off trailing zeros and decimal point, if possible.
519 String string = Double.toString(d);
520 if (string.indexOf('.') > 0 && string.indexOf('e') < 0 && string.indexOf('E') < 0) {
521 while (string.endsWith("0")) {
522 string = string.substring(0, string.length() - 1);
524 if (string.endsWith(".")) {
525 string = string.substring(0, string.length() - 1);
532 * Get the value object associated with a key.
534 * @param key A key string.
535 * @return The object associated with the key.
536 * @throws JSONException if the key is not found.
538 public Object get(String key) throws JSONException {
540 throw new JSONException("Null key.");
542 Object object = this.opt(key);
543 if (object == null) {
544 throw new JSONException("JSONObject[" + quote(key) + "] not found.");
550 * Get the enum value associated with a key.
552 * @param clazz The type of enum to retrieve.
553 * @param key A key string.
554 * @return The enum value associated with the key
555 * @throws JSONException if the key is not found or if the value cannot be
556 * converted to an enum.
558 public <E extends Enum<E>> E getEnum(Class<E> clazz, String key) throws JSONException {
559 E val = optEnum(clazz, key);
561 // JSONException should really take a throwable argument.
562 // If it did, I would re-implement this with the Enum.valueOf
563 // method and place any thrown exception in the JSONException
564 throw new JSONException(
565 "JSONObject[" + quote(key) + "] is not an enum of type " + quote(clazz.getSimpleName()) + ".");
571 * Get the boolean value associated with a key.
573 * @param key A key string.
575 * @throws JSONException if the value is not a Boolean or the String "true" or
578 public boolean getBoolean(String key) throws JSONException {
579 Object object = this.get(key);
580 if (object.equals(Boolean.FALSE) || (object instanceof String && ((String) object).equalsIgnoreCase("false"))) {
582 } else if (object.equals(Boolean.TRUE)
583 || (object instanceof String && ((String) object).equalsIgnoreCase("true"))) {
586 throw new JSONException("JSONObject[" + quote(key) + "] is not a Boolean.");
590 * Get the BigInteger value associated with a key.
592 * @param key A key string.
593 * @return The numeric value.
594 * @throws JSONException if the key is not found or if the value cannot be
595 * converted to BigInteger.
597 public BigInteger getBigInteger(String key) throws JSONException {
598 Object object = this.get(key);
600 return new BigInteger(object.toString());
601 } catch (Exception e) {
602 throw new JSONException("JSONObject[" + quote(key) + "] could not be converted to BigInteger.", e);
607 * Get the BigDecimal value associated with a key.
609 * @param key A key string.
610 * @return The numeric value.
611 * @throws JSONException if the key is not found or if the value cannot be
612 * converted to BigDecimal.
614 public BigDecimal getBigDecimal(String key) throws JSONException {
615 Object object = this.get(key);
616 if (object instanceof BigDecimal) {
617 return (BigDecimal) object;
620 return new BigDecimal(object.toString());
621 } catch (Exception e) {
622 throw new JSONException("JSONObject[" + quote(key) + "] could not be converted to BigDecimal.", e);
627 * Get the double value associated with a key.
629 * @param key A key string.
630 * @return The numeric value.
631 * @throws JSONException if the key is not found or if the value is not a Number
632 * object and cannot be converted to a number.
634 public double getDouble(String key) throws JSONException {
635 Object object = this.get(key);
637 return object instanceof Number ? ((Number) object).doubleValue() : Double.parseDouble(object.toString());
638 } catch (Exception e) {
639 throw new JSONException("JSONObject[" + quote(key) + "] is not a number.", e);
644 * Get the float value associated with a key.
646 * @param key A key string.
647 * @return The numeric value.
648 * @throws JSONException if the key is not found or if the value is not a Number
649 * object and cannot be converted to a number.
651 public float getFloat(String key) throws JSONException {
652 Object object = this.get(key);
654 return object instanceof Number ? ((Number) object).floatValue() : Float.parseFloat(object.toString());
655 } catch (Exception e) {
656 throw new JSONException("JSONObject[" + quote(key) + "] is not a number.", e);
661 * Get the Number value associated with a key.
663 * @param key A key string.
664 * @return The numeric value.
665 * @throws JSONException if the key is not found or if the value is not a Number
666 * object and cannot be converted to a number.
668 public Number getNumber(String key) throws JSONException {
669 Object object = this.get(key);
671 if (object instanceof Number) {
672 return (Number) object;
674 return stringToNumber(object.toString());
675 } catch (Exception e) {
676 throw new JSONException("JSONObject[" + quote(key) + "] is not a number.", e);
681 * Get the int value associated with a key.
683 * @param key A key string.
684 * @return The integer value.
685 * @throws JSONException if the key is not found or if the value cannot be
686 * converted to an integer.
688 public int getInt(String key) throws JSONException {
689 Object object = this.get(key);
691 return object instanceof Number ? ((Number) object).intValue() : Integer.parseInt((String) object);
692 } catch (Exception e) {
693 throw new JSONException("JSONObject[" + quote(key) + "] is not an int.", e);
698 * Get the JSONArray value associated with a key.
700 * @param key A key string.
701 * @return A JSONArray which is the value.
702 * @throws JSONException if the key is not found or if the value is not a
705 public JSONArray getJSONArray(String key) throws JSONException {
706 Object object = this.get(key);
707 if (object instanceof JSONArray) {
708 return (JSONArray) object;
710 throw new JSONException("JSONObject[" + quote(key) + "] is not a JSONArray.");
714 * Get the JSONObject value associated with a key.
716 * @param key A key string.
717 * @return A JSONObject which is the value.
718 * @throws JSONException if the key is not found or if the value is not a
721 public JSONObject getJSONObject(String key) throws JSONException {
722 Object object = this.get(key);
723 if (object instanceof JSONObject) {
724 return (JSONObject) object;
726 throw new JSONException("JSONObject[" + quote(key) + "] is not a JSONObject.");
730 * Get the long value associated with a key.
732 * @param key A key string.
733 * @return The long value.
734 * @throws JSONException if the key is not found or if the value cannot be
735 * converted to a long.
737 public long getLong(String key) throws JSONException {
738 Object object = this.get(key);
740 return object instanceof Number ? ((Number) object).longValue() : Long.parseLong((String) object);
741 } catch (Exception e) {
742 throw new JSONException("JSONObject[" + quote(key) + "] is not a long.", e);
747 * Get an array of field names from a JSONObject.
749 * @return An array of field names, or null if there are no names.
751 public static String[] getNames(JSONObject jo) {
755 return jo.keySet().toArray(new String[jo.length()]);
759 * Get an array of field names from an Object.
761 * @return An array of field names, or null if there are no names.
763 public static String[] getNames(Object object) {
764 if (object == null) {
767 Class<?> klass = object.getClass();
768 Field[] fields = klass.getFields();
769 int length = fields.length;
773 String[] names = new String[length];
774 for (int i = 0; i < length; i += 1) {
775 names[i] = fields[i].getName();
781 * Get the string associated with a key.
783 * @param key A key string.
784 * @return A string which is the value.
785 * @throws JSONException if there is no string value for the key.
787 public String getString(String key) throws JSONException {
788 Object object = this.get(key);
789 if (object instanceof String) {
790 return (String) object;
792 throw new JSONException("JSONObject[" + quote(key) + "] not a string.");
796 * Determine if the JSONObject contains a specific key.
798 * @param key A key string.
799 * @return true if the key exists in the JSONObject.
801 public boolean has(String key) {
802 return this.map.containsKey(key);
806 * Increment a property of a JSONObject. If there is no such property, create
807 * one with a value of 1. If there is such a property, and if it is an Integer,
808 * Long, Double, or Float, then add one to it.
810 * @param key A key string.
812 * @throws JSONException If there is already a property with this name that is
813 * not an Integer, Long, Double, or Float.
815 public JSONObject increment(String key) throws JSONException {
816 Object value = this.opt(key);
819 } else if (value instanceof BigInteger) {
820 this.put(key, ((BigInteger) value).add(BigInteger.ONE));
821 } else if (value instanceof BigDecimal) {
822 this.put(key, ((BigDecimal) value).add(BigDecimal.ONE));
823 } else if (value instanceof Integer) {
824 this.put(key, ((Integer) value).intValue() + 1);
825 } else if (value instanceof Long) {
826 this.put(key, ((Long) value).longValue() + 1L);
827 } else if (value instanceof Double) {
828 this.put(key, ((Double) value).doubleValue() + 1.0d);
829 } else if (value instanceof Float) {
830 this.put(key, ((Float) value).floatValue() + 1.0f);
832 throw new JSONException("Unable to increment [" + quote(key) + "].");
838 * Determine if the value associated with the key is <code>null</code> or if
841 * @param key A key string.
842 * @return true if there is no value associated with the key or if the value is
843 * the JSONObject.NULL object.
845 public boolean isNull(String key) {
846 return JSONObject.NULL.equals(this.opt(key));
850 * Get an enumeration of the keys of the JSONObject. Modifying this key Set will
851 * also modify the JSONObject. Use with caution.
853 * @see Set#iterator()
855 * @return An iterator of the keys.
857 public Iterator<String> keys() {
858 return this.keySet().iterator();
862 * Get a set of keys of the JSONObject. Modifying this key Set will also modify
863 * the JSONObject. Use with caution.
869 public Set<String> keySet() {
870 return this.map.keySet();
874 * Get a set of entries of the JSONObject. These are raw values and may not
875 * match what is returned by the JSONObject get* and opt* functions. Modifying
876 * the returned EntrySet or the Entry objects contained therein will modify the
877 * backing JSONObject. This does not return a clone or a read-only view.
881 * @see Map#entrySet()
883 * @return An Entry Set
885 protected Set<Entry<String, Object>> entrySet() {
886 return this.map.entrySet();
890 * Get the number of keys stored in the JSONObject.
892 * @return The number of keys in the JSONObject.
894 public int length() {
895 return this.map.size();
899 * Check if JSONObject is empty.
901 * @return true if JSONObject is empty, otherwise false.
903 public boolean isEmpty() {
904 return map.isEmpty();
908 * Produce a JSONArray containing the names of the elements of this JSONObject.
910 * @return A JSONArray containing the key strings, or null if the JSONObject is
913 public JSONArray names() {
914 if (this.map.isEmpty()) {
917 return new JSONArray(this.map.keySet());
921 * Produce a string from a Number.
923 * @param number A Number
925 * @throws JSONException If n is a non-finite number.
927 public static String numberToString(Number number) throws JSONException {
928 if (number == null) {
929 throw new JSONException("Null pointer");
931 testValidity(number);
933 // Shave off trailing zeros and decimal point, if possible.
935 String string = number.toString();
936 if (string.indexOf('.') > 0 && string.indexOf('e') < 0 && string.indexOf('E') < 0) {
937 while (string.endsWith("0")) {
938 string = string.substring(0, string.length() - 1);
940 if (string.endsWith(".")) {
941 string = string.substring(0, string.length() - 1);
948 * Get an optional value associated with a key.
950 * @param key A key string.
951 * @return An object which is the value, or null if there is no value.
953 public Object opt(String key) {
954 return key == null ? null : this.map.get(key);
958 * Get the enum value associated with a key.
960 * @param clazz The type of enum to retrieve.
961 * @param key A key string.
962 * @return The enum value associated with the key or null if not found
964 public <E extends Enum<E>> E optEnum(Class<E> clazz, String key) {
965 return this.optEnum(clazz, key, null);
969 * Get the enum value associated with a key.
971 * @param clazz The type of enum to retrieve.
972 * @param key A key string.
973 * @param defaultValue The default in case the value is not found
974 * @return The enum value associated with the key or defaultValue if the value
975 * is not found or cannot be assigned to <code>clazz</code>
977 public <E extends Enum<E>> E optEnum(Class<E> clazz, String key, E defaultValue) {
979 Object val = this.opt(key);
980 if (NULL.equals(val)) {
983 if (clazz.isAssignableFrom(val.getClass())) {
984 // we just checked it!
985 @SuppressWarnings("unchecked")
989 return Enum.valueOf(clazz, val.toString());
990 } catch (IllegalArgumentException e) {
992 } catch (NullPointerException e) {
998 * Get an optional boolean associated with a key. It returns false if there is
999 * no such key, or if the value is not Boolean.TRUE or the String "true".
1001 * @param key A key string.
1002 * @return The truth.
1004 public boolean optBoolean(String key) {
1005 return this.optBoolean(key, false);
1009 * Get an optional boolean associated with a key. It returns the defaultValue if
1010 * there is no such key, or if it is not a Boolean or the String "true" or
1011 * "false" (case insensitive).
1013 * @param key A key string.
1014 * @param defaultValue The default.
1015 * @return The truth.
1017 public boolean optBoolean(String key, boolean defaultValue) {
1018 Object val = this.opt(key);
1019 if (NULL.equals(val)) {
1020 return defaultValue;
1022 if (val instanceof Boolean) {
1023 return ((Boolean) val).booleanValue();
1026 // we'll use the get anyway because it does string conversion.
1027 return this.getBoolean(key);
1028 } catch (Exception e) {
1029 return defaultValue;
1034 * Get an optional BigDecimal associated with a key, or the defaultValue if
1035 * there is no such key or if its value is not a number. If the value is a
1036 * string, an attempt will be made to evaluate it as a number.
1038 * @param key A key string.
1039 * @param defaultValue The default.
1040 * @return An object which is the value.
1042 public BigDecimal optBigDecimal(String key, BigDecimal defaultValue) {
1043 Object val = this.opt(key);
1044 if (NULL.equals(val)) {
1045 return defaultValue;
1047 if (val instanceof BigDecimal) {
1048 return (BigDecimal) val;
1050 if (val instanceof BigInteger) {
1051 return new BigDecimal((BigInteger) val);
1053 if (val instanceof Double || val instanceof Float) {
1054 return new BigDecimal(((Number) val).doubleValue());
1056 if (val instanceof Long || val instanceof Integer || val instanceof Short || val instanceof Byte) {
1057 return new BigDecimal(((Number) val).longValue());
1059 // don't check if it's a string in case of unchecked Number subclasses
1061 return new BigDecimal(val.toString());
1062 } catch (Exception e) {
1063 return defaultValue;
1068 * Get an optional BigInteger associated with a key, or the defaultValue if
1069 * there is no such key or if its value is not a number. If the value is a
1070 * string, an attempt will be made to evaluate it as a number.
1072 * @param key A key string.
1073 * @param defaultValue The default.
1074 * @return An object which is the value.
1076 public BigInteger optBigInteger(String key, BigInteger defaultValue) {
1077 Object val = this.opt(key);
1078 if (NULL.equals(val)) {
1079 return defaultValue;
1081 if (val instanceof BigInteger) {
1082 return (BigInteger) val;
1084 if (val instanceof BigDecimal) {
1085 return ((BigDecimal) val).toBigInteger();
1087 if (val instanceof Double || val instanceof Float) {
1088 return new BigDecimal(((Number) val).doubleValue()).toBigInteger();
1090 if (val instanceof Long || val instanceof Integer || val instanceof Short || val instanceof Byte) {
1091 return BigInteger.valueOf(((Number) val).longValue());
1093 // don't check if it's a string in case of unchecked Number subclasses
1095 // the other opt functions handle implicit conversions, i.e.
1096 // jo.put("double",1.1d);
1097 // jo.optInt("double"); -- will return 1, not an error
1098 // this conversion to BigDecimal then to BigInteger is to maintain
1099 // that type cast support that may truncate the decimal.
1100 final String valStr = val.toString();
1101 if (isDecimalNotation(valStr)) {
1102 return new BigDecimal(valStr).toBigInteger();
1104 return new BigInteger(valStr);
1105 } catch (Exception e) {
1106 return defaultValue;
1111 * Get an optional double associated with a key, or NaN if there is no such key
1112 * or if its value is not a number. If the value is a string, an attempt will be
1113 * made to evaluate it as a number.
1115 * @param key A string which is the key.
1116 * @return An object which is the value.
1118 public double optDouble(String key) {
1119 return this.optDouble(key, Double.NaN);
1123 * Get an optional double associated with a key, or the defaultValue if there is
1124 * no such key or if its value is not a number. If the value is a string, an
1125 * attempt will be made to evaluate it as a number.
1127 * @param key A key string.
1128 * @param defaultValue The default.
1129 * @return An object which is the value.
1131 public double optDouble(String key, double defaultValue) {
1132 Object val = this.opt(key);
1133 if (NULL.equals(val)) {
1134 return defaultValue;
1136 if (val instanceof Number) {
1137 return ((Number) val).doubleValue();
1139 if (val instanceof String) {
1141 return Double.parseDouble((String) val);
1142 } catch (Exception e) {
1143 return defaultValue;
1146 return defaultValue;
1150 * Get the optional double value associated with an index. NaN is returned if
1151 * there is no value for the index, or if the value is not a number and cannot
1152 * be converted to a number.
1154 * @param key A key string.
1155 * @return The value.
1157 public float optFloat(String key) {
1158 return this.optFloat(key, Float.NaN);
1162 * Get the optional double value associated with an index. The defaultValue is
1163 * returned if there is no value for the index, or if the value is not a number
1164 * and cannot be converted to a number.
1166 * @param key A key string.
1167 * @param defaultValue The default value.
1168 * @return The value.
1170 public float optFloat(String key, float defaultValue) {
1171 Object val = this.opt(key);
1172 if (JSONObject.NULL.equals(val)) {
1173 return defaultValue;
1175 if (val instanceof Number) {
1176 return ((Number) val).floatValue();
1178 if (val instanceof String) {
1180 return Float.parseFloat((String) val);
1181 } catch (Exception e) {
1182 return defaultValue;
1185 return defaultValue;
1189 * Get an optional int value associated with a key, or zero if there is no such
1190 * key or if the value is not a number. If the value is a string, an attempt
1191 * will be made to evaluate it as a number.
1193 * @param key A key string.
1194 * @return An object which is the value.
1196 public int optInt(String key) {
1197 return this.optInt(key, 0);
1201 * Get an optional int value associated with a key, or the default if there is
1202 * no such key or if the value is not a number. If the value is a string, an
1203 * attempt will be made to evaluate it as a number.
1205 * @param key A key string.
1206 * @param defaultValue The default.
1207 * @return An object which is the value.
1209 public int optInt(String key, int defaultValue) {
1210 Object val = this.opt(key);
1211 if (NULL.equals(val)) {
1212 return defaultValue;
1214 if (val instanceof Number) {
1215 return ((Number) val).intValue();
1218 if (val instanceof String) {
1220 return new BigDecimal((String) val).intValue();
1221 } catch (Exception e) {
1222 return defaultValue;
1225 return defaultValue;
1229 * Get an optional JSONArray associated with a key. It returns null if there is
1230 * no such key, or if its value is not a JSONArray.
1232 * @param key A key string.
1233 * @return A JSONArray which is the value.
1235 public JSONArray optJSONArray(String key) {
1236 Object o = this.opt(key);
1237 return o instanceof JSONArray ? (JSONArray) o : null;
1241 * Get an optional JSONObject associated with a key. It returns null if there is
1242 * no such key, or if its value is not a JSONObject.
1244 * @param key A key string.
1245 * @return A JSONObject which is the value.
1247 public JSONObject optJSONObject(String key) {
1248 Object object = this.opt(key);
1249 return object instanceof JSONObject ? (JSONObject) object : null;
1253 * Get an optional long value associated with a key, or zero if there is no such
1254 * key or if the value is not a number. If the value is a string, an attempt
1255 * will be made to evaluate it as a number.
1257 * @param key A key string.
1258 * @return An object which is the value.
1260 public long optLong(String key) {
1261 return this.optLong(key, 0);
1265 * Get an optional long value associated with a key, or the default if there is
1266 * no such key or if the value is not a number. If the value is a string, an
1267 * attempt will be made to evaluate it as a number.
1269 * @param key A key string.
1270 * @param defaultValue The default.
1271 * @return An object which is the value.
1273 public long optLong(String key, long defaultValue) {
1274 Object val = this.opt(key);
1275 if (NULL.equals(val)) {
1276 return defaultValue;
1278 if (val instanceof Number) {
1279 return ((Number) val).longValue();
1282 if (val instanceof String) {
1284 return new BigDecimal((String) val).longValue();
1285 } catch (Exception e) {
1286 return defaultValue;
1289 return defaultValue;
1293 * Get an optional {@link Number} value associated with a key, or
1294 * <code>null</code> if there is no such key or if the value is not a number. If
1295 * the value is a string, an attempt will be made to evaluate it as a number
1296 * ({@link BigDecimal}). This method would be used in cases where type coercion
1297 * of the number value is unwanted.
1299 * @param key A key string.
1300 * @return An object which is the value.
1302 public Number optNumber(String key) {
1303 return this.optNumber(key, null);
1307 * Get an optional {@link Number} value associated with a key, or the default if
1308 * there is no such key or if the value is not a number. If the value is a
1309 * string, an attempt will be made to evaluate it as a number. This method would
1310 * be used in cases where type coercion of the number value is unwanted.
1312 * @param key A key string.
1313 * @param defaultValue The default.
1314 * @return An object which is the value.
1316 public Number optNumber(String key, Number defaultValue) {
1317 Object val = this.opt(key);
1318 if (NULL.equals(val)) {
1319 return defaultValue;
1321 if (val instanceof Number) {
1322 return (Number) val;
1325 if (val instanceof String) {
1327 return stringToNumber((String) val);
1328 } catch (Exception e) {
1329 return defaultValue;
1332 return defaultValue;
1336 * Get an optional string associated with a key. It returns an empty string if
1337 * there is no such key. If the value is not a string and is not null, then it
1338 * is converted to a string.
1340 * @param key A key string.
1341 * @return A string which is the value.
1343 public String optString(String key) {
1344 return this.optString(key, "");
1348 * Get an optional string associated with a key. It returns the defaultValue if
1349 * there is no such key.
1351 * @param key A key string.
1352 * @param defaultValue The default.
1353 * @return A string which is the value.
1355 public String optString(String key, String defaultValue) {
1356 Object object = this.opt(key);
1357 return NULL.equals(object) ? defaultValue : object.toString();
1361 * Populates the internal map of the JSONObject with the bean properties. The
1362 * bean can not be recursive.
1364 * @see JSONObject#JSONObject(Object)
1366 * @param bean the bean
1368 private void populateMap(Object bean) {
1369 Class<?> klass = bean.getClass();
1371 // If klass is a System class then set includeSuperClass to false.
1373 boolean includeSuperClass = klass.getClassLoader() != null;
1375 Method[] methods = includeSuperClass ? klass.getMethods() : klass.getDeclaredMethods();
1376 for (final Method method : methods) {
1377 final int modifiers = method.getModifiers();
1378 if (Modifier.isPublic(modifiers) && !Modifier.isStatic(modifiers) && method.getParameterTypes().length == 0
1379 && !method.isBridge() && method.getReturnType() != Void.TYPE
1380 && isValidMethodName(method.getName())) {
1381 final String key = getKeyNameFromMethod(method);
1382 if (key != null && !key.isEmpty()) {
1384 final Object result = method.invoke(bean);
1385 if (result != null) {
1386 this.map.put(key, wrap(result));
1387 // we don't use the result anywhere outside of wrap
1388 // if it's a resource we should be sure to close it
1389 // after calling toString
1390 if (result instanceof Closeable) {
1392 ((Closeable) result).close();
1393 } catch (IOException ignore) {
1397 } catch (IllegalAccessException ignore) {
1398 } catch (IllegalArgumentException ignore) {
1399 } catch (InvocationTargetException ignore) {
1406 private boolean isValidMethodName(String name) {
1407 return !"getClass".equals(name) && !"getDeclaringClass".equals(name);
1410 private String getKeyNameFromMethod(Method method) {
1411 final int ignoreDepth = -1;// getAnnotationDepth(method, JSONPropertyIgnore.class);
1412 // if (ignoreDepth > 0) {
1413 // final int forcedNameDepth = getAnnotationDepth(method, JSONPropertyName.class);
1414 // if (forcedNameDepth < 0 || ignoreDepth <= forcedNameDepth) {
1415 // // the hierarchy asked to ignore, and the nearest name override
1416 // // was higher or non-existent
1420 // JSONPropertyName annotation = getAnnotation(method, JSONPropertyName.class);
1421 // if (annotation != null && annotation.value() != null && !annotation.value().isEmpty()) {
1422 // return annotation.value();
1425 final String name = method.getName();
1426 if (name.startsWith("get") && name.length() > 3) {
1427 key = name.substring(3);
1428 } else if (name.startsWith("is") && name.length() > 2) {
1429 key = name.substring(2);
1433 // if the first letter in the key is not uppercase, then skip.
1434 // This is to maintain backwards compatibility before PR406
1435 // (https://github.com/stleary/JSON-java/pull/406/)
1436 if (Character.isLowerCase(key.charAt(0))) {
1439 if (key.length() == 1) {
1440 key = key.toLowerCase(Locale.ROOT);
1441 } else if (!Character.isUpperCase(key.charAt(1))) {
1442 key = key.substring(0, 1).toLowerCase(Locale.ROOT) + key.substring(1);
1444 return (/** @j2sNative 1 ? key.split("$")[0] : */
1449 // * Searches the class hierarchy to see if the method or it's super
1450 // * implementations and interfaces has the annotation.
1453 // * type of the annotation
1456 // * method to check
1457 // * @param annotationClass
1458 // * annotation to look for
1459 // * @return the {@link Annotation} if the annotation exists on the current method
1460 // * or one of it's super class definitions
1462 // private static <A extends Annotation> A getAnnotation(final Method m, final Class<A> annotationClass) {
1464 // // if we have invalid data the result is null
1465 // if (true || m == null || annotationClass == null) {
1469 // if (m.isAnnotationPresent(annotationClass)) {
1470 // return m.getAnnotation(annotationClass);
1473 // // if we've already reached the Object class, return null;
1474 // Class<?> c = m.getDeclaringClass();
1475 // if (c.getSuperclass() == null) {
1479 // // check directly implemented interfaces for the method being checked
1480 // for (Class<?> i : c.getInterfaces()) {
1482 // Method im = i.getMethod(m.getName(), m.getParameterTypes());
1483 // return getAnnotation(im, annotationClass);
1484 // } catch (final SecurityException ex) {
1486 // } catch (final NoSuchMethodException ex) {
1492 // return getAnnotation(
1493 // c.getSuperclass().getMethod(m.getName(), m.getParameterTypes()),
1494 // annotationClass);
1495 // } catch (final SecurityException ex) {
1497 // } catch (final NoSuchMethodException ex) {
1503 // * Searches the class hierarchy to see if the method or it's super
1504 // * implementations and interfaces has the annotation. Returns the depth of the
1505 // * annotation in the hierarchy.
1508 // * type of the annotation
1511 // * method to check
1512 // * @param annotationClass
1513 // * annotation to look for
1514 // * @return Depth of the annotation or -1 if the annotation is not on the method.
1516 // private static int getAnnotationDepth(final Method m, final Class<? extends Annotation> annotationClass) {
1517 // // if we have invalid data the result is -1
1518 // if (m == null || annotationClass == null) {
1521 // if (m.isAnnotationPresent(annotationClass)) {
1525 // // if we've already reached the Object class, return -1;
1526 // Class<?> c = m.getDeclaringClass();
1527 // if (c.getSuperclass() == null) {
1531 // // check directly implemented interfaces for the method being checked
1532 // for (Class<?> i : c.getInterfaces()) {
1534 // Method im = i.getMethod(m.getName(), m.getParameterTypes());
1535 // int d = getAnnotationDepth(im, annotationClass);
1537 // // since the annotation was on the interface, add 1
1540 // } catch (final SecurityException ex) {
1542 // } catch (final NoSuchMethodException ex) {
1548 // int d = getAnnotationDepth(
1549 // c.getSuperclass().getMethod(m.getName(), m.getParameterTypes()),
1550 // annotationClass);
1552 // // since the annotation was on the superclass, add 1
1556 // } catch (final SecurityException ex) {
1558 // } catch (final NoSuchMethodException ex) {
1564 * Put a key/boolean pair in the JSONObject.
1566 * @param key A key string.
1567 * @param value A boolean which is the value.
1569 * @throws JSONException If the value is non-finite number.
1570 * @throws NullPointerException If the key is <code>null</code>.
1572 public JSONObject put(String key, boolean value) throws JSONException {
1573 return this.put(key, value ? Boolean.TRUE : Boolean.FALSE);
1577 * Put a key/value pair in the JSONObject, where the value will be a JSONArray
1578 * which is produced from a Collection.
1580 * @param key A key string.
1581 * @param value A Collection value.
1583 * @throws JSONException If the value is non-finite number.
1584 * @throws NullPointerException If the key is <code>null</code>.
1586 public JSONObject put(String key, Collection<?> value) throws JSONException {
1587 return this.put(key, new JSONArray(value));
1591 * Put a key/double pair in the JSONObject.
1593 * @param key A key string.
1594 * @param value A double which is the value.
1596 * @throws JSONException If the value is non-finite number.
1597 * @throws NullPointerException If the key is <code>null</code>.
1599 public JSONObject put(String key, double value) throws JSONException {
1600 return this.put(key, Double.valueOf(value));
1604 * Put a key/float pair in the JSONObject.
1606 * @param key A key string.
1607 * @param value A float which is the value.
1609 * @throws JSONException If the value is non-finite number.
1610 * @throws NullPointerException If the key is <code>null</code>.
1612 public JSONObject put(String key, float value) throws JSONException {
1613 return this.put(key, Float.valueOf(value));
1617 * Put a key/int pair in the JSONObject.
1619 * @param key A key string.
1620 * @param value An int which is the value.
1622 * @throws JSONException If the value is non-finite number.
1623 * @throws NullPointerException If the key is <code>null</code>.
1625 public JSONObject put(String key, int value) throws JSONException {
1626 return this.put(key, Integer.valueOf(value));
1630 * Put a key/long pair in the JSONObject.
1632 * @param key A key string.
1633 * @param value A long which is the value.
1635 * @throws JSONException If the value is non-finite number.
1636 * @throws NullPointerException If the key is <code>null</code>.
1638 public JSONObject put(String key, long value) throws JSONException {
1639 return this.put(key, Long.valueOf(value));
1643 * Put a key/value pair in the JSONObject, where the value will be a JSONObject
1644 * which is produced from a Map.
1646 * @param key A key string.
1647 * @param value A Map value.
1649 * @throws JSONException If the value is non-finite number.
1650 * @throws NullPointerException If the key is <code>null</code>.
1652 public JSONObject put(String key, Map<?, ?> value) throws JSONException {
1653 return this.put(key, new JSONObject(value));
1657 * Put a key/value pair in the JSONObject. If the value is <code>null</code>,
1658 * then the key will be removed from the JSONObject if it is present.
1660 * @param key A key string.
1661 * @param value An object which is the value. It should be of one of these
1662 * types: Boolean, Double, Integer, JSONArray, JSONObject, Long,
1663 * String, or the JSONObject.NULL object.
1665 * @throws JSONException If the value is non-finite number.
1666 * @throws NullPointerException If the key is <code>null</code>.
1668 public JSONObject put(String key, Object value) throws JSONException {
1670 throw new NullPointerException("Null key.");
1672 if (value != null) {
1673 testValidity(value);
1674 this.map.put(key, value);
1682 * Put a key/value pair in the JSONObject, but only if the key and the value are
1683 * both non-null, and only if there is not already a member with that name.
1686 * @param value object
1688 * @throws JSONException if the key is a duplicate
1690 public JSONObject putOnce(String key, Object value) throws JSONException {
1691 if (key != null && value != null) {
1692 if (this.opt(key) != null) {
1693 throw new JSONException("Duplicate key \"" + key + "\"");
1695 return this.put(key, value);
1701 * Put a key/value pair in the JSONObject, but only if the key and the value are
1704 * @param key A key string.
1705 * @param value An object which is the value. It should be of one of these
1706 * types: Boolean, Double, Integer, JSONArray, JSONObject, Long,
1707 * String, or the JSONObject.NULL object.
1709 * @throws JSONException If the value is a non-finite number.
1711 public JSONObject putOpt(String key, Object value) throws JSONException {
1712 if (key != null && value != null) {
1713 return this.put(key, value);
1719 * Creates a JSONPointer using an initialization string and tries to match it to
1720 * an item within this JSONObject. For example, given a JSONObject initialized
1721 * with this document:
1729 * and this JSONPointer string:
1735 * Then this method will return the String "c". A JSONPointerException may be
1736 * thrown from code called by this method.
1738 * @param jsonPointer string that can be used to create a JSONPointer
1739 * @return the item matched by the JSONPointer, otherwise null
1741 public Object query(String jsonPointer) {
1742 return query(new JSONPointer(jsonPointer));
1746 * Uses a user initialized JSONPointer and tries to match it to an item within
1747 * this JSONObject. For example, given a JSONObject initialized with this
1756 * and this JSONPointer:
1762 * Then this method will return the String "c". A JSONPointerException may be
1763 * thrown from code called by this method.
1765 * @param jsonPointer string that can be used to create a JSONPointer
1766 * @return the item matched by the JSONPointer, otherwise null
1768 public Object query(JSONPointer jsonPointer) {
1769 return jsonPointer.queryFrom(this);
1773 * Queries and returns a value from this object using {@code jsonPointer}, or
1774 * returns null if the query fails due to a missing key.
1776 * @param jsonPointer the string representation of the JSON pointer
1777 * @return the queried value or {@code null}
1778 * @throws IllegalArgumentException if {@code jsonPointer} has invalid syntax
1780 public Object optQuery(String jsonPointer) {
1781 return optQuery(new JSONPointer(jsonPointer));
1785 * Queries and returns a value from this object using {@code jsonPointer}, or
1786 * returns null if the query fails due to a missing key.
1788 * @param jsonPointer The JSON pointer
1789 * @return the queried value or {@code null}
1790 * @throws IllegalArgumentException if {@code jsonPointer} has invalid syntax
1792 public Object optQuery(JSONPointer jsonPointer) {
1794 return jsonPointer.queryFrom(this);
1795 } catch (JSONPointerException e) {
1801 * Produce a string in double quotes with backslash sequences in all the right
1802 * places. A backslash will be inserted within </, producing <\/, allowing JSON
1803 * text to be delivered in HTML. In JSON text, a string cannot contain a control
1804 * character or an unescaped quote or backslash.
1806 * @param string A String
1807 * @return A String correctly formatted for insertion in a JSON text.
1809 public static String quote(String string) {
1810 StringWriter sw = new StringWriter();
1811 synchronized (sw.getBuffer()) {
1813 return quote(string, sw).toString();
1814 } catch (IOException ignored) {
1815 // will never happen - we are writing to a string writer
1821 public static Writer quote(String string, Writer w) throws IOException {
1822 if (string == null || string.isEmpty()) {
1831 int len = string.length();
1834 for (i = 0; i < len; i += 1) {
1836 c = string.charAt(i);
1865 if (c < ' ' || (c >= '\u0080' && c < '\u00a0') || (c >= '\u2000' && c < '\u2100')) {
1867 hhhh = Integer.toHexString(c);
1868 w.write("0000", 0, 4 - hhhh.length());
1880 * Remove a name and its value, if present.
1882 * @param key The name to be removed.
1883 * @return The value that was associated with the name, or null if there was no
1886 public Object remove(String key) {
1887 return this.map.remove(key);
1891 * Determine if two JSONObjects are similar. They must contain the same set of
1892 * names which must be associated with similar values.
1894 * @param other The other JSONObject
1895 * @return true if they are equal
1897 public boolean similar(Object other) {
1899 if (!(other instanceof JSONObject)) {
1902 if (!this.keySet().equals(((JSONObject) other).keySet())) {
1905 for (final Entry<String, ?> entry : this.entrySet()) {
1906 String name = entry.getKey();
1907 Object valueThis = entry.getValue();
1908 Object valueOther = ((JSONObject) other).get(name);
1909 if (valueThis == valueOther) {
1912 if (valueThis == null) {
1915 if (valueThis instanceof JSONObject) {
1916 if (!((JSONObject) valueThis).similar(valueOther)) {
1919 } else if (valueThis instanceof JSONArray) {
1920 if (!((JSONArray) valueThis).similar(valueOther)) {
1923 } else if (!valueThis.equals(valueOther)) {
1928 } catch (Throwable exception) {
1934 * Tests if the value should be tried as a decimal. It makes no test if there
1935 * are actual digits.
1937 * @param val value to test
1938 * @return true if the string is "-0" or if it contains '.', 'e', or 'E', false
1941 protected static boolean isDecimalNotation(final String val) {
1942 return val.indexOf('.') > -1 || val.indexOf('e') > -1 || val.indexOf('E') > -1 || "-0".equals(val);
1946 * Converts a string to a number using the narrowest possible type. Possible
1947 * returns for this function are BigDecimal, Double, BigInteger, Long, and
1948 * Integer. When a Double is returned, it should always be a valid Double and
1949 * not NaN or +-infinity.
1951 * @param val value to convert
1952 * @return Number representation of the value.
1953 * @throws NumberFormatException thrown if the value is not a valid number. A
1954 * public caller should catch this and wrap it in
1955 * a {@link JSONException} if applicable.
1957 protected static Number stringToNumber(final String val) throws NumberFormatException {
1958 char initial = val.charAt(0);
1959 if ((initial >= '0' && initial <= '9') || initial == '-') {
1960 // decimal representation
1961 if (isDecimalNotation(val)) {
1962 // quick dirty way to see if we need a BigDecimal instead of a Double
1963 // this only handles some cases of overflow or underflow
1964 if (val.length() > 14) {
1965 return new BigDecimal(val);
1967 final Double d = Double.valueOf(val);
1968 if (d.isInfinite() || d.isNaN()) {
1969 // if we can't parse it as a double, go up to BigDecimal
1970 // this is probably due to underflow like 4.32e-678
1971 // or overflow like 4.65e5324. The size of the string is small
1972 // but can't be held in a Double.
1973 return new BigDecimal(val);
1977 // integer representation.
1978 // This will narrow any values to the smallest reasonable Object representation
1979 // (Integer, Long, or BigInteger)
1982 // The compare string length method reduces GC,
1983 // but leads to smaller integers being placed in larger wrappers even though not
1984 // needed. i.e. 1,000,000,000 -> Long even though it's an Integer
1985 // 1,000,000,000,000,000,000 -> BigInteger even though it's a Long
1986 // if(val.length()<=9){
1987 // return Integer.valueOf(val);
1989 // if(val.length()<=18){
1990 // return Long.valueOf(val);
1992 // return new BigInteger(val);
1994 // BigInteger version: We use a similar bitLenth compare as
1995 // BigInteger#intValueExact uses. Increases GC, but objects hold
1996 // only what they need. i.e. Less runtime overhead if the value is
1997 // long lived. Which is the better tradeoff? This is closer to what's
1998 // in stringToValue.
1999 BigInteger bi = new BigInteger(val);
2000 if (bi.bitLength() <= 31) {
2001 return Integer.valueOf(bi.intValue());
2003 if (bi.bitLength() <= 63) {
2004 return Long.valueOf(bi.longValue());
2008 throw new NumberFormatException("val [" + val + "] is not a valid number.");
2012 * Try to convert a string into a number, boolean, or null. If the string can't
2013 * be converted, return the string.
2015 * @param string A String.
2016 * @return A simple JSON value.
2018 // Changes to this method must be copied to the corresponding method in
2019 // the XML class to keep full support for Android
2020 public static Object stringToValue(String string) {
2021 if (string.equals("")) {
2024 if (string.equalsIgnoreCase("true")) {
2025 return Boolean.TRUE;
2027 if (string.equalsIgnoreCase("false")) {
2028 return Boolean.FALSE;
2030 if (string.equalsIgnoreCase("null")) {
2031 return JSONObject.NULL;
2035 * If it might be a number, try converting it. If a number cannot be produced,
2036 * then the value will just be a string.
2039 char initial = string.charAt(0);
2040 if ((initial >= '0' && initial <= '9') || initial == '-') {
2042 // if we want full Big Number support this block can be replaced with:
2043 // return stringToNumber(string);
2044 if (isDecimalNotation(string)) {
2045 Double d = Double.valueOf(string);
2046 if (!d.isInfinite() && !d.isNaN()) {
2050 Long myLong = Long.valueOf(string);
2051 if (string.equals(myLong.toString())) {
2052 if (myLong.longValue() == myLong.intValue()) {
2053 return Integer.valueOf(myLong.intValue());
2058 } catch (Exception ignore) {
2065 * Throw an exception if the object is a NaN or infinite number.
2067 * @param o The object to test.
2068 * @throws JSONException If o is a non-finite number.
2070 public static void testValidity(Object o) throws JSONException {
2072 if (o instanceof Double) {
2073 if (((Double) o).isInfinite() || ((Double) o).isNaN()) {
2074 throw new JSONException("JSON does not allow non-finite numbers.");
2076 } else if (o instanceof Float) {
2077 if (((Float) o).isInfinite() || ((Float) o).isNaN()) {
2078 throw new JSONException("JSON does not allow non-finite numbers.");
2085 * Produce a JSONArray containing the values of the members of this JSONObject.
2087 * @param names A JSONArray containing a list of key strings. This determines
2088 * the sequence of the values in the result.
2089 * @return A JSONArray of values.
2090 * @throws JSONException If any of the values are non-finite numbers.
2092 public JSONArray toJSONArray(JSONArray names) throws JSONException {
2093 if (names == null || names.isEmpty()) {
2096 JSONArray ja = new JSONArray();
2097 for (int i = 0; i < names.length(); i += 1) {
2098 ja.put(this.opt(names.getString(i)));
2104 * Make a JSON text of this JSONObject. For compactness, no whitespace is added.
2105 * If this would not result in a syntactically correct JSON text, then null will
2106 * be returned instead.
2108 * <b> Warning: This method assumes that the data structure is acyclical. </b>
2110 * @return a printable, displayable, portable, transmittable representation of
2111 * the object, beginning with <code>{</code> <small>(left
2112 * brace)</small> and ending with <code>}</code> <small>(right
2116 public String toString() {
2118 return this.toString(0);
2119 } catch (Exception e) {
2125 * Make a pretty-printed JSON text of this JSONObject.
2128 * If <code>indentFactor > 0</code> and the {@link JSONObject} has only one key,
2129 * then the object will be output on a single line:
2132 * {@code {"key": 1}}
2136 * If an object has 2 or more keys, then it will be output across multiple
2137 * lines: <code><pre>{
2139 * "key2": "value 2",
2143 * <b> Warning: This method assumes that the data structure is acyclical. </b>
2145 * @param indentFactor The number of spaces to add to each level of indentation.
2146 * @return a printable, displayable, portable, transmittable representation of
2147 * the object, beginning with <code>{</code> <small>(left
2148 * brace)</small> and ending with <code>}</code> <small>(right
2150 * @throws JSONException If the object contains an invalid number.
2152 public String toString(int indentFactor) throws JSONException {
2153 StringWriter w = new StringWriter();
2154 synchronized (w.getBuffer()) {
2155 return this.write(w, indentFactor, 0).toString();
2160 * Make a JSON text of an Object value. If the object has an
2161 * value.toJSONString() method, then that method will be used to produce the
2162 * JSON text. The method is required to produce a strictly conforming text. If
2163 * the object does not contain a toJSONString method (which is the most common
2164 * case), then a text will be produced by other means. If the value is an array
2165 * or Collection, then a JSONArray will be made from it and its toJSONString
2166 * method will be called. If the value is a MAP, then a JSONObject will be made
2167 * from it and its toJSONString method will be called. Otherwise, the value's
2168 * toString method will be called, and the result will be quoted.
2171 * Warning: This method assumes that the data structure is acyclical.
2173 * @param value The value to be serialized.
2174 * @return a printable, displayable, transmittable representation of the object,
2175 * beginning with <code>{</code> <small>(left brace)</small> and
2176 * ending with <code>}</code> <small>(right brace)</small>.
2177 * @throws JSONException If the value is or contains an invalid number.
2179 public static String valueToString(Object value) throws JSONException {
2180 // moves the implementation to JSONWriter as:
2181 // 1. It makes more sense to be part of the writer class
2182 // 2. For Android support this method is not available. By implementing it in
2184 // Android users can use the writer with the built in Android JSONObject
2186 return JSONWriter.valueToString(value);
2190 * Wrap an object, if necessary. If the object is <code>null</code>, return the
2191 * NULL object. If it is an array or collection, wrap it in a JSONArray. If it
2192 * is a map, wrap it in a JSONObject. If it is a standard property (Double,
2193 * String, et al) then it is already wrapped. Otherwise, if it comes from one of
2194 * the java packages, turn it into a string. And if it doesn't, try to wrap it
2195 * in a JSONObject. If the wrapping fails, then null is returned.
2197 * @param object The object to wrap
2198 * @return The wrapped value
2200 public static Object wrap(Object object) {
2202 if (object == null) {
2205 if (object instanceof JSONObject || object instanceof JSONArray || NULL.equals(object)
2206 || object instanceof JSONString || object instanceof Byte || object instanceof Character
2207 || object instanceof Short || object instanceof Integer || object instanceof Long
2208 || object instanceof Boolean || object instanceof Float || object instanceof Double
2209 || object instanceof String || object instanceof BigInteger || object instanceof BigDecimal
2210 || object instanceof Enum) {
2214 if (object instanceof Collection) {
2215 Collection<?> coll = (Collection<?>) object;
2216 return new JSONArray(coll);
2218 if (object.getClass().isArray()) {
2219 return new JSONArray(object);
2221 if (object instanceof Map) {
2222 Map<?, ?> map = (Map<?, ?>) object;
2223 return new JSONObject(map);
2225 Package objectPackage = object.getClass().getPackage();
2226 String objectPackageName = objectPackage != null ? objectPackage.getName() : "";
2227 if (objectPackageName.startsWith("java.") || objectPackageName.startsWith("javax.")
2228 || object.getClass().getClassLoader() == null) {
2229 return object.toString();
2231 return new JSONObject(object);
2232 } catch (Exception exception) {
2238 * Write the contents of the JSONObject as JSON text to a writer. For
2239 * compactness, no whitespace is added.
2241 * <b> Warning: This method assumes that the data structure is acyclical. </b>
2243 * @return The writer.
2244 * @throws JSONException
2246 public Writer write(Writer writer) throws JSONException {
2247 return this.write(writer, 0, 0);
2250 static final Writer writeValue(Writer writer, Object value, int indentFactor, int indent)
2251 throws JSONException, IOException {
2252 if (value == null || value.equals(null)) {
2253 writer.write("null");
2254 } else if (value instanceof JSONString) {
2257 o = ((JSONString) value).toJSONString();
2258 } catch (Exception e) {
2259 throw new JSONException(e);
2261 writer.write(o != null ? o.toString() : quote(value.toString()));
2262 } else if (value instanceof Number) {
2263 // not all Numbers may match actual JSON Numbers. i.e. fractions or Imaginary
2264 final String numberAsString = numberToString((Number) value);
2266 // Use the BigDecimal constructor for its parser to validate the format.
2267 @SuppressWarnings("unused")
2268 BigDecimal testNum = new BigDecimal(numberAsString);
2269 // Close enough to a JSON number that we will use it unquoted
2270 writer.write(numberAsString);
2271 } catch (NumberFormatException ex) {
2272 // The Number value is not a valid JSON number.
2273 // Instead we will quote it as a string
2274 quote(numberAsString, writer);
2276 } else if (value instanceof Boolean) {
2277 writer.write(value.toString());
2278 } else if (value instanceof Enum<?>) {
2279 writer.write(quote(((Enum<?>) value).name()));
2280 } else if (value instanceof JSONObject) {
2281 ((JSONObject) value).write(writer, indentFactor, indent);
2282 } else if (value instanceof JSONArray) {
2283 ((JSONArray) value).write(writer, indentFactor, indent);
2284 } else if (value instanceof Map) {
2285 Map<?, ?> map = (Map<?, ?>) value;
2286 new JSONObject(map).write(writer, indentFactor, indent);
2287 } else if (value instanceof Collection) {
2288 Collection<?> coll = (Collection<?>) value;
2289 new JSONArray(coll).write(writer, indentFactor, indent);
2290 } else if (value.getClass().isArray()) {
2291 new JSONArray(value).write(writer, indentFactor, indent);
2293 quote(value.toString(), writer);
2298 static final void indent(Writer writer, int indent) throws IOException {
2299 for (int i = 0; i < indent; i += 1) {
2305 * Write the contents of the JSONObject as JSON text to a writer.
2308 * If <code>indentFactor > 0</code> and the {@link JSONObject} has only one key,
2309 * then the object will be output on a single line:
2312 * {@code {"key": 1}}
2316 * If an object has 2 or more keys, then it will be output across multiple
2317 * lines: <code><pre>{
2319 * "key2": "value 2",
2323 * <b> Warning: This method assumes that the data structure is acyclical. </b>
2325 * @param writer Writes the serialized JSON
2326 * @param indentFactor The number of spaces to add to each level of indentation.
2327 * @param indent The indentation of the top level.
2328 * @return The writer.
2329 * @throws JSONException
2331 public Writer write(Writer writer, int indentFactor, int indent) throws JSONException {
2333 boolean commanate = false;
2334 final int length = this.length();
2338 final Entry<String, ?> entry = this.entrySet().iterator().next();
2339 final String key = entry.getKey();
2340 writer.write(quote(key));
2342 if (indentFactor > 0) {
2346 writeValue(writer, entry.getValue(), indentFactor, indent);
2347 } catch (Exception e) {
2348 throw new JSONException("Unable to write JSONObject value for key: " + key, e);
2350 } else if (length != 0) {
2351 final int newindent = indent + indentFactor;
2352 for (final Entry<String, ?> entry : this.entrySet()) {
2356 if (indentFactor > 0) {
2359 indent(writer, newindent);
2360 final String key = entry.getKey();
2361 writer.write(quote(key));
2363 if (indentFactor > 0) {
2367 writeValue(writer, entry.getValue(), indentFactor, newindent);
2368 } catch (Exception e) {
2369 throw new JSONException("Unable to write JSONObject value for key: " + key, e);
2373 if (indentFactor > 0) {
2376 indent(writer, indent);
2380 } catch (IOException exception) {
2381 throw new JSONException(exception);
2386 * Returns a java.util.Map containing all of the entries in this object. If an
2387 * entry in the object is a JSONArray or JSONObject it will also be converted.
2389 * Warning: This method assumes that the data structure is acyclical.
2391 * @return a java.util.Map containing the entries of this object
2393 public Map<String, Object> toMap() {
2394 Map<String, Object> results = new HashMap<String, Object>();
2395 for (Entry<String, Object> entry : this.entrySet()) {
2397 if (entry.getValue() == null || NULL.equals(entry.getValue())) {
2399 } else if (entry.getValue() instanceof JSONObject) {
2400 value = ((JSONObject) entry.getValue()).toMap();
2401 } else if (entry.getValue() instanceof JSONArray) {
2402 value = ((JSONArray) entry.getValue()).toList();
2404 value = entry.getValue();
2406 results.put(entry.getKey(), value);