3 import java.io.Closeable;
7 * Note: This file has been adapted for SwingJS by Bob Hanson hansonr@stolaf.edu
9 Copyright (c) 2002 JSON.org
11 Permission is hereby granted, free of charge, to any person obtaining a copy
12 of this software and associated documentation files (the "Software"), to deal
13 in the Software without restriction, including without limitation the rights
14 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15 copies of the Software, and to permit persons to whom the Software is
16 furnished to do so, subject to the following conditions:
18 The above copyright notice and this permission notice shall be included in all
19 copies or substantial portions of the Software.
21 The Software shall be used for Good, not Evil.
23 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
32 import java.io.IOException;
33 import java.io.StringWriter;
34 import java.io.Writer;
35 import java.lang.annotation.Annotation;
36 import java.lang.reflect.Field;
37 import java.lang.reflect.InvocationTargetException;
38 import java.lang.reflect.Method;
39 import java.lang.reflect.Modifier;
40 import java.math.BigDecimal;
41 import java.math.BigInteger;
42 import java.util.Collection;
43 import java.util.Enumeration;
44 import java.util.HashMap;
45 import java.util.Iterator;
46 import java.util.Locale;
48 import java.util.Map.Entry;
49 import java.util.ResourceBundle;
53 * A JSONObject is an unordered collection of name/value pairs. Its external
54 * form is a string wrapped in curly braces with colons between the names and
55 * values, and commas between the values and names. The internal form is an
56 * object having <code>get</code> and <code>opt</code> methods for accessing the
57 * values by name, and <code>put</code> methods for adding or replacing values
58 * by name. The values can be any of these types: <code>Boolean</code>,
59 * <code>JSONArray</code>, <code>JSONObject</code>, <code>Number</code>,
60 * <code>String</code>, or the <code>JSONObject.NULL</code> object. A JSONObject
61 * constructor can be used to convert an external form JSON text into an
62 * internal form whose values can be retrieved with the <code>get</code> and
63 * <code>opt</code> methods, or to convert values into a JSON text using the
64 * <code>put</code> and <code>toString</code> methods. A <code>get</code> method
65 * returns a value if one can be found, and throws an exception if one cannot be
66 * found. An <code>opt</code> method returns a default value instead of throwing
67 * an exception, and so is useful for obtaining optional values.
69 * The generic <code>get()</code> and <code>opt()</code> methods return an
70 * object, which you can cast or query for type. There are also typed
71 * <code>get</code> and <code>opt</code> methods that do type checking and type
72 * coercion for you. The opt methods differ from the get methods in that they do
73 * not throw. Instead, they return a specified value, such as null.
75 * The <code>put</code> methods add or replace values in an object. For example,
78 * myString = new JSONObject().put("JSON", "Hello, World!").toString();
81 * produces the string <code>{"JSON": "Hello, World"}</code>.
83 * The texts produced by the <code>toString</code> methods strictly conform to
84 * the JSON syntax rules. The constructors are more forgiving in the texts they
87 * <li>An extra <code>,</code> <small>(comma)</small> may appear just
88 * before the closing brace.</li>
89 * <li>Strings may be quoted with <code>'</code> <small>(single
90 * quote)</small>.</li>
91 * <li>Strings do not need to be quoted at all if they do not begin with a quote
92 * or single quote, and if they do not contain leading or trailing spaces, and
93 * if they do not contain any of these characters:
94 * <code>{ } [ ] / \ : , #</code> and if they do not look like numbers and if
95 * they are not the reserved words <code>true</code>, <code>false</code>, or
96 * <code>null</code>.</li>
100 * @version 2016-08-15
102 public class JSONObject
105 * JSONObject.NULL is equivalent to the value that JavaScript calls null,
106 * whilst Java's null is equivalent to the value that JavaScript calls
109 private static final class Null
113 * There is only intended to be a single instance of the NULL object, so the
114 * clone method returns itself.
119 protected final Object clone()
125 * A Null object is equal to the null value and to itself.
128 * An object to test for nullness.
129 * @return true if the object parameter is the JSONObject.NULL object or
133 public boolean equals(Object object)
135 return object == null || object == this;
139 * A Null object is equal to the null value and to itself.
141 * @return always returns 0.
144 public int hashCode()
150 * Get the "null" string value.
152 * @return The string "null".
155 public String toString()
162 * The map where the JSONObject's properties are kept.
164 private final Map<String, Object> map;
167 * It is sometimes more convenient and less ambiguous to have a
168 * <code>NULL</code> object than to use Java's <code>null</code> value.
169 * <code>JSONObject.NULL.equals(null)</code> returns <code>true</code>.
170 * <code>JSONObject.NULL.toString()</code> returns <code>"null"</code>.
172 public static final Object NULL = new Null();
175 * Construct an empty JSONObject.
179 // HashMap is used on purpose to ensure that elements are unordered by
180 // the specification.
181 // JSON tends to be a portable transfer format to allows the container
182 // implementations to rearrange their items for a faster element
183 // retrieval based on associative access.
184 // Therefore, an implementation mustn't rely on the order of the item.
185 this.map = new HashMap<String, Object>();
189 * Construct a JSONObject from a subset of another JSONObject. An array of
190 * strings is used to identify the keys that should be copied. Missing keys
196 * An array of strings.
198 public JSONObject(JSONObject jo, String[] names)
201 for (int i = 0; i < names.length; i += 1)
205 this.putOnce(names[i], jo.opt(names[i]));
206 } catch (Exception ignore)
213 * Construct a JSONObject from a JSONTokener.
216 * A JSONTokener object containing the source string.
217 * @throws JSONException
218 * If there is a syntax error in the source string or a duplicated
221 public JSONObject(JSONTokener x) throws JSONException
227 if (x.nextClean() != '{')
229 throw x.syntaxError("A JSONObject text must begin with '{'");
237 throw x.syntaxError("A JSONObject text must end with '}'");
242 key = x.nextValue().toString();
245 // The key is followed by ':'.
250 throw x.syntaxError("Expected a ':' after a key");
253 // Use syntaxError(..) to include error location
257 // Check if key exists
258 if (this.opt(key) != null)
260 // key already exists
261 throw x.syntaxError("Duplicate key \"" + key + "\"");
263 // Only add value if non-null
264 Object value = x.nextValue();
267 this.put(key, value);
271 // Pairs are separated by ','.
273 switch (x.nextClean())
277 if (x.nextClean() == '}')
286 throw x.syntaxError("Expected a ',' or '}'");
292 * Construct a JSONObject from a Map.
295 * A map object that can be used to initialize the contents of the
297 * @throws JSONException
298 * If a value in the map is non-finite number.
299 * @throws NullPointerException
300 * If a key in the map is <code>null</code>
302 public JSONObject(Map<?, ?> m)
306 this.map = new HashMap<String, Object>();
310 this.map = new HashMap<String, Object>(m.size());
311 for (final Entry<?, ?> e : m.entrySet())
313 if (e.getKey() == null)
315 throw new NullPointerException("Null key.");
317 final Object value = e.getValue();
320 this.map.put(String.valueOf(e.getKey()), wrap(value));
327 * Construct a JSONObject from an Object using bean getters. It reflects on
328 * all of the public methods of the object. For each of the methods with no
329 * parameters and a name starting with <code>"get"</code> or <code>"is"</code>
330 * followed by an uppercase letter, the method is invoked, and a key and the
331 * value returned from the getter method are put into the new JSONObject.
333 * The key is formed by removing the <code>"get"</code> or <code>"is"</code>
334 * prefix. If the second remaining character is not upper case, then the first
335 * character is converted to lower case.
337 * Methods that are <code>static</code>, return <code>void</code>, have
338 * parameters, or are "bridge" methods, are ignored.
340 * For example, if an object has a method named <code>"getName"</code>, and if
341 * the result of calling <code>object.getName()</code> is
342 * <code>"Larry Fine"</code>, then the JSONObject will contain
343 * <code>"name": "Larry Fine"</code>.
345 * The {@link JSONPropertyName} annotation can be used on a bean getter to
346 * override key name used in the JSONObject. For example, using the object
347 * above with the <code>getName</code> method, if we annotated it with:
350 * @JSONPropertyName("FullName")
351 * public String getName()
357 * The resulting JSON object would contain
358 * <code>"FullName": "Larry Fine"</code>
360 * Similarly, the {@link JSONPropertyName} annotation can be used on non-
361 * <code>get</code> and <code>is</code> methods. We can also override key name
362 * used in the JSONObject as seen below even though the field would normally
366 * @JSONPropertyName("FullName")
367 * public String fullName()
373 * The resulting JSON object would contain
374 * <code>"FullName": "Larry Fine"</code>
376 * The {@link JSONPropertyIgnore} annotation can be used to force the bean
377 * property to not be serialized into JSON. If both {@link JSONPropertyIgnore}
378 * and {@link JSONPropertyName} are defined on the same method, a depth
379 * comparison is performed and the one closest to the concrete class being
380 * serialized is used. If both annotations are at the same level, then the
381 * {@link JSONPropertyIgnore} annotation takes precedent and the field is not
382 * serialized. For example, the following declaration would prevent the
383 * <code>getName</code> method from being serialized:
386 * @JSONPropertyName("FullName")
387 * @JSONPropertyIgnore
388 * public String getName()
396 * An object that has getter methods that should be used to make a
399 public JSONObject(Object bean)
402 this.populateMap(bean);
406 * Construct a JSONObject from an Object, using reflection to find the public
407 * members. The resulting JSONObject's keys will be the strings from the names
408 * array, and the values will be the field values associated with those keys
409 * in the object. If a key is not found or not visible, then it will not be
410 * copied into the new JSONObject.
413 * An object that has fields that should be used to make a
416 * An array of strings, the names of the fields to be obtained from
419 public JSONObject(Object object, String names[])
422 Class<?> c = object.getClass();
423 for (int i = 0; i < names.length; i += 1)
425 String name = names[i];
428 this.putOpt(name, c.getField(name).get(object));
429 } catch (Exception ignore)
436 * Construct a JSONObject from a source JSON text string. This is the most
437 * commonly used JSONObject constructor.
440 * A string beginning with <code>{</code> <small>(left
441 * brace)</small> and ending with <code>}</code> <small>(right
443 * @exception JSONException
444 * If there is a syntax error in the source string or a
447 public JSONObject(String source) throws JSONException
449 this(new JSONTokener(source));
453 * Construct a JSONObject from a ResourceBundle.
456 * The ResourceBundle base name.
458 * The Locale to load the ResourceBundle for.
459 * @throws JSONException
460 * If any JSONExceptions are detected.
462 public JSONObject(String baseName, Locale locale) throws JSONException
465 ResourceBundle bundle = ResourceBundle.getBundle(baseName, locale,
466 Thread.currentThread().getContextClassLoader());
468 // Iterate through the keys in the bundle.
470 Enumeration<String> keys = bundle.getKeys();
471 while (keys.hasMoreElements())
473 Object key = keys.nextElement();
477 // Go through the path, ensuring that there is a nested JSONObject for
479 // segment except the last. Add the value using the last segment's name
481 // the deepest nested JSONObject.
483 String[] path = ((String) key).split("\\.");
484 int last = path.length - 1;
485 JSONObject target = this;
486 for (int i = 0; i < last; i += 1)
488 String segment = path[i];
489 JSONObject nextTarget = target.optJSONObject(segment);
490 if (nextTarget == null)
492 nextTarget = new JSONObject();
493 target.put(segment, nextTarget);
497 target.put(path[last], bundle.getString((String) key));
503 * Constructor to specify an initial capacity of the internal map. Useful for
504 * library internal calls where we know, or at least can best guess, how big
505 * this JSONObject will be.
507 * @param initialCapacity
508 * initial capacity of the internal map.
510 protected JSONObject(int initialCapacity)
512 this.map = new HashMap<String, Object>(initialCapacity);
516 * Accumulate values under a key. It is similar to the put method except that
517 * if there is already an object stored under the key then a JSONArray is
518 * stored under the key to hold all of the accumulated values. If there is
519 * already a JSONArray, then the new value is appended to it. In contrast, the
520 * put method replaces the previous value.
522 * If only one value is accumulated that is not a JSONArray, then the result
523 * will be the same as using put. But if multiple values are accumulated, then
524 * the result will be like append.
529 * An object to be accumulated under the key.
531 * @throws JSONException
532 * If the value is non-finite number.
533 * @throws NullPointerException
534 * If the key is <code>null</code>.
536 public JSONObject accumulate(String key, Object value)
540 Object object = this.opt(key);
543 this.put(key, value instanceof JSONArray ? new JSONArray().put(value)
546 else if (object instanceof JSONArray)
548 ((JSONArray) object).put(value);
552 this.put(key, new JSONArray().put(object).put(value));
558 * Append values to the array under a key. If the key does not exist in the
559 * JSONObject, then the key is put in the JSONObject with its value being a
560 * JSONArray containing the value parameter. If the key was already associated
561 * with a JSONArray, then the value parameter is appended to it.
566 * An object to be accumulated under the key.
568 * @throws JSONException
569 * If the value is non-finite number or if the current value
570 * associated with the key is not a JSONArray.
571 * @throws NullPointerException
572 * If the key is <code>null</code>.
574 public JSONObject append(String key, Object value) throws JSONException
577 Object object = this.opt(key);
580 this.put(key, new JSONArray().put(value));
582 else if (object instanceof JSONArray)
584 this.put(key, ((JSONArray) object).put(value));
588 throw new JSONException(
589 "JSONObject[" + key + "] is not a JSONArray.");
595 * Produce a string from a double. The string "null" will be returned if the
596 * number is not finite.
602 public static String doubleToString(double d)
604 if (Double.isInfinite(d) || Double.isNaN(d))
609 // Shave off trailing zeros and decimal point, if possible.
611 String string = Double.toString(d);
612 if (string.indexOf('.') > 0 && string.indexOf('e') < 0
613 && string.indexOf('E') < 0)
615 while (string.endsWith("0"))
617 string = string.substring(0, string.length() - 1);
619 if (string.endsWith("."))
621 string = string.substring(0, string.length() - 1);
628 * Get the value object associated with a key.
632 * @return The object associated with the key.
633 * @throws JSONException
634 * if the key is not found.
636 public Object get(String key) throws JSONException
640 throw new JSONException("Null key.");
642 Object object = this.opt(key);
645 throw new JSONException("JSONObject[" + quote(key) + "] not found.");
651 * Get the enum value associated with a key.
654 * The type of enum to retrieve.
657 * @return The enum value associated with the key
658 * @throws JSONException
659 * if the key is not found or if the value cannot be converted to an
662 public <E extends Enum<E>> E getEnum(Class<E> clazz, String key)
665 E val = optEnum(clazz, key);
668 // JSONException should really take a throwable argument.
669 // If it did, I would re-implement this with the Enum.valueOf
670 // method and place any thrown exception in the JSONException
671 throw new JSONException(
672 "JSONObject[" + quote(key) + "] is not an enum of type "
673 + quote(clazz.getSimpleName()) + ".");
679 * Get the boolean value associated with a key.
684 * @throws JSONException
685 * if the value is not a Boolean or the String "true" or "false".
687 public boolean getBoolean(String key) throws JSONException
689 Object object = this.get(key);
690 if (object.equals(Boolean.FALSE) || (object instanceof String
691 && ((String) object).equalsIgnoreCase("false")))
695 else if (object.equals(Boolean.TRUE) || (object instanceof String
696 && ((String) object).equalsIgnoreCase("true")))
700 throw new JSONException(
701 "JSONObject[" + quote(key) + "] is not a Boolean.");
705 * Get the BigInteger value associated with a key.
709 * @return The numeric value.
710 * @throws JSONException
711 * if the key is not found or if the value cannot be converted to
714 public BigInteger getBigInteger(String key) throws JSONException
716 Object object = this.get(key);
719 return new BigInteger(object.toString());
720 } catch (Exception e)
722 throw new JSONException("JSONObject[" + quote(key)
723 + "] could not be converted to BigInteger.", e);
728 * Get the BigDecimal value associated with a key.
732 * @return The numeric value.
733 * @throws JSONException
734 * if the key is not found or if the value cannot be converted to
737 public BigDecimal getBigDecimal(String key) throws JSONException
739 Object object = this.get(key);
740 if (object instanceof BigDecimal)
742 return (BigDecimal) object;
746 return new BigDecimal(object.toString());
747 } catch (Exception e)
749 throw new JSONException("JSONObject[" + quote(key)
750 + "] could not be converted to BigDecimal.", e);
755 * Get the double value associated with a key.
759 * @return The numeric value.
760 * @throws JSONException
761 * if the key is not found or if the value is not a Number object
762 * and cannot be converted to a number.
764 public double getDouble(String key) throws JSONException
766 Object object = this.get(key);
769 return object instanceof Number ? ((Number) object).doubleValue()
770 : Double.parseDouble(object.toString());
771 } catch (Exception e)
773 throw new JSONException(
774 "JSONObject[" + quote(key) + "] is not a number.", e);
779 * Get the float value associated with a key.
783 * @return The numeric value.
784 * @throws JSONException
785 * if the key is not found or if the value is not a Number object
786 * and cannot be converted to a number.
788 public float getFloat(String key) throws JSONException
790 Object object = this.get(key);
793 return object instanceof Number ? ((Number) object).floatValue()
794 : Float.parseFloat(object.toString());
795 } catch (Exception e)
797 throw new JSONException(
798 "JSONObject[" + quote(key) + "] is not a number.", e);
803 * Get the Number value associated with a key.
807 * @return The numeric value.
808 * @throws JSONException
809 * if the key is not found or if the value is not a Number object
810 * and cannot be converted to a number.
812 public Number getNumber(String key) throws JSONException
814 Object object = this.get(key);
817 if (object instanceof Number)
819 return (Number) object;
821 return stringToNumber(object.toString());
822 } catch (Exception e)
824 throw new JSONException(
825 "JSONObject[" + quote(key) + "] is not a number.", e);
830 * Get the int value associated with a key.
834 * @return The integer value.
835 * @throws JSONException
836 * if the key is not found or if the value cannot be converted to an
839 public int getInt(String key) throws JSONException
841 Object object = this.get(key);
844 return object instanceof Number ? ((Number) object).intValue()
845 : Integer.parseInt((String) object);
846 } catch (Exception e)
848 throw new JSONException(
849 "JSONObject[" + quote(key) + "] is not an int.", e);
854 * Get the JSONArray value associated with a key.
858 * @return A JSONArray which is the value.
859 * @throws JSONException
860 * if the key is not found or if the value is not a JSONArray.
862 public JSONArray getJSONArray(String key) throws JSONException
864 Object object = this.get(key);
865 if (object instanceof JSONArray)
867 return (JSONArray) object;
869 throw new JSONException(
870 "JSONObject[" + quote(key) + "] is not a JSONArray.");
874 * Get the JSONObject value associated with a key.
878 * @return A JSONObject which is the value.
879 * @throws JSONException
880 * if the key is not found or if the value is not a JSONObject.
882 public JSONObject getJSONObject(String key) throws JSONException
884 Object object = this.get(key);
885 if (object instanceof JSONObject)
887 return (JSONObject) object;
889 throw new JSONException(
890 "JSONObject[" + quote(key) + "] is not a JSONObject.");
894 * Get the long value associated with a key.
898 * @return The long value.
899 * @throws JSONException
900 * if the key is not found or if the value cannot be converted to a
903 public long getLong(String key) throws JSONException
905 Object object = this.get(key);
908 return object instanceof Number ? ((Number) object).longValue()
909 : Long.parseLong((String) object);
910 } catch (Exception e)
912 throw new JSONException(
913 "JSONObject[" + quote(key) + "] is not a long.", e);
918 * Get an array of field names from a JSONObject.
920 * @return An array of field names, or null if there are no names.
922 public static String[] getNames(JSONObject jo)
928 return jo.keySet().toArray(new String[jo.length()]);
932 * Get an array of field names from an Object.
934 * @return An array of field names, or null if there are no names.
936 public static String[] getNames(Object object)
942 Class<?> klass = object.getClass();
943 Field[] fields = klass.getFields();
944 int length = fields.length;
949 String[] names = new String[length];
950 for (int i = 0; i < length; i += 1)
952 names[i] = fields[i].getName();
958 * Get the string associated with a key.
962 * @return A string which is the value.
963 * @throws JSONException
964 * if there is no string value for the key.
966 public String getString(String key) throws JSONException
968 Object object = this.get(key);
969 if (object instanceof String)
971 return (String) object;
973 throw new JSONException("JSONObject[" + quote(key) + "] not a string.");
977 * Determine if the JSONObject contains a specific key.
981 * @return true if the key exists in the JSONObject.
983 public boolean has(String key)
985 return this.map.containsKey(key);
989 * Increment a property of a JSONObject. If there is no such property, create
990 * one with a value of 1. If there is such a property, and if it is an
991 * Integer, Long, Double, or Float, then add one to it.
996 * @throws JSONException
997 * If there is already a property with this name that is not an
998 * Integer, Long, Double, or Float.
1000 public JSONObject increment(String key) throws JSONException
1002 Object value = this.opt(key);
1007 else if (value instanceof BigInteger)
1009 this.put(key, ((BigInteger) value).add(BigInteger.ONE));
1011 else if (value instanceof BigDecimal)
1013 this.put(key, ((BigDecimal) value).add(BigDecimal.ONE));
1015 else if (value instanceof Integer)
1017 this.put(key, ((Integer) value).intValue() + 1);
1019 else if (value instanceof Long)
1021 this.put(key, ((Long) value).longValue() + 1L);
1023 else if (value instanceof Double)
1025 this.put(key, ((Double) value).doubleValue() + 1.0d);
1027 else if (value instanceof Float)
1029 this.put(key, ((Float) value).floatValue() + 1.0f);
1033 throw new JSONException("Unable to increment [" + quote(key) + "].");
1039 * Determine if the value associated with the key is <code>null</code> or if
1040 * there is no value.
1044 * @return true if there is no value associated with the key or if the value
1045 * is the JSONObject.NULL object.
1047 public boolean isNull(String key)
1049 return JSONObject.NULL.equals(this.opt(key));
1053 * Get an enumeration of the keys of the JSONObject. Modifying this key Set
1054 * will also modify the JSONObject. Use with caution.
1056 * @see Set#iterator()
1058 * @return An iterator of the keys.
1060 public Iterator<String> keys()
1062 return this.keySet().iterator();
1066 * Get a set of keys of the JSONObject. Modifying this key Set will also
1067 * modify the JSONObject. Use with caution.
1073 public Set<String> keySet()
1075 return this.map.keySet();
1079 * Get a set of entries of the JSONObject. These are raw values and may not
1080 * match what is returned by the JSONObject get* and opt* functions. Modifying
1081 * the returned EntrySet or the Entry objects contained therein will modify
1082 * the backing JSONObject. This does not return a clone or a read-only view.
1086 * @see Map#entrySet()
1088 * @return An Entry Set
1090 protected Set<Entry<String, Object>> entrySet()
1092 return this.map.entrySet();
1096 * Get the number of keys stored in the JSONObject.
1098 * @return The number of keys in the JSONObject.
1102 return this.map.size();
1106 * Check if JSONObject is empty.
1108 * @return true if JSONObject is empty, otherwise false.
1110 public boolean isEmpty()
1112 return map.isEmpty();
1116 * Produce a JSONArray containing the names of the elements of this
1119 * @return A JSONArray containing the key strings, or null if the JSONObject
1122 public JSONArray names()
1124 if (this.map.isEmpty())
1128 return new JSONArray(this.map.keySet());
1132 * Produce a string from a Number.
1137 * @throws JSONException
1138 * If n is a non-finite number.
1140 public static String numberToString(Number number) throws JSONException
1144 throw new JSONException("Null pointer");
1146 testValidity(number);
1148 // Shave off trailing zeros and decimal point, if possible.
1150 String string = number.toString();
1151 if (string.indexOf('.') > 0 && string.indexOf('e') < 0
1152 && string.indexOf('E') < 0)
1154 while (string.endsWith("0"))
1156 string = string.substring(0, string.length() - 1);
1158 if (string.endsWith("."))
1160 string = string.substring(0, string.length() - 1);
1167 * Get an optional value associated with a key.
1171 * @return An object which is the value, or null if there is no value.
1173 public Object opt(String key)
1175 return key == null ? null : this.map.get(key);
1179 * Get the enum value associated with a key.
1182 * The type of enum to retrieve.
1185 * @return The enum value associated with the key or null if not found
1187 public <E extends Enum<E>> E optEnum(Class<E> clazz, String key)
1189 return this.optEnum(clazz, key, null);
1193 * Get the enum value associated with a key.
1196 * The type of enum to retrieve.
1199 * @param defaultValue
1200 * The default in case the value is not found
1201 * @return The enum value associated with the key or defaultValue if the value
1202 * is not found or cannot be assigned to <code>clazz</code>
1204 public <E extends Enum<E>> E optEnum(Class<E> clazz, String key,
1209 Object val = this.opt(key);
1210 if (NULL.equals(val))
1212 return defaultValue;
1214 if (clazz.isAssignableFrom(val.getClass()))
1216 // we just checked it!
1217 @SuppressWarnings("unchecked")
1221 return Enum.valueOf(clazz, val.toString());
1222 } catch (IllegalArgumentException e)
1224 return defaultValue;
1225 } catch (NullPointerException e)
1227 return defaultValue;
1232 * Get an optional boolean associated with a key. It returns false if there is
1233 * no such key, or if the value is not Boolean.TRUE or the String "true".
1237 * @return The truth.
1239 public boolean optBoolean(String key)
1241 return this.optBoolean(key, false);
1245 * Get an optional boolean associated with a key. It returns the defaultValue
1246 * if there is no such key, or if it is not a Boolean or the String "true" or
1247 * "false" (case insensitive).
1251 * @param defaultValue
1253 * @return The truth.
1255 public boolean optBoolean(String key, boolean defaultValue)
1257 Object val = this.opt(key);
1258 if (NULL.equals(val))
1260 return defaultValue;
1262 if (val instanceof Boolean)
1264 return ((Boolean) val).booleanValue();
1268 // we'll use the get anyway because it does string conversion.
1269 return this.getBoolean(key);
1270 } catch (Exception e)
1272 return defaultValue;
1277 * Get an optional BigDecimal associated with a key, or the defaultValue if
1278 * there is no such key or if its value is not a number. If the value is a
1279 * string, an attempt will be made to evaluate it as a number.
1283 * @param defaultValue
1285 * @return An object which is the value.
1287 public BigDecimal optBigDecimal(String key, BigDecimal defaultValue)
1289 Object val = this.opt(key);
1290 if (NULL.equals(val))
1292 return defaultValue;
1294 if (val instanceof BigDecimal)
1296 return (BigDecimal) val;
1298 if (val instanceof BigInteger)
1300 return new BigDecimal((BigInteger) val);
1302 if (val instanceof Double || val instanceof Float)
1304 return new BigDecimal(((Number) val).doubleValue());
1306 if (val instanceof Long || val instanceof Integer
1307 || val instanceof Short || val instanceof Byte)
1309 return new BigDecimal(((Number) val).longValue());
1311 // don't check if it's a string in case of unchecked Number subclasses
1314 return new BigDecimal(val.toString());
1315 } catch (Exception e)
1317 return defaultValue;
1322 * Get an optional BigInteger associated with a key, or the defaultValue if
1323 * there is no such key or if its value is not a number. If the value is a
1324 * string, an attempt will be made to evaluate it as a number.
1328 * @param defaultValue
1330 * @return An object which is the value.
1332 public BigInteger optBigInteger(String key, BigInteger defaultValue)
1334 Object val = this.opt(key);
1335 if (NULL.equals(val))
1337 return defaultValue;
1339 if (val instanceof BigInteger)
1341 return (BigInteger) val;
1343 if (val instanceof BigDecimal)
1345 return ((BigDecimal) val).toBigInteger();
1347 if (val instanceof Double || val instanceof Float)
1349 return new BigDecimal(((Number) val).doubleValue()).toBigInteger();
1351 if (val instanceof Long || val instanceof Integer
1352 || val instanceof Short || val instanceof Byte)
1354 return BigInteger.valueOf(((Number) val).longValue());
1356 // don't check if it's a string in case of unchecked Number subclasses
1359 // the other opt functions handle implicit conversions, i.e.
1360 // jo.put("double",1.1d);
1361 // jo.optInt("double"); -- will return 1, not an error
1362 // this conversion to BigDecimal then to BigInteger is to maintain
1363 // that type cast support that may truncate the decimal.
1364 final String valStr = val.toString();
1365 if (isDecimalNotation(valStr))
1367 return new BigDecimal(valStr).toBigInteger();
1369 return new BigInteger(valStr);
1370 } catch (Exception e)
1372 return defaultValue;
1377 * Get an optional double associated with a key, or NaN if there is no such
1378 * key or if its value is not a number. If the value is a string, an attempt
1379 * will be made to evaluate it as a number.
1382 * A string which is the key.
1383 * @return An object which is the value.
1385 public double optDouble(String key)
1387 return this.optDouble(key, Double.NaN);
1391 * Get an optional double associated with a key, or the defaultValue if there
1392 * is no such key or if its value is not a number. If the value is a string,
1393 * an attempt will be made to evaluate it as a number.
1397 * @param defaultValue
1399 * @return An object which is the value.
1401 public double optDouble(String key, double defaultValue)
1403 Object val = this.opt(key);
1404 if (NULL.equals(val))
1406 return defaultValue;
1408 if (val instanceof Number)
1410 return ((Number) val).doubleValue();
1412 if (val instanceof String)
1416 return Double.parseDouble((String) val);
1417 } catch (Exception e)
1419 return defaultValue;
1422 return defaultValue;
1426 * Get the optional double value associated with an index. NaN is returned if
1427 * there is no value for the index, or if the value is not a number and cannot
1428 * be converted to a number.
1432 * @return The value.
1434 public float optFloat(String key)
1436 return this.optFloat(key, Float.NaN);
1440 * Get the optional double value associated with an index. The defaultValue is
1441 * returned if there is no value for the index, or if the value is not a
1442 * number and cannot be converted to a number.
1446 * @param defaultValue
1447 * The default value.
1448 * @return The value.
1450 public float optFloat(String key, float defaultValue)
1452 Object val = this.opt(key);
1453 if (JSONObject.NULL.equals(val))
1455 return defaultValue;
1457 if (val instanceof Number)
1459 return ((Number) val).floatValue();
1461 if (val instanceof String)
1465 return Float.parseFloat((String) val);
1466 } catch (Exception e)
1468 return defaultValue;
1471 return defaultValue;
1475 * Get an optional int value associated with a key, or zero if there is no
1476 * such key or if the value is not a number. If the value is a string, an
1477 * attempt will be made to evaluate it as a number.
1481 * @return An object which is the value.
1483 public int optInt(String key)
1485 return this.optInt(key, 0);
1489 * Get an optional int value associated with a key, or the default if there is
1490 * no such key or if the value is not a number. If the value is a string, an
1491 * attempt will be made to evaluate it as a number.
1495 * @param defaultValue
1497 * @return An object which is the value.
1499 public int optInt(String key, int defaultValue)
1501 Object val = this.opt(key);
1502 if (NULL.equals(val))
1504 return defaultValue;
1506 if (val instanceof Number)
1508 return ((Number) val).intValue();
1511 if (val instanceof String)
1515 return new BigDecimal((String) val).intValue();
1516 } catch (Exception e)
1518 return defaultValue;
1521 return defaultValue;
1525 * Get an optional JSONArray associated with a key. It returns null if there
1526 * is no such key, or if its value is not a JSONArray.
1530 * @return A JSONArray which is the value.
1532 public JSONArray optJSONArray(String key)
1534 Object o = this.opt(key);
1535 return o instanceof JSONArray ? (JSONArray) o : null;
1539 * Get an optional JSONObject associated with a key. It returns null if there
1540 * is no such key, or if its value is not a JSONObject.
1544 * @return A JSONObject which is the value.
1546 public JSONObject optJSONObject(String key)
1548 Object object = this.opt(key);
1549 return object instanceof JSONObject ? (JSONObject) object : null;
1553 * Get an optional long value associated with a key, or zero if there is no
1554 * such key or if the value is not a number. If the value is a string, an
1555 * attempt will be made to evaluate it as a number.
1559 * @return An object which is the value.
1561 public long optLong(String key)
1563 return this.optLong(key, 0);
1567 * Get an optional long value associated with a key, or the default if there
1568 * is no such key or if the value is not a number. If the value is a string,
1569 * an attempt will be made to evaluate it as a number.
1573 * @param defaultValue
1575 * @return An object which is the value.
1577 public long optLong(String key, long defaultValue)
1579 Object val = this.opt(key);
1580 if (NULL.equals(val))
1582 return defaultValue;
1584 if (val instanceof Number)
1586 return ((Number) val).longValue();
1589 if (val instanceof String)
1593 return new BigDecimal((String) val).longValue();
1594 } catch (Exception e)
1596 return defaultValue;
1599 return defaultValue;
1603 * Get an optional {@link Number} value associated with a key, or
1604 * <code>null</code> if there is no such key or if the value is not a number.
1605 * If the value is a string, an attempt will be made to evaluate it as a
1606 * number ({@link BigDecimal}). This method would be used in cases where type
1607 * coercion of the number value is unwanted.
1611 * @return An object which is the value.
1613 public Number optNumber(String key)
1615 return this.optNumber(key, null);
1619 * Get an optional {@link Number} value associated with a key, or the default
1620 * if there is no such key or if the value is not a number. If the value is a
1621 * string, an attempt will be made to evaluate it as a number. This method
1622 * would be used in cases where type coercion of the number value is unwanted.
1626 * @param defaultValue
1628 * @return An object which is the value.
1630 public Number optNumber(String key, Number defaultValue)
1632 Object val = this.opt(key);
1633 if (NULL.equals(val))
1635 return defaultValue;
1637 if (val instanceof Number)
1639 return (Number) val;
1642 if (val instanceof String)
1646 return stringToNumber((String) val);
1647 } catch (Exception e)
1649 return defaultValue;
1652 return defaultValue;
1656 * Get an optional string associated with a key. It returns an empty string if
1657 * there is no such key. If the value is not a string and is not null, then it
1658 * is converted to a string.
1662 * @return A string which is the value.
1664 public String optString(String key)
1666 return this.optString(key, "");
1670 * Get an optional string associated with a key. It returns the defaultValue
1671 * if there is no such key.
1675 * @param defaultValue
1677 * @return A string which is the value.
1679 public String optString(String key, String defaultValue)
1681 Object object = this.opt(key);
1682 return NULL.equals(object) ? defaultValue : object.toString();
1686 * Populates the internal map of the JSONObject with the bean properties. The
1687 * bean can not be recursive.
1689 * @see JSONObject#JSONObject(Object)
1694 private void populateMap(Object bean)
1696 Class<?> klass = bean.getClass();
1698 // If klass is a System class then set includeSuperClass to false.
1700 boolean includeSuperClass = klass.getClassLoader() != null;
1702 Method[] methods = includeSuperClass ? klass.getMethods()
1703 : klass.getDeclaredMethods();
1704 for (final Method method : methods)
1706 final int modifiers = method.getModifiers();
1707 if (Modifier.isPublic(modifiers) && !Modifier.isStatic(modifiers)
1708 && method.getParameterTypes().length == 0
1709 && !method.isBridge() && method.getReturnType() != Void.TYPE
1710 && isValidMethodName(method.getName()))
1712 final String key = getKeyNameFromMethod(method);
1713 if (key != null && !key.isEmpty())
1717 final Object result = method.invoke(bean);
1720 this.map.put(key, wrap(result));
1721 // we don't use the result anywhere outside of wrap
1722 // if it's a resource we should be sure to close it
1723 // after calling toString
1724 if (result instanceof Closeable)
1728 ((Closeable) result).close();
1729 } catch (IOException ignore)
1734 } catch (IllegalAccessException ignore)
1736 } catch (IllegalArgumentException ignore)
1738 } catch (InvocationTargetException ignore)
1746 private boolean isValidMethodName(String name)
1748 return !"getClass".equals(name) && !"getDeclaringClass".equals(name);
1751 private String getKeyNameFromMethod(Method method)
1753 final int ignoreDepth = -1;// getAnnotationDepth(method,
1754 // JSONPropertyIgnore.class);
1755 // if (ignoreDepth > 0) {
1756 // final int forcedNameDepth = getAnnotationDepth(method,
1757 // JSONPropertyName.class);
1758 // if (forcedNameDepth < 0 || ignoreDepth <= forcedNameDepth) {
1759 // // the hierarchy asked to ignore, and the nearest name override
1760 // // was higher or non-existent
1764 // JSONPropertyName annotation = getAnnotation(method,
1765 // JSONPropertyName.class);
1766 // if (annotation != null && annotation.value() != null &&
1767 // !annotation.value().isEmpty()) {
1768 // return annotation.value();
1771 final String name = method.getName();
1772 if (name.startsWith("get") && name.length() > 3)
1774 key = name.substring(3);
1776 else if (name.startsWith("is") && name.length() > 2)
1778 key = name.substring(2);
1784 // if the first letter in the key is not uppercase, then skip.
1785 // This is to maintain backwards compatibility before PR406
1786 // (https://github.com/stleary/JSON-java/pull/406/)
1787 if (Character.isLowerCase(key.charAt(0)))
1791 if (key.length() == 1)
1793 key = key.toLowerCase(Locale.ROOT);
1795 else if (!Character.isUpperCase(key.charAt(1)))
1797 key = key.substring(0, 1).toLowerCase(Locale.ROOT) + key.substring(1);
1799 return (/** @j2sNative 1 ? key.split("$")[0] : */
1804 // * Searches the class hierarchy to see if the method or it's super
1805 // * implementations and interfaces has the annotation.
1808 // * type of the annotation
1811 // * method to check
1812 // * @param annotationClass
1813 // * annotation to look for
1814 // * @return the {@link Annotation} if the annotation exists on the current
1816 // * or one of it's super class definitions
1818 // private static <A extends Annotation> A getAnnotation(final Method m, final
1819 // Class<A> annotationClass) {
1821 // // if we have invalid data the result is null
1822 // if (true || m == null || annotationClass == null) {
1826 // if (m.isAnnotationPresent(annotationClass)) {
1827 // return m.getAnnotation(annotationClass);
1830 // // if we've already reached the Object class, return null;
1831 // Class<?> c = m.getDeclaringClass();
1832 // if (c.getSuperclass() == null) {
1836 // // check directly implemented interfaces for the method being checked
1837 // for (Class<?> i : c.getInterfaces()) {
1839 // Method im = i.getMethod(m.getName(), m.getParameterTypes());
1840 // return getAnnotation(im, annotationClass);
1841 // } catch (final SecurityException ex) {
1843 // } catch (final NoSuchMethodException ex) {
1849 // return getAnnotation(
1850 // c.getSuperclass().getMethod(m.getName(), m.getParameterTypes()),
1851 // annotationClass);
1852 // } catch (final SecurityException ex) {
1854 // } catch (final NoSuchMethodException ex) {
1860 // * Searches the class hierarchy to see if the method or it's super
1861 // * implementations and interfaces has the annotation. Returns the depth of
1863 // * annotation in the hierarchy.
1866 // * type of the annotation
1869 // * method to check
1870 // * @param annotationClass
1871 // * annotation to look for
1872 // * @return Depth of the annotation or -1 if the annotation is not on the
1875 // private static int getAnnotationDepth(final Method m, final Class<? extends
1876 // Annotation> annotationClass) {
1877 // // if we have invalid data the result is -1
1878 // if (m == null || annotationClass == null) {
1881 // if (m.isAnnotationPresent(annotationClass)) {
1885 // // if we've already reached the Object class, return -1;
1886 // Class<?> c = m.getDeclaringClass();
1887 // if (c.getSuperclass() == null) {
1891 // // check directly implemented interfaces for the method being checked
1892 // for (Class<?> i : c.getInterfaces()) {
1894 // Method im = i.getMethod(m.getName(), m.getParameterTypes());
1895 // int d = getAnnotationDepth(im, annotationClass);
1897 // // since the annotation was on the interface, add 1
1900 // } catch (final SecurityException ex) {
1902 // } catch (final NoSuchMethodException ex) {
1908 // int d = getAnnotationDepth(
1909 // c.getSuperclass().getMethod(m.getName(), m.getParameterTypes()),
1910 // annotationClass);
1912 // // since the annotation was on the superclass, add 1
1916 // } catch (final SecurityException ex) {
1918 // } catch (final NoSuchMethodException ex) {
1924 * Put a key/boolean pair in the JSONObject.
1929 * A boolean which is the value.
1931 * @throws JSONException
1932 * If the value is non-finite number.
1933 * @throws NullPointerException
1934 * If the key is <code>null</code>.
1936 public JSONObject put(String key, boolean value) throws JSONException
1938 return this.put(key, value ? Boolean.TRUE : Boolean.FALSE);
1942 * Put a key/value pair in the JSONObject, where the value will be a JSONArray
1943 * which is produced from a Collection.
1948 * A Collection value.
1950 * @throws JSONException
1951 * If the value is non-finite number.
1952 * @throws NullPointerException
1953 * If the key is <code>null</code>.
1955 public JSONObject put(String key, Collection<?> value)
1956 throws JSONException
1958 return this.put(key, new JSONArray(value));
1962 * Put a key/double pair in the JSONObject.
1967 * A double which is the value.
1969 * @throws JSONException
1970 * If the value is non-finite number.
1971 * @throws NullPointerException
1972 * If the key is <code>null</code>.
1974 public JSONObject put(String key, double value) throws JSONException
1976 return this.put(key, Double.valueOf(value));
1980 * Put a key/float pair in the JSONObject.
1985 * A float which is the value.
1987 * @throws JSONException
1988 * If the value is non-finite number.
1989 * @throws NullPointerException
1990 * If the key is <code>null</code>.
1992 public JSONObject put(String key, float value) throws JSONException
1994 return this.put(key, Float.valueOf(value));
1998 * Put a key/int pair in the JSONObject.
2003 * An int which is the value.
2005 * @throws JSONException
2006 * If the value is non-finite number.
2007 * @throws NullPointerException
2008 * If the key is <code>null</code>.
2010 public JSONObject put(String key, int value) throws JSONException
2012 return this.put(key, Integer.valueOf(value));
2016 * Put a key/long pair in the JSONObject.
2021 * A long which is the value.
2023 * @throws JSONException
2024 * If the value is non-finite number.
2025 * @throws NullPointerException
2026 * If the key is <code>null</code>.
2028 public JSONObject put(String key, long value) throws JSONException
2030 return this.put(key, Long.valueOf(value));
2034 * Put a key/value pair in the JSONObject, where the value will be a
2035 * JSONObject which is produced from a Map.
2042 * @throws JSONException
2043 * If the value is non-finite number.
2044 * @throws NullPointerException
2045 * If the key is <code>null</code>.
2047 public JSONObject put(String key, Map<?, ?> value) throws JSONException
2049 return this.put(key, new JSONObject(value));
2053 * Put a key/value pair in the JSONObject. If the value is <code>null</code>,
2054 * then the key will be removed from the JSONObject if it is present.
2059 * An object which is the value. It should be of one of these types:
2060 * Boolean, Double, Integer, JSONArray, JSONObject, Long, String, or
2061 * the JSONObject.NULL object.
2063 * @throws JSONException
2064 * If the value is non-finite number.
2065 * @throws NullPointerException
2066 * If the key is <code>null</code>.
2068 public JSONObject put(String key, Object value) throws JSONException
2072 throw new NullPointerException("Null key.");
2076 testValidity(value);
2077 this.map.put(key, value);
2087 * Put a key/value pair in the JSONObject, but only if the key and the value
2088 * are both non-null, and only if there is not already a member with that
2096 * @throws JSONException
2097 * if the key is a duplicate
2099 public JSONObject putOnce(String key, Object value) throws JSONException
2101 if (key != null && value != null)
2103 if (this.opt(key) != null)
2105 throw new JSONException("Duplicate key \"" + key + "\"");
2107 return this.put(key, value);
2113 * Put a key/value pair in the JSONObject, but only if the key and the value
2114 * are both non-null.
2119 * An object which is the value. It should be of one of these types:
2120 * Boolean, Double, Integer, JSONArray, JSONObject, Long, String, or
2121 * the JSONObject.NULL object.
2123 * @throws JSONException
2124 * If the value is a non-finite number.
2126 public JSONObject putOpt(String key, Object value) throws JSONException
2128 if (key != null && value != null)
2130 return this.put(key, value);
2136 * Creates a JSONPointer using an initialization string and tries to match it
2137 * to an item within this JSONObject. For example, given a JSONObject
2138 * initialized with this document:
2146 * and this JSONPointer string:
2152 * Then this method will return the String "c". A JSONPointerException may be
2153 * thrown from code called by this method.
2155 * @param jsonPointer
2156 * string that can be used to create a JSONPointer
2157 * @return the item matched by the JSONPointer, otherwise null
2159 public Object query(String jsonPointer)
2161 return query(new JSONPointer(jsonPointer));
2165 * Uses a user initialized JSONPointer and tries to match it to an item within
2166 * this JSONObject. For example, given a JSONObject initialized with this
2175 * and this JSONPointer:
2181 * Then this method will return the String "c". A JSONPointerException may be
2182 * thrown from code called by this method.
2184 * @param jsonPointer
2185 * string that can be used to create a JSONPointer
2186 * @return the item matched by the JSONPointer, otherwise null
2188 public Object query(JSONPointer jsonPointer)
2190 return jsonPointer.queryFrom(this);
2194 * Queries and returns a value from this object using {@code jsonPointer}, or
2195 * returns null if the query fails due to a missing key.
2197 * @param jsonPointer
2198 * the string representation of the JSON pointer
2199 * @return the queried value or {@code null}
2200 * @throws IllegalArgumentException
2201 * if {@code jsonPointer} has invalid syntax
2203 public Object optQuery(String jsonPointer)
2205 return optQuery(new JSONPointer(jsonPointer));
2209 * Queries and returns a value from this object using {@code jsonPointer}, or
2210 * returns null if the query fails due to a missing key.
2212 * @param jsonPointer
2214 * @return the queried value or {@code null}
2215 * @throws IllegalArgumentException
2216 * if {@code jsonPointer} has invalid syntax
2218 public Object optQuery(JSONPointer jsonPointer)
2222 return jsonPointer.queryFrom(this);
2223 } catch (JSONPointerException e)
2230 * Produce a string in double quotes with backslash sequences in all the right
2231 * places. A backslash will be inserted within </, producing <\/, allowing
2232 * JSON text to be delivered in HTML. In JSON text, a string cannot contain a
2233 * control character or an unescaped quote or backslash.
2237 * @return A String correctly formatted for insertion in a JSON text.
2239 public static String quote(String string)
2241 StringWriter sw = new StringWriter();
2242 synchronized (sw.getBuffer())
2246 return quote(string, sw).toString();
2247 } catch (IOException ignored)
2249 // will never happen - we are writing to a string writer
2255 public static Writer quote(String string, Writer w) throws IOException
2257 if (string == null || string.isEmpty())
2267 int len = string.length();
2270 for (i = 0; i < len; i += 1)
2273 c = string.charAt(i);
2304 if (c < ' ' || (c >= '\u0080' && c < '\u00a0')
2305 || (c >= '\u2000' && c < '\u2100'))
2308 hhhh = Integer.toHexString(c);
2309 w.write("0000", 0, 4 - hhhh.length());
2323 * Remove a name and its value, if present.
2326 * The name to be removed.
2327 * @return The value that was associated with the name, or null if there was
2330 public Object remove(String key)
2332 return this.map.remove(key);
2336 * Determine if two JSONObjects are similar. They must contain the same set of
2337 * names which must be associated with similar values.
2340 * The other JSONObject
2341 * @return true if they are equal
2343 public boolean similar(Object other)
2347 if (!(other instanceof JSONObject))
2351 if (!this.keySet().equals(((JSONObject) other).keySet()))
2355 for (final Entry<String, ?> entry : this.entrySet())
2357 String name = entry.getKey();
2358 Object valueThis = entry.getValue();
2359 Object valueOther = ((JSONObject) other).get(name);
2360 if (valueThis == valueOther)
2364 if (valueThis == null)
2368 if (valueThis instanceof JSONObject)
2370 if (!((JSONObject) valueThis).similar(valueOther))
2375 else if (valueThis instanceof JSONArray)
2377 if (!((JSONArray) valueThis).similar(valueOther))
2382 else if (!valueThis.equals(valueOther))
2388 } catch (Throwable exception)
2395 * Tests if the value should be tried as a decimal. It makes no test if there
2396 * are actual digits.
2400 * @return true if the string is "-0" or if it contains '.', 'e', or 'E',
2403 protected static boolean isDecimalNotation(final String val)
2405 return val.indexOf('.') > -1 || val.indexOf('e') > -1
2406 || val.indexOf('E') > -1 || "-0".equals(val);
2410 * Converts a string to a number using the narrowest possible type. Possible
2411 * returns for this function are BigDecimal, Double, BigInteger, Long, and
2412 * Integer. When a Double is returned, it should always be a valid Double and
2413 * not NaN or +-infinity.
2417 * @return Number representation of the value.
2418 * @throws NumberFormatException
2419 * thrown if the value is not a valid number. A public caller should
2420 * catch this and wrap it in a {@link JSONException} if applicable.
2422 protected static Number stringToNumber(final String val)
2423 throws NumberFormatException
2425 char initial = val.charAt(0);
2426 if ((initial >= '0' && initial <= '9') || initial == '-')
2428 // decimal representation
2429 if (isDecimalNotation(val))
2431 // quick dirty way to see if we need a BigDecimal instead of a Double
2432 // this only handles some cases of overflow or underflow
2433 if (val.length() > 14)
2435 return new BigDecimal(val);
2437 final Double d = Double.valueOf(val);
2438 if (d.isInfinite() || d.isNaN())
2440 // if we can't parse it as a double, go up to BigDecimal
2441 // this is probably due to underflow like 4.32e-678
2442 // or overflow like 4.65e5324. The size of the string is small
2443 // but can't be held in a Double.
2444 return new BigDecimal(val);
2448 // integer representation.
2449 // This will narrow any values to the smallest reasonable Object
2451 // (Integer, Long, or BigInteger)
2454 // The compare string length method reduces GC,
2455 // but leads to smaller integers being placed in larger wrappers even
2457 // needed. i.e. 1,000,000,000 -> Long even though it's an Integer
2458 // 1,000,000,000,000,000,000 -> BigInteger even though it's a Long
2459 // if(val.length()<=9){
2460 // return Integer.valueOf(val);
2462 // if(val.length()<=18){
2463 // return Long.valueOf(val);
2465 // return new BigInteger(val);
2467 // BigInteger version: We use a similar bitLenth compare as
2468 // BigInteger#intValueExact uses. Increases GC, but objects hold
2469 // only what they need. i.e. Less runtime overhead if the value is
2470 // long lived. Which is the better tradeoff? This is closer to what's
2471 // in stringToValue.
2472 BigInteger bi = new BigInteger(val);
2473 if (bi.bitLength() <= 31)
2475 return Integer.valueOf(bi.intValue());
2477 if (bi.bitLength() <= 63)
2479 return Long.valueOf(bi.longValue());
2483 throw new NumberFormatException(
2484 "val [" + val + "] is not a valid number.");
2488 * Try to convert a string into a number, boolean, or null. If the string
2489 * can't be converted, return the string.
2493 * @return A simple JSON value.
2495 // Changes to this method must be copied to the corresponding method in
2496 // the XML class to keep full support for Android
2497 public static Object stringToValue(String string)
2499 if (string.equals(""))
2503 if (string.equalsIgnoreCase("true"))
2505 return Boolean.TRUE;
2507 if (string.equalsIgnoreCase("false"))
2509 return Boolean.FALSE;
2511 if (string.equalsIgnoreCase("null"))
2513 return JSONObject.NULL;
2517 * If it might be a number, try converting it. If a number cannot be produced,
2518 * then the value will just be a string.
2521 char initial = string.charAt(0);
2522 if ((initial >= '0' && initial <= '9') || initial == '-')
2526 // if we want full Big Number support this block can be replaced with:
2527 // return stringToNumber(string);
2528 if (isDecimalNotation(string))
2530 Double d = Double.valueOf(string);
2531 if (!d.isInfinite() && !d.isNaN())
2538 Long myLong = Long.valueOf(string);
2539 if (string.equals(myLong.toString()))
2541 if (myLong.longValue() == myLong.intValue())
2543 return Integer.valueOf(myLong.intValue());
2548 } catch (Exception ignore)
2556 * Throw an exception if the object is a NaN or infinite number.
2559 * The object to test.
2560 * @throws JSONException
2561 * If o is a non-finite number.
2563 public static void testValidity(Object o) throws JSONException
2567 if (o instanceof Double)
2569 if (((Double) o).isInfinite() || ((Double) o).isNaN())
2571 throw new JSONException(
2572 "JSON does not allow non-finite numbers.");
2575 else if (o instanceof Float)
2577 if (((Float) o).isInfinite() || ((Float) o).isNaN())
2579 throw new JSONException(
2580 "JSON does not allow non-finite numbers.");
2587 * Produce a JSONArray containing the values of the members of this
2591 * A JSONArray containing a list of key strings. This determines the
2592 * sequence of the values in the result.
2593 * @return A JSONArray of values.
2594 * @throws JSONException
2595 * If any of the values are non-finite numbers.
2597 public JSONArray toJSONArray(JSONArray names) throws JSONException
2599 if (names == null || names.isEmpty())
2603 JSONArray ja = new JSONArray();
2604 for (int i = 0; i < names.length(); i += 1)
2606 ja.put(this.opt(names.getString(i)));
2612 * Make a JSON text of this JSONObject. For compactness, no whitespace is
2613 * added. If this would not result in a syntactically correct JSON text, then
2614 * null will be returned instead.
2616 * <b> Warning: This method assumes that the data structure is acyclical. </b>
2618 * @return a printable, displayable, portable, transmittable representation of
2619 * the object, beginning with <code>{</code> <small>(left
2620 * brace)</small> and ending with <code>}</code> <small>(right
2624 public String toString()
2628 return this.toString(0);
2629 } catch (Exception e)
2636 * Make a pretty-printed JSON text of this JSONObject.
2639 * If <code>indentFactor > 0</code> and the {@link JSONObject} has only one
2640 * key, then the object will be output on a single line:
2643 * {@code {"key": 1}}
2647 * If an object has 2 or more keys, then it will be output across multiple
2648 * lines: <code><pre>{
2650 * "key2": "value 2",
2654 * <b> Warning: This method assumes that the data structure is acyclical. </b>
2656 * @param indentFactor
2657 * The number of spaces to add to each level of indentation.
2658 * @return a printable, displayable, portable, transmittable representation of
2659 * the object, beginning with <code>{</code> <small>(left
2660 * brace)</small> and ending with <code>}</code> <small>(right
2662 * @throws JSONException
2663 * If the object contains an invalid number.
2665 public String toString(int indentFactor) throws JSONException
2667 StringWriter w = new StringWriter();
2668 synchronized (w.getBuffer())
2670 return this.write(w, indentFactor, 0).toString();
2675 * Make a JSON text of an Object value. If the object has an
2676 * value.toJSONString() method, then that method will be used to produce the
2677 * JSON text. The method is required to produce a strictly conforming text. If
2678 * the object does not contain a toJSONString method (which is the most common
2679 * case), then a text will be produced by other means. If the value is an
2680 * array or Collection, then a JSONArray will be made from it and its
2681 * toJSONString method will be called. If the value is a MAP, then a
2682 * JSONObject will be made from it and its toJSONString method will be called.
2683 * Otherwise, the value's toString method will be called, and the result will
2687 * Warning: This method assumes that the data structure is acyclical.
2690 * The value to be serialized.
2691 * @return a printable, displayable, transmittable representation of the
2692 * object, beginning with <code>{</code> <small>(left
2693 * brace)</small> and ending with <code>}</code> <small>(right
2695 * @throws JSONException
2696 * If the value is or contains an invalid number.
2698 public static String valueToString(Object value) throws JSONException
2700 // moves the implementation to JSONWriter as:
2701 // 1. It makes more sense to be part of the writer class
2702 // 2. For Android support this method is not available. By implementing it
2705 // Android users can use the writer with the built in Android JSONObject
2707 return JSONWriter.valueToString(value);
2711 * Wrap an object, if necessary. If the object is <code>null</code>, return
2712 * the NULL object. If it is an array or collection, wrap it in a JSONArray.
2713 * If it is a map, wrap it in a JSONObject. If it is a standard property
2714 * (Double, String, et al) then it is already wrapped. Otherwise, if it comes
2715 * from one of the java packages, turn it into a string. And if it doesn't,
2716 * try to wrap it in a JSONObject. If the wrapping fails, then null is
2720 * The object to wrap
2721 * @return The wrapped value
2723 public static Object wrap(Object object)
2731 if (object instanceof JSONObject || object instanceof JSONArray
2732 || NULL.equals(object) || object instanceof JSONString
2733 || object instanceof Byte || object instanceof Character
2734 || object instanceof Short || object instanceof Integer
2735 || object instanceof Long || object instanceof Boolean
2736 || object instanceof Float || object instanceof Double
2737 || object instanceof String || object instanceof BigInteger
2738 || object instanceof BigDecimal || object instanceof Enum)
2743 if (object instanceof Collection)
2745 Collection<?> coll = (Collection<?>) object;
2746 return new JSONArray(coll);
2748 if (object.getClass().isArray())
2750 return new JSONArray(object);
2752 if (object instanceof Map)
2754 Map<?, ?> map = (Map<?, ?>) object;
2755 return new JSONObject(map);
2757 Package objectPackage = object.getClass().getPackage();
2758 String objectPackageName = objectPackage != null
2759 ? objectPackage.getName()
2761 if (objectPackageName.startsWith("java.")
2762 || objectPackageName.startsWith("javax.")
2763 || object.getClass().getClassLoader() == null)
2765 return object.toString();
2767 return new JSONObject(object);
2768 } catch (Exception exception)
2775 * Write the contents of the JSONObject as JSON text to a writer. For
2776 * compactness, no whitespace is added.
2778 * <b> Warning: This method assumes that the data structure is acyclical. </b>
2780 * @return The writer.
2781 * @throws JSONException
2783 public Writer write(Writer writer) throws JSONException
2785 return this.write(writer, 0, 0);
2788 static final Writer writeValue(Writer writer, Object value,
2789 int indentFactor, int indent) throws JSONException, IOException
2791 if (value == null || value.equals(null))
2793 writer.write("null");
2795 else if (value instanceof JSONString)
2800 o = ((JSONString) value).toJSONString();
2801 } catch (Exception e)
2803 throw new JSONException(e);
2805 writer.write(o != null ? o.toString() : quote(value.toString()));
2807 else if (value instanceof Number)
2809 // not all Numbers may match actual JSON Numbers. i.e. fractions or
2811 final String numberAsString = numberToString((Number) value);
2814 // Use the BigDecimal constructor for its parser to validate the format.
2815 @SuppressWarnings("unused")
2816 BigDecimal testNum = new BigDecimal(numberAsString);
2817 // Close enough to a JSON number that we will use it unquoted
2818 writer.write(numberAsString);
2819 } catch (NumberFormatException ex)
2821 // The Number value is not a valid JSON number.
2822 // Instead we will quote it as a string
2823 quote(numberAsString, writer);
2826 else if (value instanceof Boolean)
2828 writer.write(value.toString());
2830 else if (value instanceof Enum<?>)
2832 writer.write(quote(((Enum<?>) value).name()));
2834 else if (value instanceof JSONObject)
2836 ((JSONObject) value).write(writer, indentFactor, indent);
2838 else if (value instanceof JSONArray)
2840 ((JSONArray) value).write(writer, indentFactor, indent);
2842 else if (value instanceof Map)
2844 Map<?, ?> map = (Map<?, ?>) value;
2845 new JSONObject(map).write(writer, indentFactor, indent);
2847 else if (value instanceof Collection)
2849 Collection<?> coll = (Collection<?>) value;
2850 new JSONArray(coll).write(writer, indentFactor, indent);
2852 else if (value.getClass().isArray())
2854 new JSONArray(value).write(writer, indentFactor, indent);
2858 quote(value.toString(), writer);
2863 static final void indent(Writer writer, int indent) throws IOException
2865 for (int i = 0; i < indent; i += 1)
2872 * Write the contents of the JSONObject as JSON text to a writer.
2875 * If <code>indentFactor > 0</code> and the {@link JSONObject} has only one
2876 * key, then the object will be output on a single line:
2879 * {@code {"key": 1}}
2883 * If an object has 2 or more keys, then it will be output across multiple
2884 * lines: <code><pre>{
2886 * "key2": "value 2",
2890 * <b> Warning: This method assumes that the data structure is acyclical. </b>
2893 * Writes the serialized JSON
2894 * @param indentFactor
2895 * The number of spaces to add to each level of indentation.
2897 * The indentation of the top level.
2898 * @return The writer.
2899 * @throws JSONException
2901 public Writer write(Writer writer, int indentFactor, int indent)
2902 throws JSONException
2906 boolean commanate = false;
2907 final int length = this.length();
2912 final Entry<String, ?> entry = this.entrySet().iterator().next();
2913 final String key = entry.getKey();
2914 writer.write(quote(key));
2916 if (indentFactor > 0)
2922 writeValue(writer, entry.getValue(), indentFactor, indent);
2923 } catch (Exception e)
2925 throw new JSONException(
2926 "Unable to write JSONObject value for key: " + key, e);
2929 else if (length != 0)
2931 final int newindent = indent + indentFactor;
2932 for (final Entry<String, ?> entry : this.entrySet())
2938 if (indentFactor > 0)
2942 indent(writer, newindent);
2943 final String key = entry.getKey();
2944 writer.write(quote(key));
2946 if (indentFactor > 0)
2952 writeValue(writer, entry.getValue(), indentFactor, newindent);
2953 } catch (Exception e)
2955 throw new JSONException(
2956 "Unable to write JSONObject value for key: " + key, e);
2960 if (indentFactor > 0)
2964 indent(writer, indent);
2968 } catch (IOException exception)
2970 throw new JSONException(exception);
2975 * Returns a java.util.Map containing all of the entries in this object. If an
2976 * entry in the object is a JSONArray or JSONObject it will also be converted.
2978 * Warning: This method assumes that the data structure is acyclical.
2980 * @return a java.util.Map containing the entries of this object
2982 public Map<String, Object> toMap()
2984 Map<String, Object> results = new HashMap<String, Object>();
2985 for (Entry<String, Object> entry : this.entrySet())
2988 if (entry.getValue() == null || NULL.equals(entry.getValue()))
2992 else if (entry.getValue() instanceof JSONObject)
2994 value = ((JSONObject) entry.getValue()).toMap();
2996 else if (entry.getValue() instanceof JSONArray)
2998 value = ((JSONArray) entry.getValue()).toList();
3002 value = entry.getValue();
3004 results.put(entry.getKey(), value);