Clover icon

Coverage Report

  1. Project Clover database Thu Dec 4 2025 16:11:35 GMT
  2. Package org.json

File JSONObject.java

 

Coverage histogram

../../img/srcFileCovDistChart4.png
49% of files have more coverage

Code metrics

336
626
97
2
3,007
1,499
372
0.59
6.45
48.5
3.84

Classes

Class Line # Actions
JSONObject 101 622 368
0.3444338734.4%
JSONObject.Null 108 4 4
0.2525%
 

Contributing tests

This file is covered by 64 tests. .

Source view

1    package org.json;
2   
3    import java.io.Closeable;
4   
5    /*
6    *
7    * Note: This file has been adapted for SwingJS by Bob Hanson hansonr@stolaf.edu
8    *
9    Copyright (c) 2002 JSON.org
10   
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:
17   
18    The above copyright notice and this permission notice shall be included in all
19    copies or substantial portions of the Software.
20   
21    The Software shall be used for Good, not Evil.
22   
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
29    SOFTWARE.
30    */
31   
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;
46    import java.util.Map;
47    import java.util.Map.Entry;
48    import java.util.ResourceBundle;
49    import java.util.Set;
50   
51    /**
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.
67    * <p>
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.
73    * <p>
74    * The <code>put</code> methods add or replace values in an object. For example,
75    *
76    * <pre>
77    * myString = new JSONObject().put(&quot;JSON&quot;, &quot;Hello, World!&quot;).toString();
78    * </pre>
79    *
80    * produces the string <code>{"JSON": "Hello, World"}</code>.
81    * <p>
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
84    * will accept:
85    * <ul>
86    * <li>An extra <code>,</code>&nbsp;<small>(comma)</small> may appear just
87    * before the closing brace.</li>
88    * <li>Strings may be quoted with <code>'</code>&nbsp;<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>
96    * </ul>
97    *
98    * @author JSON.org
99    * @version 2016-08-15
100    */
 
101    public class JSONObject
102    {
103    /**
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
106    * undefined.
107    */
 
108    private static final class Null
109    {
110   
111    /**
112    * There is only intended to be a single instance of the NULL object, so the
113    * clone method returns itself.
114    *
115    * @return NULL.
116    */
 
117  0 toggle @Override
118    protected final Object clone()
119    {
120  0 return this;
121    }
122   
123    /**
124    * A Null object is equal to the null value and to itself.
125    *
126    * @param object
127    * An object to test for nullness.
128    * @return true if the object parameter is the JSONObject.NULL object or
129    * null.
130    */
 
131  71436 toggle @Override
132    public boolean equals(Object object)
133    {
134  71436 return object == null || object == this;
135    }
136   
137    /**
138    * A Null object is equal to the null value and to itself.
139    *
140    * @return always returns 0.
141    */
 
142  0 toggle @Override
143    public int hashCode()
144    {
145  0 return 0;
146    }
147   
148    /**
149    * Get the "null" string value.
150    *
151    * @return The string "null".
152    */
 
153  0 toggle @Override
154    public String toString()
155    {
156  0 return "null";
157    }
158    }
159   
160    /**
161    * The map where the JSONObject's properties are kept.
162    */
163    private final Map<String, Object> map;
164   
165    /**
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>.
170    */
171    public static final Object NULL = new Null();
172   
173    /**
174    * Construct an empty JSONObject.
175    */
 
176  20233 toggle public JSONObject()
177    {
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  20233 this.map = new HashMap<String, Object>();
185    }
186   
187    /**
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
190    * are ignored.
191    *
192    * @param jo
193    * A JSONObject.
194    * @param names
195    * An array of strings.
196    */
 
197  0 toggle public JSONObject(JSONObject jo, String[] names)
198    {
199  0 this(names.length);
200  0 for (int i = 0; i < names.length; i += 1)
201    {
202  0 try
203    {
204  0 this.putOnce(names[i], jo.opt(names[i]));
205    } catch (Exception ignore)
206    {
207    }
208    }
209    }
210   
211    /**
212    * Construct a JSONObject from a JSONTokener.
213    *
214    * @param x
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
218    * key.
219    */
 
220  19950 toggle public JSONObject(JSONTokener x) throws JSONException
221    {
222  19950 this();
223  19950 char c;
224  19950 String key;
225   
226  19950 if (x.nextClean() != '{')
227    {
228  0 throw x.syntaxError("A JSONObject text must begin with '{'");
229    }
230  19950 for (;;)
231    {
232  151792 c = x.nextClean();
233  151795 switch (c)
234    {
235  0 case 0:
236  0 throw x.syntaxError("A JSONObject text must end with '}'");
237  1534 case '}':
238  1534 return;
239  150261 default:
240  150257 x.back();
241  150255 key = x.nextValue().toString();
242    }
243   
244    // The key is followed by ':'.
245   
246  150265 c = x.nextClean();
247  150261 if (c != ':')
248    {
249  0 throw x.syntaxError("Expected a ':' after a key");
250    }
251   
252    // Use syntaxError(..) to include error location
253   
254  150261 if (key != null)
255    {
256    // Check if key exists
257  150261 if (this.opt(key) != null)
258    {
259    // key already exists
260  0 throw x.syntaxError("Duplicate key \"" + key + "\"");
261    }
262    // Only add value if non-null
263  150262 Object value = x.nextValue();
264  150253 if (value != null)
265    {
266  150252 this.put(key, value);
267    }
268    }
269   
270    // Pairs are separated by ','.
271   
272  150251 switch (x.nextClean())
273    {
274  0 case ';':
275  131842 case ',':
276  131847 if (x.nextClean() == '}')
277    {
278  0 return;
279    }
280  131845 x.back();
281  131845 break;
282  18413 case '}':
283  18413 return;
284  0 default:
285  0 throw x.syntaxError("Expected a ',' or '}'");
286    }
287    }
288    }
289   
290    /**
291    * Construct a JSONObject from a Map.
292    *
293    * @param m
294    * A map object that can be used to initialize the contents of the
295    * JSONObject.
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>
300    */
 
301  8 toggle public JSONObject(Map<?, ?> m)
302    {
303  8 if (m == null)
304    {
305  0 this.map = new HashMap<String, Object>();
306    }
307    else
308    {
309  8 this.map = new HashMap<String, Object>(m.size());
310  8 for (final Entry<?, ?> e : m.entrySet())
311    {
312  50 if (e.getKey() == null)
313    {
314  0 throw new NullPointerException("Null key.");
315    }
316  50 final Object value = e.getValue();
317  50 if (value != null)
318    {
319  42 this.map.put(String.valueOf(e.getKey()), wrap(value));
320    }
321    }
322    }
323    }
324   
325    /**
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.
331    * <p>
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.
335    * <p>
336    * Methods that are <code>static</code>, return <code>void</code>, have
337    * parameters, or are "bridge" methods, are ignored.
338    * <p>
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>.
343    * <p>
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:
347    *
348    * <pre>
349    * &#64;JSONPropertyName("FullName")
350    * public String getName()
351    * {
352    * return this.name;
353    * }
354    * </pre>
355    *
356    * The resulting JSON object would contain
357    * <code>"FullName": "Larry Fine"</code>
358    * <p>
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
362    * be ignored:
363    *
364    * <pre>
365    * &#64;JSONPropertyName("FullName")
366    * public String fullName()
367    * {
368    * return this.name;
369    * }
370    * </pre>
371    *
372    * The resulting JSON object would contain
373    * <code>"FullName": "Larry Fine"</code>
374    * <p>
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:
383    *
384    * <pre>
385    * &#64;JSONPropertyName("FullName")
386    * &#64;JSONPropertyIgnore
387    * public String getName()
388    * {
389    * return this.name;
390    * }
391    * </pre>
392    * <p>
393    *
394    * @param bean
395    * An object that has getter methods that should be used to make a
396    * JSONObject.
397    */
 
398  283 toggle public JSONObject(Object bean)
399    {
400  283 this();
401  283 this.populateMap(bean);
402    }
403   
404    /**
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.
410    *
411    * @param object
412    * An object that has fields that should be used to make a
413    * JSONObject.
414    * @param names
415    * An array of strings, the names of the fields to be obtained from
416    * the object.
417    */
 
418  0 toggle public JSONObject(Object object, String names[])
419    {
420  0 this(names.length);
421  0 Class<?> c = object.getClass();
422  0 for (int i = 0; i < names.length; i += 1)
423    {
424  0 String name = names[i];
425  0 try
426    {
427  0 this.putOpt(name, c.getField(name).get(object));
428    } catch (Exception ignore)
429    {
430    }
431    }
432    }
433   
434    /**
435    * Construct a JSONObject from a source JSON text string. This is the most
436    * commonly used JSONObject constructor.
437    *
438    * @param source
439    * A string beginning with <code>{</code>&nbsp;<small>(left
440    * brace)</small> and ending with <code>}</code> &nbsp;<small>(right
441    * brace)</small>.
442    * @exception JSONException
443    * If there is a syntax error in the source string or a
444    * duplicated key.
445    */
 
446  118 toggle public JSONObject(String source) throws JSONException
447    {
448  118 this(new JSONTokener(source));
449    }
450   
451    /**
452    * Construct a JSONObject from a ResourceBundle.
453    *
454    * @param baseName
455    * The ResourceBundle base name.
456    * @param locale
457    * The Locale to load the ResourceBundle for.
458    * @throws JSONException
459    * If any JSONExceptions are detected.
460    */
 
461  0 toggle public JSONObject(String baseName, Locale locale) throws JSONException
462    {
463  0 this();
464  0 ResourceBundle bundle = ResourceBundle.getBundle(baseName, locale,
465    Thread.currentThread().getContextClassLoader());
466   
467    // Iterate through the keys in the bundle.
468   
469  0 Enumeration<String> keys = bundle.getKeys();
470  0 while (keys.hasMoreElements())
471    {
472  0 Object key = keys.nextElement();
473  0 if (key != null)
474    {
475   
476    // Go through the path, ensuring that there is a nested JSONObject for
477    // each
478    // segment except the last. Add the value using the last segment's name
479    // into
480    // the deepest nested JSONObject.
481   
482  0 String[] path = ((String) key).split("\\.");
483  0 int last = path.length - 1;
484  0 JSONObject target = this;
485  0 for (int i = 0; i < last; i += 1)
486    {
487  0 String segment = path[i];
488  0 JSONObject nextTarget = target.optJSONObject(segment);
489  0 if (nextTarget == null)
490    {
491  0 nextTarget = new JSONObject();
492  0 target.put(segment, nextTarget);
493    }
494  0 target = nextTarget;
495    }
496  0 target.put(path[last], bundle.getString((String) key));
497    }
498    }
499    }
500   
501    /**
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.
505    *
506    * @param initialCapacity
507    * initial capacity of the internal map.
508    */
 
509  0 toggle protected JSONObject(int initialCapacity)
510    {
511  0 this.map = new HashMap<String, Object>(initialCapacity);
512    }
513   
514    /**
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.
520    *
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.
524    *
525    * @param key
526    * A key string.
527    * @param value
528    * An object to be accumulated under the key.
529    * @return this.
530    * @throws JSONException
531    * If the value is non-finite number.
532    * @throws NullPointerException
533    * If the key is <code>null</code>.
534    */
 
535  0 toggle public JSONObject accumulate(String key, Object value)
536    throws JSONException
537    {
538  0 testValidity(value);
539  0 Object object = this.opt(key);
540  0 if (object == null)
541    {
542  0 this.put(key, value instanceof JSONArray ? new JSONArray().put(value)
543    : value);
544    }
545  0 else if (object instanceof JSONArray)
546    {
547  0 ((JSONArray) object).put(value);
548    }
549    else
550    {
551  0 this.put(key, new JSONArray().put(object).put(value));
552    }
553  0 return this;
554    }
555   
556    /**
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.
561    *
562    * @param key
563    * A key string.
564    * @param value
565    * An object to be accumulated under the key.
566    * @return this.
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>.
572    */
 
573  0 toggle public JSONObject append(String key, Object value) throws JSONException
574    {
575  0 testValidity(value);
576  0 Object object = this.opt(key);
577  0 if (object == null)
578    {
579  0 this.put(key, new JSONArray().put(value));
580    }
581  0 else if (object instanceof JSONArray)
582    {
583  0 this.put(key, ((JSONArray) object).put(value));
584    }
585    else
586    {
587  0 throw new JSONException(
588    "JSONObject[" + key + "] is not a JSONArray.");
589    }
590  0 return this;
591    }
592   
593    /**
594    * Produce a string from a double. The string "null" will be returned if the
595    * number is not finite.
596    *
597    * @param d
598    * A double.
599    * @return A String.
600    */
 
601  0 toggle public static String doubleToString(double d)
602    {
603  0 if (Double.isInfinite(d) || Double.isNaN(d))
604    {
605  0 return "null";
606    }
607   
608    // Shave off trailing zeros and decimal point, if possible.
609   
610  0 String string = Double.toString(d);
611  0 if (string.indexOf('.') > 0 && string.indexOf('e') < 0
612    && string.indexOf('E') < 0)
613    {
614  0 while (string.endsWith("0"))
615    {
616  0 string = string.substring(0, string.length() - 1);
617    }
618  0 if (string.endsWith("."))
619    {
620  0 string = string.substring(0, string.length() - 1);
621    }
622    }
623  0 return string;
624    }
625   
626    /**
627    * Get the value object associated with a key.
628    *
629    * @param key
630    * A key string.
631    * @return The object associated with the key.
632    * @throws JSONException
633    * if the key is not found.
634    */
 
635  106672 toggle public Object get(String key) throws JSONException
636    {
637  106672 if (key == null)
638    {
639  0 throw new JSONException("Null key.");
640    }
641  106672 Object object = this.opt(key);
642  106672 if (object == null)
643    {
644  0 throw new JSONException("JSONObject[" + quote(key) + "] not found.");
645    }
646  106672 return object;
647    }
648   
649    /**
650    * Get the enum value associated with a key.
651    *
652    * @param clazz
653    * The type of enum to retrieve.
654    * @param key
655    * A key string.
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
659    * enum.
660    */
 
661  0 toggle public <E extends Enum<E>> E getEnum(Class<E> clazz, String key)
662    throws JSONException
663    {
664  0 E val = optEnum(clazz, key);
665  0 if (val == null)
666    {
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  0 throw new JSONException(
671    "JSONObject[" + quote(key) + "] is not an enum of type "
672    + quote(clazz.getSimpleName()) + ".");
673    }
674  0 return val;
675    }
676   
677    /**
678    * Get the boolean value associated with a key.
679    *
680    * @param key
681    * A key string.
682    * @return The truth.
683    * @throws JSONException
684    * if the value is not a Boolean or the String "true" or "false".
685    */
 
686  0 toggle public boolean getBoolean(String key) throws JSONException
687    {
688  0 Object object = this.get(key);
689  0 if (object.equals(Boolean.FALSE) || (object instanceof String
690    && ((String) object).equalsIgnoreCase("false")))
691    {
692  0 return false;
693    }
694  0 else if (object.equals(Boolean.TRUE) || (object instanceof String
695    && ((String) object).equalsIgnoreCase("true")))
696    {
697  0 return true;
698    }
699  0 throw new JSONException(
700    "JSONObject[" + quote(key) + "] is not a Boolean.");
701    }
702   
703    /**
704    * Get the BigInteger value associated with a key.
705    *
706    * @param key
707    * A key string.
708    * @return The numeric value.
709    * @throws JSONException
710    * if the key is not found or if the value cannot be converted to
711    * BigInteger.
712    */
 
713  0 toggle public BigInteger getBigInteger(String key) throws JSONException
714    {
715  0 Object object = this.get(key);
716  0 try
717    {
718  0 return new BigInteger(object.toString());
719    } catch (Exception e)
720    {
721  0 throw new JSONException("JSONObject[" + quote(key)
722    + "] could not be converted to BigInteger.", e);
723    }
724    }
725   
726    /**
727    * Get the BigDecimal value associated with a key.
728    *
729    * @param key
730    * A key string.
731    * @return The numeric value.
732    * @throws JSONException
733    * if the key is not found or if the value cannot be converted to
734    * BigDecimal.
735    */
 
736  0 toggle public BigDecimal getBigDecimal(String key) throws JSONException
737    {
738  0 Object object = this.get(key);
739  0 if (object instanceof BigDecimal)
740    {
741  0 return (BigDecimal) object;
742    }
743  0 try
744    {
745  0 return new BigDecimal(object.toString());
746    } catch (Exception e)
747    {
748  0 throw new JSONException("JSONObject[" + quote(key)
749    + "] could not be converted to BigDecimal.", e);
750    }
751    }
752   
753    /**
754    * Get the double value associated with a key.
755    *
756    * @param key
757    * A key string.
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.
762    */
 
763  0 toggle public double getDouble(String key) throws JSONException
764    {
765  0 Object object = this.get(key);
766  0 try
767    {
768  0 return object instanceof Number ? ((Number) object).doubleValue()
769    : Double.parseDouble(object.toString());
770    } catch (Exception e)
771    {
772  0 throw new JSONException(
773    "JSONObject[" + quote(key) + "] is not a number.", e);
774    }
775    }
776   
777    /**
778    * Get the float value associated with a key.
779    *
780    * @param key
781    * A key string.
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.
786    */
 
787  0 toggle public float getFloat(String key) throws JSONException
788    {
789  0 Object object = this.get(key);
790  0 try
791    {
792  0 return object instanceof Number ? ((Number) object).floatValue()
793    : Float.parseFloat(object.toString());
794    } catch (Exception e)
795    {
796  0 throw new JSONException(
797    "JSONObject[" + quote(key) + "] is not a number.", e);
798    }
799    }
800   
801    /**
802    * Get the Number value associated with a key.
803    *
804    * @param key
805    * A key string.
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.
810    */
 
811  0 toggle public Number getNumber(String key) throws JSONException
812    {
813  0 Object object = this.get(key);
814  0 try
815    {
816  0 if (object instanceof Number)
817    {
818  0 return (Number) object;
819    }
820  0 return stringToNumber(object.toString());
821    } catch (Exception e)
822    {
823  0 throw new JSONException(
824    "JSONObject[" + quote(key) + "] is not a number.", e);
825    }
826    }
827   
828    /**
829    * Get the int value associated with a key.
830    *
831    * @param key
832    * A key string.
833    * @return The integer value.
834    * @throws JSONException
835    * if the key is not found or if the value cannot be converted to an
836    * integer.
837    */
 
838  0 toggle public int getInt(String key) throws JSONException
839    {
840  0 Object object = this.get(key);
841  0 try
842    {
843  0 return object instanceof Number ? ((Number) object).intValue()
844    : Integer.parseInt((String) object);
845    } catch (Exception e)
846    {
847  0 throw new JSONException(
848    "JSONObject[" + quote(key) + "] is not an int.", e);
849    }
850    }
851   
852    /**
853    * Get the JSONArray value associated with a key.
854    *
855    * @param key
856    * A key string.
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.
860    */
 
861  9204 toggle public JSONArray getJSONArray(String key) throws JSONException
862    {
863  9204 Object object = this.get(key);
864  9204 if (object instanceof JSONArray)
865    {
866  9204 return (JSONArray) object;
867    }
868  0 throw new JSONException(
869    "JSONObject[" + quote(key) + "] is not a JSONArray.");
870    }
871   
872    /**
873    * Get the JSONObject value associated with a key.
874    *
875    * @param key
876    * A key string.
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.
880    */
 
881  5310 toggle public JSONObject getJSONObject(String key) throws JSONException
882    {
883  5310 Object object = this.get(key);
884  5310 if (object instanceof JSONObject)
885    {
886  5310 return (JSONObject) object;
887    }
888  0 throw new JSONException(
889    "JSONObject[" + quote(key) + "] is not a JSONObject.");
890    }
891   
892    /**
893    * Get the long value associated with a key.
894    *
895    * @param key
896    * A key string.
897    * @return The long value.
898    * @throws JSONException
899    * if the key is not found or if the value cannot be converted to a
900    * long.
901    */
 
902  0 toggle public long getLong(String key) throws JSONException
903    {
904  0 Object object = this.get(key);
905  0 try
906    {
907  0 return object instanceof Number ? ((Number) object).longValue()
908    : Long.parseLong((String) object);
909    } catch (Exception e)
910    {
911  0 throw new JSONException(
912    "JSONObject[" + quote(key) + "] is not a long.", e);
913    }
914    }
915   
916    /**
917    * Get an array of field names from a JSONObject.
918    *
919    * @return An array of field names, or null if there are no names.
920    */
 
921  0 toggle public static String[] getNames(JSONObject jo)
922    {
923  0 if (jo.isEmpty())
924    {
925  0 return null;
926    }
927  0 return jo.keySet().toArray(new String[jo.length()]);
928    }
929   
930    /**
931    * Get an array of field names from an Object.
932    *
933    * @return An array of field names, or null if there are no names.
934    */
 
935  0 toggle public static String[] getNames(Object object)
936    {
937  0 if (object == null)
938    {
939  0 return null;
940    }
941  0 Class<?> klass = object.getClass();
942  0 Field[] fields = klass.getFields();
943  0 int length = fields.length;
944  0 if (length == 0)
945    {
946  0 return null;
947    }
948  0 String[] names = new String[length];
949  0 for (int i = 0; i < length; i += 1)
950    {
951  0 names[i] = fields[i].getName();
952    }
953  0 return names;
954    }
955   
956    /**
957    * Get the string associated with a key.
958    *
959    * @param key
960    * A key string.
961    * @return A string which is the value.
962    * @throws JSONException
963    * if there is no string value for the key.
964    */
 
965  76700 toggle public String getString(String key) throws JSONException
966    {
967  76700 Object object = this.get(key);
968  76700 if (object instanceof String)
969    {
970  76700 return (String) object;
971    }
972  0 throw new JSONException("JSONObject[" + quote(key) + "] not a string.");
973    }
974   
975    /**
976    * Determine if the JSONObject contains a specific key.
977    *
978    * @param key
979    * A key string.
980    * @return true if the key exists in the JSONObject.
981    */
 
982  0 toggle public boolean has(String key)
983    {
984  0 return this.map.containsKey(key);
985    }
986   
987    /**
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.
991    *
992    * @param key
993    * A key string.
994    * @return this.
995    * @throws JSONException
996    * If there is already a property with this name that is not an
997    * Integer, Long, Double, or Float.
998    */
 
999  0 toggle public JSONObject increment(String key) throws JSONException
1000    {
1001  0 Object value = this.opt(key);
1002  0 if (value == null)
1003    {
1004  0 this.put(key, 1);
1005    }
1006  0 else if (value instanceof BigInteger)
1007    {
1008  0 this.put(key, ((BigInteger) value).add(BigInteger.ONE));
1009    }
1010  0 else if (value instanceof BigDecimal)
1011    {
1012  0 this.put(key, ((BigDecimal) value).add(BigDecimal.ONE));
1013    }
1014  0 else if (value instanceof Integer)
1015    {
1016  0 this.put(key, ((Integer) value).intValue() + 1);
1017    }
1018  0 else if (value instanceof Long)
1019    {
1020  0 this.put(key, ((Long) value).longValue() + 1L);
1021    }
1022  0 else if (value instanceof Double)
1023    {
1024  0 this.put(key, ((Double) value).doubleValue() + 1.0d);
1025    }
1026  0 else if (value instanceof Float)
1027    {
1028  0 this.put(key, ((Float) value).floatValue() + 1.0f);
1029    }
1030    else
1031    {
1032  0 throw new JSONException("Unable to increment [" + quote(key) + "].");
1033    }
1034  0 return this;
1035    }
1036   
1037    /**
1038    * Determine if the value associated with the key is <code>null</code> or if
1039    * there is no value.
1040    *
1041    * @param key
1042    * A key string.
1043    * @return true if there is no value associated with the key or if the value
1044    * is the JSONObject.NULL object.
1045    */
 
1046  19234 toggle public boolean isNull(String key)
1047    {
1048  19234 return JSONObject.NULL.equals(this.opt(key));
1049    }
1050   
1051    /**
1052    * Get an enumeration of the keys of the JSONObject. Modifying this key Set
1053    * will also modify the JSONObject. Use with caution.
1054    *
1055    * @see Set#iterator()
1056    *
1057    * @return An iterator of the keys.
1058    */
 
1059  0 toggle public Iterator<String> keys()
1060    {
1061  0 return this.keySet().iterator();
1062    }
1063   
1064    /**
1065    * Get a set of keys of the JSONObject. Modifying this key Set will also
1066    * modify the JSONObject. Use with caution.
1067    *
1068    * @see Map#keySet()
1069    *
1070    * @return A keySet.
1071    */
 
1072  1534 toggle public Set<String> keySet()
1073    {
1074  1534 return this.map.keySet();
1075    }
1076   
1077    /**
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.
1082    *
1083    * Use with caution.
1084    *
1085    * @see Map#entrySet()
1086    *
1087    * @return An Entry Set
1088    */
 
1089  291 toggle protected Set<Entry<String, Object>> entrySet()
1090    {
1091  291 return this.map.entrySet();
1092    }
1093   
1094    /**
1095    * Get the number of keys stored in the JSONObject.
1096    *
1097    * @return The number of keys in the JSONObject.
1098    */
 
1099  291 toggle public int length()
1100    {
1101  291 return this.map.size();
1102    }
1103   
1104    /**
1105    * Check if JSONObject is empty.
1106    *
1107    * @return true if JSONObject is empty, otherwise false.
1108    */
 
1109  0 toggle public boolean isEmpty()
1110    {
1111  0 return map.isEmpty();
1112    }
1113   
1114    /**
1115    * Produce a JSONArray containing the names of the elements of this
1116    * JSONObject.
1117    *
1118    * @return A JSONArray containing the key strings, or null if the JSONObject
1119    * is empty.
1120    */
 
1121  0 toggle public JSONArray names()
1122    {
1123  0 if (this.map.isEmpty())
1124    {
1125  0 return null;
1126    }
1127  0 return new JSONArray(this.map.keySet());
1128    }
1129   
1130    /**
1131    * Produce a string from a Number.
1132    *
1133    * @param number
1134    * A Number
1135    * @return A String.
1136    * @throws JSONException
1137    * If n is a non-finite number.
1138    */
 
1139  449 toggle public static String numberToString(Number number) throws JSONException
1140    {
1141  449 if (number == null)
1142    {
1143  0 throw new JSONException("Null pointer");
1144    }
1145  449 testValidity(number);
1146   
1147    // Shave off trailing zeros and decimal point, if possible.
1148   
1149  449 String string = number.toString();
1150  449 if (string.indexOf('.') > 0 && string.indexOf('e') < 0
1151    && string.indexOf('E') < 0)
1152    {
1153  408 while (string.endsWith("0"))
1154    {
1155  204 string = string.substring(0, string.length() - 1);
1156    }
1157  204 if (string.endsWith("."))
1158    {
1159  204 string = string.substring(0, string.length() - 1);
1160    }
1161    }
1162  449 return string;
1163    }
1164   
1165    /**
1166    * Get an optional value associated with a key.
1167    *
1168    * @param key
1169    * A key string.
1170    * @return An object which is the value, or null if there is no value.
1171    */
 
1172  335723 toggle public Object opt(String key)
1173    {
1174  335726 return key == null ? null : this.map.get(key);
1175    }
1176   
1177    /**
1178    * Get the enum value associated with a key.
1179    *
1180    * @param clazz
1181    * The type of enum to retrieve.
1182    * @param key
1183    * A key string.
1184    * @return The enum value associated with the key or null if not found
1185    */
 
1186  0 toggle public <E extends Enum<E>> E optEnum(Class<E> clazz, String key)
1187    {
1188  0 return this.optEnum(clazz, key, null);
1189    }
1190   
1191    /**
1192    * Get the enum value associated with a key.
1193    *
1194    * @param clazz
1195    * The type of enum to retrieve.
1196    * @param key
1197    * A key string.
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>
1202    */
 
1203  0 toggle public <E extends Enum<E>> E optEnum(Class<E> clazz, String key,
1204    E defaultValue)
1205    {
1206  0 try
1207    {
1208  0 Object val = this.opt(key);
1209  0 if (NULL.equals(val))
1210    {
1211  0 return defaultValue;
1212    }
1213  0 if (clazz.isAssignableFrom(val.getClass()))
1214    {
1215    // we just checked it!
1216  0 @SuppressWarnings("unchecked")
1217    E myE = (E) val;
1218  0 return myE;
1219    }
1220  0 return Enum.valueOf(clazz, val.toString());
1221    } catch (IllegalArgumentException e)
1222    {
1223  0 return defaultValue;
1224    } catch (NullPointerException e)
1225    {
1226  0 return defaultValue;
1227    }
1228    }
1229   
1230    /**
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".
1233    *
1234    * @param key
1235    * A key string.
1236    * @return The truth.
1237    */
 
1238  0 toggle public boolean optBoolean(String key)
1239    {
1240  0 return this.optBoolean(key, false);
1241    }
1242   
1243    /**
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).
1247    *
1248    * @param key
1249    * A key string.
1250    * @param defaultValue
1251    * The default.
1252    * @return The truth.
1253    */
 
1254  33984 toggle public boolean optBoolean(String key, boolean defaultValue)
1255    {
1256  33984 Object val = this.opt(key);
1257  33984 if (NULL.equals(val))
1258    {
1259  2006 return defaultValue;
1260    }
1261  31978 if (val instanceof Boolean)
1262    {
1263  31978 return ((Boolean) val).booleanValue();
1264    }
1265  0 try
1266    {
1267    // we'll use the get anyway because it does string conversion.
1268  0 return this.getBoolean(key);
1269    } catch (Exception e)
1270    {
1271  0 return defaultValue;
1272    }
1273    }
1274   
1275    /**
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.
1279    *
1280    * @param key
1281    * A key string.
1282    * @param defaultValue
1283    * The default.
1284    * @return An object which is the value.
1285    */
 
1286  0 toggle public BigDecimal optBigDecimal(String key, BigDecimal defaultValue)
1287    {
1288  0 Object val = this.opt(key);
1289  0 if (NULL.equals(val))
1290    {
1291  0 return defaultValue;
1292    }
1293  0 if (val instanceof BigDecimal)
1294    {
1295  0 return (BigDecimal) val;
1296    }
1297  0 if (val instanceof BigInteger)
1298    {
1299  0 return new BigDecimal((BigInteger) val);
1300    }
1301  0 if (val instanceof Double || val instanceof Float)
1302    {
1303  0 return new BigDecimal(((Number) val).doubleValue());
1304    }
1305  0 if (val instanceof Long || val instanceof Integer
1306    || val instanceof Short || val instanceof Byte)
1307    {
1308  0 return new BigDecimal(((Number) val).longValue());
1309    }
1310    // don't check if it's a string in case of unchecked Number subclasses
1311  0 try
1312    {
1313  0 return new BigDecimal(val.toString());
1314    } catch (Exception e)
1315    {
1316  0 return defaultValue;
1317    }
1318    }
1319   
1320    /**
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.
1324    *
1325    * @param key
1326    * A key string.
1327    * @param defaultValue
1328    * The default.
1329    * @return An object which is the value.
1330    */
 
1331  0 toggle public BigInteger optBigInteger(String key, BigInteger defaultValue)
1332    {
1333  0 Object val = this.opt(key);
1334  0 if (NULL.equals(val))
1335    {
1336  0 return defaultValue;
1337    }
1338  0 if (val instanceof BigInteger)
1339    {
1340  0 return (BigInteger) val;
1341    }
1342  0 if (val instanceof BigDecimal)
1343    {
1344  0 return ((BigDecimal) val).toBigInteger();
1345    }
1346  0 if (val instanceof Double || val instanceof Float)
1347    {
1348  0 return new BigDecimal(((Number) val).doubleValue()).toBigInteger();
1349    }
1350  0 if (val instanceof Long || val instanceof Integer
1351    || val instanceof Short || val instanceof Byte)
1352    {
1353  0 return BigInteger.valueOf(((Number) val).longValue());
1354    }
1355    // don't check if it's a string in case of unchecked Number subclasses
1356  0 try
1357    {
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  0 final String valStr = val.toString();
1364  0 if (isDecimalNotation(valStr))
1365    {
1366  0 return new BigDecimal(valStr).toBigInteger();
1367    }
1368  0 return new BigInteger(valStr);
1369    } catch (Exception e)
1370    {
1371  0 return defaultValue;
1372    }
1373    }
1374   
1375    /**
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.
1379    *
1380    * @param key
1381    * A string which is the key.
1382    * @return An object which is the value.
1383    */
 
1384  0 toggle public double optDouble(String key)
1385    {
1386  0 return this.optDouble(key, Double.NaN);
1387    }
1388   
1389    /**
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.
1393    *
1394    * @param key
1395    * A key string.
1396    * @param defaultValue
1397    * The default.
1398    * @return An object which is the value.
1399    */
 
1400  0 toggle public double optDouble(String key, double defaultValue)
1401    {
1402  0 Object val = this.opt(key);
1403  0 if (NULL.equals(val))
1404    {
1405  0 return defaultValue;
1406    }
1407  0 if (val instanceof Number)
1408    {
1409  0 return ((Number) val).doubleValue();
1410    }
1411  0 if (val instanceof String)
1412    {
1413  0 try
1414    {
1415  0 return Double.parseDouble((String) val);
1416    } catch (Exception e)
1417    {
1418  0 return defaultValue;
1419    }
1420    }
1421  0 return defaultValue;
1422    }
1423   
1424    /**
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.
1428    *
1429    * @param key
1430    * A key string.
1431    * @return The value.
1432    */
 
1433  0 toggle public float optFloat(String key)
1434    {
1435  0 return this.optFloat(key, Float.NaN);
1436    }
1437   
1438    /**
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.
1442    *
1443    * @param key
1444    * A key string.
1445    * @param defaultValue
1446    * The default value.
1447    * @return The value.
1448    */
 
1449  0 toggle public float optFloat(String key, float defaultValue)
1450    {
1451  0 Object val = this.opt(key);
1452  0 if (JSONObject.NULL.equals(val))
1453    {
1454  0 return defaultValue;
1455    }
1456  0 if (val instanceof Number)
1457    {
1458  0 return ((Number) val).floatValue();
1459    }
1460  0 if (val instanceof String)
1461    {
1462  0 try
1463    {
1464  0 return Float.parseFloat((String) val);
1465    } catch (Exception e)
1466    {
1467  0 return defaultValue;
1468    }
1469    }
1470  0 return defaultValue;
1471    }
1472   
1473    /**
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.
1477    *
1478    * @param key
1479    * A key string.
1480    * @return An object which is the value.
1481    */
 
1482  0 toggle public int optInt(String key)
1483    {
1484  0 return this.optInt(key, 0);
1485    }
1486   
1487    /**
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.
1491    *
1492    * @param key
1493    * A key string.
1494    * @param defaultValue
1495    * The default.
1496    * @return An object which is the value.
1497    */
 
1498  0 toggle public int optInt(String key, int defaultValue)
1499    {
1500  0 Object val = this.opt(key);
1501  0 if (NULL.equals(val))
1502    {
1503  0 return defaultValue;
1504    }
1505  0 if (val instanceof Number)
1506    {
1507  0 return ((Number) val).intValue();
1508    }
1509   
1510  0 if (val instanceof String)
1511    {
1512  0 try
1513    {
1514  0 return new BigDecimal((String) val).intValue();
1515    } catch (Exception e)
1516    {
1517  0 return defaultValue;
1518    }
1519    }
1520  0 return defaultValue;
1521    }
1522   
1523    /**
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.
1526    *
1527    * @param key
1528    * A key string.
1529    * @return A JSONArray which is the value.
1530    */
 
1531  0 toggle public JSONArray optJSONArray(String key)
1532    {
1533  0 Object o = this.opt(key);
1534  0 return o instanceof JSONArray ? (JSONArray) o : null;
1535    }
1536   
1537    /**
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.
1540    *
1541    * @param key
1542    * A key string.
1543    * @return A JSONObject which is the value.
1544    */
 
1545  1770 toggle public JSONObject optJSONObject(String key)
1546    {
1547  1770 Object object = this.opt(key);
1548  1770 return object instanceof JSONObject ? (JSONObject) object : null;
1549    }
1550   
1551    /**
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.
1555    *
1556    * @param key
1557    * A key string.
1558    * @return An object which is the value.
1559    */
 
1560  0 toggle public long optLong(String key)
1561    {
1562  0 return this.optLong(key, 0);
1563    }
1564   
1565    /**
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.
1569    *
1570    * @param key
1571    * A key string.
1572    * @param defaultValue
1573    * The default.
1574    * @return An object which is the value.
1575    */
 
1576  0 toggle public long optLong(String key, long defaultValue)
1577    {
1578  0 Object val = this.opt(key);
1579  0 if (NULL.equals(val))
1580    {
1581  0 return defaultValue;
1582    }
1583  0 if (val instanceof Number)
1584    {
1585  0 return ((Number) val).longValue();
1586    }
1587   
1588  0 if (val instanceof String)
1589    {
1590  0 try
1591    {
1592  0 return new BigDecimal((String) val).longValue();
1593    } catch (Exception e)
1594    {
1595  0 return defaultValue;
1596    }
1597    }
1598  0 return defaultValue;
1599    }
1600   
1601    /**
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.
1607    *
1608    * @param key
1609    * A key string.
1610    * @return An object which is the value.
1611    */
 
1612  0 toggle public Number optNumber(String key)
1613    {
1614  0 return this.optNumber(key, null);
1615    }
1616   
1617    /**
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.
1622    *
1623    * @param key
1624    * A key string.
1625    * @param defaultValue
1626    * The default.
1627    * @return An object which is the value.
1628    */
 
1629  0 toggle public Number optNumber(String key, Number defaultValue)
1630    {
1631  0 Object val = this.opt(key);
1632  0 if (NULL.equals(val))
1633    {
1634  0 return defaultValue;
1635    }
1636  0 if (val instanceof Number)
1637    {
1638  0 return (Number) val;
1639    }
1640   
1641  0 if (val instanceof String)
1642    {
1643  0 try
1644    {
1645  0 return stringToNumber((String) val);
1646    } catch (Exception e)
1647    {
1648  0 return defaultValue;
1649    }
1650    }
1651  0 return defaultValue;
1652    }
1653   
1654    /**
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.
1658    *
1659    * @param key
1660    * A key string.
1661    * @return A string which is the value.
1662    */
 
1663  1770 toggle public String optString(String key)
1664    {
1665  1770 return this.optString(key, "");
1666    }
1667   
1668    /**
1669    * Get an optional string associated with a key. It returns the defaultValue
1670    * if there is no such key.
1671    *
1672    * @param key
1673    * A key string.
1674    * @param defaultValue
1675    * The default.
1676    * @return A string which is the value.
1677    */
 
1678  16520 toggle public String optString(String key, String defaultValue)
1679    {
1680  16520 Object object = this.opt(key);
1681  16520 return NULL.equals(object) ? defaultValue : object.toString();
1682    }
1683   
1684    /**
1685    * Populates the internal map of the JSONObject with the bean properties. The
1686    * bean can not be recursive.
1687    *
1688    * @see JSONObject#JSONObject(Object)
1689    *
1690    * @param bean
1691    * the bean
1692    */
 
1693  283 toggle private void populateMap(Object bean)
1694    {
1695  283 Class<?> klass = bean.getClass();
1696   
1697    // If klass is a System class then set includeSuperClass to false.
1698   
1699  283 boolean includeSuperClass = klass.getClassLoader() != null;
1700   
1701  283 Method[] methods = includeSuperClass ? klass.getMethods()
1702    : klass.getDeclaredMethods();
1703  283 for (final Method method : methods)
1704    {
1705  5989 final int modifiers = method.getModifiers();
1706  5989 if (Modifier.isPublic(modifiers) && !Modifier.isStatic(modifiers)
1707    && method.getParameterTypes().length == 0
1708    && !method.isBridge() && method.getReturnType() != Void.TYPE
1709    && isValidMethodName(method.getName()))
1710    {
1711  2287 final String key = getKeyNameFromMethod(method);
1712  2287 if (key != null && !key.isEmpty())
1713    {
1714  1721 try
1715    {
1716  1721 final Object result = method.invoke(bean);
1717  1721 if (result != null)
1718    {
1719  1244 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  1244 if (result instanceof Closeable)
1724    {
1725  0 try
1726    {
1727  0 ((Closeable) result).close();
1728    } catch (IOException ignore)
1729    {
1730    }
1731    }
1732    }
1733    } catch (IllegalAccessException ignore)
1734    {
1735    } catch (IllegalArgumentException ignore)
1736    {
1737    } catch (InvocationTargetException ignore)
1738    {
1739    }
1740    }
1741    }
1742    }
1743    }
1744   
 
1745  2570 toggle private boolean isValidMethodName(String name)
1746    {
1747  2570 return !"getClass".equals(name) && !"getDeclaringClass".equals(name);
1748    }
1749   
 
1750  2287 toggle private String getKeyNameFromMethod(Method method)
1751    {
1752  2287 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
1760    // return null;
1761    // }
1762    // }
1763    // JSONPropertyName annotation = getAnnotation(method,
1764    // JSONPropertyName.class);
1765    // if (annotation != null && annotation.value() != null &&
1766    // !annotation.value().isEmpty()) {
1767    // return annotation.value();
1768    // }
1769  2287 String key;
1770  2287 final String name = method.getName();
1771  2287 if (name.startsWith("get") && name.length() > 3)
1772    {
1773  1667 key = name.substring(3);
1774    }
1775  620 else if (name.startsWith("is") && name.length() > 2)
1776    {
1777  54 key = name.substring(2);
1778    }
1779    else
1780    {
1781  566 return null;
1782    }
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  1721 if (Character.isLowerCase(key.charAt(0)))
1787    {
1788  0 return null;
1789    }
1790  1721 if (key.length() == 1)
1791    {
1792  0 key = key.toLowerCase(Locale.ROOT);
1793    }
1794  1721 else if (!Character.isUpperCase(key.charAt(1)))
1795    {
1796  1721 key = key.substring(0, 1).toLowerCase(Locale.ROOT) + key.substring(1);
1797    }
1798  1721 return (/** @j2sNative 1 ? key.split("$")[0] : */
1799    key);
1800    }
1801   
1802    // /**
1803    // * Searches the class hierarchy to see if the method or it's super
1804    // * implementations and interfaces has the annotation.
1805    // *
1806    // * @param <A>
1807    // * type of the annotation
1808    // *
1809    // * @param m
1810    // * method to check
1811    // * @param annotationClass
1812    // * annotation to look for
1813    // * @return the {@link Annotation} if the annotation exists on the current
1814    // method
1815    // * or one of it's super class definitions
1816    // */
1817    // private static <A extends Annotation> A getAnnotation(final Method m, final
1818    // Class<A> annotationClass) {
1819    // return null;
1820    // // if we have invalid data the result is null
1821    // if (true || m == null || annotationClass == null) {
1822    // return null;
1823    // }
1824    //
1825    // if (m.isAnnotationPresent(annotationClass)) {
1826    // return m.getAnnotation(annotationClass);
1827    // }
1828    //
1829    // // if we've already reached the Object class, return null;
1830    // Class<?> c = m.getDeclaringClass();
1831    // if (c.getSuperclass() == null) {
1832    // return null;
1833    // }
1834    //
1835    // // check directly implemented interfaces for the method being checked
1836    // for (Class<?> i : c.getInterfaces()) {
1837    // try {
1838    // Method im = i.getMethod(m.getName(), m.getParameterTypes());
1839    // return getAnnotation(im, annotationClass);
1840    // } catch (final SecurityException ex) {
1841    // continue;
1842    // } catch (final NoSuchMethodException ex) {
1843    // continue;
1844    // }
1845    // }
1846    //
1847    // try {
1848    // return getAnnotation(
1849    // c.getSuperclass().getMethod(m.getName(), m.getParameterTypes()),
1850    // annotationClass);
1851    // } catch (final SecurityException ex) {
1852    // return null;
1853    // } catch (final NoSuchMethodException ex) {
1854    // return null;
1855    // }
1856    // }
1857    //
1858    // /**
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
1861    // the
1862    // * annotation in the hierarchy.
1863    // *
1864    // * @param <A>
1865    // * type of the annotation
1866    // *
1867    // * @param m
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
1872    // method.
1873    // */
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) {
1878    // return -1;
1879    // }
1880    // if (m.isAnnotationPresent(annotationClass)) {
1881    // return 1;
1882    // }
1883    //
1884    // // if we've already reached the Object class, return -1;
1885    // Class<?> c = m.getDeclaringClass();
1886    // if (c.getSuperclass() == null) {
1887    // return -1;
1888    // }
1889    //
1890    // // check directly implemented interfaces for the method being checked
1891    // for (Class<?> i : c.getInterfaces()) {
1892    // try {
1893    // Method im = i.getMethod(m.getName(), m.getParameterTypes());
1894    // int d = getAnnotationDepth(im, annotationClass);
1895    // if (d > 0) {
1896    // // since the annotation was on the interface, add 1
1897    // return d + 1;
1898    // }
1899    // } catch (final SecurityException ex) {
1900    // continue;
1901    // } catch (final NoSuchMethodException ex) {
1902    // continue;
1903    // }
1904    // }
1905    //
1906    // try {
1907    // int d = getAnnotationDepth(
1908    // c.getSuperclass().getMethod(m.getName(), m.getParameterTypes()),
1909    // annotationClass);
1910    // if (d > 0) {
1911    // // since the annotation was on the superclass, add 1
1912    // return d + 1;
1913    // }
1914    // return -1;
1915    // } catch (final SecurityException ex) {
1916    // return -1;
1917    // } catch (final NoSuchMethodException ex) {
1918    // return -1;
1919    // }
1920    // }
1921   
1922    /**
1923    * Put a key/boolean pair in the JSONObject.
1924    *
1925    * @param key
1926    * A key string.
1927    * @param value
1928    * A boolean which is the value.
1929    * @return this.
1930    * @throws JSONException
1931    * If the value is non-finite number.
1932    * @throws NullPointerException
1933    * If the key is <code>null</code>.
1934    */
 
1935  0 toggle public JSONObject put(String key, boolean value) throws JSONException
1936    {
1937  0 return this.put(key, value ? Boolean.TRUE : Boolean.FALSE);
1938    }
1939   
1940    /**
1941    * Put a key/value pair in the JSONObject, where the value will be a JSONArray
1942    * which is produced from a Collection.
1943    *
1944    * @param key
1945    * A key string.
1946    * @param value
1947    * A Collection value.
1948    * @return this.
1949    * @throws JSONException
1950    * If the value is non-finite number.
1951    * @throws NullPointerException
1952    * If the key is <code>null</code>.
1953    */
 
1954  0 toggle public JSONObject put(String key, Collection<?> value)
1955    throws JSONException
1956    {
1957  0 return this.put(key, new JSONArray(value));
1958    }
1959   
1960    /**
1961    * Put a key/double pair in the JSONObject.
1962    *
1963    * @param key
1964    * A key string.
1965    * @param value
1966    * A double which is the value.
1967    * @return this.
1968    * @throws JSONException
1969    * If the value is non-finite number.
1970    * @throws NullPointerException
1971    * If the key is <code>null</code>.
1972    */
 
1973  0 toggle public JSONObject put(String key, double value) throws JSONException
1974    {
1975  0 return this.put(key, Double.valueOf(value));
1976    }
1977   
1978    /**
1979    * Put a key/float pair in the JSONObject.
1980    *
1981    * @param key
1982    * A key string.
1983    * @param value
1984    * A float which is the value.
1985    * @return this.
1986    * @throws JSONException
1987    * If the value is non-finite number.
1988    * @throws NullPointerException
1989    * If the key is <code>null</code>.
1990    */
 
1991  0 toggle public JSONObject put(String key, float value) throws JSONException
1992    {
1993  0 return this.put(key, Float.valueOf(value));
1994    }
1995   
1996    /**
1997    * Put a key/int pair in the JSONObject.
1998    *
1999    * @param key
2000    * A key string.
2001    * @param value
2002    * An int which is the value.
2003    * @return this.
2004    * @throws JSONException
2005    * If the value is non-finite number.
2006    * @throws NullPointerException
2007    * If the key is <code>null</code>.
2008    */
 
2009  0 toggle public JSONObject put(String key, int value) throws JSONException
2010    {
2011  0 return this.put(key, Integer.valueOf(value));
2012    }
2013   
2014    /**
2015    * Put a key/long pair in the JSONObject.
2016    *
2017    * @param key
2018    * A key string.
2019    * @param value
2020    * A long which is the value.
2021    * @return this.
2022    * @throws JSONException
2023    * If the value is non-finite number.
2024    * @throws NullPointerException
2025    * If the key is <code>null</code>.
2026    */
 
2027  0 toggle public JSONObject put(String key, long value) throws JSONException
2028    {
2029  0 return this.put(key, Long.valueOf(value));
2030    }
2031   
2032    /**
2033    * Put a key/value pair in the JSONObject, where the value will be a
2034    * JSONObject which is produced from a Map.
2035    *
2036    * @param key
2037    * A key string.
2038    * @param value
2039    * A Map value.
2040    * @return this.
2041    * @throws JSONException
2042    * If the value is non-finite number.
2043    * @throws NullPointerException
2044    * If the key is <code>null</code>.
2045    */
 
2046  0 toggle public JSONObject put(String key, Map<?, ?> value) throws JSONException
2047    {
2048  0 return this.put(key, new JSONObject(value));
2049    }
2050   
2051    /**
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.
2054    *
2055    * @param key
2056    * A key string.
2057    * @param value
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.
2061    * @return this.
2062    * @throws JSONException
2063    * If the value is non-finite number.
2064    * @throws NullPointerException
2065    * If the key is <code>null</code>.
2066    */
 
2067  150255 toggle public JSONObject put(String key, Object value) throws JSONException
2068    {
2069  150254 if (key == null)
2070    {
2071  0 throw new NullPointerException("Null key.");
2072    }
2073  150254 if (value != null)
2074    {
2075  150254 testValidity(value);
2076  150251 this.map.put(key, value);
2077    }
2078    else
2079    {
2080  0 this.remove(key);
2081    }
2082  150251 return this;
2083    }
2084   
2085    /**
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
2088    * name.
2089    *
2090    * @param key
2091    * string
2092    * @param value
2093    * object
2094    * @return this.
2095    * @throws JSONException
2096    * if the key is a duplicate
2097    */
 
2098  0 toggle public JSONObject putOnce(String key, Object value) throws JSONException
2099    {
2100  0 if (key != null && value != null)
2101    {
2102  0 if (this.opt(key) != null)
2103    {
2104  0 throw new JSONException("Duplicate key \"" + key + "\"");
2105    }
2106  0 return this.put(key, value);
2107    }
2108  0 return this;
2109    }
2110   
2111    /**
2112    * Put a key/value pair in the JSONObject, but only if the key and the value
2113    * are both non-null.
2114    *
2115    * @param key
2116    * A key string.
2117    * @param value
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.
2121    * @return this.
2122    * @throws JSONException
2123    * If the value is a non-finite number.
2124    */
 
2125  0 toggle public JSONObject putOpt(String key, Object value) throws JSONException
2126    {
2127  0 if (key != null && value != null)
2128    {
2129  0 return this.put(key, value);
2130    }
2131  0 return this;
2132    }
2133   
2134    /**
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:
2138    *
2139    * <pre>
2140    * {
2141    * "a":{"b":"c"}
2142    * }
2143    * </pre>
2144    *
2145    * and this JSONPointer string:
2146    *
2147    * <pre>
2148    * "/a/b"
2149    * </pre>
2150    *
2151    * Then this method will return the String "c". A JSONPointerException may be
2152    * thrown from code called by this method.
2153    *
2154    * @param jsonPointer
2155    * string that can be used to create a JSONPointer
2156    * @return the item matched by the JSONPointer, otherwise null
2157    */
 
2158  0 toggle public Object query(String jsonPointer)
2159    {
2160  0 return query(new JSONPointer(jsonPointer));
2161    }
2162   
2163    /**
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
2166    * document:
2167    *
2168    * <pre>
2169    * {
2170    * "a":{"b":"c"}
2171    * }
2172    * </pre>
2173    *
2174    * and this JSONPointer:
2175    *
2176    * <pre>
2177    * "/a/b"
2178    * </pre>
2179    *
2180    * Then this method will return the String "c". A JSONPointerException may be
2181    * thrown from code called by this method.
2182    *
2183    * @param jsonPointer
2184    * string that can be used to create a JSONPointer
2185    * @return the item matched by the JSONPointer, otherwise null
2186    */
 
2187  0 toggle public Object query(JSONPointer jsonPointer)
2188    {
2189  0 return jsonPointer.queryFrom(this);
2190    }
2191   
2192    /**
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.
2195    *
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
2201    */
 
2202  0 toggle public Object optQuery(String jsonPointer)
2203    {
2204  0 return optQuery(new JSONPointer(jsonPointer));
2205    }
2206   
2207    /**
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.
2210    *
2211    * @param jsonPointer
2212    * The JSON pointer
2213    * @return the queried value or {@code null}
2214    * @throws IllegalArgumentException
2215    * if {@code jsonPointer} has invalid syntax
2216    */
 
2217  0 toggle public Object optQuery(JSONPointer jsonPointer)
2218    {
2219  0 try
2220    {
2221  0 return jsonPointer.queryFrom(this);
2222    } catch (JSONPointerException e)
2223    {
2224  0 return null;
2225    }
2226    }
2227   
2228    /**
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.
2233    *
2234    * @param string
2235    * A String
2236    * @return A String correctly formatted for insertion in a JSON text.
2237    */
 
2238  1286 toggle public static String quote(String string)
2239    {
2240  1286 StringWriter sw = new StringWriter();
2241  1286 synchronized (sw.getBuffer())
2242    {
2243  1286 try
2244    {
2245  1286 return quote(string, sw).toString();
2246    } catch (IOException ignored)
2247    {
2248    // will never happen - we are writing to a string writer
2249  0 return "";
2250    }
2251    }
2252    }
2253   
 
2254  2037 toggle public static Writer quote(String string, Writer w) throws IOException
2255    {
2256  2037 if (string == null || string.isEmpty())
2257    {
2258  100 w.write("\"\"");
2259  100 return w;
2260    }
2261   
2262  1937 char b;
2263  1937 char c = 0;
2264  1937 String hhhh;
2265  1937 int i;
2266  1937 int len = string.length();
2267   
2268  1937 w.write('"');
2269  23374 for (i = 0; i < len; i += 1)
2270    {
2271  21437 b = c;
2272  21437 c = string.charAt(i);
2273  21437 switch (c)
2274    {
2275  0 case '\\':
2276  0 case '"':
2277  0 w.write('\\');
2278  0 w.write(c);
2279  0 break;
2280  92 case '/':
2281  92 if (b == '<')
2282    {
2283  0 w.write('\\');
2284    }
2285  92 w.write(c);
2286  92 break;
2287  0 case '\b':
2288  0 w.write("\\b");
2289  0 break;
2290  0 case '\t':
2291  0 w.write("\\t");
2292  0 break;
2293  0 case '\n':
2294  0 w.write("\\n");
2295  0 break;
2296  0 case '\f':
2297  0 w.write("\\f");
2298  0 break;
2299  0 case '\r':
2300  0 w.write("\\r");
2301  0 break;
2302  21345 default:
2303  21345 if (c < ' ' || (c >= '\u0080' && c < '\u00a0')
2304    || (c >= '\u2000' && c < '\u2100'))
2305    {
2306  95 w.write("\\u");
2307  95 hhhh = Integer.toHexString(c);
2308  95 w.write("0000", 0, 4 - hhhh.length());
2309  95 w.write(hhhh);
2310    }
2311    else
2312    {
2313  21250 w.write(c);
2314    }
2315    }
2316    }
2317  1937 w.write('"');
2318  1937 return w;
2319    }
2320   
2321    /**
2322    * Remove a name and its value, if present.
2323    *
2324    * @param key
2325    * The name to be removed.
2326    * @return The value that was associated with the name, or null if there was
2327    * no value.
2328    */
 
2329  0 toggle public Object remove(String key)
2330    {
2331  0 return this.map.remove(key);
2332    }
2333   
2334    /**
2335    * Determine if two JSONObjects are similar. They must contain the same set of
2336    * names which must be associated with similar values.
2337    *
2338    * @param other
2339    * The other JSONObject
2340    * @return true if they are equal
2341    */
 
2342  0 toggle public boolean similar(Object other)
2343    {
2344  0 try
2345    {
2346  0 if (!(other instanceof JSONObject))
2347    {
2348  0 return false;
2349    }
2350  0 if (!this.keySet().equals(((JSONObject) other).keySet()))
2351    {
2352  0 return false;
2353    }
2354  0 for (final Entry<String, ?> entry : this.entrySet())
2355    {
2356  0 String name = entry.getKey();
2357  0 Object valueThis = entry.getValue();
2358  0 Object valueOther = ((JSONObject) other).get(name);
2359  0 if (valueThis == valueOther)
2360    {
2361  0 continue;
2362    }
2363  0 if (valueThis == null)
2364    {
2365  0 return false;
2366    }
2367  0 if (valueThis instanceof JSONObject)
2368    {
2369  0 if (!((JSONObject) valueThis).similar(valueOther))
2370    {
2371  0 return false;
2372    }
2373    }
2374  0 else if (valueThis instanceof JSONArray)
2375    {
2376  0 if (!((JSONArray) valueThis).similar(valueOther))
2377    {
2378  0 return false;
2379    }
2380    }
2381  0 else if (!valueThis.equals(valueOther))
2382    {
2383  0 return false;
2384    }
2385    }
2386  0 return true;
2387    } catch (Throwable exception)
2388    {
2389  0 return false;
2390    }
2391    }
2392   
2393    /**
2394    * Tests if the value should be tried as a decimal. It makes no test if there
2395    * are actual digits.
2396    *
2397    * @param val
2398    * value to test
2399    * @return true if the string is "-0" or if it contains '.', 'e', or 'E',
2400    * false otherwise.
2401    */
 
2402  16760 toggle protected static boolean isDecimalNotation(final String val)
2403    {
2404  16760 return val.indexOf('.') > -1 || val.indexOf('e') > -1
2405    || val.indexOf('E') > -1 || "-0".equals(val);
2406    }
2407   
2408    /**
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.
2413    *
2414    * @param val
2415    * value to convert
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.
2420    */
 
2421  0 toggle protected static Number stringToNumber(final String val)
2422    throws NumberFormatException
2423    {
2424  0 char initial = val.charAt(0);
2425  0 if ((initial >= '0' && initial <= '9') || initial == '-')
2426    {
2427    // decimal representation
2428  0 if (isDecimalNotation(val))
2429    {
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  0 if (val.length() > 14)
2433    {
2434  0 return new BigDecimal(val);
2435    }
2436  0 final Double d = Double.valueOf(val);
2437  0 if (d.isInfinite() || d.isNaN())
2438    {
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  0 return new BigDecimal(val);
2444    }
2445  0 return d;
2446    }
2447    // integer representation.
2448    // This will narrow any values to the smallest reasonable Object
2449    // representation
2450    // (Integer, Long, or BigInteger)
2451   
2452    // string version
2453    // The compare string length method reduces GC,
2454    // but leads to smaller integers being placed in larger wrappers even
2455    // though not
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);
2460    // }
2461    // if(val.length()<=18){
2462    // return Long.valueOf(val);
2463    // }
2464    // return new BigInteger(val);
2465   
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  0 BigInteger bi = new BigInteger(val);
2472  0 if (bi.bitLength() <= 31)
2473    {
2474  0 return Integer.valueOf(bi.intValue());
2475    }
2476  0 if (bi.bitLength() <= 63)
2477    {
2478  0 return Long.valueOf(bi.longValue());
2479    }
2480  0 return bi;
2481    }
2482  0 throw new NumberFormatException(
2483    "val [" + val + "] is not a valid number.");
2484    }
2485   
2486    /**
2487    * Try to convert a string into a number, boolean, or null. If the string
2488    * can't be converted, return the string.
2489    *
2490    * @param string
2491    * A String.
2492    * @return A simple JSON value.
2493    */
2494    // Changes to this method must be copied to the corresponding method in
2495    // the XML class to keep full support for Android
 
2496  54181 toggle public static Object stringToValue(String string)
2497    {
2498  54182 if (string.equals(""))
2499    {
2500  0 return string;
2501    }
2502  54182 if (string.equalsIgnoreCase("true"))
2503    {
2504  2245 return Boolean.TRUE;
2505    }
2506  51938 if (string.equalsIgnoreCase("false"))
2507    {
2508  31397 return Boolean.FALSE;
2509    }
2510  20541 if (string.equalsIgnoreCase("null"))
2511    {
2512  3781 return JSONObject.NULL;
2513    }
2514   
2515    /*
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.
2518    */
2519   
2520  16760 char initial = string.charAt(0);
2521  16760 if ((initial >= '0' && initial <= '9') || initial == '-')
2522    {
2523  16760 try
2524    {
2525    // if we want full Big Number support this block can be replaced with:
2526    // return stringToNumber(string);
2527  16760 if (isDecimalNotation(string))
2528    {
2529  3304 Double d = Double.valueOf(string);
2530  3304 if (!d.isInfinite() && !d.isNaN())
2531    {
2532  3304 return d;
2533    }
2534    }
2535    else
2536    {
2537  13456 Long myLong = Long.valueOf(string);
2538  13456 if (string.equals(myLong.toString()))
2539    {
2540  13456 if (myLong.longValue() == myLong.intValue())
2541    {
2542  13456 return Integer.valueOf(myLong.intValue());
2543    }
2544  0 return myLong;
2545    }
2546    }
2547    } catch (Exception ignore)
2548    {
2549    }
2550    }
2551  0 return string;
2552    }
2553   
2554    /**
2555    * Throw an exception if the object is a NaN or infinite number.
2556    *
2557    * @param o
2558    * The object to test.
2559    * @throws JSONException
2560    * If o is a non-finite number.
2561    */
 
2562  150704 toggle public static void testValidity(Object o) throws JSONException
2563    {
2564  150702 if (o != null)
2565    {
2566  150703 if (o instanceof Double)
2567    {
2568  3309 if (((Double) o).isInfinite() || ((Double) o).isNaN())
2569    {
2570  0 throw new JSONException(
2571    "JSON does not allow non-finite numbers.");
2572    }
2573    }
2574  147394 else if (o instanceof Float)
2575    {
2576  199 if (((Float) o).isInfinite() || ((Float) o).isNaN())
2577    {
2578  0 throw new JSONException(
2579    "JSON does not allow non-finite numbers.");
2580    }
2581    }
2582    }
2583    }
2584   
2585    /**
2586    * Produce a JSONArray containing the values of the members of this
2587    * JSONObject.
2588    *
2589    * @param names
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.
2595    */
 
2596  0 toggle public JSONArray toJSONArray(JSONArray names) throws JSONException
2597    {
2598  0 if (names == null || names.isEmpty())
2599    {
2600  0 return null;
2601    }
2602  0 JSONArray ja = new JSONArray();
2603  0 for (int i = 0; i < names.length(); i += 1)
2604    {
2605  0 ja.put(this.opt(names.getString(i)));
2606    }
2607  0 return ja;
2608    }
2609   
2610    /**
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.
2614    * <p>
2615    * <b> Warning: This method assumes that the data structure is acyclical. </b>
2616    *
2617    * @return a printable, displayable, portable, transmittable representation of
2618    * the object, beginning with <code>{</code>&nbsp;<small>(left
2619    * brace)</small> and ending with <code>}</code>&nbsp;<small>(right
2620    * brace)</small>.
2621    */
 
2622  8 toggle @Override
2623    public String toString()
2624    {
2625  8 try
2626    {
2627  8 return this.toString(0);
2628    } catch (Exception e)
2629    {
2630  0 return null;
2631    }
2632    }
2633   
2634    /**
2635    * Make a pretty-printed JSON text of this JSONObject.
2636    *
2637    * <p>
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:
2640    *
2641    * <pre>
2642    * {@code {"key": 1}}
2643    * </pre>
2644    *
2645    * <p>
2646    * If an object has 2 or more keys, then it will be output across multiple
2647    * lines: <code><pre>{
2648    * "key1": 1,
2649    * "key2": "value 2",
2650    * "key3": 3
2651    * }</pre></code>
2652    * <p>
2653    * <b> Warning: This method assumes that the data structure is acyclical. </b>
2654    *
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>&nbsp;<small>(left
2659    * brace)</small> and ending with <code>}</code>&nbsp;<small>(right
2660    * brace)</small>.
2661    * @throws JSONException
2662    * If the object contains an invalid number.
2663    */
 
2664  8 toggle public String toString(int indentFactor) throws JSONException
2665    {
2666  8 StringWriter w = new StringWriter();
2667  8 synchronized (w.getBuffer())
2668    {
2669  8 return this.write(w, indentFactor, 0).toString();
2670    }
2671    }
2672   
2673    /**
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
2683    * be quoted.
2684    *
2685    * <p>
2686    * Warning: This method assumes that the data structure is acyclical.
2687    *
2688    * @param value
2689    * The value to be serialized.
2690    * @return a printable, displayable, transmittable representation of the
2691    * object, beginning with <code>{</code>&nbsp;<small>(left
2692    * brace)</small> and ending with <code>}</code>&nbsp;<small>(right
2693    * brace)</small>.
2694    * @throws JSONException
2695    * If the value is or contains an invalid number.
2696    */
 
2697  0 toggle public static String valueToString(Object value) throws JSONException
2698    {
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
2702    // in
2703    // the Writer
2704    // Android users can use the writer with the built in Android JSONObject
2705    // implementation.
2706  0 return JSONWriter.valueToString(value);
2707    }
2708   
2709    /**
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
2716    * returned.
2717    *
2718    * @param object
2719    * The object to wrap
2720    * @return The wrapped value
2721    */
 
2722  1580 toggle public static Object wrap(Object object)
2723    {
2724  1580 try
2725    {
2726  1580 if (object == null)
2727    {
2728  0 return NULL;
2729    }
2730  1580 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)
2738    {
2739  1254 return object;
2740    }
2741   
2742  326 if (object instanceof Collection)
2743    {
2744  43 Collection<?> coll = (Collection<?>) object;
2745  43 return new JSONArray(coll);
2746    }
2747  283 if (object.getClass().isArray())
2748    {
2749  0 return new JSONArray(object);
2750    }
2751  283 if (object instanceof Map)
2752    {
2753  8 Map<?, ?> map = (Map<?, ?>) object;
2754  8 return new JSONObject(map);
2755    }
2756  275 Package objectPackage = object.getClass().getPackage();
2757  275 String objectPackageName = objectPackage != null
2758    ? objectPackage.getName()
2759    : "";
2760  275 if (objectPackageName.startsWith("java.")
2761    || objectPackageName.startsWith("javax.")
2762    || object.getClass().getClassLoader() == null)
2763    {
2764  0 return object.toString();
2765    }
2766  275 return new JSONObject(object);
2767    } catch (Exception exception)
2768    {
2769  0 return null;
2770    }
2771    }
2772   
2773    /**
2774    * Write the contents of the JSONObject as JSON text to a writer. For
2775    * compactness, no whitespace is added.
2776    * <p>
2777    * <b> Warning: This method assumes that the data structure is acyclical. </b>
2778    *
2779    * @return The writer.
2780    * @throws JSONException
2781    */
 
2782  0 toggle public Writer write(Writer writer) throws JSONException
2783    {
2784  0 return this.write(writer, 0, 0);
2785    }
2786   
 
2787  1580 toggle static final Writer writeValue(Writer writer, Object value,
2788    int indentFactor, int indent) throws JSONException, IOException
2789    {
2790  1580 if (value == null || value.equals(null))
2791    {
2792  0 writer.write("null");
2793    }
2794  1580 else if (value instanceof JSONString)
2795    {
2796  0 Object o;
2797  0 try
2798    {
2799  0 o = ((JSONString) value).toJSONString();
2800    } catch (Exception e)
2801    {
2802  0 throw new JSONException(e);
2803    }
2804  0 writer.write(o != null ? o.toString() : quote(value.toString()));
2805    }
2806  1580 else if (value instanceof Number)
2807    {
2808    // not all Numbers may match actual JSON Numbers. i.e. fractions or
2809    // Imaginary
2810  449 final String numberAsString = numberToString((Number) value);
2811  449 try
2812    {
2813    // Use the BigDecimal constructor for its parser to validate the format.
2814  449 @SuppressWarnings("unused")
2815    BigDecimal testNum = new BigDecimal(numberAsString);
2816    // Close enough to a JSON number that we will use it unquoted
2817  449 writer.write(numberAsString);
2818    } catch (NumberFormatException ex)
2819    {
2820    // The Number value is not a valid JSON number.
2821    // Instead we will quote it as a string
2822  0 quote(numberAsString, writer);
2823    }
2824    }
2825  1131 else if (value instanceof Boolean)
2826    {
2827  54 writer.write(value.toString());
2828    }
2829  1077 else if (value instanceof Enum<?>)
2830    {
2831  0 writer.write(quote(((Enum<?>) value).name()));
2832    }
2833  1077 else if (value instanceof JSONObject)
2834    {
2835  283 ((JSONObject) value).write(writer, indentFactor, indent);
2836    }
2837  794 else if (value instanceof JSONArray)
2838    {
2839  43 ((JSONArray) value).write(writer, indentFactor, indent);
2840    }
2841  751 else if (value instanceof Map)
2842    {
2843  0 Map<?, ?> map = (Map<?, ?>) value;
2844  0 new JSONObject(map).write(writer, indentFactor, indent);
2845    }
2846  751 else if (value instanceof Collection)
2847    {
2848  0 Collection<?> coll = (Collection<?>) value;
2849  0 new JSONArray(coll).write(writer, indentFactor, indent);
2850    }
2851  751 else if (value.getClass().isArray())
2852    {
2853  0 new JSONArray(value).write(writer, indentFactor, indent);
2854    }
2855    else
2856    {
2857  751 quote(value.toString(), writer);
2858    }
2859  1580 return writer;
2860    }
2861   
 
2862  1885 toggle static final void indent(Writer writer, int indent) throws IOException
2863    {
2864  1885 for (int i = 0; i < indent; i += 1)
2865    {
2866  0 writer.write(' ');
2867    }
2868    }
2869   
2870    /**
2871    * Write the contents of the JSONObject as JSON text to a writer.
2872    *
2873    * <p>
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:
2876    *
2877    * <pre>
2878    * {@code {"key": 1}}
2879    * </pre>
2880    *
2881    * <p>
2882    * If an object has 2 or more keys, then it will be output across multiple
2883    * lines: <code><pre>{
2884    * "key1": 1,
2885    * "key2": "value 2",
2886    * "key3": 3
2887    * }</pre></code>
2888    * <p>
2889    * <b> Warning: This method assumes that the data structure is acyclical. </b>
2890    *
2891    * @param writer
2892    * Writes the serialized JSON
2893    * @param indentFactor
2894    * The number of spaces to add to each level of indentation.
2895    * @param indent
2896    * The indentation of the top level.
2897    * @return The writer.
2898    * @throws JSONException
2899    */
 
2900  291 toggle public Writer write(Writer writer, int indentFactor, int indent)
2901    throws JSONException
2902    {
2903  291 try
2904    {
2905  291 boolean commanate = false;
2906  291 final int length = this.length();
2907  291 writer.write('{');
2908   
2909  291 if (length == 1)
2910    {
2911  0 final Entry<String, ?> entry = this.entrySet().iterator().next();
2912  0 final String key = entry.getKey();
2913  0 writer.write(quote(key));
2914  0 writer.write(':');
2915  0 if (indentFactor > 0)
2916    {
2917  0 writer.write(' ');
2918    }
2919  0 try
2920    {
2921  0 writeValue(writer, entry.getValue(), indentFactor, indent);
2922    } catch (Exception e)
2923    {
2924  0 throw new JSONException(
2925    "Unable to write JSONObject value for key: " + key, e);
2926    }
2927    }
2928  291 else if (length != 0)
2929    {
2930  291 final int newindent = indent + indentFactor;
2931  291 for (final Entry<String, ?> entry : this.entrySet())
2932    {
2933  1286 if (commanate)
2934    {
2935  995 writer.write(',');
2936    }
2937  1286 if (indentFactor > 0)
2938    {
2939  0 writer.write('\n');
2940    }
2941  1286 indent(writer, newindent);
2942  1286 final String key = entry.getKey();
2943  1286 writer.write(quote(key));
2944  1286 writer.write(':');
2945  1286 if (indentFactor > 0)
2946    {
2947  0 writer.write(' ');
2948    }
2949  1286 try
2950    {
2951  1286 writeValue(writer, entry.getValue(), indentFactor, newindent);
2952    } catch (Exception e)
2953    {
2954  0 throw new JSONException(
2955    "Unable to write JSONObject value for key: " + key, e);
2956    }
2957  1286 commanate = true;
2958    }
2959  291 if (indentFactor > 0)
2960    {
2961  0 writer.write('\n');
2962    }
2963  291 indent(writer, indent);
2964    }
2965  291 writer.write('}');
2966  291 return writer;
2967    } catch (IOException exception)
2968    {
2969  0 throw new JSONException(exception);
2970    }
2971    }
2972   
2973    /**
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.
2976    * <p>
2977    * Warning: This method assumes that the data structure is acyclical.
2978    *
2979    * @return a java.util.Map containing the entries of this object
2980    */
 
2981  0 toggle public Map<String, Object> toMap()
2982    {
2983  0 Map<String, Object> results = new HashMap<String, Object>();
2984  0 for (Entry<String, Object> entry : this.entrySet())
2985    {
2986  0 Object value;
2987  0 if (entry.getValue() == null || NULL.equals(entry.getValue()))
2988    {
2989  0 value = null;
2990    }
2991  0 else if (entry.getValue() instanceof JSONObject)
2992    {
2993  0 value = ((JSONObject) entry.getValue()).toMap();
2994    }
2995  0 else if (entry.getValue() instanceof JSONArray)
2996    {
2997  0 value = ((JSONArray) entry.getValue()).toList();
2998    }
2999    else
3000    {
3001  0 value = entry.getValue();
3002    }
3003  0 results.put(entry.getKey(), value);
3004    }
3005  0 return results;
3006    }
3007    }