3 import java.io.Closeable;
6 Copyright (c) 2002 JSON.org
8 Permission is hereby granted, free of charge, to any person obtaining a copy
9 of this software and associated documentation files (the "Software"), to deal
10 in the Software without restriction, including without limitation the rights
11 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 copies of the Software, and to permit persons to whom the Software is
13 furnished to do so, subject to the following conditions:
15 The above copyright notice and this permission notice shall be included in all
16 copies or substantial portions of the Software.
18 The Software shall be used for Good, not Evil.
20 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
29 import java.io.IOException;
30 import java.io.StringWriter;
31 import java.io.Writer;
32 import java.lang.annotation.Annotation;
33 import java.lang.reflect.Field;
34 import java.lang.reflect.InvocationTargetException;
35 import java.lang.reflect.Method;
36 import java.lang.reflect.Modifier;
37 import java.math.BigDecimal;
38 import java.math.BigInteger;
39 import java.util.Collection;
40 import java.util.Enumeration;
41 import java.util.HashMap;
42 import java.util.Iterator;
43 import java.util.Locale;
45 import java.util.Map.Entry;
46 import java.util.ResourceBundle;
50 * A JSONObject is an unordered collection of name/value pairs. Its external
51 * form is a string wrapped in curly braces with colons between the names and
52 * values, and commas between the values and names. The internal form is an
53 * object having <code>get</code> and <code>opt</code> methods for accessing
54 * the values by name, and <code>put</code> methods for adding or replacing
55 * values by name. The values can be any of these types: <code>Boolean</code>,
56 * <code>JSONArray</code>, <code>JSONObject</code>, <code>Number</code>,
57 * <code>String</code>, or the <code>JSONObject.NULL</code> object. A
58 * JSONObject constructor can be used to convert an external form JSON text
59 * into an internal form whose values can be retrieved with the
60 * <code>get</code> and <code>opt</code> methods, or to convert values into a
61 * JSON text using the <code>put</code> and <code>toString</code> methods. A
62 * <code>get</code> method returns a value if one can be found, and throws an
63 * exception if one cannot be found. An <code>opt</code> method returns a
64 * default value instead of throwing an exception, and so is useful for
65 * obtaining optional values.
67 * The generic <code>get()</code> and <code>opt()</code> methods return an
68 * object, which you can cast or query for type. There are also typed
69 * <code>get</code> and <code>opt</code> methods that do type checking and type
70 * coercion for you. The opt methods differ from the get methods in that they
71 * do not throw. Instead, they return a specified value, such as null.
73 * The <code>put</code> methods add or replace values in an object. For
77 * myString = new JSONObject()
78 * .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
92 * quote or single quote, and if they do not contain leading or trailing
93 * spaces, and if they do not contain any of these characters:
94 * <code>{ } [ ] / \ : , #</code> and if they do not look like numbers and
95 * if they are not the reserved words <code>true</code>, <code>false</code>,
96 * or <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,
105 * whilst Java's null is equivalent to the value that JavaScript calls
108 private static final class Null {
111 * There is only intended to be a single instance of the NULL object,
112 * so the clone method returns itself.
117 protected final Object clone() {
122 * A Null object is equal to the null value and to itself.
125 * An object to test for nullness.
126 * @return true if the object parameter is the JSONObject.NULL object or
130 public boolean equals(Object object) {
131 return object == null || object == this;
134 * A Null object is equal to the null value and to itself.
136 * @return always returns 0.
139 public int hashCode() {
144 * Get the "null" string value.
146 * @return The string "null".
149 public String toString() {
155 * The map where the JSONObject's properties are kept.
157 private final Map<String, Object> map;
160 * It is sometimes more convenient and less ambiguous to have a
161 * <code>NULL</code> object than to use Java's <code>null</code> value.
162 * <code>JSONObject.NULL.equals(null)</code> returns <code>true</code>.
163 * <code>JSONObject.NULL.toString()</code> returns <code>"null"</code>.
165 public static final Object NULL = new Null();
168 * Construct an empty JSONObject.
170 public JSONObject() {
171 // HashMap is used on purpose to ensure that elements are unordered by
172 // the specification.
173 // JSON tends to be a portable transfer format to allows the container
174 // implementations to rearrange their items for a faster element
175 // retrieval based on associative access.
176 // Therefore, an implementation mustn't rely on the order of the item.
177 this.map = new HashMap<String, Object>();
181 * Construct a JSONObject from a subset of another JSONObject. An array of
182 * strings is used to identify the keys that should be copied. Missing keys
188 * An array of strings.
190 public JSONObject(JSONObject jo, String[] names) {
192 for (int i = 0; i < names.length; i += 1) {
194 this.putOnce(names[i], jo.opt(names[i]));
195 } catch (Exception ignore) {
201 * Construct a JSONObject from a JSONTokener.
204 * A JSONTokener object containing the source string.
205 * @throws JSONException
206 * If there is a syntax error in the source string or a
209 public JSONObject(JSONTokener x) throws JSONException {
214 if (x.nextClean() != '{') {
215 throw x.syntaxError("A JSONObject text must begin with '{'");
221 throw x.syntaxError("A JSONObject text must end with '}'");
226 key = x.nextValue().toString();
229 // The key is followed by ':'.
233 throw x.syntaxError("Expected a ':' after a key");
236 // Use syntaxError(..) to include error location
239 // Check if key exists
240 if (this.opt(key) != null) {
241 // key already exists
242 throw x.syntaxError("Duplicate key \"" + key + "\"");
244 // Only add value if non-null
245 Object value = x.nextValue();
247 this.put(key, value);
251 // Pairs are separated by ','.
253 switch (x.nextClean()) {
256 if (x.nextClean() == '}') {
264 throw x.syntaxError("Expected a ',' or '}'");
270 * Construct a JSONObject from a Map.
273 * A map object that can be used to initialize the contents of
275 * @throws JSONException
276 * If a value in the map is non-finite number.
277 * @throws NullPointerException
278 * If a key in the map is <code>null</code>
280 public JSONObject(Map<?, ?> m) {
282 this.map = new HashMap<String, Object>();
284 this.map = new HashMap<String, Object>(m.size());
285 for (final Entry<?, ?> e : m.entrySet()) {
286 if(e.getKey() == null) {
287 throw new NullPointerException("Null key.");
289 final Object value = e.getValue();
291 this.map.put(String.valueOf(e.getKey()), wrap(value));
298 * Construct a JSONObject from an Object using bean getters. It reflects on
299 * all of the public methods of the object. For each of the methods with no
300 * parameters and a name starting with <code>"get"</code> or
301 * <code>"is"</code> followed by an uppercase letter, the method is invoked,
302 * and a key and the value returned from the getter method are put into the
305 * The key is formed by removing the <code>"get"</code> or <code>"is"</code>
306 * prefix. If the second remaining character is not upper case, then the
307 * first character is converted to lower case.
309 * Methods that are <code>static</code>, return <code>void</code>,
310 * have parameters, or are "bridge" methods, are ignored.
312 * For example, if an object has a method named <code>"getName"</code>, and
313 * if the result of calling <code>object.getName()</code> is
314 * <code>"Larry Fine"</code>, then the JSONObject will contain
315 * <code>"name": "Larry Fine"</code>.
317 * The {@link JSONPropertyName} annotation can be used on a bean getter to
318 * override key name used in the JSONObject. For example, using the object
319 * above with the <code>getName</code> method, if we annotated it with:
321 * @JSONPropertyName("FullName")
322 * public String getName() { return this.name; }
324 * The resulting JSON object would contain <code>"FullName": "Larry Fine"</code>
326 * Similarly, the {@link JSONPropertyName} annotation can be used on non-
327 * <code>get</code> and <code>is</code> methods. We can also override key
328 * name used in the JSONObject as seen below even though the field would normally
331 * @JSONPropertyName("FullName")
332 * public String fullName() { return this.name; }
334 * The resulting JSON object would contain <code>"FullName": "Larry Fine"</code>
336 * The {@link JSONPropertyIgnore} annotation can be used to force the bean property
337 * to not be serialized into JSON. If both {@link JSONPropertyIgnore} and
338 * {@link JSONPropertyName} are defined on the same method, a depth comparison is
339 * performed and the one closest to the concrete class being serialized is used.
340 * If both annotations are at the same level, then the {@link JSONPropertyIgnore}
341 * annotation takes precedent and the field is not serialized.
342 * For example, the following declaration would prevent the <code>getName</code>
343 * method from being serialized:
345 * @JSONPropertyName("FullName")
346 * @JSONPropertyIgnore
347 * public String getName() { return this.name; }
352 * An object that has getter methods that should be used to make
355 public JSONObject(Object bean) {
357 this.populateMap(bean);
361 * Construct a JSONObject from an Object, using reflection to find the
362 * public members. The resulting JSONObject's keys will be the strings from
363 * the names array, and the values will be the field values associated with
364 * those keys in the object. If a key is not found or not visible, then it
365 * will not be copied into the new JSONObject.
368 * An object that has fields that should be used to make a
371 * An array of strings, the names of the fields to be obtained
374 public JSONObject(Object object, String names[]) {
376 Class<?> c = object.getClass();
377 for (int i = 0; i < names.length; i += 1) {
378 String name = names[i];
380 this.putOpt(name, c.getField(name).get(object));
381 } catch (Exception ignore) {
387 * Construct a JSONObject from a source JSON text string. This is the most
388 * commonly used JSONObject constructor.
391 * A string beginning with <code>{</code> <small>(left
392 * brace)</small> and ending with <code>}</code>
393 * <small>(right brace)</small>.
394 * @exception JSONException
395 * If there is a syntax error in the source string or a
398 public JSONObject(String source) throws JSONException {
399 this(new JSONTokener(source));
403 * Construct a JSONObject from a ResourceBundle.
406 * The ResourceBundle base name.
408 * The Locale to load the ResourceBundle for.
409 * @throws JSONException
410 * If any JSONExceptions are detected.
412 public JSONObject(String baseName, Locale locale) throws JSONException {
414 ResourceBundle bundle = ResourceBundle.getBundle(baseName, locale,
415 Thread.currentThread().getContextClassLoader());
417 // Iterate through the keys in the bundle.
419 Enumeration<String> keys = bundle.getKeys();
420 while (keys.hasMoreElements()) {
421 Object key = keys.nextElement();
424 // Go through the path, ensuring that there is a nested JSONObject for each
425 // segment except the last. Add the value using the last segment's name into
426 // the deepest nested JSONObject.
428 String[] path = ((String) key).split("\\.");
429 int last = path.length - 1;
430 JSONObject target = this;
431 for (int i = 0; i < last; i += 1) {
432 String segment = path[i];
433 JSONObject nextTarget = target.optJSONObject(segment);
434 if (nextTarget == null) {
435 nextTarget = new JSONObject();
436 target.put(segment, nextTarget);
440 target.put(path[last], bundle.getString((String) key));
446 * Constructor to specify an initial capacity of the internal map. Useful for library
447 * internal calls where we know, or at least can best guess, how big this JSONObject
450 * @param initialCapacity initial capacity of the internal map.
452 protected JSONObject(int initialCapacity){
453 this.map = new HashMap<String, Object>(initialCapacity);
457 * Accumulate values under a key. It is similar to the put method except
458 * that if there is already an object stored under the key then a JSONArray
459 * is stored under the key to hold all of the accumulated values. If there
460 * is already a JSONArray, then the new value is appended to it. In
461 * contrast, the put method replaces the previous value.
463 * If only one value is accumulated that is not a JSONArray, then the result
464 * will be the same as using put. But if multiple values are accumulated,
465 * then the result will be like append.
470 * An object to be accumulated under the key.
472 * @throws JSONException
473 * If the value is non-finite number.
474 * @throws NullPointerException
475 * If the key is <code>null</code>.
477 public JSONObject accumulate(String key, Object value) throws JSONException {
479 Object object = this.opt(key);
480 if (object == null) {
482 value instanceof JSONArray ? new JSONArray().put(value)
484 } else if (object instanceof JSONArray) {
485 ((JSONArray) object).put(value);
487 this.put(key, new JSONArray().put(object).put(value));
493 * Append values to the array under a key. If the key does not exist in the
494 * JSONObject, then the key is put in the JSONObject with its value being a
495 * JSONArray containing the value parameter. If the key was already
496 * associated with a JSONArray, then the value parameter is appended to it.
501 * An object to be accumulated under the key.
503 * @throws JSONException
504 * If the value is non-finite number or if the current value associated with
505 * the key is not a JSONArray.
506 * @throws NullPointerException
507 * If the key is <code>null</code>.
509 public JSONObject append(String key, Object value) throws JSONException {
511 Object object = this.opt(key);
512 if (object == null) {
513 this.put(key, new JSONArray().put(value));
514 } else if (object instanceof JSONArray) {
515 this.put(key, ((JSONArray) object).put(value));
517 throw new JSONException("JSONObject[" + key
518 + "] is not a JSONArray.");
524 * Produce a string from a double. The string "null" will be returned if the
525 * number is not finite.
531 public static String doubleToString(double d) {
532 if (Double.isInfinite(d) || Double.isNaN(d)) {
536 // Shave off trailing zeros and decimal point, if possible.
538 String string = Double.toString(d);
539 if (string.indexOf('.') > 0 && string.indexOf('e') < 0
540 && string.indexOf('E') < 0) {
541 while (string.endsWith("0")) {
542 string = string.substring(0, string.length() - 1);
544 if (string.endsWith(".")) {
545 string = string.substring(0, string.length() - 1);
552 * Get the value object associated with a key.
556 * @return The object associated with the key.
557 * @throws JSONException
558 * if the key is not found.
560 public Object get(String key) throws JSONException {
562 throw new JSONException("Null key.");
564 Object object = this.opt(key);
565 if (object == null) {
566 throw new JSONException("JSONObject[" + quote(key) + "] not found.");
572 * Get the enum value associated with a key.
575 * The type of enum to retrieve.
578 * @return The enum value associated with the key
579 * @throws JSONException
580 * if the key is not found or if the value cannot be converted
583 public <E extends Enum<E>> E getEnum(Class<E> clazz, String key) throws JSONException {
584 E val = optEnum(clazz, key);
586 // JSONException should really take a throwable argument.
587 // If it did, I would re-implement this with the Enum.valueOf
588 // method and place any thrown exception in the JSONException
589 throw new JSONException("JSONObject[" + quote(key)
590 + "] is not an enum of type " + quote(clazz.getSimpleName())
597 * Get the boolean value associated with a key.
602 * @throws JSONException
603 * if the value is not a Boolean or the String "true" or
606 public boolean getBoolean(String key) throws JSONException {
607 Object object = this.get(key);
608 if (object.equals(Boolean.FALSE)
609 || (object instanceof String && ((String) object)
610 .equalsIgnoreCase("false"))) {
612 } else if (object.equals(Boolean.TRUE)
613 || (object instanceof String && ((String) object)
614 .equalsIgnoreCase("true"))) {
617 throw new JSONException("JSONObject[" + quote(key)
618 + "] is not a Boolean.");
622 * Get the BigInteger value associated with a key.
626 * @return The numeric value.
627 * @throws JSONException
628 * if the key is not found or if the value cannot
629 * be converted to BigInteger.
631 public BigInteger getBigInteger(String key) throws JSONException {
632 Object object = this.get(key);
634 return new BigInteger(object.toString());
635 } catch (Exception e) {
636 throw new JSONException("JSONObject[" + quote(key)
637 + "] could not be converted to BigInteger.", e);
642 * Get the BigDecimal value associated with a key.
646 * @return The numeric value.
647 * @throws JSONException
648 * if the key is not found or if the value
649 * cannot be converted to BigDecimal.
651 public BigDecimal getBigDecimal(String key) throws JSONException {
652 Object object = this.get(key);
653 if (object instanceof BigDecimal) {
654 return (BigDecimal)object;
657 return new BigDecimal(object.toString());
658 } catch (Exception e) {
659 throw new JSONException("JSONObject[" + quote(key)
660 + "] could not be converted to BigDecimal.", e);
665 * Get the double value associated with a key.
669 * @return The numeric value.
670 * @throws JSONException
671 * if the key is not found or if the value is not a Number
672 * object and cannot be converted to a number.
674 public double getDouble(String key) throws JSONException {
675 Object object = this.get(key);
677 return object instanceof Number ? ((Number) object).doubleValue()
678 : Double.parseDouble(object.toString());
679 } catch (Exception e) {
680 throw new JSONException("JSONObject[" + quote(key)
681 + "] is not a number.", e);
686 * Get the float value associated with a key.
690 * @return The numeric value.
691 * @throws JSONException
692 * if the key is not found or if the value is not a Number
693 * object and cannot be converted to a number.
695 public float getFloat(String key) throws JSONException {
696 Object object = this.get(key);
698 return object instanceof Number ? ((Number) object).floatValue()
699 : Float.parseFloat(object.toString());
700 } catch (Exception e) {
701 throw new JSONException("JSONObject[" + quote(key)
702 + "] is not a number.", e);
707 * Get the Number value associated with a key.
711 * @return The numeric value.
712 * @throws JSONException
713 * if the key is not found or if the value is not a Number
714 * object and cannot be converted to a number.
716 public Number getNumber(String key) throws JSONException {
717 Object object = this.get(key);
719 if (object instanceof Number) {
720 return (Number)object;
722 return stringToNumber(object.toString());
723 } catch (Exception e) {
724 throw new JSONException("JSONObject[" + quote(key)
725 + "] is not a number.", e);
730 * Get the int value associated with a key.
734 * @return The integer value.
735 * @throws JSONException
736 * if the key is not found or if the value cannot be converted
739 public int getInt(String key) throws JSONException {
740 Object object = this.get(key);
742 return object instanceof Number ? ((Number) object).intValue()
743 : Integer.parseInt((String) object);
744 } catch (Exception e) {
745 throw new JSONException("JSONObject[" + quote(key)
746 + "] is not an int.", e);
751 * Get the JSONArray value associated with a key.
755 * @return A JSONArray which is the value.
756 * @throws JSONException
757 * if the key is not found or if the value is not a JSONArray.
759 public JSONArray getJSONArray(String key) throws JSONException {
760 Object object = this.get(key);
761 if (object instanceof JSONArray) {
762 return (JSONArray) object;
764 throw new JSONException("JSONObject[" + quote(key)
765 + "] is not a JSONArray.");
769 * Get the JSONObject value associated with a key.
773 * @return A JSONObject which is the value.
774 * @throws JSONException
775 * if the key is not found or if the value is not a JSONObject.
777 public JSONObject getJSONObject(String key) throws JSONException {
778 Object object = this.get(key);
779 if (object instanceof JSONObject) {
780 return (JSONObject) object;
782 throw new JSONException("JSONObject[" + quote(key)
783 + "] is not a JSONObject.");
787 * Get the long value associated with a key.
791 * @return The long value.
792 * @throws JSONException
793 * if the key is not found or if the value cannot be converted
796 public long getLong(String key) throws JSONException {
797 Object object = this.get(key);
799 return object instanceof Number ? ((Number) object).longValue()
800 : Long.parseLong((String) object);
801 } catch (Exception e) {
802 throw new JSONException("JSONObject[" + quote(key)
803 + "] is not a long.", e);
808 * Get an array of field names from a JSONObject.
810 * @return An array of field names, or null if there are no names.
812 public static String[] getNames(JSONObject jo) {
816 return jo.keySet().toArray(new String[jo.length()]);
820 * Get an array of field names from an Object.
822 * @return An array of field names, or null if there are no names.
824 public static String[] getNames(Object object) {
825 if (object == null) {
828 Class<?> klass = object.getClass();
829 Field[] fields = klass.getFields();
830 int length = fields.length;
834 String[] names = new String[length];
835 for (int i = 0; i < length; i += 1) {
836 names[i] = fields[i].getName();
842 * Get the string associated with a key.
846 * @return A string which is the value.
847 * @throws JSONException
848 * if there is no string value for the key.
850 public String getString(String key) throws JSONException {
851 Object object = this.get(key);
852 if (object instanceof String) {
853 return (String) object;
855 throw new JSONException("JSONObject[" + quote(key) + "] not a string.");
859 * Determine if the JSONObject contains a specific key.
863 * @return true if the key exists in the JSONObject.
865 public boolean has(String key) {
866 return this.map.containsKey(key);
870 * Increment a property of a JSONObject. If there is no such property,
871 * create one with a value of 1. If there is such a property, and if it is
872 * an Integer, Long, Double, or Float, then add one to it.
877 * @throws JSONException
878 * If there is already a property with this name that is not an
879 * Integer, Long, Double, or Float.
881 public JSONObject increment(String key) throws JSONException {
882 Object value = this.opt(key);
885 } else if (value instanceof BigInteger) {
886 this.put(key, ((BigInteger)value).add(BigInteger.ONE));
887 } else if (value instanceof BigDecimal) {
888 this.put(key, ((BigDecimal)value).add(BigDecimal.ONE));
889 } else if (value instanceof Integer) {
890 this.put(key, ((Integer) value).intValue() + 1);
891 } else if (value instanceof Long) {
892 this.put(key, ((Long) value).longValue() + 1L);
893 } else if (value instanceof Double) {
894 this.put(key, ((Double) value).doubleValue() + 1.0d);
895 } else if (value instanceof Float) {
896 this.put(key, ((Float) value).floatValue() + 1.0f);
898 throw new JSONException("Unable to increment [" + quote(key) + "].");
904 * Determine if the value associated with the key is <code>null</code> or if there is no
909 * @return true if there is no value associated with the key or if the value
910 * is the JSONObject.NULL object.
912 public boolean isNull(String key) {
913 return JSONObject.NULL.equals(this.opt(key));
917 * Get an enumeration of the keys of the JSONObject. Modifying this key Set will also
918 * modify the JSONObject. Use with caution.
920 * @see Set#iterator()
922 * @return An iterator of the keys.
924 public Iterator<String> keys() {
925 return this.keySet().iterator();
929 * Get a set of keys of the JSONObject. Modifying this key Set will also modify the
930 * JSONObject. Use with caution.
936 public Set<String> keySet() {
937 return this.map.keySet();
941 * Get a set of entries of the JSONObject. These are raw values and may not
942 * match what is returned by the JSONObject get* and opt* functions. Modifying
943 * the returned EntrySet or the Entry objects contained therein will modify the
944 * backing JSONObject. This does not return a clone or a read-only view.
948 * @see Map#entrySet()
950 * @return An Entry Set
952 protected Set<Entry<String, Object>> entrySet() {
953 return this.map.entrySet();
957 * Get the number of keys stored in the JSONObject.
959 * @return The number of keys in the JSONObject.
961 public int length() {
962 return this.map.size();
966 * Check if JSONObject is empty.
968 * @return true if JSONObject is empty, otherwise false.
970 public boolean isEmpty() {
971 return map.isEmpty();
975 * Produce a JSONArray containing the names of the elements of this
978 * @return A JSONArray containing the key strings, or null if the JSONObject
981 public JSONArray names() {
982 if(this.map.isEmpty()) {
985 return new JSONArray(this.map.keySet());
989 * Produce a string from a Number.
994 * @throws JSONException
995 * If n is a non-finite number.
997 public static String numberToString(Number number) throws JSONException {
998 if (number == null) {
999 throw new JSONException("Null pointer");
1001 testValidity(number);
1003 // Shave off trailing zeros and decimal point, if possible.
1005 String string = number.toString();
1006 if (string.indexOf('.') > 0 && string.indexOf('e') < 0
1007 && string.indexOf('E') < 0) {
1008 while (string.endsWith("0")) {
1009 string = string.substring(0, string.length() - 1);
1011 if (string.endsWith(".")) {
1012 string = string.substring(0, string.length() - 1);
1019 * Get an optional value associated with a key.
1023 * @return An object which is the value, or null if there is no value.
1025 public Object opt(String key) {
1026 return key == null ? null : this.map.get(key);
1030 * Get the enum value associated with a key.
1033 * The type of enum to retrieve.
1036 * @return The enum value associated with the key or null if not found
1038 public <E extends Enum<E>> E optEnum(Class<E> clazz, String key) {
1039 return this.optEnum(clazz, key, null);
1043 * Get the enum value associated with a key.
1046 * The type of enum to retrieve.
1049 * @param defaultValue
1050 * The default in case the value is not found
1051 * @return The enum value associated with the key or defaultValue
1052 * if the value is not found or cannot be assigned to <code>clazz</code>
1054 public <E extends Enum<E>> E optEnum(Class<E> clazz, String key, E defaultValue) {
1056 Object val = this.opt(key);
1057 if (NULL.equals(val)) {
1058 return defaultValue;
1060 if (clazz.isAssignableFrom(val.getClass())) {
1061 // we just checked it!
1062 @SuppressWarnings("unchecked")
1066 return Enum.valueOf(clazz, val.toString());
1067 } catch (IllegalArgumentException e) {
1068 return defaultValue;
1069 } catch (NullPointerException e) {
1070 return defaultValue;
1075 * Get an optional boolean associated with a key. It returns false if there
1076 * is no such key, or if the value is not Boolean.TRUE or the String "true".
1080 * @return The truth.
1082 public boolean optBoolean(String key) {
1083 return this.optBoolean(key, false);
1087 * Get an optional boolean associated with a key. It returns the
1088 * defaultValue if there is no such key, or if it is not a Boolean or the
1089 * String "true" or "false" (case insensitive).
1093 * @param defaultValue
1095 * @return The truth.
1097 public boolean optBoolean(String key, boolean defaultValue) {
1098 Object val = this.opt(key);
1099 if (NULL.equals(val)) {
1100 return defaultValue;
1102 if (val instanceof Boolean){
1103 return ((Boolean) val).booleanValue();
1106 // we'll use the get anyway because it does string conversion.
1107 return this.getBoolean(key);
1108 } catch (Exception e) {
1109 return defaultValue;
1114 * Get an optional BigDecimal associated with a key, or the defaultValue if
1115 * there is no such key or if its value is not a number. If the value is a
1116 * string, an attempt will be made to evaluate it as a number.
1120 * @param defaultValue
1122 * @return An object which is the value.
1124 public BigDecimal optBigDecimal(String key, BigDecimal defaultValue) {
1125 Object val = this.opt(key);
1126 if (NULL.equals(val)) {
1127 return defaultValue;
1129 if (val instanceof BigDecimal){
1130 return (BigDecimal) val;
1132 if (val instanceof BigInteger){
1133 return new BigDecimal((BigInteger) val);
1135 if (val instanceof Double || val instanceof Float){
1136 return new BigDecimal(((Number) val).doubleValue());
1138 if (val instanceof Long || val instanceof Integer
1139 || val instanceof Short || val instanceof Byte){
1140 return new BigDecimal(((Number) val).longValue());
1142 // don't check if it's a string in case of unchecked Number subclasses
1144 return new BigDecimal(val.toString());
1145 } catch (Exception e) {
1146 return defaultValue;
1151 * Get an optional BigInteger associated with a key, or the defaultValue if
1152 * there is no such key or if its value is not a number. If the value is a
1153 * string, an attempt will be made to evaluate it as a number.
1157 * @param defaultValue
1159 * @return An object which is the value.
1161 public BigInteger optBigInteger(String key, BigInteger defaultValue) {
1162 Object val = this.opt(key);
1163 if (NULL.equals(val)) {
1164 return defaultValue;
1166 if (val instanceof BigInteger){
1167 return (BigInteger) val;
1169 if (val instanceof BigDecimal){
1170 return ((BigDecimal) val).toBigInteger();
1172 if (val instanceof Double || val instanceof Float){
1173 return new BigDecimal(((Number) val).doubleValue()).toBigInteger();
1175 if (val instanceof Long || val instanceof Integer
1176 || val instanceof Short || val instanceof Byte){
1177 return BigInteger.valueOf(((Number) val).longValue());
1179 // don't check if it's a string in case of unchecked Number subclasses
1181 // the other opt functions handle implicit conversions, i.e.
1182 // jo.put("double",1.1d);
1183 // jo.optInt("double"); -- will return 1, not an error
1184 // this conversion to BigDecimal then to BigInteger is to maintain
1185 // that type cast support that may truncate the decimal.
1186 final String valStr = val.toString();
1187 if(isDecimalNotation(valStr)) {
1188 return new BigDecimal(valStr).toBigInteger();
1190 return new BigInteger(valStr);
1191 } catch (Exception e) {
1192 return defaultValue;
1197 * Get an optional double associated with a key, or NaN if there is no such
1198 * key or if its value is not a number. If the value is a string, an attempt
1199 * will be made to evaluate it as a number.
1202 * A string which is the key.
1203 * @return An object which is the value.
1205 public double optDouble(String key) {
1206 return this.optDouble(key, Double.NaN);
1210 * Get an optional double associated with a key, or the defaultValue if
1211 * there is no such key or if its value is not a number. If the value is a
1212 * string, an attempt will be made to evaluate it as a number.
1216 * @param defaultValue
1218 * @return An object which is the value.
1220 public double optDouble(String key, double defaultValue) {
1221 Object val = this.opt(key);
1222 if (NULL.equals(val)) {
1223 return defaultValue;
1225 if (val instanceof Number){
1226 return ((Number) val).doubleValue();
1228 if (val instanceof String) {
1230 return Double.parseDouble((String) val);
1231 } catch (Exception e) {
1232 return defaultValue;
1235 return defaultValue;
1239 * Get the optional double value associated with an index. NaN is returned
1240 * if there is no value for the index, or if the value is not a number and
1241 * cannot be converted to a number.
1245 * @return The value.
1247 public float optFloat(String key) {
1248 return this.optFloat(key, Float.NaN);
1252 * Get the optional double value associated with an index. The defaultValue
1253 * is returned if there is no value for the index, or if the value is not a
1254 * number and cannot be converted to a number.
1258 * @param defaultValue
1259 * The default value.
1260 * @return The value.
1262 public float optFloat(String key, float defaultValue) {
1263 Object val = this.opt(key);
1264 if (JSONObject.NULL.equals(val)) {
1265 return defaultValue;
1267 if (val instanceof Number){
1268 return ((Number) val).floatValue();
1270 if (val instanceof String) {
1272 return Float.parseFloat((String) val);
1273 } catch (Exception e) {
1274 return defaultValue;
1277 return defaultValue;
1281 * Get an optional int value associated with a key, or zero if there is no
1282 * such key or if the value is not a number. If the value is a string, an
1283 * attempt will be made to evaluate it as a number.
1287 * @return An object which is the value.
1289 public int optInt(String key) {
1290 return this.optInt(key, 0);
1294 * Get an optional int value associated with a key, or the default if there
1295 * is no such key or if the value is not a number. If the value is a string,
1296 * an attempt will be made to evaluate it as a number.
1300 * @param defaultValue
1302 * @return An object which is the value.
1304 public int optInt(String key, int defaultValue) {
1305 Object val = this.opt(key);
1306 if (NULL.equals(val)) {
1307 return defaultValue;
1309 if (val instanceof Number){
1310 return ((Number) val).intValue();
1313 if (val instanceof String) {
1315 return new BigDecimal((String) val).intValue();
1316 } catch (Exception e) {
1317 return defaultValue;
1320 return defaultValue;
1324 * Get an optional JSONArray associated with a key. It returns null if there
1325 * is no such key, or if its value is not a JSONArray.
1329 * @return A JSONArray which is the value.
1331 public JSONArray optJSONArray(String key) {
1332 Object o = this.opt(key);
1333 return o instanceof JSONArray ? (JSONArray) o : null;
1337 * Get an optional JSONObject associated with a key. It returns null if
1338 * there is no such key, or if its value is not a JSONObject.
1342 * @return A JSONObject which is the value.
1344 public JSONObject optJSONObject(String key) {
1345 Object object = this.opt(key);
1346 return object instanceof JSONObject ? (JSONObject) object : null;
1350 * Get an optional long value associated with a key, or zero if there is no
1351 * such key or if the value is not a number. If the value is a string, an
1352 * attempt will be made to evaluate it as a number.
1356 * @return An object which is the value.
1358 public long optLong(String key) {
1359 return this.optLong(key, 0);
1363 * Get an optional long value associated with a key, or the default if there
1364 * is no such key or if the value is not a number. If the value is a string,
1365 * an attempt will be made to evaluate it as a number.
1369 * @param defaultValue
1371 * @return An object which is the value.
1373 public long optLong(String key, long defaultValue) {
1374 Object val = this.opt(key);
1375 if (NULL.equals(val)) {
1376 return defaultValue;
1378 if (val instanceof Number){
1379 return ((Number) val).longValue();
1382 if (val instanceof String) {
1384 return new BigDecimal((String) val).longValue();
1385 } catch (Exception e) {
1386 return defaultValue;
1389 return defaultValue;
1393 * Get an optional {@link Number} value associated with a key, or <code>null</code>
1394 * if there is no such key or if the value is not a number. If the value is a string,
1395 * an attempt will be made to evaluate it as a number ({@link BigDecimal}). This method
1396 * would be used in cases where type coercion of the number value is unwanted.
1400 * @return An object which is the value.
1402 public Number optNumber(String key) {
1403 return this.optNumber(key, null);
1407 * Get an optional {@link Number} value associated with a key, or the default if there
1408 * is no such key or if the value is not a number. If the value is a string,
1409 * an attempt will be made to evaluate it as a number. This method
1410 * would be used in cases where type coercion of the number value is unwanted.
1414 * @param defaultValue
1416 * @return An object which is the value.
1418 public Number optNumber(String key, Number defaultValue) {
1419 Object val = this.opt(key);
1420 if (NULL.equals(val)) {
1421 return defaultValue;
1423 if (val instanceof Number){
1424 return (Number) val;
1427 if (val instanceof String) {
1429 return stringToNumber((String) val);
1430 } catch (Exception e) {
1431 return defaultValue;
1434 return defaultValue;
1438 * Get an optional string associated with a key. It returns an empty string
1439 * if there is no such key. If the value is not a string and is not null,
1440 * then it is converted to a string.
1444 * @return A string which is the value.
1446 public String optString(String key) {
1447 return this.optString(key, "");
1451 * Get an optional string associated with a key. It returns the defaultValue
1452 * if there is no such key.
1456 * @param defaultValue
1458 * @return A string which is the value.
1460 public String optString(String key, String defaultValue) {
1461 Object object = this.opt(key);
1462 return NULL.equals(object) ? defaultValue : object.toString();
1466 * Populates the internal map of the JSONObject with the bean properties. The
1467 * bean can not be recursive.
1469 * @see JSONObject#JSONObject(Object)
1474 private void populateMap(Object bean) {
1475 Class<?> klass = bean.getClass();
1477 // If klass is a System class then set includeSuperClass to false.
1479 boolean includeSuperClass = klass.getClassLoader() != null;
1481 Method[] methods = includeSuperClass ? klass.getMethods() : klass.getDeclaredMethods();
1482 for (final Method method : methods) {
1483 final int modifiers = method.getModifiers();
1484 if (Modifier.isPublic(modifiers)
1485 && !Modifier.isStatic(modifiers)
1486 && method.getParameterTypes().length == 0
1487 && !method.isBridge()
1488 && method.getReturnType() != Void.TYPE
1489 && isValidMethodName(method.getName())) {
1490 final String key = getKeyNameFromMethod(method);
1491 if (key != null && !key.isEmpty()) {
1493 final Object result = method.invoke(bean);
1494 if (result != null) {
1495 this.map.put(key, wrap(result));
1496 // we don't use the result anywhere outside of wrap
1497 // if it's a resource we should be sure to close it
1498 // after calling toString
1499 if (result instanceof Closeable) {
1501 ((Closeable) result).close();
1502 } catch (IOException ignore) {
1506 } catch (IllegalAccessException ignore) {
1507 } catch (IllegalArgumentException ignore) {
1508 } catch (InvocationTargetException ignore) {
1515 private boolean isValidMethodName(String name) {
1516 return !"getClass".equals(name) && !"getDeclaringClass".equals(name);
1519 private String getKeyNameFromMethod(Method method) {
1520 final int ignoreDepth = -1;//getAnnotationDepth(method, JSONPropertyIgnore.class);
1521 // if (ignoreDepth > 0) {
1522 // final int forcedNameDepth = getAnnotationDepth(method, JSONPropertyName.class);
1523 // if (forcedNameDepth < 0 || ignoreDepth <= forcedNameDepth) {
1524 // // the hierarchy asked to ignore, and the nearest name override
1525 // // was higher or non-existent
1529 // JSONPropertyName annotation = getAnnotation(method, JSONPropertyName.class);
1530 // if (annotation != null && annotation.value() != null && !annotation.value().isEmpty()) {
1531 // return annotation.value();
1534 final String name = method.getName();
1535 if (name.startsWith("get") && name.length() > 3) {
1536 key = name.substring(3);
1537 } else if (name.startsWith("is") && name.length() > 2) {
1538 key = name.substring(2);
1542 // if the first letter in the key is not uppercase, then skip.
1543 // This is to maintain backwards compatibility before PR406
1544 // (https://github.com/stleary/JSON-java/pull/406/)
1545 if (Character.isLowerCase(key.charAt(0))) {
1548 if (key.length() == 1) {
1549 key = key.toLowerCase(Locale.ROOT);
1550 } else if (!Character.isUpperCase(key.charAt(1))) {
1551 key = key.substring(0, 1).toLowerCase(Locale.ROOT) + key.substring(1);
1553 * remove j2s signature
1557 * key = key.split("$")[0];
1564 * Searches the class hierarchy to see if the method or it's super
1565 * implementations and interfaces has the annotation.
1568 * type of the annotation
1572 * @param annotationClass
1573 * annotation to look for
1574 * @return the {@link Annotation} if the annotation exists on the current method
1575 * or one of it's super class definitions
1577 private static <A extends Annotation> A getAnnotation(final Method m, final Class<A> annotationClass) {
1578 // if we have invalid data the result is null
1579 if (true || m == null || annotationClass == null) {
1583 // if (m.isAnnotationPresent(annotationClass)) {
1584 // return m.getAnnotation(annotationClass);
1587 // // if we've already reached the Object class, return null;
1588 // Class<?> c = m.getDeclaringClass();
1589 // if (c.getSuperclass() == null) {
1593 // // check directly implemented interfaces for the method being checked
1594 // for (Class<?> i : c.getInterfaces()) {
1596 // Method im = i.getMethod(m.getName(), m.getParameterTypes());
1597 // return getAnnotation(im, annotationClass);
1598 // } catch (final SecurityException ex) {
1600 // } catch (final NoSuchMethodException ex) {
1606 // return getAnnotation(
1607 // c.getSuperclass().getMethod(m.getName(), m.getParameterTypes()),
1608 // annotationClass);
1609 // } catch (final SecurityException ex) {
1611 // } catch (final NoSuchMethodException ex) {
1617 * Searches the class hierarchy to see if the method or it's super
1618 * implementations and interfaces has the annotation. Returns the depth of the
1619 * annotation in the hierarchy.
1622 * type of the annotation
1626 * @param annotationClass
1627 * annotation to look for
1628 * @return Depth of the annotation or -1 if the annotation is not on the method.
1630 private static int getAnnotationDepth(final Method m, final Class<? extends Annotation> annotationClass) {
1631 // if we have invalid data the result is -1
1632 if (true || m == null || annotationClass == null) {
1636 // if (m.isAnnotationPresent(annotationClass)) {
1640 // // if we've already reached the Object class, return -1;
1641 // Class<?> c = m.getDeclaringClass();
1642 // if (c.getSuperclass() == null) {
1646 // // check directly implemented interfaces for the method being checked
1647 // for (Class<?> i : c.getInterfaces()) {
1649 // Method im = i.getMethod(m.getName(), m.getParameterTypes());
1650 // int d = getAnnotationDepth(im, annotationClass);
1652 // // since the annotation was on the interface, add 1
1655 // } catch (final SecurityException ex) {
1657 // } catch (final NoSuchMethodException ex) {
1663 // int d = getAnnotationDepth(
1664 // c.getSuperclass().getMethod(m.getName(), m.getParameterTypes()),
1665 // annotationClass);
1667 // // since the annotation was on the superclass, add 1
1671 // } catch (final SecurityException ex) {
1673 // } catch (final NoSuchMethodException ex) {
1679 * Put a key/boolean pair in the JSONObject.
1684 * A boolean which is the value.
1686 * @throws JSONException
1687 * If the value is non-finite number.
1688 * @throws NullPointerException
1689 * If the key is <code>null</code>.
1691 public JSONObject put(String key, boolean value) throws JSONException {
1692 return this.put(key, value ? Boolean.TRUE : Boolean.FALSE);
1696 * Put a key/value pair in the JSONObject, where the value will be a
1697 * JSONArray which is produced from a Collection.
1702 * A Collection value.
1704 * @throws JSONException
1705 * If the value is non-finite number.
1706 * @throws NullPointerException
1707 * If the key is <code>null</code>.
1709 public JSONObject put(String key, Collection<?> value) throws JSONException {
1710 return this.put(key, new JSONArray(value));
1714 * Put a key/double pair in the JSONObject.
1719 * A double which is the value.
1721 * @throws JSONException
1722 * If the value is non-finite number.
1723 * @throws NullPointerException
1724 * If the key is <code>null</code>.
1726 public JSONObject put(String key, double value) throws JSONException {
1727 return this.put(key, Double.valueOf(value));
1731 * Put a key/float pair in the JSONObject.
1736 * A float which is the value.
1738 * @throws JSONException
1739 * If the value is non-finite number.
1740 * @throws NullPointerException
1741 * If the key is <code>null</code>.
1743 public JSONObject put(String key, float value) throws JSONException {
1744 return this.put(key, Float.valueOf(value));
1748 * Put a key/int pair in the JSONObject.
1753 * An int which is the value.
1755 * @throws JSONException
1756 * If the value is non-finite number.
1757 * @throws NullPointerException
1758 * If the key is <code>null</code>.
1760 public JSONObject put(String key, int value) throws JSONException {
1761 return this.put(key, Integer.valueOf(value));
1765 * Put a key/long pair in the JSONObject.
1770 * A long which is the value.
1772 * @throws JSONException
1773 * If the value is non-finite number.
1774 * @throws NullPointerException
1775 * If the key is <code>null</code>.
1777 public JSONObject put(String key, long value) throws JSONException {
1778 return this.put(key, Long.valueOf(value));
1782 * Put a key/value pair in the JSONObject, where the value will be a
1783 * JSONObject which is produced from a Map.
1790 * @throws JSONException
1791 * If the value is non-finite number.
1792 * @throws NullPointerException
1793 * If the key is <code>null</code>.
1795 public JSONObject put(String key, Map<?, ?> value) throws JSONException {
1796 return this.put(key, new JSONObject(value));
1800 * Put a key/value pair in the JSONObject. If the value is <code>null</code>, then the
1801 * key will be removed from the JSONObject if it is present.
1806 * An object which is the value. It should be of one of these
1807 * types: Boolean, Double, Integer, JSONArray, JSONObject, Long,
1808 * String, or the JSONObject.NULL object.
1810 * @throws JSONException
1811 * If the value is non-finite number.
1812 * @throws NullPointerException
1813 * If the key is <code>null</code>.
1815 public JSONObject put(String key, Object value) throws JSONException {
1817 throw new NullPointerException("Null key.");
1819 if (value != null) {
1820 testValidity(value);
1821 this.map.put(key, value);
1829 * Put a key/value pair in the JSONObject, but only if the key and the value
1830 * are both non-null, and only if there is not already a member with that
1834 * @param value object
1836 * @throws JSONException
1837 * if the key is a duplicate
1839 public JSONObject putOnce(String key, Object value) throws JSONException {
1840 if (key != null && value != null) {
1841 if (this.opt(key) != null) {
1842 throw new JSONException("Duplicate key \"" + key + "\"");
1844 return this.put(key, value);
1850 * Put a key/value pair in the JSONObject, but only if the key and the value
1851 * are both non-null.
1856 * An object which is the value. It should be of one of these
1857 * types: Boolean, Double, Integer, JSONArray, JSONObject, Long,
1858 * String, or the JSONObject.NULL object.
1860 * @throws JSONException
1861 * If the value is a non-finite number.
1863 public JSONObject putOpt(String key, Object value) throws JSONException {
1864 if (key != null && value != null) {
1865 return this.put(key, value);
1871 * Creates a JSONPointer using an initialization string and tries to
1872 * match it to an item within this JSONObject. For example, given a
1873 * JSONObject initialized with this document:
1879 * and this JSONPointer string:
1883 * Then this method will return the String "c".
1884 * A JSONPointerException may be thrown from code called by this method.
1886 * @param jsonPointer string that can be used to create a JSONPointer
1887 * @return the item matched by the JSONPointer, otherwise null
1889 public Object query(String jsonPointer) {
1890 return query(new JSONPointer(jsonPointer));
1893 * Uses a user initialized JSONPointer and tries to
1894 * match it to an item within this JSONObject. For example, given a
1895 * JSONObject initialized with this document:
1901 * and this JSONPointer:
1905 * Then this method will return the String "c".
1906 * A JSONPointerException may be thrown from code called by this method.
1908 * @param jsonPointer string that can be used to create a JSONPointer
1909 * @return the item matched by the JSONPointer, otherwise null
1911 public Object query(JSONPointer jsonPointer) {
1912 return jsonPointer.queryFrom(this);
1916 * Queries and returns a value from this object using {@code jsonPointer}, or
1917 * returns null if the query fails due to a missing key.
1919 * @param jsonPointer the string representation of the JSON pointer
1920 * @return the queried value or {@code null}
1921 * @throws IllegalArgumentException if {@code jsonPointer} has invalid syntax
1923 public Object optQuery(String jsonPointer) {
1924 return optQuery(new JSONPointer(jsonPointer));
1928 * Queries and returns a value from this object using {@code jsonPointer}, or
1929 * returns null if the query fails due to a missing key.
1931 * @param jsonPointer The JSON pointer
1932 * @return the queried value or {@code null}
1933 * @throws IllegalArgumentException if {@code jsonPointer} has invalid syntax
1935 public Object optQuery(JSONPointer jsonPointer) {
1937 return jsonPointer.queryFrom(this);
1938 } catch (JSONPointerException e) {
1944 * Produce a string in double quotes with backslash sequences in all the
1945 * right places. A backslash will be inserted within </, producing <\/,
1946 * allowing JSON text to be delivered in HTML. In JSON text, a string cannot
1947 * contain a control character or an unescaped quote or backslash.
1951 * @return A String correctly formatted for insertion in a JSON text.
1953 public static String quote(String string) {
1954 StringWriter sw = new StringWriter();
1955 synchronized (sw.getBuffer()) {
1957 return quote(string, sw).toString();
1958 } catch (IOException ignored) {
1959 // will never happen - we are writing to a string writer
1965 public static Writer quote(String string, Writer w) throws IOException {
1966 if (string == null || string.isEmpty()) {
1975 int len = string.length();
1978 for (i = 0; i < len; i += 1) {
1980 c = string.charAt(i);
2009 if (c < ' ' || (c >= '\u0080' && c < '\u00a0')
2010 || (c >= '\u2000' && c < '\u2100')) {
2012 hhhh = Integer.toHexString(c);
2013 w.write("0000", 0, 4 - hhhh.length());
2025 * Remove a name and its value, if present.
2028 * The name to be removed.
2029 * @return The value that was associated with the name, or null if there was
2032 public Object remove(String key) {
2033 return this.map.remove(key);
2037 * Determine if two JSONObjects are similar.
2038 * They must contain the same set of names which must be associated with
2041 * @param other The other JSONObject
2042 * @return true if they are equal
2044 public boolean similar(Object other) {
2046 if (!(other instanceof JSONObject)) {
2049 if (!this.keySet().equals(((JSONObject)other).keySet())) {
2052 for (final Entry<String,?> entry : this.entrySet()) {
2053 String name = entry.getKey();
2054 Object valueThis = entry.getValue();
2055 Object valueOther = ((JSONObject)other).get(name);
2056 if(valueThis == valueOther) {
2059 if(valueThis == null) {
2062 if (valueThis instanceof JSONObject) {
2063 if (!((JSONObject)valueThis).similar(valueOther)) {
2066 } else if (valueThis instanceof JSONArray) {
2067 if (!((JSONArray)valueThis).similar(valueOther)) {
2070 } else if (!valueThis.equals(valueOther)) {
2075 } catch (Throwable exception) {
2081 * Tests if the value should be tried as a decimal. It makes no test if there are actual digits.
2083 * @param val value to test
2084 * @return true if the string is "-0" or if it contains '.', 'e', or 'E', false otherwise.
2086 protected static boolean isDecimalNotation(final String val) {
2087 return val.indexOf('.') > -1 || val.indexOf('e') > -1
2088 || val.indexOf('E') > -1 || "-0".equals(val);
2092 * Converts a string to a number using the narrowest possible type. Possible
2093 * returns for this function are BigDecimal, Double, BigInteger, Long, and Integer.
2094 * When a Double is returned, it should always be a valid Double and not NaN or +-infinity.
2096 * @param val value to convert
2097 * @return Number representation of the value.
2098 * @throws NumberFormatException thrown if the value is not a valid number. A public
2099 * caller should catch this and wrap it in a {@link JSONException} if applicable.
2101 protected static Number stringToNumber(final String val) throws NumberFormatException {
2102 char initial = val.charAt(0);
2103 if ((initial >= '0' && initial <= '9') || initial == '-') {
2104 // decimal representation
2105 if (isDecimalNotation(val)) {
2106 // quick dirty way to see if we need a BigDecimal instead of a Double
2107 // this only handles some cases of overflow or underflow
2108 if (val.length()>14) {
2109 return new BigDecimal(val);
2111 final Double d = Double.valueOf(val);
2112 if (d.isInfinite() || d.isNaN()) {
2113 // if we can't parse it as a double, go up to BigDecimal
2114 // this is probably due to underflow like 4.32e-678
2115 // or overflow like 4.65e5324. The size of the string is small
2116 // but can't be held in a Double.
2117 return new BigDecimal(val);
2121 // integer representation.
2122 // This will narrow any values to the smallest reasonable Object representation
2123 // (Integer, Long, or BigInteger)
2126 // The compare string length method reduces GC,
2127 // but leads to smaller integers being placed in larger wrappers even though not
2128 // needed. i.e. 1,000,000,000 -> Long even though it's an Integer
2129 // 1,000,000,000,000,000,000 -> BigInteger even though it's a Long
2130 //if(val.length()<=9){
2131 // return Integer.valueOf(val);
2133 //if(val.length()<=18){
2134 // return Long.valueOf(val);
2136 //return new BigInteger(val);
2138 // BigInteger version: We use a similar bitLenth compare as
2139 // BigInteger#intValueExact uses. Increases GC, but objects hold
2140 // only what they need. i.e. Less runtime overhead if the value is
2141 // long lived. Which is the better tradeoff? This is closer to what's
2142 // in stringToValue.
2143 BigInteger bi = new BigInteger(val);
2144 if(bi.bitLength()<=31){
2145 return Integer.valueOf(bi.intValue());
2147 if(bi.bitLength()<=63){
2148 return Long.valueOf(bi.longValue());
2152 throw new NumberFormatException("val ["+val+"] is not a valid number.");
2156 * Try to convert a string into a number, boolean, or null. If the string
2157 * can't be converted, return the string.
2161 * @return A simple JSON value.
2163 // Changes to this method must be copied to the corresponding method in
2164 // the XML class to keep full support for Android
2165 public static Object stringToValue(String string) {
2166 if (string.equals("")) {
2169 if (string.equalsIgnoreCase("true")) {
2170 return Boolean.TRUE;
2172 if (string.equalsIgnoreCase("false")) {
2173 return Boolean.FALSE;
2175 if (string.equalsIgnoreCase("null")) {
2176 return JSONObject.NULL;
2180 * If it might be a number, try converting it. If a number cannot be
2181 * produced, then the value will just be a string.
2184 char initial = string.charAt(0);
2185 if ((initial >= '0' && initial <= '9') || initial == '-') {
2187 // if we want full Big Number support this block can be replaced with:
2188 // return stringToNumber(string);
2189 if (isDecimalNotation(string)) {
2190 Double d = Double.valueOf(string);
2191 if (!d.isInfinite() && !d.isNaN()) {
2195 Long myLong = Long.valueOf(string);
2196 if (string.equals(myLong.toString())) {
2197 if (myLong.longValue() == myLong.intValue()) {
2198 return Integer.valueOf(myLong.intValue());
2203 } catch (Exception ignore) {
2210 * Throw an exception if the object is a NaN or infinite number.
2213 * The object to test.
2214 * @throws JSONException
2215 * If o is a non-finite number.
2217 public static void testValidity(Object o) throws JSONException {
2219 if (o instanceof Double) {
2220 if (((Double) o).isInfinite() || ((Double) o).isNaN()) {
2221 throw new JSONException(
2222 "JSON does not allow non-finite numbers.");
2224 } else if (o instanceof Float) {
2225 if (((Float) o).isInfinite() || ((Float) o).isNaN()) {
2226 throw new JSONException(
2227 "JSON does not allow non-finite numbers.");
2234 * Produce a JSONArray containing the values of the members of this
2238 * A JSONArray containing a list of key strings. This determines
2239 * the sequence of the values in the result.
2240 * @return A JSONArray of values.
2241 * @throws JSONException
2242 * If any of the values are non-finite numbers.
2244 public JSONArray toJSONArray(JSONArray names) throws JSONException {
2245 if (names == null || names.isEmpty()) {
2248 JSONArray ja = new JSONArray();
2249 for (int i = 0; i < names.length(); i += 1) {
2250 ja.put(this.opt(names.getString(i)));
2256 * Make a JSON text of this JSONObject. For compactness, no whitespace is
2257 * added. If this would not result in a syntactically correct JSON text,
2258 * then null will be returned instead.
2260 * Warning: This method assumes that the data structure is acyclical.
2263 * @return a printable, displayable, portable, transmittable representation
2264 * of the object, beginning with <code>{</code> <small>(left
2265 * brace)</small> and ending with <code>}</code> <small>(right
2269 public String toString() {
2271 return this.toString(0);
2272 } catch (Exception e) {
2278 * Make a pretty-printed JSON text of this JSONObject.
2280 * <p>If <code>indentFactor > 0</code> and the {@link JSONObject}
2281 * has only one key, then the object will be output on a single line:
2282 * <pre>{@code {"key": 1}}</pre>
2284 * <p>If an object has 2 or more keys, then it will be output across
2285 * multiple lines: <code><pre>{
2287 * "key2": "value 2",
2291 * Warning: This method assumes that the data structure is acyclical.
2294 * @param indentFactor
2295 * The number of spaces to add to each level of indentation.
2296 * @return a printable, displayable, portable, transmittable representation
2297 * of the object, beginning with <code>{</code> <small>(left
2298 * brace)</small> and ending with <code>}</code> <small>(right
2300 * @throws JSONException
2301 * If the object contains an invalid number.
2303 public String toString(int indentFactor) throws JSONException {
2304 StringWriter w = new StringWriter();
2305 synchronized (w.getBuffer()) {
2306 return this.write(w, indentFactor, 0).toString();
2311 * Make a JSON text of an Object value. If the object has an
2312 * value.toJSONString() method, then that method will be used to produce the
2313 * JSON text. The method is required to produce a strictly conforming text.
2314 * If the object does not contain a toJSONString method (which is the most
2315 * common case), then a text will be produced by other means. If the value
2316 * is an array or Collection, then a JSONArray will be made from it and its
2317 * toJSONString method will be called. If the value is a MAP, then a
2318 * JSONObject will be made from it and its toJSONString method will be
2319 * called. Otherwise, the value's toString method will be called, and the
2320 * result will be quoted.
2323 * Warning: This method assumes that the data structure is acyclical.
2326 * The value to be serialized.
2327 * @return a printable, displayable, transmittable representation of the
2328 * object, beginning with <code>{</code> <small>(left
2329 * brace)</small> and ending with <code>}</code> <small>(right
2331 * @throws JSONException
2332 * If the value is or contains an invalid number.
2334 public static String valueToString(Object value) throws JSONException {
2335 // moves the implementation to JSONWriter as:
2336 // 1. It makes more sense to be part of the writer class
2337 // 2. For Android support this method is not available. By implementing it in the Writer
2338 // Android users can use the writer with the built in Android JSONObject implementation.
2339 return JSONWriter.valueToString(value);
2343 * Wrap an object, if necessary. If the object is <code>null</code>, return the NULL
2344 * object. If it is an array or collection, wrap it in a JSONArray. If it is
2345 * a map, wrap it in a JSONObject. If it is a standard property (Double,
2346 * String, et al) then it is already wrapped. Otherwise, if it comes from
2347 * one of the java packages, turn it into a string. And if it doesn't, try
2348 * to wrap it in a JSONObject. If the wrapping fails, then null is returned.
2351 * The object to wrap
2352 * @return The wrapped value
2354 public static Object wrap(Object object) {
2356 if (object == null) {
2359 if (object instanceof JSONObject || object instanceof JSONArray
2360 || NULL.equals(object) || object instanceof JSONString
2361 || object instanceof Byte || object instanceof Character
2362 || object instanceof Short || object instanceof Integer
2363 || object instanceof Long || object instanceof Boolean
2364 || object instanceof Float || object instanceof Double
2365 || object instanceof String || object instanceof BigInteger
2366 || object instanceof BigDecimal || object instanceof Enum) {
2370 if (object instanceof Collection) {
2371 Collection<?> coll = (Collection<?>) object;
2372 return new JSONArray(coll);
2374 if (object.getClass().isArray()) {
2375 return new JSONArray(object);
2377 if (object instanceof Map) {
2378 Map<?, ?> map = (Map<?, ?>) object;
2379 return new JSONObject(map);
2381 Package objectPackage = object.getClass().getPackage();
2382 String objectPackageName = objectPackage != null ? objectPackage
2384 if (objectPackageName.startsWith("java.")
2385 || objectPackageName.startsWith("javax.")
2386 || object.getClass().getClassLoader() == null) {
2387 return object.toString();
2389 return new JSONObject(object);
2390 } catch (Exception exception) {
2396 * Write the contents of the JSONObject as JSON text to a writer. For
2397 * compactness, no whitespace is added.
2399 * Warning: This method assumes that the data structure is acyclical.
2402 * @return The writer.
2403 * @throws JSONException
2405 public Writer write(Writer writer) throws JSONException {
2406 return this.write(writer, 0, 0);
2409 static final Writer writeValue(Writer writer, Object value,
2410 int indentFactor, int indent) throws JSONException, IOException {
2411 if (value == null || value.equals(null)) {
2412 writer.write("null");
2413 } else if (value instanceof JSONString) {
2416 o = ((JSONString) value).toJSONString();
2417 } catch (Exception e) {
2418 throw new JSONException(e);
2420 writer.write(o != null ? o.toString() : quote(value.toString()));
2421 } else if (value instanceof Number) {
2422 // not all Numbers may match actual JSON Numbers. i.e. fractions or Imaginary
2423 final String numberAsString = numberToString((Number) value);
2425 // Use the BigDecimal constructor for its parser to validate the format.
2426 @SuppressWarnings("unused")
2427 BigDecimal testNum = new BigDecimal(numberAsString);
2428 // Close enough to a JSON number that we will use it unquoted
2429 writer.write(numberAsString);
2430 } catch (NumberFormatException ex){
2431 // The Number value is not a valid JSON number.
2432 // Instead we will quote it as a string
2433 quote(numberAsString, writer);
2435 } else if (value instanceof Boolean) {
2436 writer.write(value.toString());
2437 } else if (value instanceof Enum<?>) {
2438 writer.write(quote(((Enum<?>)value).name()));
2439 } else if (value instanceof JSONObject) {
2440 ((JSONObject) value).write(writer, indentFactor, indent);
2441 } else if (value instanceof JSONArray) {
2442 ((JSONArray) value).write(writer, indentFactor, indent);
2443 } else if (value instanceof Map) {
2444 Map<?, ?> map = (Map<?, ?>) value;
2445 new JSONObject(map).write(writer, indentFactor, indent);
2446 } else if (value instanceof Collection) {
2447 Collection<?> coll = (Collection<?>) value;
2448 new JSONArray(coll).write(writer, indentFactor, indent);
2449 } else if (value.getClass().isArray()) {
2450 new JSONArray(value).write(writer, indentFactor, indent);
2452 quote(value.toString(), writer);
2457 static final void indent(Writer writer, int indent) throws IOException {
2458 for (int i = 0; i < indent; i += 1) {
2464 * Write the contents of the JSONObject as JSON text to a writer.
2466 * <p>If <code>indentFactor > 0</code> and the {@link JSONObject}
2467 * has only one key, then the object will be output on a single line:
2468 * <pre>{@code {"key": 1}}</pre>
2470 * <p>If an object has 2 or more keys, then it will be output across
2471 * multiple lines: <code><pre>{
2473 * "key2": "value 2",
2477 * Warning: This method assumes that the data structure is acyclical.
2481 * Writes the serialized JSON
2482 * @param indentFactor
2483 * The number of spaces to add to each level of indentation.
2485 * The indentation of the top level.
2486 * @return The writer.
2487 * @throws JSONException
2489 public Writer write(Writer writer, int indentFactor, int indent)
2490 throws JSONException {
2492 boolean commanate = false;
2493 final int length = this.length();
2497 final Entry<String,?> entry = this.entrySet().iterator().next();
2498 final String key = entry.getKey();
2499 writer.write(quote(key));
2501 if (indentFactor > 0) {
2505 writeValue(writer, entry.getValue(), indentFactor, indent);
2506 } catch (Exception e) {
2507 throw new JSONException("Unable to write JSONObject value for key: " + key, e);
2509 } else if (length != 0) {
2510 final int newindent = indent + indentFactor;
2511 for (final Entry<String,?> entry : this.entrySet()) {
2515 if (indentFactor > 0) {
2518 indent(writer, newindent);
2519 final String key = entry.getKey();
2520 writer.write(quote(key));
2522 if (indentFactor > 0) {
2526 writeValue(writer, entry.getValue(), indentFactor, newindent);
2527 } catch (Exception e) {
2528 throw new JSONException("Unable to write JSONObject value for key: " + key, e);
2532 if (indentFactor > 0) {
2535 indent(writer, indent);
2539 } catch (IOException exception) {
2540 throw new JSONException(exception);
2545 * Returns a java.util.Map containing all of the entries in this object.
2546 * If an entry in the object is a JSONArray or JSONObject it will also
2549 * Warning: This method assumes that the data structure is acyclical.
2551 * @return a java.util.Map containing the entries of this object
2553 public Map<String, Object> toMap() {
2554 Map<String, Object> results = new HashMap<String, Object>();
2555 for (Entry<String, Object> entry : this.entrySet()) {
2557 if (entry.getValue() == null || NULL.equals(entry.getValue())) {
2559 } else if (entry.getValue() instanceof JSONObject) {
2560 value = ((JSONObject) entry.getValue()).toMap();
2561 } else if (entry.getValue() instanceof JSONArray) {
2562 value = ((JSONArray) entry.getValue()).toList();
2564 value = entry.getValue();
2566 results.put(entry.getKey(), value);