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.annotation.Annotation;
36 import java.lang.reflect.Field;
37 import java.lang.reflect.InvocationTargetException;
38 import java.lang.reflect.Method;
39 import java.lang.reflect.Modifier;
40 import java.math.BigDecimal;
41 import java.math.BigInteger;
42 import java.util.Collection;
43 import java.util.Enumeration;
44 import java.util.HashMap;
45 import java.util.Iterator;
46 import java.util.Locale;
48 import java.util.Map.Entry;
49 import java.util.ResourceBundle;
53 * A JSONObject is an unordered collection of name/value pairs. Its external
54 * form is a string wrapped in curly braces with colons between the names and
55 * values, and commas between the values and names. The internal form is an
56 * object having <code>get</code> and <code>opt</code> methods for accessing the
57 * values by name, and <code>put</code> methods for adding or replacing values
58 * by name. The values can be any of these types: <code>Boolean</code>,
59 * <code>JSONArray</code>, <code>JSONObject</code>, <code>Number</code>,
60 * <code>String</code>, or the <code>JSONObject.NULL</code> object. A JSONObject
61 * constructor can be used to convert an external form JSON text into an
62 * internal form whose values can be retrieved with the <code>get</code> and
63 * <code>opt</code> methods, or to convert values into a JSON text using the
64 * <code>put</code> and <code>toString</code> methods. A <code>get</code> method
65 * returns a value if one can be found, and throws an exception if one cannot be
66 * found. An <code>opt</code> method returns a default value instead of throwing
67 * an exception, and so is useful for obtaining optional values.
69 * The generic <code>get()</code> and <code>opt()</code> methods return an
70 * object, which you can cast or query for type. There are also typed
71 * <code>get</code> and <code>opt</code> methods that do type checking and type
72 * coercion for you. The opt methods differ from the get methods in that they do
73 * not throw. Instead, they return a specified value, such as null.
75 * The <code>put</code> methods add or replace values in an object. For example,
78 * myString = new JSONObject().put("JSON", "Hello, World!").toString();
81 * produces the string <code>{"JSON": "Hello, World"}</code>.
83 * The texts produced by the <code>toString</code> methods strictly conform to
84 * the JSON syntax rules. The constructors are more forgiving in the texts they
87 * <li>An extra <code>,</code> <small>(comma)</small> may appear just
88 * before the closing brace.</li>
89 * <li>Strings may be quoted with <code>'</code> <small>(single
90 * quote)</small>.</li>
91 * <li>Strings do not need to be quoted at all if they do not begin with a quote
92 * or single quote, and if they do not contain leading or trailing spaces, and
93 * if they do not contain any of these characters:
94 * <code>{ } [ ] / \ : , #</code> and if they do not look like numbers and if
95 * they are not the reserved words <code>true</code>, <code>false</code>, or
96 * <code>null</code>.</li>
100 * @version 2016-08-15
102 public class JSONObject {
104 * JSONObject.NULL is equivalent to the value that JavaScript calls null, whilst
105 * Java's null is equivalent to the value that JavaScript calls undefined.
107 private static final class Null {
110 * There is only intended to be a single instance of the NULL object, so the
111 * clone method returns itself.
116 protected final Object clone() {
121 * A Null object is equal to the null value and to itself.
123 * @param object An object to test for nullness.
124 * @return true if the object parameter is the JSONObject.NULL object or null.
127 public boolean equals(Object object) {
128 return object == null || object == this;
132 * A Null object is equal to the null value and to itself.
134 * @return always returns 0.
137 public int hashCode() {
142 * Get the "null" string value.
144 * @return The string "null".
147 public String toString() {
153 * The map where the JSONObject's properties are kept.
155 private final Map<String, Object> map;
158 * It is sometimes more convenient and less ambiguous to have a
159 * <code>NULL</code> object than to use Java's <code>null</code> value.
160 * <code>JSONObject.NULL.equals(null)</code> returns <code>true</code>.
161 * <code>JSONObject.NULL.toString()</code> returns <code>"null"</code>.
163 public static final Object NULL = new Null();
166 * Construct an empty JSONObject.
168 public JSONObject() {
169 // HashMap is used on purpose to ensure that elements are unordered by
170 // the specification.
171 // JSON tends to be a portable transfer format to allows the container
172 // implementations to rearrange their items for a faster element
173 // retrieval based on associative access.
174 // Therefore, an implementation mustn't rely on the order of the item.
175 this.map = new HashMap<String, Object>();
179 * Construct a JSONObject from a subset of another JSONObject. An array of
180 * strings is used to identify the keys that should be copied. Missing keys are
183 * @param jo A JSONObject.
184 * @param names An array of strings.
186 public JSONObject(JSONObject jo, String[] names) {
188 for (int i = 0; i < names.length; i += 1) {
190 this.putOnce(names[i], jo.opt(names[i]));
191 } catch (Exception ignore) {
197 * Construct a JSONObject from a JSONTokener.
199 * @param x A JSONTokener object containing the source string.
200 * @throws JSONException If there is a syntax error in the source string or a
203 public JSONObject(JSONTokener x) throws JSONException {
208 if (x.nextClean() != '{') {
209 throw x.syntaxError("A JSONObject text must begin with '{'");
215 throw x.syntaxError("A JSONObject text must end with '}'");
220 key = x.nextValue().toString();
223 // The key is followed by ':'.
227 throw x.syntaxError("Expected a ':' after a key");
230 // Use syntaxError(..) to include error location
233 // Check if key exists
234 if (this.opt(key) != null) {
235 // key already exists
236 throw x.syntaxError("Duplicate key \"" + key + "\"");
238 // Only add value if non-null
239 Object value = x.nextValue();
241 this.put(key, value);
245 // Pairs are separated by ','.
247 switch (x.nextClean()) {
250 if (x.nextClean() == '}') {
258 throw x.syntaxError("Expected a ',' or '}'");
264 * Construct a JSONObject from a Map.
266 * @param m A map object that can be used to initialize the contents of the
268 * @throws JSONException If a value in the map is non-finite number.
269 * @throws NullPointerException If a key in the map is <code>null</code>
271 public JSONObject(Map<?, ?> m) {
273 this.map = new HashMap<String, Object>();
275 this.map = new HashMap<String, Object>(m.size());
276 for (final Entry<?, ?> e : m.entrySet()) {
277 if (e.getKey() == null) {
278 throw new NullPointerException("Null key.");
280 final Object value = e.getValue();
282 this.map.put(String.valueOf(e.getKey()), wrap(value));
289 * Construct a JSONObject from an Object using bean getters. It reflects on all
290 * of the public methods of the object. For each of the methods with no
291 * parameters and a name starting with <code>"get"</code> or <code>"is"</code>
292 * followed by an uppercase letter, the method is invoked, and a key and the
293 * value returned from the getter method are put into the new JSONObject.
295 * The key is formed by removing the <code>"get"</code> or <code>"is"</code>
296 * prefix. If the second remaining character is not upper case, then the first
297 * character is converted to lower case.
299 * Methods that are <code>static</code>, return <code>void</code>, have
300 * parameters, or are "bridge" methods, are ignored.
302 * For example, if an object has a method named <code>"getName"</code>, and if
303 * the result of calling <code>object.getName()</code> is
304 * <code>"Larry Fine"</code>, then the JSONObject will contain
305 * <code>"name": "Larry Fine"</code>.
307 * The {@link JSONPropertyName} annotation can be used on a bean getter to
308 * override key name used in the JSONObject. For example, using the object above
309 * with the <code>getName</code> method, if we annotated it with:
312 * @JSONPropertyName("FullName")
313 * public String getName() {
318 * The resulting JSON object would contain <code>"FullName": "Larry Fine"</code>
320 * Similarly, the {@link JSONPropertyName} annotation can be used on non-
321 * <code>get</code> and <code>is</code> methods. We can also override key name
322 * used in the JSONObject as seen below even though the field would normally be
326 * @JSONPropertyName("FullName")
327 * public String fullName() {
332 * The resulting JSON object would contain <code>"FullName": "Larry Fine"</code>
334 * The {@link JSONPropertyIgnore} annotation can be used to force the bean
335 * property to not be serialized into JSON. If both {@link JSONPropertyIgnore}
336 * and {@link JSONPropertyName} are defined on the same method, a depth
337 * comparison is performed and the one closest to the concrete class being
338 * serialized is used. If both annotations are at the same level, then the
339 * {@link JSONPropertyIgnore} annotation takes precedent and the field is not
340 * serialized. For example, the following declaration would prevent the
341 * <code>getName</code> method from being serialized:
344 * @JSONPropertyName("FullName")
345 * @JSONPropertyIgnore
346 * public String getName() {
352 * @param bean An object that has getter methods that should be used to make a
355 public JSONObject(Object bean) {
357 this.populateMap(bean);
361 * Construct a JSONObject from an Object, using reflection to find the public
362 * members. The resulting JSONObject's keys will be the strings from the names
363 * array, and the values will be the field values associated with those keys in
364 * the object. If a key is not found or not visible, then it will not be copied
365 * into the new JSONObject.
367 * @param object An object that has fields that should be used to make a
369 * @param names An array of strings, the names of the fields to be obtained
372 public JSONObject(Object object, String names[]) {
374 Class<?> c = object.getClass();
375 for (int i = 0; i < names.length; i += 1) {
376 String name = names[i];
378 this.putOpt(name, c.getField(name).get(object));
379 } catch (Exception ignore) {
385 * Construct a JSONObject from a source JSON text string. This is the most
386 * commonly used JSONObject constructor.
388 * @param source A string beginning with <code>{</code> <small>(left
389 * brace)</small> and ending with <code>}</code>
390 * <small>(right brace)</small>.
391 * @exception JSONException If there is a syntax error in the source string or a
394 public JSONObject(String source) throws JSONException {
395 this(new JSONTokener(source));
399 * Construct a JSONObject from a ResourceBundle.
401 * @param baseName The ResourceBundle base name.
402 * @param locale The Locale to load the ResourceBundle for.
403 * @throws JSONException If any JSONExceptions are detected.
405 public JSONObject(String baseName, Locale locale) throws JSONException {
407 ResourceBundle bundle = ResourceBundle.getBundle(baseName, locale,
408 Thread.currentThread().getContextClassLoader());
410 // Iterate through the keys in the bundle.
412 Enumeration<String> keys = bundle.getKeys();
413 while (keys.hasMoreElements()) {
414 Object key = keys.nextElement();
417 // Go through the path, ensuring that there is a nested JSONObject for each
418 // segment except the last. Add the value using the last segment's name into
419 // the deepest nested JSONObject.
421 String[] path = ((String) key).split("\\.");
422 int last = path.length - 1;
423 JSONObject target = this;
424 for (int i = 0; i < last; i += 1) {
425 String segment = path[i];
426 JSONObject nextTarget = target.optJSONObject(segment);
427 if (nextTarget == null) {
428 nextTarget = new JSONObject();
429 target.put(segment, nextTarget);
433 target.put(path[last], bundle.getString((String) key));
439 * Constructor to specify an initial capacity of the internal map. Useful for
440 * library internal calls where we know, or at least can best guess, how big
441 * this JSONObject will be.
443 * @param initialCapacity initial capacity of the internal map.
445 protected JSONObject(int initialCapacity) {
446 this.map = new HashMap<String, Object>(initialCapacity);
450 * Accumulate values under a key. It is similar to the put method except that if
451 * there is already an object stored under the key then a JSONArray is stored
452 * under the key to hold all of the accumulated values. If there is already a
453 * JSONArray, then the new value is appended to it. In contrast, the put method
454 * replaces the previous value.
456 * If only one value is accumulated that is not a JSONArray, then the result
457 * will be the same as using put. But if multiple values are accumulated, then
458 * the result will be like append.
460 * @param key A key string.
461 * @param value An object to be accumulated under the key.
463 * @throws JSONException If the value is non-finite number.
464 * @throws NullPointerException If the key is <code>null</code>.
466 public JSONObject accumulate(String key, Object value) throws JSONException {
468 Object object = this.opt(key);
469 if (object == null) {
470 this.put(key, value instanceof JSONArray ? new JSONArray().put(value) : value);
471 } else if (object instanceof JSONArray) {
472 ((JSONArray) object).put(value);
474 this.put(key, new JSONArray().put(object).put(value));
480 * Append values to the array under a key. If the key does not exist in the
481 * JSONObject, then the key is put in the JSONObject with its value being a
482 * JSONArray containing the value parameter. If the key was already associated
483 * with a JSONArray, then the value parameter is appended to it.
485 * @param key A key string.
486 * @param value An object to be accumulated under the key.
488 * @throws JSONException If the value is non-finite number or if the
489 * current value associated with the key is not a
491 * @throws NullPointerException If the key is <code>null</code>.
493 public JSONObject append(String key, Object value) throws JSONException {
495 Object object = this.opt(key);
496 if (object == null) {
497 this.put(key, new JSONArray().put(value));
498 } else if (object instanceof JSONArray) {
499 this.put(key, ((JSONArray) object).put(value));
501 throw new JSONException("JSONObject[" + key + "] is not a JSONArray.");
507 * Produce a string from a double. The string "null" will be returned if the
508 * number is not finite.
513 public static String doubleToString(double d) {
514 if (Double.isInfinite(d) || Double.isNaN(d)) {
518 // Shave off trailing zeros and decimal point, if possible.
520 String string = Double.toString(d);
521 if (string.indexOf('.') > 0 && string.indexOf('e') < 0 && string.indexOf('E') < 0) {
522 while (string.endsWith("0")) {
523 string = string.substring(0, string.length() - 1);
525 if (string.endsWith(".")) {
526 string = string.substring(0, string.length() - 1);
533 * Get the value object associated with a key.
535 * @param key A key string.
536 * @return The object associated with the key.
537 * @throws JSONException if the key is not found.
539 public Object get(String key) throws JSONException {
541 throw new JSONException("Null key.");
543 Object object = this.opt(key);
544 if (object == null) {
545 throw new JSONException("JSONObject[" + quote(key) + "] not found.");
551 * Get the enum value associated with a key.
553 * @param clazz The type of enum to retrieve.
554 * @param key A key string.
555 * @return The enum value associated with the key
556 * @throws JSONException if the key is not found or if the value cannot be
557 * converted to an enum.
559 public <E extends Enum<E>> E getEnum(Class<E> clazz, String key) throws JSONException {
560 E val = optEnum(clazz, key);
562 // JSONException should really take a throwable argument.
563 // If it did, I would re-implement this with the Enum.valueOf
564 // method and place any thrown exception in the JSONException
565 throw new JSONException(
566 "JSONObject[" + quote(key) + "] is not an enum of type " + quote(clazz.getSimpleName()) + ".");
572 * Get the boolean value associated with a key.
574 * @param key A key string.
576 * @throws JSONException if the value is not a Boolean or the String "true" or
579 public boolean getBoolean(String key) throws JSONException {
580 Object object = this.get(key);
581 if (object.equals(Boolean.FALSE) || (object instanceof String && ((String) object).equalsIgnoreCase("false"))) {
583 } else if (object.equals(Boolean.TRUE)
584 || (object instanceof String && ((String) object).equalsIgnoreCase("true"))) {
587 throw new JSONException("JSONObject[" + quote(key) + "] is not a Boolean.");
591 * Get the BigInteger value associated with a key.
593 * @param key A key string.
594 * @return The numeric value.
595 * @throws JSONException if the key is not found or if the value cannot be
596 * converted to BigInteger.
598 public BigInteger getBigInteger(String key) throws JSONException {
599 Object object = this.get(key);
601 return new BigInteger(object.toString());
602 } catch (Exception e) {
603 throw new JSONException("JSONObject[" + quote(key) + "] could not be converted to BigInteger.", e);
608 * Get the BigDecimal value associated with a key.
610 * @param key A key string.
611 * @return The numeric value.
612 * @throws JSONException if the key is not found or if the value cannot be
613 * converted to BigDecimal.
615 public BigDecimal getBigDecimal(String key) throws JSONException {
616 Object object = this.get(key);
617 if (object instanceof BigDecimal) {
618 return (BigDecimal) object;
621 return new BigDecimal(object.toString());
622 } catch (Exception e) {
623 throw new JSONException("JSONObject[" + quote(key) + "] could not be converted to BigDecimal.", e);
628 * Get the double value associated with a key.
630 * @param key A key string.
631 * @return The numeric value.
632 * @throws JSONException if the key is not found or if the value is not a Number
633 * object and cannot be converted to a number.
635 public double getDouble(String key) throws JSONException {
636 Object object = this.get(key);
638 return object instanceof Number ? ((Number) object).doubleValue() : Double.parseDouble(object.toString());
639 } catch (Exception e) {
640 throw new JSONException("JSONObject[" + quote(key) + "] is not a number.", e);
645 * Get the float value associated with a key.
647 * @param key A key string.
648 * @return The numeric value.
649 * @throws JSONException if the key is not found or if the value is not a Number
650 * object and cannot be converted to a number.
652 public float getFloat(String key) throws JSONException {
653 Object object = this.get(key);
655 return object instanceof Number ? ((Number) object).floatValue() : Float.parseFloat(object.toString());
656 } catch (Exception e) {
657 throw new JSONException("JSONObject[" + quote(key) + "] is not a number.", e);
662 * Get the Number value associated with a key.
664 * @param key A key string.
665 * @return The numeric value.
666 * @throws JSONException if the key is not found or if the value is not a Number
667 * object and cannot be converted to a number.
669 public Number getNumber(String key) throws JSONException {
670 Object object = this.get(key);
672 if (object instanceof Number) {
673 return (Number) object;
675 return stringToNumber(object.toString());
676 } catch (Exception e) {
677 throw new JSONException("JSONObject[" + quote(key) + "] is not a number.", e);
682 * Get the int value associated with a key.
684 * @param key A key string.
685 * @return The integer value.
686 * @throws JSONException if the key is not found or if the value cannot be
687 * converted to an integer.
689 public int getInt(String key) throws JSONException {
690 Object object = this.get(key);
692 return object instanceof Number ? ((Number) object).intValue() : Integer.parseInt((String) object);
693 } catch (Exception e) {
694 throw new JSONException("JSONObject[" + quote(key) + "] is not an int.", e);
699 * Get the JSONArray value associated with a key.
701 * @param key A key string.
702 * @return A JSONArray which is the value.
703 * @throws JSONException if the key is not found or if the value is not a
706 public JSONArray getJSONArray(String key) throws JSONException {
707 Object object = this.get(key);
708 if (object instanceof JSONArray) {
709 return (JSONArray) object;
711 throw new JSONException("JSONObject[" + quote(key) + "] is not a JSONArray.");
715 * Get the JSONObject value associated with a key.
717 * @param key A key string.
718 * @return A JSONObject which is the value.
719 * @throws JSONException if the key is not found or if the value is not a
722 public JSONObject getJSONObject(String key) throws JSONException {
723 Object object = this.get(key);
724 if (object instanceof JSONObject) {
725 return (JSONObject) object;
727 throw new JSONException("JSONObject[" + quote(key) + "] is not a JSONObject.");
731 * Get the long value associated with a key.
733 * @param key A key string.
734 * @return The long value.
735 * @throws JSONException if the key is not found or if the value cannot be
736 * converted to a long.
738 public long getLong(String key) throws JSONException {
739 Object object = this.get(key);
741 return object instanceof Number ? ((Number) object).longValue() : Long.parseLong((String) object);
742 } catch (Exception e) {
743 throw new JSONException("JSONObject[" + quote(key) + "] is not a long.", e);
748 * Get an array of field names from a JSONObject.
750 * @return An array of field names, or null if there are no names.
752 public static String[] getNames(JSONObject jo) {
756 return jo.keySet().toArray(new String[jo.length()]);
760 * Get an array of field names from an Object.
762 * @return An array of field names, or null if there are no names.
764 public static String[] getNames(Object object) {
765 if (object == null) {
768 Class<?> klass = object.getClass();
769 Field[] fields = klass.getFields();
770 int length = fields.length;
774 String[] names = new String[length];
775 for (int i = 0; i < length; i += 1) {
776 names[i] = fields[i].getName();
782 * Get the string associated with a key.
784 * @param key A key string.
785 * @return A string which is the value.
786 * @throws JSONException if there is no string value for the key.
788 public String getString(String key) throws JSONException {
789 Object object = this.get(key);
790 if (object instanceof String) {
791 return (String) object;
793 throw new JSONException("JSONObject[" + quote(key) + "] not a string.");
797 * Determine if the JSONObject contains a specific key.
799 * @param key A key string.
800 * @return true if the key exists in the JSONObject.
802 public boolean has(String key) {
803 return this.map.containsKey(key);
807 * Increment a property of a JSONObject. If there is no such property, create
808 * one with a value of 1. If there is such a property, and if it is an Integer,
809 * Long, Double, or Float, then add one to it.
811 * @param key A key string.
813 * @throws JSONException If there is already a property with this name that is
814 * not an Integer, Long, Double, or Float.
816 public JSONObject increment(String key) throws JSONException {
817 Object value = this.opt(key);
820 } else if (value instanceof BigInteger) {
821 this.put(key, ((BigInteger) value).add(BigInteger.ONE));
822 } else if (value instanceof BigDecimal) {
823 this.put(key, ((BigDecimal) value).add(BigDecimal.ONE));
824 } else if (value instanceof Integer) {
825 this.put(key, ((Integer) value).intValue() + 1);
826 } else if (value instanceof Long) {
827 this.put(key, ((Long) value).longValue() + 1L);
828 } else if (value instanceof Double) {
829 this.put(key, ((Double) value).doubleValue() + 1.0d);
830 } else if (value instanceof Float) {
831 this.put(key, ((Float) value).floatValue() + 1.0f);
833 throw new JSONException("Unable to increment [" + quote(key) + "].");
839 * Determine if the value associated with the key is <code>null</code> or if
842 * @param key A key string.
843 * @return true if there is no value associated with the key or if the value is
844 * the JSONObject.NULL object.
846 public boolean isNull(String key) {
847 return JSONObject.NULL.equals(this.opt(key));
851 * Get an enumeration of the keys of the JSONObject. Modifying this key Set will
852 * also modify the JSONObject. Use with caution.
854 * @see Set#iterator()
856 * @return An iterator of the keys.
858 public Iterator<String> keys() {
859 return this.keySet().iterator();
863 * Get a set of keys of the JSONObject. Modifying this key Set will also modify
864 * the JSONObject. Use with caution.
870 public Set<String> keySet() {
871 return this.map.keySet();
875 * Get a set of entries of the JSONObject. These are raw values and may not
876 * match what is returned by the JSONObject get* and opt* functions. Modifying
877 * the returned EntrySet or the Entry objects contained therein will modify the
878 * backing JSONObject. This does not return a clone or a read-only view.
882 * @see Map#entrySet()
884 * @return An Entry Set
886 protected Set<Entry<String, Object>> entrySet() {
887 return this.map.entrySet();
891 * Get the number of keys stored in the JSONObject.
893 * @return The number of keys in the JSONObject.
895 public int length() {
896 return this.map.size();
900 * Check if JSONObject is empty.
902 * @return true if JSONObject is empty, otherwise false.
904 public boolean isEmpty() {
905 return map.isEmpty();
909 * Produce a JSONArray containing the names of the elements of this JSONObject.
911 * @return A JSONArray containing the key strings, or null if the JSONObject is
914 public JSONArray names() {
915 if (this.map.isEmpty()) {
918 return new JSONArray(this.map.keySet());
922 * Produce a string from a Number.
924 * @param number A Number
926 * @throws JSONException If n is a non-finite number.
928 public static String numberToString(Number number) throws JSONException {
929 if (number == null) {
930 throw new JSONException("Null pointer");
932 testValidity(number);
934 // Shave off trailing zeros and decimal point, if possible.
936 String string = number.toString();
937 if (string.indexOf('.') > 0 && string.indexOf('e') < 0 && string.indexOf('E') < 0) {
938 while (string.endsWith("0")) {
939 string = string.substring(0, string.length() - 1);
941 if (string.endsWith(".")) {
942 string = string.substring(0, string.length() - 1);
949 * Get an optional value associated with a key.
951 * @param key A key string.
952 * @return An object which is the value, or null if there is no value.
954 public Object opt(String key) {
955 return key == null ? null : this.map.get(key);
959 * Get the enum value associated with a key.
961 * @param clazz The type of enum to retrieve.
962 * @param key A key string.
963 * @return The enum value associated with the key or null if not found
965 public <E extends Enum<E>> E optEnum(Class<E> clazz, String key) {
966 return this.optEnum(clazz, key, null);
970 * Get the enum value associated with a key.
972 * @param clazz The type of enum to retrieve.
973 * @param key A key string.
974 * @param defaultValue The default in case the value is not found
975 * @return The enum value associated with the key or defaultValue if the value
976 * is not found or cannot be assigned to <code>clazz</code>
978 public <E extends Enum<E>> E optEnum(Class<E> clazz, String key, E defaultValue) {
980 Object val = this.opt(key);
981 if (NULL.equals(val)) {
984 if (clazz.isAssignableFrom(val.getClass())) {
985 // we just checked it!
986 @SuppressWarnings("unchecked")
990 return Enum.valueOf(clazz, val.toString());
991 } catch (IllegalArgumentException e) {
993 } catch (NullPointerException e) {
999 * Get an optional boolean associated with a key. It returns false if there is
1000 * no such key, or if the value is not Boolean.TRUE or the String "true".
1002 * @param key A key string.
1003 * @return The truth.
1005 public boolean optBoolean(String key) {
1006 return this.optBoolean(key, false);
1010 * Get an optional boolean associated with a key. It returns the defaultValue if
1011 * there is no such key, or if it is not a Boolean or the String "true" or
1012 * "false" (case insensitive).
1014 * @param key A key string.
1015 * @param defaultValue The default.
1016 * @return The truth.
1018 public boolean optBoolean(String key, boolean defaultValue) {
1019 Object val = this.opt(key);
1020 if (NULL.equals(val)) {
1021 return defaultValue;
1023 if (val instanceof Boolean) {
1024 return ((Boolean) val).booleanValue();
1027 // we'll use the get anyway because it does string conversion.
1028 return this.getBoolean(key);
1029 } catch (Exception e) {
1030 return defaultValue;
1035 * Get an optional BigDecimal associated with a key, or the defaultValue if
1036 * there is no such key or if its value is not a number. If the value is a
1037 * string, an attempt will be made to evaluate it as a number.
1039 * @param key A key string.
1040 * @param defaultValue The default.
1041 * @return An object which is the value.
1043 public BigDecimal optBigDecimal(String key, BigDecimal defaultValue) {
1044 Object val = this.opt(key);
1045 if (NULL.equals(val)) {
1046 return defaultValue;
1048 if (val instanceof BigDecimal) {
1049 return (BigDecimal) val;
1051 if (val instanceof BigInteger) {
1052 return new BigDecimal((BigInteger) val);
1054 if (val instanceof Double || val instanceof Float) {
1055 return new BigDecimal(((Number) val).doubleValue());
1057 if (val instanceof Long || val instanceof Integer || val instanceof Short || val instanceof Byte) {
1058 return new BigDecimal(((Number) val).longValue());
1060 // don't check if it's a string in case of unchecked Number subclasses
1062 return new BigDecimal(val.toString());
1063 } catch (Exception e) {
1064 return defaultValue;
1069 * Get an optional BigInteger associated with a key, or the defaultValue if
1070 * there is no such key or if its value is not a number. If the value is a
1071 * string, an attempt will be made to evaluate it as a number.
1073 * @param key A key string.
1074 * @param defaultValue The default.
1075 * @return An object which is the value.
1077 public BigInteger optBigInteger(String key, BigInteger defaultValue) {
1078 Object val = this.opt(key);
1079 if (NULL.equals(val)) {
1080 return defaultValue;
1082 if (val instanceof BigInteger) {
1083 return (BigInteger) val;
1085 if (val instanceof BigDecimal) {
1086 return ((BigDecimal) val).toBigInteger();
1088 if (val instanceof Double || val instanceof Float) {
1089 return new BigDecimal(((Number) val).doubleValue()).toBigInteger();
1091 if (val instanceof Long || val instanceof Integer || val instanceof Short || val instanceof Byte) {
1092 return BigInteger.valueOf(((Number) val).longValue());
1094 // don't check if it's a string in case of unchecked Number subclasses
1096 // the other opt functions handle implicit conversions, i.e.
1097 // jo.put("double",1.1d);
1098 // jo.optInt("double"); -- will return 1, not an error
1099 // this conversion to BigDecimal then to BigInteger is to maintain
1100 // that type cast support that may truncate the decimal.
1101 final String valStr = val.toString();
1102 if (isDecimalNotation(valStr)) {
1103 return new BigDecimal(valStr).toBigInteger();
1105 return new BigInteger(valStr);
1106 } catch (Exception e) {
1107 return defaultValue;
1112 * Get an optional double associated with a key, or NaN if there is no such key
1113 * or if its value is not a number. If the value is a string, an attempt will be
1114 * made to evaluate it as a number.
1116 * @param key A string which is the key.
1117 * @return An object which is the value.
1119 public double optDouble(String key) {
1120 return this.optDouble(key, Double.NaN);
1124 * Get an optional double associated with a key, or the defaultValue if there is
1125 * no such key or if its value is not a number. If the value is a string, an
1126 * attempt will be made to evaluate it as a number.
1128 * @param key A key string.
1129 * @param defaultValue The default.
1130 * @return An object which is the value.
1132 public double optDouble(String key, double defaultValue) {
1133 Object val = this.opt(key);
1134 if (NULL.equals(val)) {
1135 return defaultValue;
1137 if (val instanceof Number) {
1138 return ((Number) val).doubleValue();
1140 if (val instanceof String) {
1142 return Double.parseDouble((String) val);
1143 } catch (Exception e) {
1144 return defaultValue;
1147 return defaultValue;
1151 * Get the optional double value associated with an index. NaN is returned if
1152 * there is no value for the index, or if the value is not a number and cannot
1153 * be converted to a number.
1155 * @param key A key string.
1156 * @return The value.
1158 public float optFloat(String key) {
1159 return this.optFloat(key, Float.NaN);
1163 * Get the optional double value associated with an index. The defaultValue is
1164 * returned if there is no value for the index, or if the value is not a number
1165 * and cannot be converted to a number.
1167 * @param key A key string.
1168 * @param defaultValue The default value.
1169 * @return The value.
1171 public float optFloat(String key, float defaultValue) {
1172 Object val = this.opt(key);
1173 if (JSONObject.NULL.equals(val)) {
1174 return defaultValue;
1176 if (val instanceof Number) {
1177 return ((Number) val).floatValue();
1179 if (val instanceof String) {
1181 return Float.parseFloat((String) val);
1182 } catch (Exception e) {
1183 return defaultValue;
1186 return defaultValue;
1190 * Get an optional int value associated with a key, or zero if there is no such
1191 * key or if the value is not a number. If the value is a string, an attempt
1192 * will be made to evaluate it as a number.
1194 * @param key A key string.
1195 * @return An object which is the value.
1197 public int optInt(String key) {
1198 return this.optInt(key, 0);
1202 * Get an optional int value associated with a key, or the default if there is
1203 * no such key or if the value is not a number. If the value is a string, an
1204 * attempt will be made to evaluate it as a number.
1206 * @param key A key string.
1207 * @param defaultValue The default.
1208 * @return An object which is the value.
1210 public int optInt(String key, int defaultValue) {
1211 Object val = this.opt(key);
1212 if (NULL.equals(val)) {
1213 return defaultValue;
1215 if (val instanceof Number) {
1216 return ((Number) val).intValue();
1219 if (val instanceof String) {
1221 return new BigDecimal((String) val).intValue();
1222 } catch (Exception e) {
1223 return defaultValue;
1226 return defaultValue;
1230 * Get an optional JSONArray associated with a key. It returns null if there is
1231 * no such key, or if its value is not a JSONArray.
1233 * @param key A key string.
1234 * @return A JSONArray which is the value.
1236 public JSONArray optJSONArray(String key) {
1237 Object o = this.opt(key);
1238 return o instanceof JSONArray ? (JSONArray) o : null;
1242 * Get an optional JSONObject associated with a key. It returns null if there is
1243 * no such key, or if its value is not a JSONObject.
1245 * @param key A key string.
1246 * @return A JSONObject which is the value.
1248 public JSONObject optJSONObject(String key) {
1249 Object object = this.opt(key);
1250 return object instanceof JSONObject ? (JSONObject) object : null;
1254 * Get an optional long value associated with a key, or zero if there is no such
1255 * key or if the value is not a number. If the value is a string, an attempt
1256 * will be made to evaluate it as a number.
1258 * @param key A key string.
1259 * @return An object which is the value.
1261 public long optLong(String key) {
1262 return this.optLong(key, 0);
1266 * Get an optional long value associated with a key, or the default if there is
1267 * no such key or if the value is not a number. If the value is a string, an
1268 * attempt will be made to evaluate it as a number.
1270 * @param key A key string.
1271 * @param defaultValue The default.
1272 * @return An object which is the value.
1274 public long optLong(String key, long defaultValue) {
1275 Object val = this.opt(key);
1276 if (NULL.equals(val)) {
1277 return defaultValue;
1279 if (val instanceof Number) {
1280 return ((Number) val).longValue();
1283 if (val instanceof String) {
1285 return new BigDecimal((String) val).longValue();
1286 } catch (Exception e) {
1287 return defaultValue;
1290 return defaultValue;
1294 * Get an optional {@link Number} value associated with a key, or
1295 * <code>null</code> if there is no such key or if the value is not a number. If
1296 * the value is a string, an attempt will be made to evaluate it as a number
1297 * ({@link BigDecimal}). This method would be used in cases where type coercion
1298 * of the number value is unwanted.
1300 * @param key A key string.
1301 * @return An object which is the value.
1303 public Number optNumber(String key) {
1304 return this.optNumber(key, null);
1308 * Get an optional {@link Number} value associated with a key, or the default if
1309 * there is no such key or if the value is not a number. If the value is a
1310 * string, an attempt will be made to evaluate it as a number. This method would
1311 * be used in cases where type coercion of the number value is unwanted.
1313 * @param key A key string.
1314 * @param defaultValue The default.
1315 * @return An object which is the value.
1317 public Number optNumber(String key, Number defaultValue) {
1318 Object val = this.opt(key);
1319 if (NULL.equals(val)) {
1320 return defaultValue;
1322 if (val instanceof Number) {
1323 return (Number) val;
1326 if (val instanceof String) {
1328 return stringToNumber((String) val);
1329 } catch (Exception e) {
1330 return defaultValue;
1333 return defaultValue;
1337 * Get an optional string associated with a key. It returns an empty string if
1338 * there is no such key. If the value is not a string and is not null, then it
1339 * is converted to a string.
1341 * @param key A key string.
1342 * @return A string which is the value.
1344 public String optString(String key) {
1345 return this.optString(key, "");
1349 * Get an optional string associated with a key. It returns the defaultValue if
1350 * there is no such key.
1352 * @param key A key string.
1353 * @param defaultValue The default.
1354 * @return A string which is the value.
1356 public String optString(String key, String defaultValue) {
1357 Object object = this.opt(key);
1358 return NULL.equals(object) ? defaultValue : object.toString();
1362 * Populates the internal map of the JSONObject with the bean properties. The
1363 * bean can not be recursive.
1365 * @see JSONObject#JSONObject(Object)
1367 * @param bean the bean
1369 private void populateMap(Object bean) {
1370 Class<?> klass = bean.getClass();
1372 // If klass is a System class then set includeSuperClass to false.
1374 boolean includeSuperClass = klass.getClassLoader() != null;
1376 Method[] methods = includeSuperClass ? klass.getMethods() : klass.getDeclaredMethods();
1377 for (final Method method : methods) {
1378 final int modifiers = method.getModifiers();
1379 if (Modifier.isPublic(modifiers) && !Modifier.isStatic(modifiers) && method.getParameterTypes().length == 0
1380 && !method.isBridge() && method.getReturnType() != Void.TYPE
1381 && isValidMethodName(method.getName())) {
1382 final String key = getKeyNameFromMethod(method);
1383 if (key != null && !key.isEmpty()) {
1385 final Object result = method.invoke(bean);
1386 if (result != null) {
1387 this.map.put(key, wrap(result));
1388 // we don't use the result anywhere outside of wrap
1389 // if it's a resource we should be sure to close it
1390 // after calling toString
1391 if (result instanceof Closeable) {
1393 ((Closeable) result).close();
1394 } catch (IOException ignore) {
1398 } catch (IllegalAccessException ignore) {
1399 } catch (IllegalArgumentException ignore) {
1400 } catch (InvocationTargetException ignore) {
1407 private boolean isValidMethodName(String name) {
1408 return !"getClass".equals(name) && !"getDeclaringClass".equals(name);
1411 private String getKeyNameFromMethod(Method method) {
1412 final int ignoreDepth = -1;// getAnnotationDepth(method, JSONPropertyIgnore.class);
1413 // if (ignoreDepth > 0) {
1414 // final int forcedNameDepth = getAnnotationDepth(method, JSONPropertyName.class);
1415 // if (forcedNameDepth < 0 || ignoreDepth <= forcedNameDepth) {
1416 // // the hierarchy asked to ignore, and the nearest name override
1417 // // was higher or non-existent
1421 // JSONPropertyName annotation = getAnnotation(method, JSONPropertyName.class);
1422 // if (annotation != null && annotation.value() != null && !annotation.value().isEmpty()) {
1423 // return annotation.value();
1426 final String name = method.getName();
1427 if (name.startsWith("get") && name.length() > 3) {
1428 key = name.substring(3);
1429 } else if (name.startsWith("is") && name.length() > 2) {
1430 key = name.substring(2);
1434 // if the first letter in the key is not uppercase, then skip.
1435 // This is to maintain backwards compatibility before PR406
1436 // (https://github.com/stleary/JSON-java/pull/406/)
1437 if (Character.isLowerCase(key.charAt(0))) {
1440 if (key.length() == 1) {
1441 key = key.toLowerCase(Locale.ROOT);
1442 } else if (!Character.isUpperCase(key.charAt(1))) {
1443 key = key.substring(0, 1).toLowerCase(Locale.ROOT) + key.substring(1);
1445 return (/** @j2sNative 1 ? key.split("$")[0] : */
1450 // * Searches the class hierarchy to see if the method or it's super
1451 // * implementations and interfaces has the annotation.
1454 // * type of the annotation
1457 // * method to check
1458 // * @param annotationClass
1459 // * annotation to look for
1460 // * @return the {@link Annotation} if the annotation exists on the current method
1461 // * or one of it's super class definitions
1463 // private static <A extends Annotation> A getAnnotation(final Method m, final Class<A> annotationClass) {
1465 // // if we have invalid data the result is null
1466 // if (true || m == null || annotationClass == null) {
1470 // if (m.isAnnotationPresent(annotationClass)) {
1471 // return m.getAnnotation(annotationClass);
1474 // // if we've already reached the Object class, return null;
1475 // Class<?> c = m.getDeclaringClass();
1476 // if (c.getSuperclass() == null) {
1480 // // check directly implemented interfaces for the method being checked
1481 // for (Class<?> i : c.getInterfaces()) {
1483 // Method im = i.getMethod(m.getName(), m.getParameterTypes());
1484 // return getAnnotation(im, annotationClass);
1485 // } catch (final SecurityException ex) {
1487 // } catch (final NoSuchMethodException ex) {
1493 // return getAnnotation(
1494 // c.getSuperclass().getMethod(m.getName(), m.getParameterTypes()),
1495 // annotationClass);
1496 // } catch (final SecurityException ex) {
1498 // } catch (final NoSuchMethodException ex) {
1504 // * Searches the class hierarchy to see if the method or it's super
1505 // * implementations and interfaces has the annotation. Returns the depth of the
1506 // * annotation in the hierarchy.
1509 // * type of the annotation
1512 // * method to check
1513 // * @param annotationClass
1514 // * annotation to look for
1515 // * @return Depth of the annotation or -1 if the annotation is not on the method.
1517 // private static int getAnnotationDepth(final Method m, final Class<? extends Annotation> annotationClass) {
1518 // // if we have invalid data the result is -1
1519 // if (m == null || annotationClass == null) {
1522 // if (m.isAnnotationPresent(annotationClass)) {
1526 // // if we've already reached the Object class, return -1;
1527 // Class<?> c = m.getDeclaringClass();
1528 // if (c.getSuperclass() == null) {
1532 // // check directly implemented interfaces for the method being checked
1533 // for (Class<?> i : c.getInterfaces()) {
1535 // Method im = i.getMethod(m.getName(), m.getParameterTypes());
1536 // int d = getAnnotationDepth(im, annotationClass);
1538 // // since the annotation was on the interface, add 1
1541 // } catch (final SecurityException ex) {
1543 // } catch (final NoSuchMethodException ex) {
1549 // int d = getAnnotationDepth(
1550 // c.getSuperclass().getMethod(m.getName(), m.getParameterTypes()),
1551 // annotationClass);
1553 // // since the annotation was on the superclass, add 1
1557 // } catch (final SecurityException ex) {
1559 // } catch (final NoSuchMethodException ex) {
1565 * Put a key/boolean pair in the JSONObject.
1567 * @param key A key string.
1568 * @param value A boolean which is the value.
1570 * @throws JSONException If the value is non-finite number.
1571 * @throws NullPointerException If the key is <code>null</code>.
1573 public JSONObject put(String key, boolean value) throws JSONException {
1574 return this.put(key, value ? Boolean.TRUE : Boolean.FALSE);
1578 * Put a key/value pair in the JSONObject, where the value will be a JSONArray
1579 * which is produced from a Collection.
1581 * @param key A key string.
1582 * @param value A Collection value.
1584 * @throws JSONException If the value is non-finite number.
1585 * @throws NullPointerException If the key is <code>null</code>.
1587 public JSONObject put(String key, Collection<?> value) throws JSONException {
1588 return this.put(key, new JSONArray(value));
1592 * Put a key/double pair in the JSONObject.
1594 * @param key A key string.
1595 * @param value A double which is the value.
1597 * @throws JSONException If the value is non-finite number.
1598 * @throws NullPointerException If the key is <code>null</code>.
1600 public JSONObject put(String key, double value) throws JSONException {
1601 return this.put(key, Double.valueOf(value));
1605 * Put a key/float pair in the JSONObject.
1607 * @param key A key string.
1608 * @param value A float which is the value.
1610 * @throws JSONException If the value is non-finite number.
1611 * @throws NullPointerException If the key is <code>null</code>.
1613 public JSONObject put(String key, float value) throws JSONException {
1614 return this.put(key, Float.valueOf(value));
1618 * Put a key/int pair in the JSONObject.
1620 * @param key A key string.
1621 * @param value An int which is the value.
1623 * @throws JSONException If the value is non-finite number.
1624 * @throws NullPointerException If the key is <code>null</code>.
1626 public JSONObject put(String key, int value) throws JSONException {
1627 return this.put(key, Integer.valueOf(value));
1631 * Put a key/long pair in the JSONObject.
1633 * @param key A key string.
1634 * @param value A long which is the value.
1636 * @throws JSONException If the value is non-finite number.
1637 * @throws NullPointerException If the key is <code>null</code>.
1639 public JSONObject put(String key, long value) throws JSONException {
1640 return this.put(key, Long.valueOf(value));
1644 * Put a key/value pair in the JSONObject, where the value will be a JSONObject
1645 * which is produced from a Map.
1647 * @param key A key string.
1648 * @param value A Map value.
1650 * @throws JSONException If the value is non-finite number.
1651 * @throws NullPointerException If the key is <code>null</code>.
1653 public JSONObject put(String key, Map<?, ?> value) throws JSONException {
1654 return this.put(key, new JSONObject(value));
1658 * Put a key/value pair in the JSONObject. If the value is <code>null</code>,
1659 * then the key will be removed from the JSONObject if it is present.
1661 * @param key A key string.
1662 * @param value An object which is the value. It should be of one of these
1663 * types: Boolean, Double, Integer, JSONArray, JSONObject, Long,
1664 * String, or the JSONObject.NULL object.
1666 * @throws JSONException If the value is non-finite number.
1667 * @throws NullPointerException If the key is <code>null</code>.
1669 public JSONObject put(String key, Object value) throws JSONException {
1671 throw new NullPointerException("Null key.");
1673 if (value != null) {
1674 testValidity(value);
1675 this.map.put(key, value);
1683 * Put a key/value pair in the JSONObject, but only if the key and the value are
1684 * both non-null, and only if there is not already a member with that name.
1687 * @param value object
1689 * @throws JSONException if the key is a duplicate
1691 public JSONObject putOnce(String key, Object value) throws JSONException {
1692 if (key != null && value != null) {
1693 if (this.opt(key) != null) {
1694 throw new JSONException("Duplicate key \"" + key + "\"");
1696 return this.put(key, value);
1702 * Put a key/value pair in the JSONObject, but only if the key and the value are
1705 * @param key A key string.
1706 * @param value An object which is the value. It should be of one of these
1707 * types: Boolean, Double, Integer, JSONArray, JSONObject, Long,
1708 * String, or the JSONObject.NULL object.
1710 * @throws JSONException If the value is a non-finite number.
1712 public JSONObject putOpt(String key, Object value) throws JSONException {
1713 if (key != null && value != null) {
1714 return this.put(key, value);
1720 * Creates a JSONPointer using an initialization string and tries to match it to
1721 * an item within this JSONObject. For example, given a JSONObject initialized
1722 * with this document:
1730 * and this JSONPointer string:
1736 * Then this method will return the String "c". A JSONPointerException may be
1737 * thrown from code called by this method.
1739 * @param jsonPointer string that can be used to create a JSONPointer
1740 * @return the item matched by the JSONPointer, otherwise null
1742 public Object query(String jsonPointer) {
1743 return query(new JSONPointer(jsonPointer));
1747 * Uses a user initialized JSONPointer and tries to match it to an item within
1748 * this JSONObject. For example, given a JSONObject initialized with this
1757 * and this JSONPointer:
1763 * Then this method will return the String "c". A JSONPointerException may be
1764 * thrown from code called by this method.
1766 * @param jsonPointer string that can be used to create a JSONPointer
1767 * @return the item matched by the JSONPointer, otherwise null
1769 public Object query(JSONPointer jsonPointer) {
1770 return jsonPointer.queryFrom(this);
1774 * Queries and returns a value from this object using {@code jsonPointer}, or
1775 * returns null if the query fails due to a missing key.
1777 * @param jsonPointer the string representation of the JSON pointer
1778 * @return the queried value or {@code null}
1779 * @throws IllegalArgumentException if {@code jsonPointer} has invalid syntax
1781 public Object optQuery(String jsonPointer) {
1782 return optQuery(new JSONPointer(jsonPointer));
1786 * Queries and returns a value from this object using {@code jsonPointer}, or
1787 * returns null if the query fails due to a missing key.
1789 * @param jsonPointer The JSON pointer
1790 * @return the queried value or {@code null}
1791 * @throws IllegalArgumentException if {@code jsonPointer} has invalid syntax
1793 public Object optQuery(JSONPointer jsonPointer) {
1795 return jsonPointer.queryFrom(this);
1796 } catch (JSONPointerException e) {
1802 * Produce a string in double quotes with backslash sequences in all the right
1803 * places. A backslash will be inserted within </, producing <\/, allowing JSON
1804 * text to be delivered in HTML. In JSON text, a string cannot contain a control
1805 * character or an unescaped quote or backslash.
1807 * @param string A String
1808 * @return A String correctly formatted for insertion in a JSON text.
1810 public static String quote(String string) {
1811 StringWriter sw = new StringWriter();
1812 synchronized (sw.getBuffer()) {
1814 return quote(string, sw).toString();
1815 } catch (IOException ignored) {
1816 // will never happen - we are writing to a string writer
1822 public static Writer quote(String string, Writer w) throws IOException {
1823 if (string == null || string.isEmpty()) {
1832 int len = string.length();
1835 for (i = 0; i < len; i += 1) {
1837 c = string.charAt(i);
1866 if (c < ' ' || (c >= '\u0080' && c < '\u00a0') || (c >= '\u2000' && c < '\u2100')) {
1868 hhhh = Integer.toHexString(c);
1869 w.write("0000", 0, 4 - hhhh.length());
1881 * Remove a name and its value, if present.
1883 * @param key The name to be removed.
1884 * @return The value that was associated with the name, or null if there was no
1887 public Object remove(String key) {
1888 return this.map.remove(key);
1892 * Determine if two JSONObjects are similar. They must contain the same set of
1893 * names which must be associated with similar values.
1895 * @param other The other JSONObject
1896 * @return true if they are equal
1898 public boolean similar(Object other) {
1900 if (!(other instanceof JSONObject)) {
1903 if (!this.keySet().equals(((JSONObject) other).keySet())) {
1906 for (final Entry<String, ?> entry : this.entrySet()) {
1907 String name = entry.getKey();
1908 Object valueThis = entry.getValue();
1909 Object valueOther = ((JSONObject) other).get(name);
1910 if (valueThis == valueOther) {
1913 if (valueThis == null) {
1916 if (valueThis instanceof JSONObject) {
1917 if (!((JSONObject) valueThis).similar(valueOther)) {
1920 } else if (valueThis instanceof JSONArray) {
1921 if (!((JSONArray) valueThis).similar(valueOther)) {
1924 } else if (!valueThis.equals(valueOther)) {
1929 } catch (Throwable exception) {
1935 * Tests if the value should be tried as a decimal. It makes no test if there
1936 * are actual digits.
1938 * @param val value to test
1939 * @return true if the string is "-0" or if it contains '.', 'e', or 'E', false
1942 protected static boolean isDecimalNotation(final String val) {
1943 return val.indexOf('.') > -1 || val.indexOf('e') > -1 || val.indexOf('E') > -1 || "-0".equals(val);
1947 * Converts a string to a number using the narrowest possible type. Possible
1948 * returns for this function are BigDecimal, Double, BigInteger, Long, and
1949 * Integer. When a Double is returned, it should always be a valid Double and
1950 * not NaN or +-infinity.
1952 * @param val value to convert
1953 * @return Number representation of the value.
1954 * @throws NumberFormatException thrown if the value is not a valid number. A
1955 * public caller should catch this and wrap it in
1956 * a {@link JSONException} if applicable.
1958 protected static Number stringToNumber(final String val) throws NumberFormatException {
1959 char initial = val.charAt(0);
1960 if ((initial >= '0' && initial <= '9') || initial == '-') {
1961 // decimal representation
1962 if (isDecimalNotation(val)) {
1963 // quick dirty way to see if we need a BigDecimal instead of a Double
1964 // this only handles some cases of overflow or underflow
1965 if (val.length() > 14) {
1966 return new BigDecimal(val);
1968 final Double d = Double.valueOf(val);
1969 if (d.isInfinite() || d.isNaN()) {
1970 // if we can't parse it as a double, go up to BigDecimal
1971 // this is probably due to underflow like 4.32e-678
1972 // or overflow like 4.65e5324. The size of the string is small
1973 // but can't be held in a Double.
1974 return new BigDecimal(val);
1978 // integer representation.
1979 // This will narrow any values to the smallest reasonable Object representation
1980 // (Integer, Long, or BigInteger)
1983 // The compare string length method reduces GC,
1984 // but leads to smaller integers being placed in larger wrappers even though not
1985 // needed. i.e. 1,000,000,000 -> Long even though it's an Integer
1986 // 1,000,000,000,000,000,000 -> BigInteger even though it's a Long
1987 // if(val.length()<=9){
1988 // return Integer.valueOf(val);
1990 // if(val.length()<=18){
1991 // return Long.valueOf(val);
1993 // return new BigInteger(val);
1995 // BigInteger version: We use a similar bitLenth compare as
1996 // BigInteger#intValueExact uses. Increases GC, but objects hold
1997 // only what they need. i.e. Less runtime overhead if the value is
1998 // long lived. Which is the better tradeoff? This is closer to what's
1999 // in stringToValue.
2000 BigInteger bi = new BigInteger(val);
2001 if (bi.bitLength() <= 31) {
2002 return Integer.valueOf(bi.intValue());
2004 if (bi.bitLength() <= 63) {
2005 return Long.valueOf(bi.longValue());
2009 throw new NumberFormatException("val [" + val + "] is not a valid number.");
2013 * Try to convert a string into a number, boolean, or null. If the string can't
2014 * be converted, return the string.
2016 * @param string A String.
2017 * @return A simple JSON value.
2019 // Changes to this method must be copied to the corresponding method in
2020 // the XML class to keep full support for Android
2021 public static Object stringToValue(String string) {
2022 if (string.equals("")) {
2025 if (string.equalsIgnoreCase("true")) {
2026 return Boolean.TRUE;
2028 if (string.equalsIgnoreCase("false")) {
2029 return Boolean.FALSE;
2031 if (string.equalsIgnoreCase("null")) {
2032 return JSONObject.NULL;
2036 * If it might be a number, try converting it. If a number cannot be produced,
2037 * then the value will just be a string.
2040 char initial = string.charAt(0);
2041 if ((initial >= '0' && initial <= '9') || initial == '-') {
2043 // if we want full Big Number support this block can be replaced with:
2044 // return stringToNumber(string);
2045 if (isDecimalNotation(string)) {
2046 Double d = Double.valueOf(string);
2047 if (!d.isInfinite() && !d.isNaN()) {
2051 Long myLong = Long.valueOf(string);
2052 if (string.equals(myLong.toString())) {
2053 if (myLong.longValue() == myLong.intValue()) {
2054 return Integer.valueOf(myLong.intValue());
2059 } catch (Exception ignore) {
2066 * Throw an exception if the object is a NaN or infinite number.
2068 * @param o The object to test.
2069 * @throws JSONException If o is a non-finite number.
2071 public static void testValidity(Object o) throws JSONException {
2073 if (o instanceof Double) {
2074 if (((Double) o).isInfinite() || ((Double) o).isNaN()) {
2075 throw new JSONException("JSON does not allow non-finite numbers.");
2077 } else if (o instanceof Float) {
2078 if (((Float) o).isInfinite() || ((Float) o).isNaN()) {
2079 throw new JSONException("JSON does not allow non-finite numbers.");
2086 * Produce a JSONArray containing the values of the members of this JSONObject.
2088 * @param names A JSONArray containing a list of key strings. This determines
2089 * the sequence of the values in the result.
2090 * @return A JSONArray of values.
2091 * @throws JSONException If any of the values are non-finite numbers.
2093 public JSONArray toJSONArray(JSONArray names) throws JSONException {
2094 if (names == null || names.isEmpty()) {
2097 JSONArray ja = new JSONArray();
2098 for (int i = 0; i < names.length(); i += 1) {
2099 ja.put(this.opt(names.getString(i)));
2105 * Make a JSON text of this JSONObject. For compactness, no whitespace is added.
2106 * If this would not result in a syntactically correct JSON text, then null will
2107 * be returned instead.
2109 * <b> Warning: This method assumes that the data structure is acyclical. </b>
2111 * @return a printable, displayable, portable, transmittable representation of
2112 * the object, beginning with <code>{</code> <small>(left
2113 * brace)</small> and ending with <code>}</code> <small>(right
2117 public String toString() {
2119 return this.toString(0);
2120 } catch (Exception e) {
2126 * Make a pretty-printed JSON text of this JSONObject.
2129 * If <code>indentFactor > 0</code> and the {@link JSONObject} has only one key,
2130 * then the object will be output on a single line:
2133 * {@code {"key": 1}}
2137 * If an object has 2 or more keys, then it will be output across multiple
2138 * lines: <code><pre>{
2140 * "key2": "value 2",
2144 * <b> Warning: This method assumes that the data structure is acyclical. </b>
2146 * @param indentFactor The number of spaces to add to each level of indentation.
2147 * @return a printable, displayable, portable, transmittable representation of
2148 * the object, beginning with <code>{</code> <small>(left
2149 * brace)</small> and ending with <code>}</code> <small>(right
2151 * @throws JSONException If the object contains an invalid number.
2153 public String toString(int indentFactor) throws JSONException {
2154 StringWriter w = new StringWriter();
2155 synchronized (w.getBuffer()) {
2156 return this.write(w, indentFactor, 0).toString();
2161 * Make a JSON text of an Object value. If the object has an
2162 * value.toJSONString() method, then that method will be used to produce the
2163 * JSON text. The method is required to produce a strictly conforming text. If
2164 * the object does not contain a toJSONString method (which is the most common
2165 * case), then a text will be produced by other means. If the value is an array
2166 * or Collection, then a JSONArray will be made from it and its toJSONString
2167 * method will be called. If the value is a MAP, then a JSONObject will be made
2168 * from it and its toJSONString method will be called. Otherwise, the value's
2169 * toString method will be called, and the result will be quoted.
2172 * Warning: This method assumes that the data structure is acyclical.
2174 * @param value The value to be serialized.
2175 * @return a printable, displayable, transmittable representation of the object,
2176 * beginning with <code>{</code> <small>(left brace)</small> and
2177 * ending with <code>}</code> <small>(right brace)</small>.
2178 * @throws JSONException If the value is or contains an invalid number.
2180 public static String valueToString(Object value) throws JSONException {
2181 // moves the implementation to JSONWriter as:
2182 // 1. It makes more sense to be part of the writer class
2183 // 2. For Android support this method is not available. By implementing it in
2185 // Android users can use the writer with the built in Android JSONObject
2187 return JSONWriter.valueToString(value);
2191 * Wrap an object, if necessary. If the object is <code>null</code>, return the
2192 * NULL object. If it is an array or collection, wrap it in a JSONArray. If it
2193 * is a map, wrap it in a JSONObject. If it is a standard property (Double,
2194 * String, et al) then it is already wrapped. Otherwise, if it comes from one of
2195 * the java packages, turn it into a string. And if it doesn't, try to wrap it
2196 * in a JSONObject. If the wrapping fails, then null is returned.
2198 * @param object The object to wrap
2199 * @return The wrapped value
2201 public static Object wrap(Object object) {
2203 if (object == null) {
2206 if (object instanceof JSONObject || object instanceof JSONArray || NULL.equals(object)
2207 || object instanceof JSONString || object instanceof Byte || object instanceof Character
2208 || object instanceof Short || object instanceof Integer || object instanceof Long
2209 || object instanceof Boolean || object instanceof Float || object instanceof Double
2210 || object instanceof String || object instanceof BigInteger || object instanceof BigDecimal
2211 || object instanceof Enum) {
2215 if (object instanceof Collection) {
2216 Collection<?> coll = (Collection<?>) object;
2217 return new JSONArray(coll);
2219 if (object.getClass().isArray()) {
2220 return new JSONArray(object);
2222 if (object instanceof Map) {
2223 Map<?, ?> map = (Map<?, ?>) object;
2224 return new JSONObject(map);
2226 Package objectPackage = object.getClass().getPackage();
2227 String objectPackageName = objectPackage != null ? objectPackage.getName() : "";
2228 if (objectPackageName.startsWith("java.") || objectPackageName.startsWith("javax.")
2229 || object.getClass().getClassLoader() == null) {
2230 return object.toString();
2232 return new JSONObject(object);
2233 } catch (Exception exception) {
2239 * Write the contents of the JSONObject as JSON text to a writer. For
2240 * compactness, no whitespace is added.
2242 * <b> Warning: This method assumes that the data structure is acyclical. </b>
2244 * @return The writer.
2245 * @throws JSONException
2247 public Writer write(Writer writer) throws JSONException {
2248 return this.write(writer, 0, 0);
2251 static final Writer writeValue(Writer writer, Object value, int indentFactor, int indent)
2252 throws JSONException, IOException {
2253 if (value == null || value.equals(null)) {
2254 writer.write("null");
2255 } else if (value instanceof JSONString) {
2258 o = ((JSONString) value).toJSONString();
2259 } catch (Exception e) {
2260 throw new JSONException(e);
2262 writer.write(o != null ? o.toString() : quote(value.toString()));
2263 } else if (value instanceof Number) {
2264 // not all Numbers may match actual JSON Numbers. i.e. fractions or Imaginary
2265 final String numberAsString = numberToString((Number) value);
2267 // Use the BigDecimal constructor for its parser to validate the format.
2268 @SuppressWarnings("unused")
2269 BigDecimal testNum = new BigDecimal(numberAsString);
2270 // Close enough to a JSON number that we will use it unquoted
2271 writer.write(numberAsString);
2272 } catch (NumberFormatException ex) {
2273 // The Number value is not a valid JSON number.
2274 // Instead we will quote it as a string
2275 quote(numberAsString, writer);
2277 } else if (value instanceof Boolean) {
2278 writer.write(value.toString());
2279 } else if (value instanceof Enum<?>) {
2280 writer.write(quote(((Enum<?>) value).name()));
2281 } else if (value instanceof JSONObject) {
2282 ((JSONObject) value).write(writer, indentFactor, indent);
2283 } else if (value instanceof JSONArray) {
2284 ((JSONArray) value).write(writer, indentFactor, indent);
2285 } else if (value instanceof Map) {
2286 Map<?, ?> map = (Map<?, ?>) value;
2287 new JSONObject(map).write(writer, indentFactor, indent);
2288 } else if (value instanceof Collection) {
2289 Collection<?> coll = (Collection<?>) value;
2290 new JSONArray(coll).write(writer, indentFactor, indent);
2291 } else if (value.getClass().isArray()) {
2292 new JSONArray(value).write(writer, indentFactor, indent);
2294 quote(value.toString(), writer);
2299 static final void indent(Writer writer, int indent) throws IOException {
2300 for (int i = 0; i < indent; i += 1) {
2306 * Write the contents of the JSONObject as JSON text to a writer.
2309 * If <code>indentFactor > 0</code> and the {@link JSONObject} has only one key,
2310 * then the object will be output on a single line:
2313 * {@code {"key": 1}}
2317 * If an object has 2 or more keys, then it will be output across multiple
2318 * lines: <code><pre>{
2320 * "key2": "value 2",
2324 * <b> Warning: This method assumes that the data structure is acyclical. </b>
2326 * @param writer Writes the serialized JSON
2327 * @param indentFactor The number of spaces to add to each level of indentation.
2328 * @param indent The indentation of the top level.
2329 * @return The writer.
2330 * @throws JSONException
2332 public Writer write(Writer writer, int indentFactor, int indent) throws JSONException {
2334 boolean commanate = false;
2335 final int length = this.length();
2339 final Entry<String, ?> entry = this.entrySet().iterator().next();
2340 final String key = entry.getKey();
2341 writer.write(quote(key));
2343 if (indentFactor > 0) {
2347 writeValue(writer, entry.getValue(), indentFactor, indent);
2348 } catch (Exception e) {
2349 throw new JSONException("Unable to write JSONObject value for key: " + key, e);
2351 } else if (length != 0) {
2352 final int newindent = indent + indentFactor;
2353 for (final Entry<String, ?> entry : this.entrySet()) {
2357 if (indentFactor > 0) {
2360 indent(writer, newindent);
2361 final String key = entry.getKey();
2362 writer.write(quote(key));
2364 if (indentFactor > 0) {
2368 writeValue(writer, entry.getValue(), indentFactor, newindent);
2369 } catch (Exception e) {
2370 throw new JSONException("Unable to write JSONObject value for key: " + key, e);
2374 if (indentFactor > 0) {
2377 indent(writer, indent);
2381 } catch (IOException exception) {
2382 throw new JSONException(exception);
2387 * Returns a java.util.Map containing all of the entries in this object. If an
2388 * entry in the object is a JSONArray or JSONObject it will also be converted.
2390 * Warning: This method assumes that the data structure is acyclical.
2392 * @return a java.util.Map containing the entries of this object
2394 public Map<String, Object> toMap() {
2395 Map<String, Object> results = new HashMap<String, Object>();
2396 for (Entry<String, Object> entry : this.entrySet()) {
2398 if (entry.getValue() == null || NULL.equals(entry.getValue())) {
2400 } else if (entry.getValue() instanceof JSONObject) {
2401 value = ((JSONObject) entry.getValue()).toMap();
2402 } else if (entry.getValue() instanceof JSONArray) {
2403 value = ((JSONArray) entry.getValue()).toList();
2405 value = entry.getValue();
2407 results.put(entry.getKey(), value);