Clover icon

Coverage Report

  1. Project Clover database Mon Nov 11 2024 20:42:03 GMT
  2. Package org.json

File JSONObject.java

 

Coverage histogram

../../img/srcFileCovDistChart3.png
52% of files have more coverage

Code metrics

336
626
97
2
3,008
1,500
372
0.59
6.45
48.5
3.84

Classes

Class Line # Actions
JSONObject 102 622 368
0.2235965722.4%
JSONObject.Null 109 4 4
0.2525%
 

Contributing tests

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