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