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);
1557 * Searches the class hierarchy to see if the method or it's super
1558 * implementations and interfaces has the annotation.
1561 * type of the annotation
1565 * @param annotationClass
1566 * annotation to look for
1567 * @return the {@link Annotation} if the annotation exists on the current method
1568 * or one of it's super class definitions
1570 private static <A extends Annotation> A getAnnotation(final Method m, final Class<A> annotationClass) {
1571 // if we have invalid data the result is null
1572 if (true || m == null || annotationClass == null) {
1576 // if (m.isAnnotationPresent(annotationClass)) {
1577 // return m.getAnnotation(annotationClass);
1580 // // if we've already reached the Object class, return null;
1581 // Class<?> c = m.getDeclaringClass();
1582 // if (c.getSuperclass() == null) {
1586 // // check directly implemented interfaces for the method being checked
1587 // for (Class<?> i : c.getInterfaces()) {
1589 // Method im = i.getMethod(m.getName(), m.getParameterTypes());
1590 // return getAnnotation(im, annotationClass);
1591 // } catch (final SecurityException ex) {
1593 // } catch (final NoSuchMethodException ex) {
1599 // return getAnnotation(
1600 // c.getSuperclass().getMethod(m.getName(), m.getParameterTypes()),
1601 // annotationClass);
1602 // } catch (final SecurityException ex) {
1604 // } catch (final NoSuchMethodException ex) {
1610 * Searches the class hierarchy to see if the method or it's super
1611 * implementations and interfaces has the annotation. Returns the depth of the
1612 * annotation in the hierarchy.
1615 * type of the annotation
1619 * @param annotationClass
1620 * annotation to look for
1621 * @return Depth of the annotation or -1 if the annotation is not on the method.
1623 private static int getAnnotationDepth(final Method m, final Class<? extends Annotation> annotationClass) {
1624 // if we have invalid data the result is -1
1625 if (true || m == null || annotationClass == null) {
1629 // if (m.isAnnotationPresent(annotationClass)) {
1633 // // if we've already reached the Object class, return -1;
1634 // Class<?> c = m.getDeclaringClass();
1635 // if (c.getSuperclass() == null) {
1639 // // check directly implemented interfaces for the method being checked
1640 // for (Class<?> i : c.getInterfaces()) {
1642 // Method im = i.getMethod(m.getName(), m.getParameterTypes());
1643 // int d = getAnnotationDepth(im, annotationClass);
1645 // // since the annotation was on the interface, add 1
1648 // } catch (final SecurityException ex) {
1650 // } catch (final NoSuchMethodException ex) {
1656 // int d = getAnnotationDepth(
1657 // c.getSuperclass().getMethod(m.getName(), m.getParameterTypes()),
1658 // annotationClass);
1660 // // since the annotation was on the superclass, add 1
1664 // } catch (final SecurityException ex) {
1666 // } catch (final NoSuchMethodException ex) {
1672 * Put a key/boolean pair in the JSONObject.
1677 * A boolean which is the value.
1679 * @throws JSONException
1680 * If the value is non-finite number.
1681 * @throws NullPointerException
1682 * If the key is <code>null</code>.
1684 public JSONObject put(String key, boolean value) throws JSONException {
1685 return this.put(key, value ? Boolean.TRUE : Boolean.FALSE);
1689 * Put a key/value pair in the JSONObject, where the value will be a
1690 * JSONArray which is produced from a Collection.
1695 * A Collection value.
1697 * @throws JSONException
1698 * If the value is non-finite number.
1699 * @throws NullPointerException
1700 * If the key is <code>null</code>.
1702 public JSONObject put(String key, Collection<?> value) throws JSONException {
1703 return this.put(key, new JSONArray(value));
1707 * Put a key/double pair in the JSONObject.
1712 * A double which is the value.
1714 * @throws JSONException
1715 * If the value is non-finite number.
1716 * @throws NullPointerException
1717 * If the key is <code>null</code>.
1719 public JSONObject put(String key, double value) throws JSONException {
1720 return this.put(key, Double.valueOf(value));
1724 * Put a key/float pair in the JSONObject.
1729 * A float which is the value.
1731 * @throws JSONException
1732 * If the value is non-finite number.
1733 * @throws NullPointerException
1734 * If the key is <code>null</code>.
1736 public JSONObject put(String key, float value) throws JSONException {
1737 return this.put(key, Float.valueOf(value));
1741 * Put a key/int pair in the JSONObject.
1746 * An int which is the value.
1748 * @throws JSONException
1749 * If the value is non-finite number.
1750 * @throws NullPointerException
1751 * If the key is <code>null</code>.
1753 public JSONObject put(String key, int value) throws JSONException {
1754 return this.put(key, Integer.valueOf(value));
1758 * Put a key/long pair in the JSONObject.
1763 * A long which is the value.
1765 * @throws JSONException
1766 * If the value is non-finite number.
1767 * @throws NullPointerException
1768 * If the key is <code>null</code>.
1770 public JSONObject put(String key, long value) throws JSONException {
1771 return this.put(key, Long.valueOf(value));
1775 * Put a key/value pair in the JSONObject, where the value will be a
1776 * JSONObject which is produced from a Map.
1783 * @throws JSONException
1784 * If the value is non-finite number.
1785 * @throws NullPointerException
1786 * If the key is <code>null</code>.
1788 public JSONObject put(String key, Map<?, ?> value) throws JSONException {
1789 return this.put(key, new JSONObject(value));
1793 * Put a key/value pair in the JSONObject. If the value is <code>null</code>, then the
1794 * key will be removed from the JSONObject if it is present.
1799 * An object which is the value. It should be of one of these
1800 * types: Boolean, Double, Integer, JSONArray, JSONObject, Long,
1801 * String, or the JSONObject.NULL object.
1803 * @throws JSONException
1804 * If the value is non-finite number.
1805 * @throws NullPointerException
1806 * If the key is <code>null</code>.
1808 public JSONObject put(String key, Object value) throws JSONException {
1810 throw new NullPointerException("Null key.");
1812 if (value != null) {
1813 testValidity(value);
1814 this.map.put(key, value);
1822 * Put a key/value pair in the JSONObject, but only if the key and the value
1823 * are both non-null, and only if there is not already a member with that
1827 * @param value object
1829 * @throws JSONException
1830 * if the key is a duplicate
1832 public JSONObject putOnce(String key, Object value) throws JSONException {
1833 if (key != null && value != null) {
1834 if (this.opt(key) != null) {
1835 throw new JSONException("Duplicate key \"" + key + "\"");
1837 return this.put(key, value);
1843 * Put a key/value pair in the JSONObject, but only if the key and the value
1844 * are both non-null.
1849 * An object which is the value. It should be of one of these
1850 * types: Boolean, Double, Integer, JSONArray, JSONObject, Long,
1851 * String, or the JSONObject.NULL object.
1853 * @throws JSONException
1854 * If the value is a non-finite number.
1856 public JSONObject putOpt(String key, Object value) throws JSONException {
1857 if (key != null && value != null) {
1858 return this.put(key, value);
1864 * Creates a JSONPointer using an initialization string and tries to
1865 * match it to an item within this JSONObject. For example, given a
1866 * JSONObject initialized with this document:
1872 * and this JSONPointer string:
1876 * Then this method will return the String "c".
1877 * A JSONPointerException may be thrown from code called by this method.
1879 * @param jsonPointer string that can be used to create a JSONPointer
1880 * @return the item matched by the JSONPointer, otherwise null
1882 public Object query(String jsonPointer) {
1883 return query(new JSONPointer(jsonPointer));
1886 * Uses a user initialized JSONPointer and tries to
1887 * match it to an item within this JSONObject. For example, given a
1888 * JSONObject initialized with this document:
1894 * and this JSONPointer:
1898 * Then this method will return the String "c".
1899 * A JSONPointerException may be thrown from code called by this method.
1901 * @param jsonPointer string that can be used to create a JSONPointer
1902 * @return the item matched by the JSONPointer, otherwise null
1904 public Object query(JSONPointer jsonPointer) {
1905 return jsonPointer.queryFrom(this);
1909 * Queries and returns a value from this object using {@code jsonPointer}, or
1910 * returns null if the query fails due to a missing key.
1912 * @param jsonPointer the string representation of the JSON pointer
1913 * @return the queried value or {@code null}
1914 * @throws IllegalArgumentException if {@code jsonPointer} has invalid syntax
1916 public Object optQuery(String jsonPointer) {
1917 return optQuery(new JSONPointer(jsonPointer));
1921 * Queries and returns a value from this object using {@code jsonPointer}, or
1922 * returns null if the query fails due to a missing key.
1924 * @param jsonPointer The JSON pointer
1925 * @return the queried value or {@code null}
1926 * @throws IllegalArgumentException if {@code jsonPointer} has invalid syntax
1928 public Object optQuery(JSONPointer jsonPointer) {
1930 return jsonPointer.queryFrom(this);
1931 } catch (JSONPointerException e) {
1937 * Produce a string in double quotes with backslash sequences in all the
1938 * right places. A backslash will be inserted within </, producing <\/,
1939 * allowing JSON text to be delivered in HTML. In JSON text, a string cannot
1940 * contain a control character or an unescaped quote or backslash.
1944 * @return A String correctly formatted for insertion in a JSON text.
1946 public static String quote(String string) {
1947 StringWriter sw = new StringWriter();
1948 synchronized (sw.getBuffer()) {
1950 return quote(string, sw).toString();
1951 } catch (IOException ignored) {
1952 // will never happen - we are writing to a string writer
1958 public static Writer quote(String string, Writer w) throws IOException {
1959 if (string == null || string.isEmpty()) {
1968 int len = string.length();
1971 for (i = 0; i < len; i += 1) {
1973 c = string.charAt(i);
2002 if (c < ' ' || (c >= '\u0080' && c < '\u00a0')
2003 || (c >= '\u2000' && c < '\u2100')) {
2005 hhhh = Integer.toHexString(c);
2006 w.write("0000", 0, 4 - hhhh.length());
2018 * Remove a name and its value, if present.
2021 * The name to be removed.
2022 * @return The value that was associated with the name, or null if there was
2025 public Object remove(String key) {
2026 return this.map.remove(key);
2030 * Determine if two JSONObjects are similar.
2031 * They must contain the same set of names which must be associated with
2034 * @param other The other JSONObject
2035 * @return true if they are equal
2037 public boolean similar(Object other) {
2039 if (!(other instanceof JSONObject)) {
2042 if (!this.keySet().equals(((JSONObject)other).keySet())) {
2045 for (final Entry<String,?> entry : this.entrySet()) {
2046 String name = entry.getKey();
2047 Object valueThis = entry.getValue();
2048 Object valueOther = ((JSONObject)other).get(name);
2049 if(valueThis == valueOther) {
2052 if(valueThis == null) {
2055 if (valueThis instanceof JSONObject) {
2056 if (!((JSONObject)valueThis).similar(valueOther)) {
2059 } else if (valueThis instanceof JSONArray) {
2060 if (!((JSONArray)valueThis).similar(valueOther)) {
2063 } else if (!valueThis.equals(valueOther)) {
2068 } catch (Throwable exception) {
2074 * Tests if the value should be tried as a decimal. It makes no test if there are actual digits.
2076 * @param val value to test
2077 * @return true if the string is "-0" or if it contains '.', 'e', or 'E', false otherwise.
2079 protected static boolean isDecimalNotation(final String val) {
2080 return val.indexOf('.') > -1 || val.indexOf('e') > -1
2081 || val.indexOf('E') > -1 || "-0".equals(val);
2085 * Converts a string to a number using the narrowest possible type. Possible
2086 * returns for this function are BigDecimal, Double, BigInteger, Long, and Integer.
2087 * When a Double is returned, it should always be a valid Double and not NaN or +-infinity.
2089 * @param val value to convert
2090 * @return Number representation of the value.
2091 * @throws NumberFormatException thrown if the value is not a valid number. A public
2092 * caller should catch this and wrap it in a {@link JSONException} if applicable.
2094 protected static Number stringToNumber(final String val) throws NumberFormatException {
2095 char initial = val.charAt(0);
2096 if ((initial >= '0' && initial <= '9') || initial == '-') {
2097 // decimal representation
2098 if (isDecimalNotation(val)) {
2099 // quick dirty way to see if we need a BigDecimal instead of a Double
2100 // this only handles some cases of overflow or underflow
2101 if (val.length()>14) {
2102 return new BigDecimal(val);
2104 final Double d = Double.valueOf(val);
2105 if (d.isInfinite() || d.isNaN()) {
2106 // if we can't parse it as a double, go up to BigDecimal
2107 // this is probably due to underflow like 4.32e-678
2108 // or overflow like 4.65e5324. The size of the string is small
2109 // but can't be held in a Double.
2110 return new BigDecimal(val);
2114 // integer representation.
2115 // This will narrow any values to the smallest reasonable Object representation
2116 // (Integer, Long, or BigInteger)
2119 // The compare string length method reduces GC,
2120 // but leads to smaller integers being placed in larger wrappers even though not
2121 // needed. i.e. 1,000,000,000 -> Long even though it's an Integer
2122 // 1,000,000,000,000,000,000 -> BigInteger even though it's a Long
2123 //if(val.length()<=9){
2124 // return Integer.valueOf(val);
2126 //if(val.length()<=18){
2127 // return Long.valueOf(val);
2129 //return new BigInteger(val);
2131 // BigInteger version: We use a similar bitLenth compare as
2132 // BigInteger#intValueExact uses. Increases GC, but objects hold
2133 // only what they need. i.e. Less runtime overhead if the value is
2134 // long lived. Which is the better tradeoff? This is closer to what's
2135 // in stringToValue.
2136 BigInteger bi = new BigInteger(val);
2137 if(bi.bitLength()<=31){
2138 return Integer.valueOf(bi.intValue());
2140 if(bi.bitLength()<=63){
2141 return Long.valueOf(bi.longValue());
2145 throw new NumberFormatException("val ["+val+"] is not a valid number.");
2149 * Try to convert a string into a number, boolean, or null. If the string
2150 * can't be converted, return the string.
2154 * @return A simple JSON value.
2156 // Changes to this method must be copied to the corresponding method in
2157 // the XML class to keep full support for Android
2158 public static Object stringToValue(String string) {
2159 if (string.equals("")) {
2162 if (string.equalsIgnoreCase("true")) {
2163 return Boolean.TRUE;
2165 if (string.equalsIgnoreCase("false")) {
2166 return Boolean.FALSE;
2168 if (string.equalsIgnoreCase("null")) {
2169 return JSONObject.NULL;
2173 * If it might be a number, try converting it. If a number cannot be
2174 * produced, then the value will just be a string.
2177 char initial = string.charAt(0);
2178 if ((initial >= '0' && initial <= '9') || initial == '-') {
2180 // if we want full Big Number support this block can be replaced with:
2181 // return stringToNumber(string);
2182 if (isDecimalNotation(string)) {
2183 Double d = Double.valueOf(string);
2184 if (!d.isInfinite() && !d.isNaN()) {
2188 Long myLong = Long.valueOf(string);
2189 if (string.equals(myLong.toString())) {
2190 if (myLong.longValue() == myLong.intValue()) {
2191 return Integer.valueOf(myLong.intValue());
2196 } catch (Exception ignore) {
2203 * Throw an exception if the object is a NaN or infinite number.
2206 * The object to test.
2207 * @throws JSONException
2208 * If o is a non-finite number.
2210 public static void testValidity(Object o) throws JSONException {
2212 if (o instanceof Double) {
2213 if (((Double) o).isInfinite() || ((Double) o).isNaN()) {
2214 throw new JSONException(
2215 "JSON does not allow non-finite numbers.");
2217 } else if (o instanceof Float) {
2218 if (((Float) o).isInfinite() || ((Float) o).isNaN()) {
2219 throw new JSONException(
2220 "JSON does not allow non-finite numbers.");
2227 * Produce a JSONArray containing the values of the members of this
2231 * A JSONArray containing a list of key strings. This determines
2232 * the sequence of the values in the result.
2233 * @return A JSONArray of values.
2234 * @throws JSONException
2235 * If any of the values are non-finite numbers.
2237 public JSONArray toJSONArray(JSONArray names) throws JSONException {
2238 if (names == null || names.isEmpty()) {
2241 JSONArray ja = new JSONArray();
2242 for (int i = 0; i < names.length(); i += 1) {
2243 ja.put(this.opt(names.getString(i)));
2249 * Make a JSON text of this JSONObject. For compactness, no whitespace is
2250 * added. If this would not result in a syntactically correct JSON text,
2251 * then null will be returned instead.
2253 * Warning: This method assumes that the data structure is acyclical.
2256 * @return a printable, displayable, portable, transmittable representation
2257 * of the object, beginning with <code>{</code> <small>(left
2258 * brace)</small> and ending with <code>}</code> <small>(right
2262 public String toString() {
2264 return this.toString(0);
2265 } catch (Exception e) {
2271 * Make a pretty-printed JSON text of this JSONObject.
2273 * <p>If <code>indentFactor > 0</code> and the {@link JSONObject}
2274 * has only one key, then the object will be output on a single line:
2275 * <pre>{@code {"key": 1}}</pre>
2277 * <p>If an object has 2 or more keys, then it will be output across
2278 * multiple lines: <code><pre>{
2280 * "key2": "value 2",
2284 * Warning: This method assumes that the data structure is acyclical.
2287 * @param indentFactor
2288 * The number of spaces to add to each level of indentation.
2289 * @return a printable, displayable, portable, transmittable representation
2290 * of the object, beginning with <code>{</code> <small>(left
2291 * brace)</small> and ending with <code>}</code> <small>(right
2293 * @throws JSONException
2294 * If the object contains an invalid number.
2296 public String toString(int indentFactor) throws JSONException {
2297 StringWriter w = new StringWriter();
2298 synchronized (w.getBuffer()) {
2299 return this.write(w, indentFactor, 0).toString();
2304 * Make a JSON text of an Object value. If the object has an
2305 * value.toJSONString() method, then that method will be used to produce the
2306 * JSON text. The method is required to produce a strictly conforming text.
2307 * If the object does not contain a toJSONString method (which is the most
2308 * common case), then a text will be produced by other means. If the value
2309 * is an array or Collection, then a JSONArray will be made from it and its
2310 * toJSONString method will be called. If the value is a MAP, then a
2311 * JSONObject will be made from it and its toJSONString method will be
2312 * called. Otherwise, the value's toString method will be called, and the
2313 * result will be quoted.
2316 * Warning: This method assumes that the data structure is acyclical.
2319 * The value to be serialized.
2320 * @return a printable, displayable, transmittable representation of the
2321 * object, beginning with <code>{</code> <small>(left
2322 * brace)</small> and ending with <code>}</code> <small>(right
2324 * @throws JSONException
2325 * If the value is or contains an invalid number.
2327 public static String valueToString(Object value) throws JSONException {
2328 // moves the implementation to JSONWriter as:
2329 // 1. It makes more sense to be part of the writer class
2330 // 2. For Android support this method is not available. By implementing it in the Writer
2331 // Android users can use the writer with the built in Android JSONObject implementation.
2332 return JSONWriter.valueToString(value);
2336 * Wrap an object, if necessary. If the object is <code>null</code>, return the NULL
2337 * object. If it is an array or collection, wrap it in a JSONArray. If it is
2338 * a map, wrap it in a JSONObject. If it is a standard property (Double,
2339 * String, et al) then it is already wrapped. Otherwise, if it comes from
2340 * one of the java packages, turn it into a string. And if it doesn't, try
2341 * to wrap it in a JSONObject. If the wrapping fails, then null is returned.
2344 * The object to wrap
2345 * @return The wrapped value
2347 public static Object wrap(Object object) {
2349 if (object == null) {
2352 if (object instanceof JSONObject || object instanceof JSONArray
2353 || NULL.equals(object) || object instanceof JSONString
2354 || object instanceof Byte || object instanceof Character
2355 || object instanceof Short || object instanceof Integer
2356 || object instanceof Long || object instanceof Boolean
2357 || object instanceof Float || object instanceof Double
2358 || object instanceof String || object instanceof BigInteger
2359 || object instanceof BigDecimal || object instanceof Enum) {
2363 if (object instanceof Collection) {
2364 Collection<?> coll = (Collection<?>) object;
2365 return new JSONArray(coll);
2367 if (object.getClass().isArray()) {
2368 return new JSONArray(object);
2370 if (object instanceof Map) {
2371 Map<?, ?> map = (Map<?, ?>) object;
2372 return new JSONObject(map);
2374 Package objectPackage = object.getClass().getPackage();
2375 String objectPackageName = objectPackage != null ? objectPackage
2377 if (objectPackageName.startsWith("java.")
2378 || objectPackageName.startsWith("javax.")
2379 || object.getClass().getClassLoader() == null) {
2380 return object.toString();
2382 return new JSONObject(object);
2383 } catch (Exception exception) {
2389 * Write the contents of the JSONObject as JSON text to a writer. For
2390 * compactness, no whitespace is added.
2392 * Warning: This method assumes that the data structure is acyclical.
2395 * @return The writer.
2396 * @throws JSONException
2398 public Writer write(Writer writer) throws JSONException {
2399 return this.write(writer, 0, 0);
2402 static final Writer writeValue(Writer writer, Object value,
2403 int indentFactor, int indent) throws JSONException, IOException {
2404 if (value == null || value.equals(null)) {
2405 writer.write("null");
2406 } else if (value instanceof JSONString) {
2409 o = ((JSONString) value).toJSONString();
2410 } catch (Exception e) {
2411 throw new JSONException(e);
2413 writer.write(o != null ? o.toString() : quote(value.toString()));
2414 } else if (value instanceof Number) {
2415 // not all Numbers may match actual JSON Numbers. i.e. fractions or Imaginary
2416 final String numberAsString = numberToString((Number) value);
2418 // Use the BigDecimal constructor for its parser to validate the format.
2419 @SuppressWarnings("unused")
2420 BigDecimal testNum = new BigDecimal(numberAsString);
2421 // Close enough to a JSON number that we will use it unquoted
2422 writer.write(numberAsString);
2423 } catch (NumberFormatException ex){
2424 // The Number value is not a valid JSON number.
2425 // Instead we will quote it as a string
2426 quote(numberAsString, writer);
2428 } else if (value instanceof Boolean) {
2429 writer.write(value.toString());
2430 } else if (value instanceof Enum<?>) {
2431 writer.write(quote(((Enum<?>)value).name()));
2432 } else if (value instanceof JSONObject) {
2433 ((JSONObject) value).write(writer, indentFactor, indent);
2434 } else if (value instanceof JSONArray) {
2435 ((JSONArray) value).write(writer, indentFactor, indent);
2436 } else if (value instanceof Map) {
2437 Map<?, ?> map = (Map<?, ?>) value;
2438 new JSONObject(map).write(writer, indentFactor, indent);
2439 } else if (value instanceof Collection) {
2440 Collection<?> coll = (Collection<?>) value;
2441 new JSONArray(coll).write(writer, indentFactor, indent);
2442 } else if (value.getClass().isArray()) {
2443 new JSONArray(value).write(writer, indentFactor, indent);
2445 quote(value.toString(), writer);
2450 static final void indent(Writer writer, int indent) throws IOException {
2451 for (int i = 0; i < indent; i += 1) {
2457 * Write the contents of the JSONObject as JSON text to a writer.
2459 * <p>If <code>indentFactor > 0</code> and the {@link JSONObject}
2460 * has only one key, then the object will be output on a single line:
2461 * <pre>{@code {"key": 1}}</pre>
2463 * <p>If an object has 2 or more keys, then it will be output across
2464 * multiple lines: <code><pre>{
2466 * "key2": "value 2",
2470 * Warning: This method assumes that the data structure is acyclical.
2474 * Writes the serialized JSON
2475 * @param indentFactor
2476 * The number of spaces to add to each level of indentation.
2478 * The indentation of the top level.
2479 * @return The writer.
2480 * @throws JSONException
2482 public Writer write(Writer writer, int indentFactor, int indent)
2483 throws JSONException {
2485 boolean commanate = false;
2486 final int length = this.length();
2490 final Entry<String,?> entry = this.entrySet().iterator().next();
2491 final String key = entry.getKey();
2492 writer.write(quote(key));
2494 if (indentFactor > 0) {
2498 writeValue(writer, entry.getValue(), indentFactor, indent);
2499 } catch (Exception e) {
2500 throw new JSONException("Unable to write JSONObject value for key: " + key, e);
2502 } else if (length != 0) {
2503 final int newindent = indent + indentFactor;
2504 for (final Entry<String,?> entry : this.entrySet()) {
2508 if (indentFactor > 0) {
2511 indent(writer, newindent);
2512 final String key = entry.getKey();
2513 writer.write(quote(key));
2515 if (indentFactor > 0) {
2519 writeValue(writer, entry.getValue(), indentFactor, newindent);
2520 } catch (Exception e) {
2521 throw new JSONException("Unable to write JSONObject value for key: " + key, e);
2525 if (indentFactor > 0) {
2528 indent(writer, indent);
2532 } catch (IOException exception) {
2533 throw new JSONException(exception);
2538 * Returns a java.util.Map containing all of the entries in this object.
2539 * If an entry in the object is a JSONArray or JSONObject it will also
2542 * Warning: This method assumes that the data structure is acyclical.
2544 * @return a java.util.Map containing the entries of this object
2546 public Map<String, Object> toMap() {
2547 Map<String, Object> results = new HashMap<String, Object>();
2548 for (Entry<String, Object> entry : this.entrySet()) {
2550 if (entry.getValue() == null || NULL.equals(entry.getValue())) {
2552 } else if (entry.getValue() instanceof JSONObject) {
2553 value = ((JSONObject) entry.getValue()).toMap();
2554 } else if (entry.getValue() instanceof JSONArray) {
2555 value = ((JSONArray) entry.getValue()).toList();
2557 value = entry.getValue();
2559 results.put(entry.getKey(), value);