3 import java.io.Closeable;
7 * Note: This file has been adapted for SwingJS by Bob Hanson hansonr@stolaf.edu
9 Copyright (c) 2002 JSON.org
11 Permission is hereby granted, free of charge, to any person obtaining a copy
12 of this software and associated documentation files (the "Software"), to deal
13 in the Software without restriction, including without limitation the rights
14 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15 copies of the Software, and to permit persons to whom the Software is
16 furnished to do so, subject to the following conditions:
18 The above copyright notice and this permission notice shall be included in all
19 copies or substantial portions of the Software.
21 The Software shall be used for Good, not Evil.
23 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
32 import java.io.IOException;
33 import java.io.StringWriter;
34 import java.io.Writer;
35 import java.lang.reflect.Field;
36 import java.lang.reflect.InvocationTargetException;
37 import java.lang.reflect.Method;
38 import java.lang.reflect.Modifier;
39 import java.math.BigDecimal;
40 import java.math.BigInteger;
41 import java.util.Collection;
42 import java.util.Enumeration;
43 import java.util.HashMap;
44 import java.util.Iterator;
45 import java.util.Locale;
47 import java.util.Map.Entry;
48 import java.util.ResourceBundle;
52 * A JSONObject is an unordered collection of name/value pairs. Its external
53 * form is a string wrapped in curly braces with colons between the names and
54 * values, and commas between the values and names. The internal form is an
55 * object having <code>get</code> and <code>opt</code> methods for accessing the
56 * values by name, and <code>put</code> methods for adding or replacing values
57 * by name. The values can be any of these types: <code>Boolean</code>,
58 * <code>JSONArray</code>, <code>JSONObject</code>, <code>Number</code>,
59 * <code>String</code>, or the <code>JSONObject.NULL</code> object. A JSONObject
60 * constructor can be used to convert an external form JSON text into an
61 * internal form whose values can be retrieved with the <code>get</code> and
62 * <code>opt</code> methods, or to convert values into a JSON text using the
63 * <code>put</code> and <code>toString</code> methods. A <code>get</code> method
64 * returns a value if one can be found, and throws an exception if one cannot be
65 * found. An <code>opt</code> method returns a default value instead of throwing
66 * an exception, and so is useful for obtaining optional values.
68 * The generic <code>get()</code> and <code>opt()</code> methods return an
69 * object, which you can cast or query for type. There are also typed
70 * <code>get</code> and <code>opt</code> methods that do type checking and type
71 * coercion for you. The opt methods differ from the get methods in that they do
72 * not throw. Instead, they return a specified value, such as null.
74 * The <code>put</code> methods add or replace values in an object. For example,
77 * myString = new JSONObject().put("JSON", "Hello, World!").toString();
80 * produces the string <code>{"JSON": "Hello, World"}</code>.
82 * The texts produced by the <code>toString</code> methods strictly conform to
83 * the JSON syntax rules. The constructors are more forgiving in the texts they
86 * <li>An extra <code>,</code> <small>(comma)</small> may appear just
87 * before the closing brace.</li>
88 * <li>Strings may be quoted with <code>'</code> <small>(single
89 * quote)</small>.</li>
90 * <li>Strings do not need to be quoted at all if they do not begin with a quote
91 * or single quote, and if they do not contain leading or trailing spaces, and
92 * if they do not contain any of these characters:
93 * <code>{ } [ ] / \ : , #</code> and if they do not look like numbers and if
94 * they are not the reserved words <code>true</code>, <code>false</code>, or
95 * <code>null</code>.</li>
101 public class JSONObject
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
112 * There is only intended to be a single instance of the NULL object, so the
113 * clone method returns itself.
118 protected final Object clone()
124 * A Null object is equal to the null value and to itself.
127 * An object to test for nullness.
128 * @return true if the object parameter is the JSONObject.NULL object or
132 public boolean equals(Object object)
134 return object == null || object == this;
138 * A Null object is equal to the null value and to itself.
140 * @return always returns 0.
143 public int hashCode()
149 * Get the "null" string value.
151 * @return The string "null".
154 public String toString()
161 * The map where the JSONObject's properties are kept.
163 private final Map<String, Object> map;
166 * It is sometimes more convenient and less ambiguous to have a
167 * <code>NULL</code> object than to use Java's <code>null</code> value.
168 * <code>JSONObject.NULL.equals(null)</code> returns <code>true</code>.
169 * <code>JSONObject.NULL.toString()</code> returns <code>"null"</code>.
171 public static final Object NULL = new Null();
174 * Construct an empty JSONObject.
178 // HashMap is used on purpose to ensure that elements are unordered by
179 // the specification.
180 // JSON tends to be a portable transfer format to allows the container
181 // implementations to rearrange their items for a faster element
182 // retrieval based on associative access.
183 // Therefore, an implementation mustn't rely on the order of the item.
184 this.map = new HashMap<String, Object>();
188 * Construct a JSONObject from a subset of another JSONObject. An array of
189 * strings is used to identify the keys that should be copied. Missing keys
195 * An array of strings.
197 public JSONObject(JSONObject jo, String[] names)
200 for (int i = 0; i < names.length; i += 1)
204 this.putOnce(names[i], jo.opt(names[i]));
205 } catch (Exception ignore)
212 * Construct a JSONObject from a JSONTokener.
215 * A JSONTokener object containing the source string.
216 * @throws JSONException
217 * If there is a syntax error in the source string or a duplicated
220 public JSONObject(JSONTokener x) throws JSONException
226 if (x.nextClean() != '{')
228 throw x.syntaxError("A JSONObject text must begin with '{'");
236 throw x.syntaxError("A JSONObject text must end with '}'");
241 key = x.nextValue().toString();
244 // The key is followed by ':'.
249 throw x.syntaxError("Expected a ':' after a key");
252 // Use syntaxError(..) to include error location
256 // Check if key exists
257 if (this.opt(key) != null)
259 // key already exists
260 throw x.syntaxError("Duplicate key \"" + key + "\"");
262 // Only add value if non-null
263 Object value = x.nextValue();
266 this.put(key, value);
270 // Pairs are separated by ','.
272 switch (x.nextClean())
276 if (x.nextClean() == '}')
285 throw x.syntaxError("Expected a ',' or '}'");
291 * Construct a JSONObject from a Map.
294 * A map object that can be used to initialize the contents of the
296 * @throws JSONException
297 * If a value in the map is non-finite number.
298 * @throws NullPointerException
299 * If a key in the map is <code>null</code>
301 public JSONObject(Map<?, ?> m)
305 this.map = new HashMap<String, Object>();
309 this.map = new HashMap<String, Object>(m.size());
310 for (final Entry<?, ?> e : m.entrySet())
312 if (e.getKey() == null)
314 throw new NullPointerException("Null key.");
316 final Object value = e.getValue();
319 this.map.put(String.valueOf(e.getKey()), wrap(value));
326 * Construct a JSONObject from an Object using bean getters. It reflects on
327 * all of the public methods of the object. For each of the methods with no
328 * parameters and a name starting with <code>"get"</code> or <code>"is"</code>
329 * followed by an uppercase letter, the method is invoked, and a key and the
330 * value returned from the getter method are put into the new JSONObject.
332 * The key is formed by removing the <code>"get"</code> or <code>"is"</code>
333 * prefix. If the second remaining character is not upper case, then the first
334 * character is converted to lower case.
336 * Methods that are <code>static</code>, return <code>void</code>, have
337 * parameters, or are "bridge" methods, are ignored.
339 * For example, if an object has a method named <code>"getName"</code>, and if
340 * the result of calling <code>object.getName()</code> is
341 * <code>"Larry Fine"</code>, then the JSONObject will contain
342 * <code>"name": "Larry Fine"</code>.
344 * The {@link JSONPropertyName} annotation can be used on a bean getter to
345 * override key name used in the JSONObject. For example, using the object
346 * above with the <code>getName</code> method, if we annotated it with:
349 * @JSONPropertyName("FullName")
350 * public String getName()
356 * The resulting JSON object would contain
357 * <code>"FullName": "Larry Fine"</code>
359 * Similarly, the {@link JSONPropertyName} annotation can be used on non-
360 * <code>get</code> and <code>is</code> methods. We can also override key name
361 * used in the JSONObject as seen below even though the field would normally
365 * @JSONPropertyName("FullName")
366 * public String fullName()
372 * The resulting JSON object would contain
373 * <code>"FullName": "Larry Fine"</code>
375 * The {@link JSONPropertyIgnore} annotation can be used to force the bean
376 * property to not be serialized into JSON. If both {@link JSONPropertyIgnore}
377 * and {@link JSONPropertyName} are defined on the same method, a depth
378 * comparison is performed and the one closest to the concrete class being
379 * serialized is used. If both annotations are at the same level, then the
380 * {@link JSONPropertyIgnore} annotation takes precedent and the field is not
381 * serialized. For example, the following declaration would prevent the
382 * <code>getName</code> method from being serialized:
385 * @JSONPropertyName("FullName")
386 * @JSONPropertyIgnore
387 * public String getName()
395 * An object that has getter methods that should be used to make a
398 public JSONObject(Object bean)
401 this.populateMap(bean);
405 * Construct a JSONObject from an Object, using reflection to find the public
406 * members. The resulting JSONObject's keys will be the strings from the names
407 * array, and the values will be the field values associated with those keys
408 * in the object. If a key is not found or not visible, then it will not be
409 * copied into the new JSONObject.
412 * An object that has fields that should be used to make a
415 * An array of strings, the names of the fields to be obtained from
418 public JSONObject(Object object, String names[])
421 Class<?> c = object.getClass();
422 for (int i = 0; i < names.length; i += 1)
424 String name = names[i];
427 this.putOpt(name, c.getField(name).get(object));
428 } catch (Exception ignore)
435 * Construct a JSONObject from a source JSON text string. This is the most
436 * commonly used JSONObject constructor.
439 * A string beginning with <code>{</code> <small>(left
440 * brace)</small> and ending with <code>}</code> <small>(right
442 * @exception JSONException
443 * If there is a syntax error in the source string or a
446 public JSONObject(String source) throws JSONException
448 this(new JSONTokener(source));
452 * Construct a JSONObject from a ResourceBundle.
455 * The ResourceBundle base name.
457 * The Locale to load the ResourceBundle for.
458 * @throws JSONException
459 * If any JSONExceptions are detected.
461 public JSONObject(String baseName, Locale locale) throws JSONException
464 ResourceBundle bundle = ResourceBundle.getBundle(baseName, locale,
465 Thread.currentThread().getContextClassLoader());
467 // Iterate through the keys in the bundle.
469 Enumeration<String> keys = bundle.getKeys();
470 while (keys.hasMoreElements())
472 Object key = keys.nextElement();
476 // Go through the path, ensuring that there is a nested JSONObject for
478 // segment except the last. Add the value using the last segment's name
480 // the deepest nested JSONObject.
482 String[] path = ((String) key).split("\\.");
483 int last = path.length - 1;
484 JSONObject target = this;
485 for (int i = 0; i < last; i += 1)
487 String segment = path[i];
488 JSONObject nextTarget = target.optJSONObject(segment);
489 if (nextTarget == null)
491 nextTarget = new JSONObject();
492 target.put(segment, nextTarget);
496 target.put(path[last], bundle.getString((String) key));
502 * Constructor to specify an initial capacity of the internal map. Useful for
503 * library internal calls where we know, or at least can best guess, how big
504 * this JSONObject will be.
506 * @param initialCapacity
507 * initial capacity of the internal map.
509 protected JSONObject(int initialCapacity)
511 this.map = new HashMap<String, Object>(initialCapacity);
515 * Accumulate values under a key. It is similar to the put method except that
516 * if there is already an object stored under the key then a JSONArray is
517 * stored under the key to hold all of the accumulated values. If there is
518 * already a JSONArray, then the new value is appended to it. In contrast, the
519 * put method replaces the previous value.
521 * If only one value is accumulated that is not a JSONArray, then the result
522 * will be the same as using put. But if multiple values are accumulated, then
523 * the result will be like append.
528 * An object to be accumulated under the key.
530 * @throws JSONException
531 * If the value is non-finite number.
532 * @throws NullPointerException
533 * If the key is <code>null</code>.
535 public JSONObject accumulate(String key, Object value)
539 Object object = this.opt(key);
542 this.put(key, value instanceof JSONArray ? new JSONArray().put(value)
545 else if (object instanceof JSONArray)
547 ((JSONArray) object).put(value);
551 this.put(key, new JSONArray().put(object).put(value));
557 * Append values to the array under a key. If the key does not exist in the
558 * JSONObject, then the key is put in the JSONObject with its value being a
559 * JSONArray containing the value parameter. If the key was already associated
560 * with a JSONArray, then the value parameter is appended to it.
565 * An object to be accumulated under the key.
567 * @throws JSONException
568 * If the value is non-finite number or if the current value
569 * associated with the key is not a JSONArray.
570 * @throws NullPointerException
571 * If the key is <code>null</code>.
573 public JSONObject append(String key, Object value) throws JSONException
576 Object object = this.opt(key);
579 this.put(key, new JSONArray().put(value));
581 else if (object instanceof JSONArray)
583 this.put(key, ((JSONArray) object).put(value));
587 throw new JSONException(
588 "JSONObject[" + key + "] is not a JSONArray.");
594 * Produce a string from a double. The string "null" will be returned if the
595 * number is not finite.
601 public static String doubleToString(double d)
603 if (Double.isInfinite(d) || Double.isNaN(d))
608 // Shave off trailing zeros and decimal point, if possible.
610 String string = Double.toString(d);
611 if (string.indexOf('.') > 0 && string.indexOf('e') < 0
612 && string.indexOf('E') < 0)
614 while (string.endsWith("0"))
616 string = string.substring(0, string.length() - 1);
618 if (string.endsWith("."))
620 string = string.substring(0, string.length() - 1);
627 * Get the value object associated with a key.
631 * @return The object associated with the key.
632 * @throws JSONException
633 * if the key is not found.
635 public Object get(String key) throws JSONException
639 throw new JSONException("Null key.");
641 Object object = this.opt(key);
644 throw new JSONException("JSONObject[" + quote(key) + "] not found.");
650 * Get the enum value associated with a key.
653 * The type of enum to retrieve.
656 * @return The enum value associated with the key
657 * @throws JSONException
658 * if the key is not found or if the value cannot be converted to an
661 public <E extends Enum<E>> E getEnum(Class<E> clazz, String key)
664 E val = optEnum(clazz, key);
667 // JSONException should really take a throwable argument.
668 // If it did, I would re-implement this with the Enum.valueOf
669 // method and place any thrown exception in the JSONException
670 throw new JSONException(
671 "JSONObject[" + quote(key) + "] is not an enum of type "
672 + quote(clazz.getSimpleName()) + ".");
678 * Get the boolean value associated with a key.
683 * @throws JSONException
684 * if the value is not a Boolean or the String "true" or "false".
686 public boolean getBoolean(String key) throws JSONException
688 Object object = this.get(key);
689 if (object.equals(Boolean.FALSE) || (object instanceof String
690 && ((String) object).equalsIgnoreCase("false")))
694 else if (object.equals(Boolean.TRUE) || (object instanceof String
695 && ((String) object).equalsIgnoreCase("true")))
699 throw new JSONException(
700 "JSONObject[" + quote(key) + "] is not a Boolean.");
704 * Get the BigInteger value associated with a key.
708 * @return The numeric value.
709 * @throws JSONException
710 * if the key is not found or if the value cannot be converted to
713 public BigInteger getBigInteger(String key) throws JSONException
715 Object object = this.get(key);
718 return new BigInteger(object.toString());
719 } catch (Exception e)
721 throw new JSONException("JSONObject[" + quote(key)
722 + "] could not be converted to BigInteger.", e);
727 * Get the BigDecimal value associated with a key.
731 * @return The numeric value.
732 * @throws JSONException
733 * if the key is not found or if the value cannot be converted to
736 public BigDecimal getBigDecimal(String key) throws JSONException
738 Object object = this.get(key);
739 if (object instanceof BigDecimal)
741 return (BigDecimal) object;
745 return new BigDecimal(object.toString());
746 } catch (Exception e)
748 throw new JSONException("JSONObject[" + quote(key)
749 + "] could not be converted to BigDecimal.", e);
754 * Get the double value associated with a key.
758 * @return The numeric value.
759 * @throws JSONException
760 * if the key is not found or if the value is not a Number object
761 * and cannot be converted to a number.
763 public double getDouble(String key) throws JSONException
765 Object object = this.get(key);
768 return object instanceof Number ? ((Number) object).doubleValue()
769 : Double.parseDouble(object.toString());
770 } catch (Exception e)
772 throw new JSONException(
773 "JSONObject[" + quote(key) + "] is not a number.", e);
778 * Get the float value associated with a key.
782 * @return The numeric value.
783 * @throws JSONException
784 * if the key is not found or if the value is not a Number object
785 * and cannot be converted to a number.
787 public float getFloat(String key) throws JSONException
789 Object object = this.get(key);
792 return object instanceof Number ? ((Number) object).floatValue()
793 : Float.parseFloat(object.toString());
794 } catch (Exception e)
796 throw new JSONException(
797 "JSONObject[" + quote(key) + "] is not a number.", e);
802 * Get the Number value associated with a key.
806 * @return The numeric value.
807 * @throws JSONException
808 * if the key is not found or if the value is not a Number object
809 * and cannot be converted to a number.
811 public Number getNumber(String key) throws JSONException
813 Object object = this.get(key);
816 if (object instanceof Number)
818 return (Number) object;
820 return stringToNumber(object.toString());
821 } catch (Exception e)
823 throw new JSONException(
824 "JSONObject[" + quote(key) + "] is not a number.", e);
829 * Get the int value associated with a key.
833 * @return The integer value.
834 * @throws JSONException
835 * if the key is not found or if the value cannot be converted to an
838 public int getInt(String key) throws JSONException
840 Object object = this.get(key);
843 return object instanceof Number ? ((Number) object).intValue()
844 : Integer.parseInt((String) object);
845 } catch (Exception e)
847 throw new JSONException(
848 "JSONObject[" + quote(key) + "] is not an int.", e);
853 * Get the JSONArray value associated with a key.
857 * @return A JSONArray which is the value.
858 * @throws JSONException
859 * if the key is not found or if the value is not a JSONArray.
861 public JSONArray getJSONArray(String key) throws JSONException
863 Object object = this.get(key);
864 if (object instanceof JSONArray)
866 return (JSONArray) object;
868 throw new JSONException(
869 "JSONObject[" + quote(key) + "] is not a JSONArray.");
873 * Get the JSONObject value associated with a key.
877 * @return A JSONObject which is the value.
878 * @throws JSONException
879 * if the key is not found or if the value is not a JSONObject.
881 public JSONObject getJSONObject(String key) throws JSONException
883 Object object = this.get(key);
884 if (object instanceof JSONObject)
886 return (JSONObject) object;
888 throw new JSONException(
889 "JSONObject[" + quote(key) + "] is not a JSONObject.");
893 * Get the long value associated with a key.
897 * @return The long value.
898 * @throws JSONException
899 * if the key is not found or if the value cannot be converted to a
902 public long getLong(String key) throws JSONException
904 Object object = this.get(key);
907 return object instanceof Number ? ((Number) object).longValue()
908 : Long.parseLong((String) object);
909 } catch (Exception e)
911 throw new JSONException(
912 "JSONObject[" + quote(key) + "] is not a long.", e);
917 * Get an array of field names from a JSONObject.
919 * @return An array of field names, or null if there are no names.
921 public static String[] getNames(JSONObject jo)
927 return jo.keySet().toArray(new String[jo.length()]);
931 * Get an array of field names from an Object.
933 * @return An array of field names, or null if there are no names.
935 public static String[] getNames(Object object)
941 Class<?> klass = object.getClass();
942 Field[] fields = klass.getFields();
943 int length = fields.length;
948 String[] names = new String[length];
949 for (int i = 0; i < length; i += 1)
951 names[i] = fields[i].getName();
957 * Get the string associated with a key.
961 * @return A string which is the value.
962 * @throws JSONException
963 * if there is no string value for the key.
965 public String getString(String key) throws JSONException
967 Object object = this.get(key);
968 if (object instanceof String)
970 return (String) object;
972 throw new JSONException("JSONObject[" + quote(key) + "] not a string.");
976 * Determine if the JSONObject contains a specific key.
980 * @return true if the key exists in the JSONObject.
982 public boolean has(String key)
984 return this.map.containsKey(key);
988 * Increment a property of a JSONObject. If there is no such property, create
989 * one with a value of 1. If there is such a property, and if it is an
990 * Integer, Long, Double, or Float, then add one to it.
995 * @throws JSONException
996 * If there is already a property with this name that is not an
997 * Integer, Long, Double, or Float.
999 public JSONObject increment(String key) throws JSONException
1001 Object value = this.opt(key);
1006 else if (value instanceof BigInteger)
1008 this.put(key, ((BigInteger) value).add(BigInteger.ONE));
1010 else if (value instanceof BigDecimal)
1012 this.put(key, ((BigDecimal) value).add(BigDecimal.ONE));
1014 else if (value instanceof Integer)
1016 this.put(key, ((Integer) value).intValue() + 1);
1018 else if (value instanceof Long)
1020 this.put(key, ((Long) value).longValue() + 1L);
1022 else if (value instanceof Double)
1024 this.put(key, ((Double) value).doubleValue() + 1.0d);
1026 else if (value instanceof Float)
1028 this.put(key, ((Float) value).floatValue() + 1.0f);
1032 throw new JSONException("Unable to increment [" + quote(key) + "].");
1038 * Determine if the value associated with the key is <code>null</code> or if
1039 * there is no value.
1043 * @return true if there is no value associated with the key or if the value
1044 * is the JSONObject.NULL object.
1046 public boolean isNull(String key)
1048 return JSONObject.NULL.equals(this.opt(key));
1052 * Get an enumeration of the keys of the JSONObject. Modifying this key Set
1053 * will also modify the JSONObject. Use with caution.
1055 * @see Set#iterator()
1057 * @return An iterator of the keys.
1059 public Iterator<String> keys()
1061 return this.keySet().iterator();
1065 * Get a set of keys of the JSONObject. Modifying this key Set will also
1066 * modify the JSONObject. Use with caution.
1072 public Set<String> keySet()
1074 return this.map.keySet();
1078 * Get a set of entries of the JSONObject. These are raw values and may not
1079 * match what is returned by the JSONObject get* and opt* functions. Modifying
1080 * the returned EntrySet or the Entry objects contained therein will modify
1081 * the backing JSONObject. This does not return a clone or a read-only view.
1085 * @see Map#entrySet()
1087 * @return An Entry Set
1089 protected Set<Entry<String, Object>> entrySet()
1091 return this.map.entrySet();
1095 * Get the number of keys stored in the JSONObject.
1097 * @return The number of keys in the JSONObject.
1101 return this.map.size();
1105 * Check if JSONObject is empty.
1107 * @return true if JSONObject is empty, otherwise false.
1109 public boolean isEmpty()
1111 return map.isEmpty();
1115 * Produce a JSONArray containing the names of the elements of this
1118 * @return A JSONArray containing the key strings, or null if the JSONObject
1121 public JSONArray names()
1123 if (this.map.isEmpty())
1127 return new JSONArray(this.map.keySet());
1131 * Produce a string from a Number.
1136 * @throws JSONException
1137 * If n is a non-finite number.
1139 public static String numberToString(Number number) throws JSONException
1143 throw new JSONException("Null pointer");
1145 testValidity(number);
1147 // Shave off trailing zeros and decimal point, if possible.
1149 String string = number.toString();
1150 if (string.indexOf('.') > 0 && string.indexOf('e') < 0
1151 && string.indexOf('E') < 0)
1153 while (string.endsWith("0"))
1155 string = string.substring(0, string.length() - 1);
1157 if (string.endsWith("."))
1159 string = string.substring(0, string.length() - 1);
1166 * Get an optional value associated with a key.
1170 * @return An object which is the value, or null if there is no value.
1172 public Object opt(String key)
1174 return key == null ? null : this.map.get(key);
1178 * Get the enum value associated with a key.
1181 * The type of enum to retrieve.
1184 * @return The enum value associated with the key or null if not found
1186 public <E extends Enum<E>> E optEnum(Class<E> clazz, String key)
1188 return this.optEnum(clazz, key, null);
1192 * Get the enum value associated with a key.
1195 * The type of enum to retrieve.
1198 * @param defaultValue
1199 * The default in case the value is not found
1200 * @return The enum value associated with the key or defaultValue if the value
1201 * is not found or cannot be assigned to <code>clazz</code>
1203 public <E extends Enum<E>> E optEnum(Class<E> clazz, String key,
1208 Object val = this.opt(key);
1209 if (NULL.equals(val))
1211 return defaultValue;
1213 if (clazz.isAssignableFrom(val.getClass()))
1215 // we just checked it!
1216 @SuppressWarnings("unchecked")
1220 return Enum.valueOf(clazz, val.toString());
1221 } catch (IllegalArgumentException e)
1223 return defaultValue;
1224 } catch (NullPointerException e)
1226 return defaultValue;
1231 * Get an optional boolean associated with a key. It returns false if there is
1232 * no such key, or if the value is not Boolean.TRUE or the String "true".
1236 * @return The truth.
1238 public boolean optBoolean(String key)
1240 return this.optBoolean(key, false);
1244 * Get an optional boolean associated with a key. It returns the defaultValue
1245 * if there is no such key, or if it is not a Boolean or the String "true" or
1246 * "false" (case insensitive).
1250 * @param defaultValue
1252 * @return The truth.
1254 public boolean optBoolean(String key, boolean defaultValue)
1256 Object val = this.opt(key);
1257 if (NULL.equals(val))
1259 return defaultValue;
1261 if (val instanceof Boolean)
1263 return ((Boolean) val).booleanValue();
1267 // we'll use the get anyway because it does string conversion.
1268 return this.getBoolean(key);
1269 } catch (Exception e)
1271 return defaultValue;
1276 * Get an optional BigDecimal associated with a key, or the defaultValue if
1277 * there is no such key or if its value is not a number. If the value is a
1278 * string, an attempt will be made to evaluate it as a number.
1282 * @param defaultValue
1284 * @return An object which is the value.
1286 public BigDecimal optBigDecimal(String key, BigDecimal defaultValue)
1288 Object val = this.opt(key);
1289 if (NULL.equals(val))
1291 return defaultValue;
1293 if (val instanceof BigDecimal)
1295 return (BigDecimal) val;
1297 if (val instanceof BigInteger)
1299 return new BigDecimal((BigInteger) val);
1301 if (val instanceof Double || val instanceof Float)
1303 return new BigDecimal(((Number) val).doubleValue());
1305 if (val instanceof Long || val instanceof Integer
1306 || val instanceof Short || val instanceof Byte)
1308 return new BigDecimal(((Number) val).longValue());
1310 // don't check if it's a string in case of unchecked Number subclasses
1313 return new BigDecimal(val.toString());
1314 } catch (Exception e)
1316 return defaultValue;
1321 * Get an optional BigInteger associated with a key, or the defaultValue if
1322 * there is no such key or if its value is not a number. If the value is a
1323 * string, an attempt will be made to evaluate it as a number.
1327 * @param defaultValue
1329 * @return An object which is the value.
1331 public BigInteger optBigInteger(String key, BigInteger defaultValue)
1333 Object val = this.opt(key);
1334 if (NULL.equals(val))
1336 return defaultValue;
1338 if (val instanceof BigInteger)
1340 return (BigInteger) val;
1342 if (val instanceof BigDecimal)
1344 return ((BigDecimal) val).toBigInteger();
1346 if (val instanceof Double || val instanceof Float)
1348 return new BigDecimal(((Number) val).doubleValue()).toBigInteger();
1350 if (val instanceof Long || val instanceof Integer
1351 || val instanceof Short || val instanceof Byte)
1353 return BigInteger.valueOf(((Number) val).longValue());
1355 // don't check if it's a string in case of unchecked Number subclasses
1358 // the other opt functions handle implicit conversions, i.e.
1359 // jo.put("double",1.1d);
1360 // jo.optInt("double"); -- will return 1, not an error
1361 // this conversion to BigDecimal then to BigInteger is to maintain
1362 // that type cast support that may truncate the decimal.
1363 final String valStr = val.toString();
1364 if (isDecimalNotation(valStr))
1366 return new BigDecimal(valStr).toBigInteger();
1368 return new BigInteger(valStr);
1369 } catch (Exception e)
1371 return defaultValue;
1376 * Get an optional double associated with a key, or NaN if there is no such
1377 * key or if its value is not a number. If the value is a string, an attempt
1378 * will be made to evaluate it as a number.
1381 * A string which is the key.
1382 * @return An object which is the value.
1384 public double optDouble(String key)
1386 return this.optDouble(key, Double.NaN);
1390 * Get an optional double associated with a key, or the defaultValue if there
1391 * is no such key or if its value is not a number. If the value is a string,
1392 * an attempt will be made to evaluate it as a number.
1396 * @param defaultValue
1398 * @return An object which is the value.
1400 public double optDouble(String key, double defaultValue)
1402 Object val = this.opt(key);
1403 if (NULL.equals(val))
1405 return defaultValue;
1407 if (val instanceof Number)
1409 return ((Number) val).doubleValue();
1411 if (val instanceof String)
1415 return Double.parseDouble((String) val);
1416 } catch (Exception e)
1418 return defaultValue;
1421 return defaultValue;
1425 * Get the optional double value associated with an index. NaN is returned if
1426 * there is no value for the index, or if the value is not a number and cannot
1427 * be converted to a number.
1431 * @return The value.
1433 public float optFloat(String key)
1435 return this.optFloat(key, Float.NaN);
1439 * Get the optional double value associated with an index. The defaultValue is
1440 * returned if there is no value for the index, or if the value is not a
1441 * number and cannot be converted to a number.
1445 * @param defaultValue
1446 * The default value.
1447 * @return The value.
1449 public float optFloat(String key, float defaultValue)
1451 Object val = this.opt(key);
1452 if (JSONObject.NULL.equals(val))
1454 return defaultValue;
1456 if (val instanceof Number)
1458 return ((Number) val).floatValue();
1460 if (val instanceof String)
1464 return Float.parseFloat((String) val);
1465 } catch (Exception e)
1467 return defaultValue;
1470 return defaultValue;
1474 * Get an optional int value associated with a key, or zero if there is no
1475 * such key or if the value is not a number. If the value is a string, an
1476 * attempt will be made to evaluate it as a number.
1480 * @return An object which is the value.
1482 public int optInt(String key)
1484 return this.optInt(key, 0);
1488 * Get an optional int value associated with a key, or the default if there is
1489 * no such key or if the value is not a number. If the value is a string, an
1490 * attempt will be made to evaluate it as a number.
1494 * @param defaultValue
1496 * @return An object which is the value.
1498 public int optInt(String key, int defaultValue)
1500 Object val = this.opt(key);
1501 if (NULL.equals(val))
1503 return defaultValue;
1505 if (val instanceof Number)
1507 return ((Number) val).intValue();
1510 if (val instanceof String)
1514 return new BigDecimal((String) val).intValue();
1515 } catch (Exception e)
1517 return defaultValue;
1520 return defaultValue;
1524 * Get an optional JSONArray associated with a key. It returns null if there
1525 * is no such key, or if its value is not a JSONArray.
1529 * @return A JSONArray which is the value.
1531 public JSONArray optJSONArray(String key)
1533 Object o = this.opt(key);
1534 return o instanceof JSONArray ? (JSONArray) o : null;
1538 * Get an optional JSONObject associated with a key. It returns null if there
1539 * is no such key, or if its value is not a JSONObject.
1543 * @return A JSONObject which is the value.
1545 public JSONObject optJSONObject(String key)
1547 Object object = this.opt(key);
1548 return object instanceof JSONObject ? (JSONObject) object : null;
1552 * Get an optional long value associated with a key, or zero if there is no
1553 * such key or if the value is not a number. If the value is a string, an
1554 * attempt will be made to evaluate it as a number.
1558 * @return An object which is the value.
1560 public long optLong(String key)
1562 return this.optLong(key, 0);
1566 * Get an optional long value associated with a key, or the default if there
1567 * is no such key or if the value is not a number. If the value is a string,
1568 * an attempt will be made to evaluate it as a number.
1572 * @param defaultValue
1574 * @return An object which is the value.
1576 public long optLong(String key, long defaultValue)
1578 Object val = this.opt(key);
1579 if (NULL.equals(val))
1581 return defaultValue;
1583 if (val instanceof Number)
1585 return ((Number) val).longValue();
1588 if (val instanceof String)
1592 return new BigDecimal((String) val).longValue();
1593 } catch (Exception e)
1595 return defaultValue;
1598 return defaultValue;
1602 * Get an optional {@link Number} value associated with a key, or
1603 * <code>null</code> if there is no such key or if the value is not a number.
1604 * If the value is a string, an attempt will be made to evaluate it as a
1605 * number ({@link BigDecimal}). This method would be used in cases where type
1606 * coercion of the number value is unwanted.
1610 * @return An object which is the value.
1612 public Number optNumber(String key)
1614 return this.optNumber(key, null);
1618 * Get an optional {@link Number} value associated with a key, or the default
1619 * if there is no such key or if the value is not a number. If the value is a
1620 * string, an attempt will be made to evaluate it as a number. This method
1621 * would be used in cases where type coercion of the number value is unwanted.
1625 * @param defaultValue
1627 * @return An object which is the value.
1629 public Number optNumber(String key, Number defaultValue)
1631 Object val = this.opt(key);
1632 if (NULL.equals(val))
1634 return defaultValue;
1636 if (val instanceof Number)
1638 return (Number) val;
1641 if (val instanceof String)
1645 return stringToNumber((String) val);
1646 } catch (Exception e)
1648 return defaultValue;
1651 return defaultValue;
1655 * Get an optional string associated with a key. It returns an empty string if
1656 * there is no such key. If the value is not a string and is not null, then it
1657 * is converted to a string.
1661 * @return A string which is the value.
1663 public String optString(String key)
1665 return this.optString(key, "");
1669 * Get an optional string associated with a key. It returns the defaultValue
1670 * if there is no such key.
1674 * @param defaultValue
1676 * @return A string which is the value.
1678 public String optString(String key, String defaultValue)
1680 Object object = this.opt(key);
1681 return NULL.equals(object) ? defaultValue : object.toString();
1685 * Populates the internal map of the JSONObject with the bean properties. The
1686 * bean can not be recursive.
1688 * @see JSONObject#JSONObject(Object)
1693 private void populateMap(Object bean)
1695 Class<?> klass = bean.getClass();
1697 // If klass is a System class then set includeSuperClass to false.
1699 boolean includeSuperClass = klass.getClassLoader() != null;
1701 Method[] methods = includeSuperClass ? klass.getMethods()
1702 : klass.getDeclaredMethods();
1703 for (final Method method : methods)
1705 final int modifiers = method.getModifiers();
1706 if (Modifier.isPublic(modifiers) && !Modifier.isStatic(modifiers)
1707 && method.getParameterTypes().length == 0
1708 && !method.isBridge() && method.getReturnType() != Void.TYPE
1709 && isValidMethodName(method.getName()))
1711 final String key = getKeyNameFromMethod(method);
1712 if (key != null && !key.isEmpty())
1716 final Object result = method.invoke(bean);
1719 this.map.put(key, wrap(result));
1720 // we don't use the result anywhere outside of wrap
1721 // if it's a resource we should be sure to close it
1722 // after calling toString
1723 if (result instanceof Closeable)
1727 ((Closeable) result).close();
1728 } catch (IOException ignore)
1733 } catch (IllegalAccessException ignore)
1735 } catch (IllegalArgumentException ignore)
1737 } catch (InvocationTargetException ignore)
1745 private boolean isValidMethodName(String name)
1747 return !"getClass".equals(name) && !"getDeclaringClass".equals(name);
1750 private String getKeyNameFromMethod(Method method)
1752 final int ignoreDepth = -1;// getAnnotationDepth(method,
1753 // JSONPropertyIgnore.class);
1754 // if (ignoreDepth > 0) {
1755 // final int forcedNameDepth = getAnnotationDepth(method,
1756 // JSONPropertyName.class);
1757 // if (forcedNameDepth < 0 || ignoreDepth <= forcedNameDepth) {
1758 // // the hierarchy asked to ignore, and the nearest name override
1759 // // was higher or non-existent
1763 // JSONPropertyName annotation = getAnnotation(method,
1764 // JSONPropertyName.class);
1765 // if (annotation != null && annotation.value() != null &&
1766 // !annotation.value().isEmpty()) {
1767 // return annotation.value();
1770 final String name = method.getName();
1771 if (name.startsWith("get") && name.length() > 3)
1773 key = name.substring(3);
1775 else if (name.startsWith("is") && name.length() > 2)
1777 key = name.substring(2);
1783 // if the first letter in the key is not uppercase, then skip.
1784 // This is to maintain backwards compatibility before PR406
1785 // (https://github.com/stleary/JSON-java/pull/406/)
1786 if (Character.isLowerCase(key.charAt(0)))
1790 if (key.length() == 1)
1792 key = key.toLowerCase(Locale.ROOT);
1794 else if (!Character.isUpperCase(key.charAt(1)))
1796 key = key.substring(0, 1).toLowerCase(Locale.ROOT) + key.substring(1);
1798 return (/** @j2sNative 1 ? key.split("$")[0] : */
1803 // * Searches the class hierarchy to see if the method or it's super
1804 // * implementations and interfaces has the annotation.
1807 // * type of the annotation
1810 // * method to check
1811 // * @param annotationClass
1812 // * annotation to look for
1813 // * @return the {@link Annotation} if the annotation exists on the current
1815 // * or one of it's super class definitions
1817 // private static <A extends Annotation> A getAnnotation(final Method m, final
1818 // Class<A> annotationClass) {
1820 // // if we have invalid data the result is null
1821 // if (true || m == null || annotationClass == null) {
1825 // if (m.isAnnotationPresent(annotationClass)) {
1826 // return m.getAnnotation(annotationClass);
1829 // // if we've already reached the Object class, return null;
1830 // Class<?> c = m.getDeclaringClass();
1831 // if (c.getSuperclass() == null) {
1835 // // check directly implemented interfaces for the method being checked
1836 // for (Class<?> i : c.getInterfaces()) {
1838 // Method im = i.getMethod(m.getName(), m.getParameterTypes());
1839 // return getAnnotation(im, annotationClass);
1840 // } catch (final SecurityException ex) {
1842 // } catch (final NoSuchMethodException ex) {
1848 // return getAnnotation(
1849 // c.getSuperclass().getMethod(m.getName(), m.getParameterTypes()),
1850 // annotationClass);
1851 // } catch (final SecurityException ex) {
1853 // } catch (final NoSuchMethodException ex) {
1859 // * Searches the class hierarchy to see if the method or it's super
1860 // * implementations and interfaces has the annotation. Returns the depth of
1862 // * annotation in the hierarchy.
1865 // * type of the annotation
1868 // * method to check
1869 // * @param annotationClass
1870 // * annotation to look for
1871 // * @return Depth of the annotation or -1 if the annotation is not on the
1874 // private static int getAnnotationDepth(final Method m, final Class<? extends
1875 // Annotation> annotationClass) {
1876 // // if we have invalid data the result is -1
1877 // if (m == null || annotationClass == null) {
1880 // if (m.isAnnotationPresent(annotationClass)) {
1884 // // if we've already reached the Object class, return -1;
1885 // Class<?> c = m.getDeclaringClass();
1886 // if (c.getSuperclass() == null) {
1890 // // check directly implemented interfaces for the method being checked
1891 // for (Class<?> i : c.getInterfaces()) {
1893 // Method im = i.getMethod(m.getName(), m.getParameterTypes());
1894 // int d = getAnnotationDepth(im, annotationClass);
1896 // // since the annotation was on the interface, add 1
1899 // } catch (final SecurityException ex) {
1901 // } catch (final NoSuchMethodException ex) {
1907 // int d = getAnnotationDepth(
1908 // c.getSuperclass().getMethod(m.getName(), m.getParameterTypes()),
1909 // annotationClass);
1911 // // since the annotation was on the superclass, add 1
1915 // } catch (final SecurityException ex) {
1917 // } catch (final NoSuchMethodException ex) {
1923 * Put a key/boolean pair in the JSONObject.
1928 * A boolean which is the value.
1930 * @throws JSONException
1931 * If the value is non-finite number.
1932 * @throws NullPointerException
1933 * If the key is <code>null</code>.
1935 public JSONObject put(String key, boolean value) throws JSONException
1937 return this.put(key, value ? Boolean.TRUE : Boolean.FALSE);
1941 * Put a key/value pair in the JSONObject, where the value will be a JSONArray
1942 * which is produced from a Collection.
1947 * A Collection value.
1949 * @throws JSONException
1950 * If the value is non-finite number.
1951 * @throws NullPointerException
1952 * If the key is <code>null</code>.
1954 public JSONObject put(String key, Collection<?> value)
1955 throws JSONException
1957 return this.put(key, new JSONArray(value));
1961 * Put a key/double pair in the JSONObject.
1966 * A double which is the value.
1968 * @throws JSONException
1969 * If the value is non-finite number.
1970 * @throws NullPointerException
1971 * If the key is <code>null</code>.
1973 public JSONObject put(String key, double value) throws JSONException
1975 return this.put(key, Double.valueOf(value));
1979 * Put a key/float pair in the JSONObject.
1984 * A float which is the value.
1986 * @throws JSONException
1987 * If the value is non-finite number.
1988 * @throws NullPointerException
1989 * If the key is <code>null</code>.
1991 public JSONObject put(String key, float value) throws JSONException
1993 return this.put(key, Float.valueOf(value));
1997 * Put a key/int pair in the JSONObject.
2002 * An int which is the value.
2004 * @throws JSONException
2005 * If the value is non-finite number.
2006 * @throws NullPointerException
2007 * If the key is <code>null</code>.
2009 public JSONObject put(String key, int value) throws JSONException
2011 return this.put(key, Integer.valueOf(value));
2015 * Put a key/long pair in the JSONObject.
2020 * A long which is the value.
2022 * @throws JSONException
2023 * If the value is non-finite number.
2024 * @throws NullPointerException
2025 * If the key is <code>null</code>.
2027 public JSONObject put(String key, long value) throws JSONException
2029 return this.put(key, Long.valueOf(value));
2033 * Put a key/value pair in the JSONObject, where the value will be a
2034 * JSONObject which is produced from a Map.
2041 * @throws JSONException
2042 * If the value is non-finite number.
2043 * @throws NullPointerException
2044 * If the key is <code>null</code>.
2046 public JSONObject put(String key, Map<?, ?> value) throws JSONException
2048 return this.put(key, new JSONObject(value));
2052 * Put a key/value pair in the JSONObject. If the value is <code>null</code>,
2053 * then the key will be removed from the JSONObject if it is present.
2058 * An object which is the value. It should be of one of these types:
2059 * Boolean, Double, Integer, JSONArray, JSONObject, Long, String, or
2060 * the JSONObject.NULL object.
2062 * @throws JSONException
2063 * If the value is non-finite number.
2064 * @throws NullPointerException
2065 * If the key is <code>null</code>.
2067 public JSONObject put(String key, Object value) throws JSONException
2071 throw new NullPointerException("Null key.");
2075 testValidity(value);
2076 this.map.put(key, value);
2086 * Put a key/value pair in the JSONObject, but only if the key and the value
2087 * are both non-null, and only if there is not already a member with that
2095 * @throws JSONException
2096 * if the key is a duplicate
2098 public JSONObject putOnce(String key, Object value) throws JSONException
2100 if (key != null && value != null)
2102 if (this.opt(key) != null)
2104 throw new JSONException("Duplicate key \"" + key + "\"");
2106 return this.put(key, value);
2112 * Put a key/value pair in the JSONObject, but only if the key and the value
2113 * are both non-null.
2118 * An object which is the value. It should be of one of these types:
2119 * Boolean, Double, Integer, JSONArray, JSONObject, Long, String, or
2120 * the JSONObject.NULL object.
2122 * @throws JSONException
2123 * If the value is a non-finite number.
2125 public JSONObject putOpt(String key, Object value) throws JSONException
2127 if (key != null && value != null)
2129 return this.put(key, value);
2135 * Creates a JSONPointer using an initialization string and tries to match it
2136 * to an item within this JSONObject. For example, given a JSONObject
2137 * initialized with this document:
2145 * and this JSONPointer string:
2151 * Then this method will return the String "c". A JSONPointerException may be
2152 * thrown from code called by this method.
2154 * @param jsonPointer
2155 * string that can be used to create a JSONPointer
2156 * @return the item matched by the JSONPointer, otherwise null
2158 public Object query(String jsonPointer)
2160 return query(new JSONPointer(jsonPointer));
2164 * Uses a user initialized JSONPointer and tries to match it to an item within
2165 * this JSONObject. For example, given a JSONObject initialized with this
2174 * and this JSONPointer:
2180 * Then this method will return the String "c". A JSONPointerException may be
2181 * thrown from code called by this method.
2183 * @param jsonPointer
2184 * string that can be used to create a JSONPointer
2185 * @return the item matched by the JSONPointer, otherwise null
2187 public Object query(JSONPointer jsonPointer)
2189 return jsonPointer.queryFrom(this);
2193 * Queries and returns a value from this object using {@code jsonPointer}, or
2194 * returns null if the query fails due to a missing key.
2196 * @param jsonPointer
2197 * the string representation of the JSON pointer
2198 * @return the queried value or {@code null}
2199 * @throws IllegalArgumentException
2200 * if {@code jsonPointer} has invalid syntax
2202 public Object optQuery(String jsonPointer)
2204 return optQuery(new JSONPointer(jsonPointer));
2208 * Queries and returns a value from this object using {@code jsonPointer}, or
2209 * returns null if the query fails due to a missing key.
2211 * @param jsonPointer
2213 * @return the queried value or {@code null}
2214 * @throws IllegalArgumentException
2215 * if {@code jsonPointer} has invalid syntax
2217 public Object optQuery(JSONPointer jsonPointer)
2221 return jsonPointer.queryFrom(this);
2222 } catch (JSONPointerException e)
2229 * Produce a string in double quotes with backslash sequences in all the right
2230 * places. A backslash will be inserted within </, producing <\/, allowing
2231 * JSON text to be delivered in HTML. In JSON text, a string cannot contain a
2232 * control character or an unescaped quote or backslash.
2236 * @return A String correctly formatted for insertion in a JSON text.
2238 public static String quote(String string)
2240 StringWriter sw = new StringWriter();
2241 synchronized (sw.getBuffer())
2245 return quote(string, sw).toString();
2246 } catch (IOException ignored)
2248 // will never happen - we are writing to a string writer
2254 public static Writer quote(String string, Writer w) throws IOException
2256 if (string == null || string.isEmpty())
2266 int len = string.length();
2269 for (i = 0; i < len; i += 1)
2272 c = string.charAt(i);
2303 if (c < ' ' || (c >= '\u0080' && c < '\u00a0')
2304 || (c >= '\u2000' && c < '\u2100'))
2307 hhhh = Integer.toHexString(c);
2308 w.write("0000", 0, 4 - hhhh.length());
2322 * Remove a name and its value, if present.
2325 * The name to be removed.
2326 * @return The value that was associated with the name, or null if there was
2329 public Object remove(String key)
2331 return this.map.remove(key);
2335 * Determine if two JSONObjects are similar. They must contain the same set of
2336 * names which must be associated with similar values.
2339 * The other JSONObject
2340 * @return true if they are equal
2342 public boolean similar(Object other)
2346 if (!(other instanceof JSONObject))
2350 if (!this.keySet().equals(((JSONObject) other).keySet()))
2354 for (final Entry<String, ?> entry : this.entrySet())
2356 String name = entry.getKey();
2357 Object valueThis = entry.getValue();
2358 Object valueOther = ((JSONObject) other).get(name);
2359 if (valueThis == valueOther)
2363 if (valueThis == null)
2367 if (valueThis instanceof JSONObject)
2369 if (!((JSONObject) valueThis).similar(valueOther))
2374 else if (valueThis instanceof JSONArray)
2376 if (!((JSONArray) valueThis).similar(valueOther))
2381 else if (!valueThis.equals(valueOther))
2387 } catch (Throwable exception)
2394 * Tests if the value should be tried as a decimal. It makes no test if there
2395 * are actual digits.
2399 * @return true if the string is "-0" or if it contains '.', 'e', or 'E',
2402 protected static boolean isDecimalNotation(final String val)
2404 return val.indexOf('.') > -1 || val.indexOf('e') > -1
2405 || val.indexOf('E') > -1 || "-0".equals(val);
2409 * Converts a string to a number using the narrowest possible type. Possible
2410 * returns for this function are BigDecimal, Double, BigInteger, Long, and
2411 * Integer. When a Double is returned, it should always be a valid Double and
2412 * not NaN or +-infinity.
2416 * @return Number representation of the value.
2417 * @throws NumberFormatException
2418 * thrown if the value is not a valid number. A public caller should
2419 * catch this and wrap it in a {@link JSONException} if applicable.
2421 protected static Number stringToNumber(final String val)
2422 throws NumberFormatException
2424 char initial = val.charAt(0);
2425 if ((initial >= '0' && initial <= '9') || initial == '-')
2427 // decimal representation
2428 if (isDecimalNotation(val))
2430 // quick dirty way to see if we need a BigDecimal instead of a Double
2431 // this only handles some cases of overflow or underflow
2432 if (val.length() > 14)
2434 return new BigDecimal(val);
2436 final Double d = Double.valueOf(val);
2437 if (d.isInfinite() || d.isNaN())
2439 // if we can't parse it as a double, go up to BigDecimal
2440 // this is probably due to underflow like 4.32e-678
2441 // or overflow like 4.65e5324. The size of the string is small
2442 // but can't be held in a Double.
2443 return new BigDecimal(val);
2447 // integer representation.
2448 // This will narrow any values to the smallest reasonable Object
2450 // (Integer, Long, or BigInteger)
2453 // The compare string length method reduces GC,
2454 // but leads to smaller integers being placed in larger wrappers even
2456 // needed. i.e. 1,000,000,000 -> Long even though it's an Integer
2457 // 1,000,000,000,000,000,000 -> BigInteger even though it's a Long
2458 // if(val.length()<=9){
2459 // return Integer.valueOf(val);
2461 // if(val.length()<=18){
2462 // return Long.valueOf(val);
2464 // return new BigInteger(val);
2466 // BigInteger version: We use a similar bitLenth compare as
2467 // BigInteger#intValueExact uses. Increases GC, but objects hold
2468 // only what they need. i.e. Less runtime overhead if the value is
2469 // long lived. Which is the better tradeoff? This is closer to what's
2470 // in stringToValue.
2471 BigInteger bi = new BigInteger(val);
2472 if (bi.bitLength() <= 31)
2474 return Integer.valueOf(bi.intValue());
2476 if (bi.bitLength() <= 63)
2478 return Long.valueOf(bi.longValue());
2482 throw new NumberFormatException(
2483 "val [" + val + "] is not a valid number.");
2487 * Try to convert a string into a number, boolean, or null. If the string
2488 * can't be converted, return the string.
2492 * @return A simple JSON value.
2494 // Changes to this method must be copied to the corresponding method in
2495 // the XML class to keep full support for Android
2496 public static Object stringToValue(String string)
2498 if (string.equals(""))
2502 if (string.equalsIgnoreCase("true"))
2504 return Boolean.TRUE;
2506 if (string.equalsIgnoreCase("false"))
2508 return Boolean.FALSE;
2510 if (string.equalsIgnoreCase("null"))
2512 return JSONObject.NULL;
2516 * If it might be a number, try converting it. If a number cannot be produced,
2517 * then the value will just be a string.
2520 char initial = string.charAt(0);
2521 if ((initial >= '0' && initial <= '9') || initial == '-')
2525 // if we want full Big Number support this block can be replaced with:
2526 // return stringToNumber(string);
2527 if (isDecimalNotation(string))
2529 Double d = Double.valueOf(string);
2530 if (!d.isInfinite() && !d.isNaN())
2537 Long myLong = Long.valueOf(string);
2538 if (string.equals(myLong.toString()))
2540 if (myLong.longValue() == myLong.intValue())
2542 return Integer.valueOf(myLong.intValue());
2547 } catch (Exception ignore)
2555 * Throw an exception if the object is a NaN or infinite number.
2558 * The object to test.
2559 * @throws JSONException
2560 * If o is a non-finite number.
2562 public static void testValidity(Object o) throws JSONException
2566 if (o instanceof Double)
2568 if (((Double) o).isInfinite() || ((Double) o).isNaN())
2570 throw new JSONException(
2571 "JSON does not allow non-finite numbers.");
2574 else if (o instanceof Float)
2576 if (((Float) o).isInfinite() || ((Float) o).isNaN())
2578 throw new JSONException(
2579 "JSON does not allow non-finite numbers.");
2586 * Produce a JSONArray containing the values of the members of this
2590 * A JSONArray containing a list of key strings. This determines the
2591 * sequence of the values in the result.
2592 * @return A JSONArray of values.
2593 * @throws JSONException
2594 * If any of the values are non-finite numbers.
2596 public JSONArray toJSONArray(JSONArray names) throws JSONException
2598 if (names == null || names.isEmpty())
2602 JSONArray ja = new JSONArray();
2603 for (int i = 0; i < names.length(); i += 1)
2605 ja.put(this.opt(names.getString(i)));
2611 * Make a JSON text of this JSONObject. For compactness, no whitespace is
2612 * added. If this would not result in a syntactically correct JSON text, then
2613 * null will be returned instead.
2615 * <b> Warning: This method assumes that the data structure is acyclical. </b>
2617 * @return a printable, displayable, portable, transmittable representation of
2618 * the object, beginning with <code>{</code> <small>(left
2619 * brace)</small> and ending with <code>}</code> <small>(right
2623 public String toString()
2627 return this.toString(0);
2628 } catch (Exception e)
2635 * Make a pretty-printed JSON text of this JSONObject.
2638 * If <code>indentFactor > 0</code> and the {@link JSONObject} has only one
2639 * key, then the object will be output on a single line:
2642 * {@code {"key": 1}}
2646 * If an object has 2 or more keys, then it will be output across multiple
2647 * lines: <code><pre>{
2649 * "key2": "value 2",
2653 * <b> Warning: This method assumes that the data structure is acyclical. </b>
2655 * @param indentFactor
2656 * The number of spaces to add to each level of indentation.
2657 * @return a printable, displayable, portable, transmittable representation of
2658 * the object, beginning with <code>{</code> <small>(left
2659 * brace)</small> and ending with <code>}</code> <small>(right
2661 * @throws JSONException
2662 * If the object contains an invalid number.
2664 public String toString(int indentFactor) throws JSONException
2666 StringWriter w = new StringWriter();
2667 synchronized (w.getBuffer())
2669 return this.write(w, indentFactor, 0).toString();
2674 * Make a JSON text of an Object value. If the object has an
2675 * value.toJSONString() method, then that method will be used to produce the
2676 * JSON text. The method is required to produce a strictly conforming text. If
2677 * the object does not contain a toJSONString method (which is the most common
2678 * case), then a text will be produced by other means. If the value is an
2679 * array or Collection, then a JSONArray will be made from it and its
2680 * toJSONString method will be called. If the value is a MAP, then a
2681 * JSONObject will be made from it and its toJSONString method will be called.
2682 * Otherwise, the value's toString method will be called, and the result will
2686 * Warning: This method assumes that the data structure is acyclical.
2689 * The value to be serialized.
2690 * @return a printable, displayable, transmittable representation of the
2691 * object, beginning with <code>{</code> <small>(left
2692 * brace)</small> and ending with <code>}</code> <small>(right
2694 * @throws JSONException
2695 * If the value is or contains an invalid number.
2697 public static String valueToString(Object value) throws JSONException
2699 // moves the implementation to JSONWriter as:
2700 // 1. It makes more sense to be part of the writer class
2701 // 2. For Android support this method is not available. By implementing it
2704 // Android users can use the writer with the built in Android JSONObject
2706 return JSONWriter.valueToString(value);
2710 * Wrap an object, if necessary. If the object is <code>null</code>, return
2711 * the NULL object. If it is an array or collection, wrap it in a JSONArray.
2712 * If it is a map, wrap it in a JSONObject. If it is a standard property
2713 * (Double, String, et al) then it is already wrapped. Otherwise, if it comes
2714 * from one of the java packages, turn it into a string. And if it doesn't,
2715 * try to wrap it in a JSONObject. If the wrapping fails, then null is
2719 * The object to wrap
2720 * @return The wrapped value
2722 public static Object wrap(Object object)
2730 if (object instanceof JSONObject || object instanceof JSONArray
2731 || NULL.equals(object) || object instanceof JSONString
2732 || object instanceof Byte || object instanceof Character
2733 || object instanceof Short || object instanceof Integer
2734 || object instanceof Long || object instanceof Boolean
2735 || object instanceof Float || object instanceof Double
2736 || object instanceof String || object instanceof BigInteger
2737 || object instanceof BigDecimal || object instanceof Enum)
2742 if (object instanceof Collection)
2744 Collection<?> coll = (Collection<?>) object;
2745 return new JSONArray(coll);
2747 if (object.getClass().isArray())
2749 return new JSONArray(object);
2751 if (object instanceof Map)
2753 Map<?, ?> map = (Map<?, ?>) object;
2754 return new JSONObject(map);
2756 Package objectPackage = object.getClass().getPackage();
2757 String objectPackageName = objectPackage != null
2758 ? objectPackage.getName()
2760 if (objectPackageName.startsWith("java.")
2761 || objectPackageName.startsWith("javax.")
2762 || object.getClass().getClassLoader() == null)
2764 return object.toString();
2766 return new JSONObject(object);
2767 } catch (Exception exception)
2774 * Write the contents of the JSONObject as JSON text to a writer. For
2775 * compactness, no whitespace is added.
2777 * <b> Warning: This method assumes that the data structure is acyclical. </b>
2779 * @return The writer.
2780 * @throws JSONException
2782 public Writer write(Writer writer) throws JSONException
2784 return this.write(writer, 0, 0);
2787 static final Writer writeValue(Writer writer, Object value,
2788 int indentFactor, int indent) throws JSONException, IOException
2790 if (value == null || value.equals(null))
2792 writer.write("null");
2794 else if (value instanceof JSONString)
2799 o = ((JSONString) value).toJSONString();
2800 } catch (Exception e)
2802 throw new JSONException(e);
2804 writer.write(o != null ? o.toString() : quote(value.toString()));
2806 else if (value instanceof Number)
2808 // not all Numbers may match actual JSON Numbers. i.e. fractions or
2810 final String numberAsString = numberToString((Number) value);
2813 // Use the BigDecimal constructor for its parser to validate the format.
2814 @SuppressWarnings("unused")
2815 BigDecimal testNum = new BigDecimal(numberAsString);
2816 // Close enough to a JSON number that we will use it unquoted
2817 writer.write(numberAsString);
2818 } catch (NumberFormatException ex)
2820 // The Number value is not a valid JSON number.
2821 // Instead we will quote it as a string
2822 quote(numberAsString, writer);
2825 else if (value instanceof Boolean)
2827 writer.write(value.toString());
2829 else if (value instanceof Enum<?>)
2831 writer.write(quote(((Enum<?>) value).name()));
2833 else if (value instanceof JSONObject)
2835 ((JSONObject) value).write(writer, indentFactor, indent);
2837 else if (value instanceof JSONArray)
2839 ((JSONArray) value).write(writer, indentFactor, indent);
2841 else if (value instanceof Map)
2843 Map<?, ?> map = (Map<?, ?>) value;
2844 new JSONObject(map).write(writer, indentFactor, indent);
2846 else if (value instanceof Collection)
2848 Collection<?> coll = (Collection<?>) value;
2849 new JSONArray(coll).write(writer, indentFactor, indent);
2851 else if (value.getClass().isArray())
2853 new JSONArray(value).write(writer, indentFactor, indent);
2857 quote(value.toString(), writer);
2862 static final void indent(Writer writer, int indent) throws IOException
2864 for (int i = 0; i < indent; i += 1)
2871 * Write the contents of the JSONObject as JSON text to a writer.
2874 * If <code>indentFactor > 0</code> and the {@link JSONObject} has only one
2875 * key, then the object will be output on a single line:
2878 * {@code {"key": 1}}
2882 * If an object has 2 or more keys, then it will be output across multiple
2883 * lines: <code><pre>{
2885 * "key2": "value 2",
2889 * <b> Warning: This method assumes that the data structure is acyclical. </b>
2892 * Writes the serialized JSON
2893 * @param indentFactor
2894 * The number of spaces to add to each level of indentation.
2896 * The indentation of the top level.
2897 * @return The writer.
2898 * @throws JSONException
2900 public Writer write(Writer writer, int indentFactor, int indent)
2901 throws JSONException
2905 boolean commanate = false;
2906 final int length = this.length();
2911 final Entry<String, ?> entry = this.entrySet().iterator().next();
2912 final String key = entry.getKey();
2913 writer.write(quote(key));
2915 if (indentFactor > 0)
2921 writeValue(writer, entry.getValue(), indentFactor, indent);
2922 } catch (Exception e)
2924 throw new JSONException(
2925 "Unable to write JSONObject value for key: " + key, e);
2928 else if (length != 0)
2930 final int newindent = indent + indentFactor;
2931 for (final Entry<String, ?> entry : this.entrySet())
2937 if (indentFactor > 0)
2941 indent(writer, newindent);
2942 final String key = entry.getKey();
2943 writer.write(quote(key));
2945 if (indentFactor > 0)
2951 writeValue(writer, entry.getValue(), indentFactor, newindent);
2952 } catch (Exception e)
2954 throw new JSONException(
2955 "Unable to write JSONObject value for key: " + key, e);
2959 if (indentFactor > 0)
2963 indent(writer, indent);
2967 } catch (IOException exception)
2969 throw new JSONException(exception);
2974 * Returns a java.util.Map containing all of the entries in this object. If an
2975 * entry in the object is a JSONArray or JSONObject it will also be converted.
2977 * Warning: This method assumes that the data structure is acyclical.
2979 * @return a java.util.Map containing the entries of this object
2981 public Map<String, Object> toMap()
2983 Map<String, Object> results = new HashMap<String, Object>();
2984 for (Entry<String, Object> entry : this.entrySet())
2987 if (entry.getValue() == null || NULL.equals(entry.getValue()))
2991 else if (entry.getValue() instanceof JSONObject)
2993 value = ((JSONObject) entry.getValue()).toMap();
2995 else if (entry.getValue() instanceof JSONArray)
2997 value = ((JSONArray) entry.getValue()).toList();
3001 value = entry.getValue();
3003 results.put(entry.getKey(), value);