001package org.json; 002 003/* 004 Copyright (c) 2002 JSON.org 005 006 Permission is hereby granted, free of charge, to any person obtaining a copy 007 of this software and associated documentation files (the "Software"), to deal 008 in the Software without restriction, including without limitation the rights 009 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 010 copies of the Software, and to permit persons to whom the Software is 011 furnished to do so, subject to the following conditions: 012 013 The above copyright notice and this permission notice shall be included in all 014 copies or substantial portions of the Software. 015 016 The Software shall be used for Good, not Evil. 017 018 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 019 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 020 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 021 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 022 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 023 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 024 SOFTWARE. 025 */ 026 027import java.io.IOException; 028import java.io.StringWriter; 029import java.io.Writer; 030import java.lang.reflect.Field; 031import java.lang.reflect.Method; 032import java.lang.reflect.Modifier; 033import java.math.BigDecimal; 034import java.math.BigInteger; 035import java.util.*; 036import java.util.Map.Entry; 037 038/** 039 * A JSONObject is an unordered collection of name/value pairs. Its external 040 * form is a string wrapped in curly braces with colons between the names and 041 * values, and commas between the values and names. The internal form is an 042 * object having <code>get</code> and <code>opt</code> methods for accessing 043 * the values by name, and <code>put</code> methods for adding or replacing 044 * values by name. The values can be any of these types: <code>Boolean</code>, 045 * <code>JSONArray</code>, <code>JSONObject</code>, <code>Number</code>, 046 * <code>String</code>, or the <code>JSONObject.NULL</code> object. A 047 * JSONObject constructor can be used to convert an external form JSON text 048 * into an internal form whose values can be retrieved with the 049 * <code>get</code> and <code>opt</code> methods, or to convert values into a 050 * JSON text using the <code>put</code> and <code>toString</code> methods. A 051 * <code>get</code> method returns a value if one can be found, and throws an 052 * exception if one cannot be found. An <code>opt</code> method returns a 053 * default value instead of throwing an exception, and so is useful for 054 * obtaining optional values. 055 * <p> 056 * The generic <code>get()</code> and <code>opt()</code> methods return an 057 * object, which you can cast or query for type. There are also typed 058 * <code>get</code> and <code>opt</code> methods that do type checking and type 059 * coercion for you. The opt methods differ from the get methods in that they 060 * do not throw. Instead, they return a specified value, such as null. 061 * <p> 062 * The <code>put</code> methods add or replace values in an object. For 063 * example, 064 * 065 * <pre> 066 * myString = new JSONObject() 067 * .put("JSON", "Hello, World!").toString(); 068 * </pre> 069 * 070 * produces the string <code>{"JSON": "Hello, World"}</code>. 071 * <p> 072 * The texts produced by the <code>toString</code> methods strictly conform to 073 * the JSON syntax rules. The constructors are more forgiving in the texts they 074 * will accept: 075 * <ul> 076 * <li>An extra <code>,</code> <small>(comma)</small> may appear just 077 * before the closing brace.</li> 078 * <li>Strings may be quoted with <code>'</code> <small>(single 079 * quote)</small>.</li> 080 * <li>Strings do not need to be quoted at all if they do not begin with a 081 * quote or single quote, and if they do not contain leading or trailing 082 * spaces, and if they do not contain any of these characters: 083 * <code>{ } [ ] / \ : , #</code> and if they do not look like numbers and 084 * if they are not the reserved words <code>true</code>, <code>false</code>, 085 * or <code>null</code>.</li> 086 * </ul> 087 * 088 * @author JSON.org 089 * @version 2016-03-05 090 */ 091public class JSONObject { 092 /** 093 * JSONObject.NULL is equivalent to the value that JavaScript calls null, 094 * whilst Java's null is equivalent to the value that JavaScript calls 095 * undefined. 096 */ 097 private static final class Null { 098 099 /** 100 * There is only intended to be a single instance of the NULL object, 101 * so the clone method returns itself. 102 * 103 * @return NULL. 104 */ 105 @Override 106 protected final Object clone() { 107 return this; 108 } 109 110 /** 111 * A Null object is equal to the null value and to itself. 112 * 113 * @param object 114 * An object to test for nullness. 115 * @return true if the object parameter is the JSONObject.NULL object or 116 * null. 117 */ 118 @Override 119 public boolean equals(Object object) { 120 return object == null || object == this; 121 } 122 123 /** 124 * Get the "null" string value. 125 * 126 * @return The string "null". 127 */ 128 public String toString() { 129 return "null"; 130 } 131 } 132 133 /** 134 * The map where the JSONObject's properties are kept. 135 */ 136 private final Map<String, Object> map; 137 138 /** 139 * It is sometimes more convenient and less ambiguous to have a 140 * <code>NULL</code> object than to use Java's <code>null</code> value. 141 * <code>JSONObject.NULL.equals(null)</code> returns <code>true</code>. 142 * <code>JSONObject.NULL.toString()</code> returns <code>"null"</code>. 143 */ 144 public static final Object NULL = new Null(); 145 146 /** 147 * Construct an empty JSONObject. 148 */ 149 public JSONObject() { 150 this.map = new HashMap<String, Object>(); 151 } 152 153 /** 154 * Construct a JSONObject from a subset of another JSONObject. An array of 155 * strings is used to identify the keys that should be copied. Missing keys 156 * are ignored. 157 * 158 * @param jo 159 * A JSONObject. 160 * @param names 161 * An array of strings. 162 */ 163 public JSONObject(JSONObject jo, String[] names) { 164 this(); 165 for (int i = 0; i < names.length; i += 1) { 166 try { 167 this.putOnce(names[i], jo.opt(names[i])); 168 } catch (Exception ignore) { 169 } 170 } 171 } 172 173 /** 174 * Construct a JSONObject from a JSONTokener. 175 * 176 * @param x 177 * A JSONTokener object containing the source string. 178 * @throws JSONException 179 * If there is a syntax error in the source string or a 180 * duplicated key. 181 */ 182 public JSONObject(JSONTokener x) throws JSONException { 183 this(); 184 char c; 185 String key; 186 187 if (x.nextClean() != '{') { 188 throw x.syntaxError("A JSONObject text must begin with '{'"); 189 } 190 for (;;) { 191 c = x.nextClean(); 192 switch (c) { 193 case 0: 194 throw x.syntaxError("A JSONObject text must end with '}'"); 195 case '}': 196 return; 197 default: 198 x.back(); 199 key = x.nextValue().toString(); 200 } 201 202// The key is followed by ':'. 203 204 c = x.nextClean(); 205 if (c != ':') { 206 throw x.syntaxError("Expected a ':' after a key"); 207 } 208 this.putOnce(key, x.nextValue()); 209 210// Pairs are separated by ','. 211 212 switch (x.nextClean()) { 213 case ';': 214 case ',': 215 if (x.nextClean() == '}') { 216 return; 217 } 218 x.back(); 219 break; 220 case '}': 221 return; 222 default: 223 throw x.syntaxError("Expected a ',' or '}'"); 224 } 225 } 226 } 227 228 /** 229 * Construct a JSONObject from a Map. 230 * 231 * @param map 232 * A map object that can be used to initialize the contents of 233 * the JSONObject. 234 */ 235 public JSONObject(Map<?, ?> map) { 236 this.map = new HashMap<String, Object>(); 237 if (map != null) { 238 for (final Entry<?, ?> e : map.entrySet()) { 239 final Object value = e.getValue(); 240 if (value != null) { 241 this.map.put(String.valueOf(e.getKey()), wrap(value)); 242 } 243 } 244 } 245 } 246 247 /** 248 * Construct a JSONObject from an Object using bean getters. It reflects on 249 * all of the public methods of the object. For each of the methods with no 250 * parameters and a name starting with <code>"get"</code> or 251 * <code>"is"</code> followed by an uppercase letter, the method is invoked, 252 * and a key and the value returned from the getter method are put into the 253 * new JSONObject. 254 * 255 * The key is formed by removing the <code>"get"</code> or <code>"is"</code> 256 * prefix. If the second remaining character is not upper case, then the 257 * first character is converted to lower case. 258 * 259 * For example, if an object has a method named <code>"getName"</code>, and 260 * if the result of calling <code>object.getName()</code> is 261 * <code>"Larry Fine"</code>, then the JSONObject will contain 262 * <code>"name": "Larry Fine"</code>. 263 * 264 * @param bean 265 * An object that has getter methods that should be used to make 266 * a JSONObject. 267 */ 268 public JSONObject(Object bean) { 269 this(); 270 this.populateMap(bean); 271 } 272 273 /** 274 * Construct a JSONObject from an Object, using reflection to find the 275 * public members. The resulting JSONObject's keys will be the strings from 276 * the names array, and the values will be the field values associated with 277 * those keys in the object. If a key is not found or not visible, then it 278 * will not be copied into the new JSONObject. 279 * 280 * @param object 281 * An object that has fields that should be used to make a 282 * JSONObject. 283 * @param names 284 * An array of strings, the names of the fields to be obtained 285 * from the object. 286 */ 287 public JSONObject(Object object, String names[]) { 288 this(); 289 Class<?> c = object.getClass(); 290 for (int i = 0; i < names.length; i += 1) { 291 String name = names[i]; 292 try { 293 this.putOpt(name, c.getField(name).get(object)); 294 } catch (Exception ignore) { 295 } 296 } 297 } 298 299 /** 300 * Construct a JSONObject from a source JSON text string. This is the most 301 * commonly used JSONObject constructor. 302 * 303 * @param source 304 * A string beginning with <code>{</code> <small>(left 305 * brace)</small> and ending with <code>}</code> 306 * <small>(right brace)</small>. 307 * @exception JSONException 308 * If there is a syntax error in the source string or a 309 * duplicated key. 310 */ 311 public JSONObject(String source) throws JSONException { 312 this(new JSONTokener(source)); 313 } 314 315 /** 316 * Construct a JSONObject from a ResourceBundle. 317 * 318 * @param baseName 319 * The ResourceBundle base name. 320 * @param locale 321 * The Locale to load the ResourceBundle for. 322 * @throws JSONException 323 * If any JSONExceptions are detected. 324 */ 325 public JSONObject(String baseName, Locale locale) throws JSONException { 326 this(); 327 ResourceBundle bundle = ResourceBundle.getBundle(baseName, locale, 328 Thread.currentThread().getContextClassLoader()); 329 330// Iterate through the keys in the bundle. 331 332 Enumeration<String> keys = bundle.getKeys(); 333 while (keys.hasMoreElements()) { 334 Object key = keys.nextElement(); 335 if (key != null) { 336 337// Go through the path, ensuring that there is a nested JSONObject for each 338// segment except the last. Add the value using the last segment's name into 339// the deepest nested JSONObject. 340 341 String[] path = ((String) key).split("\\."); 342 int last = path.length - 1; 343 JSONObject target = this; 344 for (int i = 0; i < last; i += 1) { 345 String segment = path[i]; 346 JSONObject nextTarget = target.optJSONObject(segment); 347 if (nextTarget == null) { 348 nextTarget = new JSONObject(); 349 target.put(segment, nextTarget); 350 } 351 target = nextTarget; 352 } 353 target.put(path[last], bundle.getString((String) key)); 354 } 355 } 356 } 357 358 /** 359 * Accumulate values under a key. It is similar to the put method except 360 * that if there is already an object stored under the key then a JSONArray 361 * is stored under the key to hold all of the accumulated values. If there 362 * is already a JSONArray, then the new value is appended to it. In 363 * contrast, the put method replaces the previous value. 364 * 365 * If only one value is accumulated that is not a JSONArray, then the result 366 * will be the same as using put. But if multiple values are accumulated, 367 * then the result will be like append. 368 * 369 * @param key 370 * A key string. 371 * @param value 372 * An object to be accumulated under the key. 373 * @return this. 374 * @throws JSONException 375 * If the value is an invalid number or if the key is null. 376 */ 377 public JSONObject accumulate(String key, Object value) throws JSONException { 378 testValidity(value); 379 Object object = this.opt(key); 380 if (object == null) { 381 this.put(key, 382 value instanceof JSONArray ? new JSONArray().put(value) 383 : value); 384 } else if (object instanceof JSONArray) { 385 ((JSONArray) object).put(value); 386 } else { 387 this.put(key, new JSONArray().put(object).put(value)); 388 } 389 return this; 390 } 391 392 /** 393 * Append values to the array under a key. If the key does not exist in the 394 * JSONObject, then the key is put in the JSONObject with its value being a 395 * JSONArray containing the value parameter. If the key was already 396 * associated with a JSONArray, then the value parameter is appended to it. 397 * 398 * @param key 399 * A key string. 400 * @param value 401 * An object to be accumulated under the key. 402 * @return this. 403 * @throws JSONException 404 * If the key is null or if the current value associated with 405 * the key is not a JSONArray. 406 */ 407 public JSONObject append(String key, Object value) throws JSONException { 408 testValidity(value); 409 Object object = this.opt(key); 410 if (object == null) { 411 this.put(key, new JSONArray().put(value)); 412 } else if (object instanceof JSONArray) { 413 this.put(key, ((JSONArray) object).put(value)); 414 } else { 415 throw new JSONException("JSONObject[" + key 416 + "] is not a JSONArray."); 417 } 418 return this; 419 } 420 421 /** 422 * Produce a string from a double. The string "null" will be returned if the 423 * number is not finite. 424 * 425 * @param d 426 * A double. 427 * @return A String. 428 */ 429 public static String doubleToString(double d) { 430 if (Double.isInfinite(d) || Double.isNaN(d)) { 431 return "null"; 432 } 433 434// Shave off trailing zeros and decimal point, if possible. 435 436 String string = Double.toString(d); 437 if (string.indexOf('.') > 0 && string.indexOf('e') < 0 438 && string.indexOf('E') < 0) { 439 while (string.endsWith("0")) { 440 string = string.substring(0, string.length() - 1); 441 } 442 if (string.endsWith(".")) { 443 string = string.substring(0, string.length() - 1); 444 } 445 } 446 return string; 447 } 448 449 /** 450 * Get the value object associated with a key. 451 * 452 * @param key 453 * A key string. 454 * @return The object associated with the key. 455 * @throws JSONException 456 * if the key is not found. 457 */ 458 public Object get(String key) throws JSONException { 459 if (key == null) { 460 throw new JSONException("Null key."); 461 } 462 Object object = this.opt(key); 463 if (object == null) { 464 throw new JSONException("JSONObject[" + quote(key) + "] not found."); 465 } 466 return object; 467 } 468 469 /** 470 * Get the enum value associated with a key. 471 * 472 * @param clazz 473 * The type of enum to retrieve. 474 * @param key 475 * A key string. 476 * @return The enum value associated with the key 477 * @throws JSONException 478 * if the key is not found or if the value cannot be converted 479 * to an enum. 480 */ 481 public <E extends Enum<E>> E getEnum(Class<E> clazz, String key) throws JSONException { 482 E val = optEnum(clazz, key); 483 if(val==null) { 484 // JSONException should really take a throwable argument. 485 // If it did, I would re-implement this with the Enum.valueOf 486 // method and place any thrown exception in the JSONException 487 throw new JSONException("JSONObject[" + quote(key) 488 + "] is not an enum of type " + quote(clazz.getSimpleName()) 489 + "."); 490 } 491 return val; 492 } 493 494 /** 495 * Get the boolean value associated with a key. 496 * 497 * @param key 498 * A key string. 499 * @return The truth. 500 * @throws JSONException 501 * if the value is not a Boolean or the String "true" or 502 * "false". 503 */ 504 public boolean getBoolean(String key) throws JSONException { 505 Object object = this.get(key); 506 if (object.equals(Boolean.FALSE) 507 || (object instanceof String && ((String) object) 508 .equalsIgnoreCase("false"))) { 509 return false; 510 } else if (object.equals(Boolean.TRUE) 511 || (object instanceof String && ((String) object) 512 .equalsIgnoreCase("true"))) { 513 return true; 514 } 515 throw new JSONException("JSONObject[" + quote(key) 516 + "] is not a Boolean."); 517 } 518 519 /** 520 * Get the BigInteger value associated with a key. 521 * 522 * @param key 523 * A key string. 524 * @return The numeric value. 525 * @throws JSONException 526 * if the key is not found or if the value cannot 527 * be converted to BigInteger. 528 */ 529 public BigInteger getBigInteger(String key) throws JSONException { 530 Object object = this.get(key); 531 try { 532 return new BigInteger(object.toString()); 533 } catch (Exception e) { 534 throw new JSONException("JSONObject[" + quote(key) 535 + "] could not be converted to BigInteger."); 536 } 537 } 538 539 /** 540 * Get the BigDecimal value associated with a key. 541 * 542 * @param key 543 * A key string. 544 * @return The numeric value. 545 * @throws JSONException 546 * if the key is not found or if the value 547 * cannot be converted to BigDecimal. 548 */ 549 public BigDecimal getBigDecimal(String key) throws JSONException { 550 Object object = this.get(key); 551 try { 552 return new BigDecimal(object.toString()); 553 } catch (Exception e) { 554 throw new JSONException("JSONObject[" + quote(key) 555 + "] could not be converted to BigDecimal."); 556 } 557 } 558 559 /** 560 * Get the double value associated with a key. 561 * 562 * @param key 563 * A key string. 564 * @return The numeric value. 565 * @throws JSONException 566 * if the key is not found or if the value is not a Number 567 * object and cannot be converted to a number. 568 */ 569 public double getDouble(String key) throws JSONException { 570 Object object = this.get(key); 571 try { 572 return object instanceof Number ? ((Number) object).doubleValue() 573 : Double.parseDouble((String) object); 574 } catch (Exception e) { 575 throw new JSONException("JSONObject[" + quote(key) 576 + "] is not a number."); 577 } 578 } 579 580 /** 581 * Get the int value associated with a key. 582 * 583 * @param key 584 * A key string. 585 * @return The integer value. 586 * @throws JSONException 587 * if the key is not found or if the value cannot be converted 588 * to an integer. 589 */ 590 public int getInt(String key) throws JSONException { 591 Object object = this.get(key); 592 try { 593 return object instanceof Number ? ((Number) object).intValue() 594 : Integer.parseInt((String) object); 595 } catch (Exception e) { 596 throw new JSONException("JSONObject[" + quote(key) 597 + "] is not an int."); 598 } 599 } 600 601 /** 602 * Get the JSONArray value associated with a key. 603 * 604 * @param key 605 * A key string. 606 * @return A JSONArray which is the value. 607 * @throws JSONException 608 * if the key is not found or if the value is not a JSONArray. 609 */ 610 public JSONArray getJSONArray(String key) throws JSONException { 611 Object object = this.get(key); 612 if (object instanceof JSONArray) { 613 return (JSONArray) object; 614 } 615 throw new JSONException("JSONObject[" + quote(key) 616 + "] is not a JSONArray."); 617 } 618 619 /** 620 * Get the JSONObject value associated with a key. 621 * 622 * @param key 623 * A key string. 624 * @return A JSONObject which is the value. 625 * @throws JSONException 626 * if the key is not found or if the value is not a JSONObject. 627 */ 628 public JSONObject getJSONObject(String key) throws JSONException { 629 Object object = this.get(key); 630 if (object instanceof JSONObject) { 631 return (JSONObject) object; 632 } 633 throw new JSONException("JSONObject[" + quote(key) 634 + "] is not a JSONObject."); 635 } 636 637 /** 638 * Get the long value associated with a key. 639 * 640 * @param key 641 * A key string. 642 * @return The long value. 643 * @throws JSONException 644 * if the key is not found or if the value cannot be converted 645 * to a long. 646 */ 647 public long getLong(String key) throws JSONException { 648 Object object = this.get(key); 649 try { 650 return object instanceof Number ? ((Number) object).longValue() 651 : Long.parseLong((String) object); 652 } catch (Exception e) { 653 throw new JSONException("JSONObject[" + quote(key) 654 + "] is not a long."); 655 } 656 } 657 658 /** 659 * Get an array of field names from a JSONObject. 660 * 661 * @return An array of field names, or null if there are no names. 662 */ 663 public static String[] getNames(JSONObject jo) { 664 int length = jo.length(); 665 if (length == 0) { 666 return null; 667 } 668 Iterator<String> iterator = jo.keys(); 669 String[] names = new String[length]; 670 int i = 0; 671 while (iterator.hasNext()) { 672 names[i] = iterator.next(); 673 i += 1; 674 } 675 return names; 676 } 677 678 /** 679 * Get an array of field names from an Object. 680 * 681 * @return An array of field names, or null if there are no names. 682 */ 683 public static String[] getNames(Object object) { 684 if (object == null) { 685 return null; 686 } 687 Class<?> klass = object.getClass(); 688 Field[] fields = klass.getFields(); 689 int length = fields.length; 690 if (length == 0) { 691 return null; 692 } 693 String[] names = new String[length]; 694 for (int i = 0; i < length; i += 1) { 695 names[i] = fields[i].getName(); 696 } 697 return names; 698 } 699 700 /** 701 * Get the string associated with a key. 702 * 703 * @param key 704 * A key string. 705 * @return A string which is the value. 706 * @throws JSONException 707 * if there is no string value for the key. 708 */ 709 public String getString(String key) throws JSONException { 710 Object object = this.get(key); 711 if (object instanceof String) { 712 return (String) object; 713 } 714 throw new JSONException("JSONObject[" + quote(key) + "] not a string."); 715 } 716 717 /** 718 * Determine if the JSONObject contains a specific key. 719 * 720 * @param key 721 * A key string. 722 * @return true if the key exists in the JSONObject. 723 */ 724 public boolean has(String key) { 725 return this.map.containsKey(key); 726 } 727 728 /** 729 * Increment a property of a JSONObject. If there is no such property, 730 * create one with a value of 1. If there is such a property, and if it is 731 * an Integer, Long, Double, or Float, then add one to it. 732 * 733 * @param key 734 * A key string. 735 * @return this. 736 * @throws JSONException 737 * If there is already a property with this name that is not an 738 * Integer, Long, Double, or Float. 739 */ 740 public JSONObject increment(String key) throws JSONException { 741 Object value = this.opt(key); 742 if (value == null) { 743 this.put(key, 1); 744 } else if (value instanceof BigInteger) { 745 this.put(key, ((BigInteger)value).add(BigInteger.ONE)); 746 } else if (value instanceof BigDecimal) { 747 this.put(key, ((BigDecimal)value).add(BigDecimal.ONE)); 748 } else if (value instanceof Integer) { 749 this.put(key, (Integer) value + 1); 750 } else if (value instanceof Long) { 751 this.put(key, (Long) value + 1); 752 } else if (value instanceof Double) { 753 this.put(key, (Double) value + 1); 754 } else if (value instanceof Float) { 755 this.put(key, (Float) value + 1); 756 } else { 757 throw new JSONException("Unable to increment [" + quote(key) + "]."); 758 } 759 return this; 760 } 761 762 /** 763 * Determine if the value associated with the key is null or if there is no 764 * value. 765 * 766 * @param key 767 * A key string. 768 * @return true if there is no value associated with the key or if the value 769 * is the JSONObject.NULL object. 770 */ 771 public boolean isNull(String key) { 772 return JSONObject.NULL.equals(this.opt(key)); 773 } 774 775 /** 776 * Get an enumeration of the keys of the JSONObject. 777 * 778 * @return An iterator of the keys. 779 */ 780 public Iterator<String> keys() { 781 return this.keySet().iterator(); 782 } 783 784 /** 785 * Get a set of keys of the JSONObject. 786 * 787 * @return A keySet. 788 */ 789 public Set<String> keySet() { 790 return this.map.keySet(); 791 } 792 793 /** 794 * Get the number of keys stored in the JSONObject. 795 * 796 * @return The number of keys in the JSONObject. 797 */ 798 public int length() { 799 return this.map.size(); 800 } 801 802 /** 803 * Produce a JSONArray containing the names of the elements of this 804 * JSONObject. 805 * 806 * @return A JSONArray containing the key strings, or null if the JSONObject 807 * is empty. 808 */ 809 public JSONArray names() { 810 JSONArray ja = new JSONArray(); 811 Iterator<String> keys = this.keys(); 812 while (keys.hasNext()) { 813 ja.put(keys.next()); 814 } 815 return ja.length() == 0 ? null : ja; 816 } 817 818 /** 819 * Produce a string from a Number. 820 * 821 * @param number 822 * A Number 823 * @return A String. 824 * @throws JSONException 825 * If n is a non-finite number. 826 */ 827 public static String numberToString(Number number) throws JSONException { 828 if (number == null) { 829 throw new JSONException("Null pointer"); 830 } 831 testValidity(number); 832 833// Shave off trailing zeros and decimal point, if possible. 834 835 String string = number.toString(); 836 if (string.indexOf('.') > 0 && string.indexOf('e') < 0 837 && string.indexOf('E') < 0) { 838 while (string.endsWith("0")) { 839 string = string.substring(0, string.length() - 1); 840 } 841 if (string.endsWith(".")) { 842 string = string.substring(0, string.length() - 1); 843 } 844 } 845 return string; 846 } 847 848 /** 849 * Get an optional value associated with a key. 850 * 851 * @param key 852 * A key string. 853 * @return An object which is the value, or null if there is no value. 854 */ 855 public Object opt(String key) { 856 return key == null ? null : this.map.get(key); 857 } 858 859 /** 860 * Get the enum value associated with a key. 861 * 862 * @param clazz 863 * The type of enum to retrieve. 864 * @param key 865 * A key string. 866 * @return The enum value associated with the key or null if not found 867 */ 868 public <E extends Enum<E>> E optEnum(Class<E> clazz, String key) { 869 return this.optEnum(clazz, key, null); 870 } 871 872 /** 873 * Get the enum value associated with a key. 874 * 875 * @param clazz 876 * The type of enum to retrieve. 877 * @param key 878 * A key string. 879 * @param defaultValue 880 * The default in case the value is not found 881 * @return The enum value associated with the key or defaultValue 882 * if the value is not found or cannot be assigned to clazz 883 */ 884 public <E extends Enum<E>> E optEnum(Class<E> clazz, String key, E defaultValue) { 885 try { 886 Object val = this.opt(key); 887 if (NULL.equals(val)) { 888 return defaultValue; 889 } 890 if (clazz.isAssignableFrom(val.getClass())) { 891 // we just checked it! 892 @SuppressWarnings("unchecked") 893 E myE = (E) val; 894 return myE; 895 } 896 return Enum.valueOf(clazz, val.toString()); 897 } catch (IllegalArgumentException e) { 898 return defaultValue; 899 } catch (NullPointerException e) { 900 return defaultValue; 901 } 902 } 903 904 /** 905 * Get an optional boolean associated with a key. It returns false if there 906 * is no such key, or if the value is not Boolean.TRUE or the String "true". 907 * 908 * @param key 909 * A key string. 910 * @return The truth. 911 */ 912 public boolean optBoolean(String key) { 913 return this.optBoolean(key, false); 914 } 915 916 /** 917 * Get an optional boolean associated with a key. It returns the 918 * defaultValue if there is no such key, or if it is not a Boolean or the 919 * String "true" or "false" (case insensitive). 920 * 921 * @param key 922 * A key string. 923 * @param defaultValue 924 * The default. 925 * @return The truth. 926 */ 927 public boolean optBoolean(String key, boolean defaultValue) { 928 try { 929 return this.getBoolean(key); 930 } catch (Exception e) { 931 return defaultValue; 932 } 933 } 934 935 /** 936 * Get an optional double associated with a key, or NaN if there is no such 937 * key or if its value is not a number. If the value is a string, an attempt 938 * will be made to evaluate it as a number. 939 * 940 * @param key 941 * A string which is the key. 942 * @return An object which is the value. 943 */ 944 public double optDouble(String key) { 945 return this.optDouble(key, Double.NaN); 946 } 947 948 /** 949 * Get an optional BigInteger associated with a key, or the defaultValue if 950 * there is no such key or if its value is not a number. If the value is a 951 * string, an attempt will be made to evaluate it as a number. 952 * 953 * @param key 954 * A key string. 955 * @param defaultValue 956 * The default. 957 * @return An object which is the value. 958 */ 959 public BigInteger optBigInteger(String key, BigInteger defaultValue) { 960 try { 961 return this.getBigInteger(key); 962 } catch (Exception e) { 963 return defaultValue; 964 } 965 } 966 967 /** 968 * Get an optional BigDecimal associated with a key, or the defaultValue if 969 * there is no such key or if its value is not a number. If the value is a 970 * string, an attempt will be made to evaluate it as a number. 971 * 972 * @param key 973 * A key string. 974 * @param defaultValue 975 * The default. 976 * @return An object which is the value. 977 */ 978 public BigDecimal optBigDecimal(String key, BigDecimal defaultValue) { 979 try { 980 return this.getBigDecimal(key); 981 } catch (Exception e) { 982 return defaultValue; 983 } 984 } 985 986 /** 987 * Get an optional double associated with a key, or the defaultValue if 988 * there is no such key or if its value is not a number. If the value is a 989 * string, an attempt will be made to evaluate it as a number. 990 * 991 * @param key 992 * A key string. 993 * @param defaultValue 994 * The default. 995 * @return An object which is the value. 996 */ 997 public double optDouble(String key, double defaultValue) { 998 try { 999 return this.getDouble(key); 1000 } catch (Exception e) { 1001 return defaultValue; 1002 } 1003 } 1004 1005 /** 1006 * Get an optional int value associated with a key, or zero if there is no 1007 * such key or if the value is not a number. If the value is a string, an 1008 * attempt will be made to evaluate it as a number. 1009 * 1010 * @param key 1011 * A key string. 1012 * @return An object which is the value. 1013 */ 1014 public int optInt(String key) { 1015 return this.optInt(key, 0); 1016 } 1017 1018 /** 1019 * Get an optional int value associated with a key, or the default if there 1020 * is no such key or if the value is not a number. If the value is a string, 1021 * an attempt will be made to evaluate it as a number. 1022 * 1023 * @param key 1024 * A key string. 1025 * @param defaultValue 1026 * The default. 1027 * @return An object which is the value. 1028 */ 1029 public int optInt(String key, int defaultValue) { 1030 try { 1031 return this.getInt(key); 1032 } catch (Exception e) { 1033 return defaultValue; 1034 } 1035 } 1036 1037 /** 1038 * Get an optional JSONArray associated with a key. It returns null if there 1039 * is no such key, or if its value is not a JSONArray. 1040 * 1041 * @param key 1042 * A key string. 1043 * @return A JSONArray which is the value. 1044 */ 1045 public JSONArray optJSONArray(String key) { 1046 Object o = this.opt(key); 1047 return o instanceof JSONArray ? (JSONArray) o : null; 1048 } 1049 1050 /** 1051 * Get an optional JSONObject associated with a key. It returns null if 1052 * there is no such key, or if its value is not a JSONObject. 1053 * 1054 * @param key 1055 * A key string. 1056 * @return A JSONObject which is the value. 1057 */ 1058 public JSONObject optJSONObject(String key) { 1059 Object object = this.opt(key); 1060 return object instanceof JSONObject ? (JSONObject) object : null; 1061 } 1062 1063 /** 1064 * Get an optional long value associated with a key, or zero if there is no 1065 * such key or if the value is not a number. If the value is a string, an 1066 * attempt will be made to evaluate it as a number. 1067 * 1068 * @param key 1069 * A key string. 1070 * @return An object which is the value. 1071 */ 1072 public long optLong(String key) { 1073 return this.optLong(key, 0); 1074 } 1075 1076 /** 1077 * Get an optional long value associated with a key, or the default if there 1078 * is no such key or if the value is not a number. If the value is a string, 1079 * an attempt will be made to evaluate it as a number. 1080 * 1081 * @param key 1082 * A key string. 1083 * @param defaultValue 1084 * The default. 1085 * @return An object which is the value. 1086 */ 1087 public long optLong(String key, long defaultValue) { 1088 try { 1089 return this.getLong(key); 1090 } catch (Exception e) { 1091 return defaultValue; 1092 } 1093 } 1094 1095 /** 1096 * Get an optional string associated with a key. It returns an empty string 1097 * if there is no such key. If the value is not a string and is not null, 1098 * then it is converted to a string. 1099 * 1100 * @param key 1101 * A key string. 1102 * @return A string which is the value. 1103 */ 1104 public String optString(String key) { 1105 return this.optString(key, ""); 1106 } 1107 1108 /** 1109 * Get an optional string associated with a key. It returns the defaultValue 1110 * if there is no such key. 1111 * 1112 * @param key 1113 * A key string. 1114 * @param defaultValue 1115 * The default. 1116 * @return A string which is the value. 1117 */ 1118 public String optString(String key, String defaultValue) { 1119 Object object = this.opt(key); 1120 return NULL.equals(object) ? defaultValue : object.toString(); 1121 } 1122 1123 private void populateMap(Object bean) { 1124 Class<?> klass = bean.getClass(); 1125 1126// If klass is a System class then set includeSuperClass to false. 1127 1128 boolean includeSuperClass = klass.getClassLoader() != null; 1129 1130 Method[] methods = includeSuperClass ? klass.getMethods() : klass 1131 .getDeclaredMethods(); 1132 for (int i = 0; i < methods.length; i += 1) { 1133 try { 1134 Method method = methods[i]; 1135 if (Modifier.isPublic(method.getModifiers())) { 1136 String name = method.getName(); 1137 String key = ""; 1138 if (name.startsWith("get")) { 1139 if ("getClass".equals(name) 1140 || "getDeclaringClass".equals(name)) { 1141 key = ""; 1142 } else { 1143 key = name.substring(3); 1144 } 1145 } else if (name.startsWith("is")) { 1146 key = name.substring(2); 1147 } 1148 if (key.length() > 0 1149 && Character.isUpperCase(key.charAt(0)) 1150 && method.getParameterTypes().length == 0) { 1151 if (key.length() == 1) { 1152 key = key.toLowerCase(); 1153 } else if (!Character.isUpperCase(key.charAt(1))) { 1154 key = key.substring(0, 1).toLowerCase() 1155 + key.substring(1); 1156 } 1157 1158 Object result = method.invoke(bean, (Object[]) null); 1159 if (result != null) { 1160 this.map.put(key, wrap(result)); 1161 } 1162 } 1163 } 1164 } catch (Exception ignore) { 1165 } 1166 } 1167 } 1168 1169 /** 1170 * Put a key/boolean pair in the JSONObject. 1171 * 1172 * @param key 1173 * A key string. 1174 * @param value 1175 * A boolean which is the value. 1176 * @return this. 1177 * @throws JSONException 1178 * If the key is null. 1179 */ 1180 public JSONObject put(String key, boolean value) throws JSONException { 1181 this.put(key, value ? Boolean.TRUE : Boolean.FALSE); 1182 return this; 1183 } 1184 1185 /** 1186 * Put a key/value pair in the JSONObject, where the value will be a 1187 * JSONArray which is produced from a Collection. 1188 * 1189 * @param key 1190 * A key string. 1191 * @param value 1192 * A Collection value. 1193 * @return this. 1194 * @throws JSONException 1195 */ 1196 public JSONObject put(String key, Collection<?> value) throws JSONException { 1197 this.put(key, new JSONArray(value)); 1198 return this; 1199 } 1200 1201 /** 1202 * Put a key/double pair in the JSONObject. 1203 * 1204 * @param key 1205 * A key string. 1206 * @param value 1207 * A double which is the value. 1208 * @return this. 1209 * @throws JSONException 1210 * If the key is null or if the number is invalid. 1211 */ 1212 public JSONObject put(String key, double value) throws JSONException { 1213 this.put(key, new Double(value)); 1214 return this; 1215 } 1216 1217 /** 1218 * Put a key/int pair in the JSONObject. 1219 * 1220 * @param key 1221 * A key string. 1222 * @param value 1223 * An int which is the value. 1224 * @return this. 1225 * @throws JSONException 1226 * If the key is null. 1227 */ 1228 public JSONObject put(String key, int value) throws JSONException { 1229 this.put(key, new Integer(value)); 1230 return this; 1231 } 1232 1233 /** 1234 * Put a key/long pair in the JSONObject. 1235 * 1236 * @param key 1237 * A key string. 1238 * @param value 1239 * A long which is the value. 1240 * @return this. 1241 * @throws JSONException 1242 * If the key is null. 1243 */ 1244 public JSONObject put(String key, long value) throws JSONException { 1245 this.put(key, new Long(value)); 1246 return this; 1247 } 1248 1249 /** 1250 * Put a key/value pair in the JSONObject, where the value will be a 1251 * JSONObject which is produced from a Map. 1252 * 1253 * @param key 1254 * A key string. 1255 * @param value 1256 * A Map value. 1257 * @return this. 1258 * @throws JSONException 1259 */ 1260 public JSONObject put(String key, Map<?, ?> value) throws JSONException { 1261 this.put(key, new JSONObject(value)); 1262 return this; 1263 } 1264 1265 /** 1266 * Put a key/value pair in the JSONObject. If the value is null, then the 1267 * key will be removed from the JSONObject if it is present. 1268 * 1269 * @param key 1270 * A key string. 1271 * @param value 1272 * An object which is the value. It should be of one of these 1273 * types: Boolean, Double, Integer, JSONArray, JSONObject, Long, 1274 * String, or the JSONObject.NULL object. 1275 * @return this. 1276 * @throws JSONException 1277 * If the value is non-finite number or if the key is null. 1278 */ 1279 public JSONObject put(String key, Object value) throws JSONException { 1280 if (key == null) { 1281 throw new NullPointerException("Null key."); 1282 } 1283 if (value != null) { 1284 testValidity(value); 1285 this.map.put(key, value); 1286 } else { 1287 this.remove(key); 1288 } 1289 return this; 1290 } 1291 1292 /** 1293 * Put a key/value pair in the JSONObject, but only if the key and the value 1294 * are both non-null, and only if there is not already a member with that 1295 * name. 1296 * 1297 * @param key string 1298 * @param value object 1299 * @return this. 1300 * @throws JSONException 1301 * if the key is a duplicate 1302 */ 1303 public JSONObject putOnce(String key, Object value) throws JSONException { 1304 if (key != null && value != null) { 1305 if (this.opt(key) != null) { 1306 throw new JSONException("Duplicate key \"" + key + "\""); 1307 } 1308 this.put(key, value); 1309 } 1310 return this; 1311 } 1312 1313 /** 1314 * Put a key/value pair in the JSONObject, but only if the key and the value 1315 * are both non-null. 1316 * 1317 * @param key 1318 * A key string. 1319 * @param value 1320 * An object which is the value. It should be of one of these 1321 * types: Boolean, Double, Integer, JSONArray, JSONObject, Long, 1322 * String, or the JSONObject.NULL object. 1323 * @return this. 1324 * @throws JSONException 1325 * If the value is a non-finite number. 1326 */ 1327 public JSONObject putOpt(String key, Object value) throws JSONException { 1328 if (key != null && value != null) { 1329 this.put(key, value); 1330 } 1331 return this; 1332 } 1333 1334 /** 1335 * Produce a string in double quotes with backslash sequences in all the 1336 * right places. A backslash will be inserted within </, producing <\/, 1337 * allowing JSON text to be delivered in HTML. In JSON text, a string cannot 1338 * contain a control character or an unescaped quote or backslash. 1339 * 1340 * @param string 1341 * A String 1342 * @return A String correctly formatted for insertion in a JSON text. 1343 */ 1344 public static String quote(String string) { 1345 StringWriter sw = new StringWriter(); 1346 synchronized (sw.getBuffer()) { 1347 try { 1348 return quote(string, sw).toString(); 1349 } catch (IOException ignored) { 1350 // will never happen - we are writing to a string writer 1351 return ""; 1352 } 1353 } 1354 } 1355 1356 public static Writer quote(String string, Writer w) throws IOException { 1357 if (string == null || string.length() == 0) { 1358 w.write("\"\""); 1359 return w; 1360 } 1361 1362 char b; 1363 char c = 0; 1364 String hhhh; 1365 int i; 1366 int len = string.length(); 1367 1368 w.write('"'); 1369 for (i = 0; i < len; i += 1) { 1370 b = c; 1371 c = string.charAt(i); 1372 switch (c) { 1373 case '\\': 1374 case '"': 1375 w.write('\\'); 1376 w.write(c); 1377 break; 1378 case '/': 1379 if (b == '<') { 1380 w.write('\\'); 1381 } 1382 w.write(c); 1383 break; 1384 case '\b': 1385 w.write("\\b"); 1386 break; 1387 case '\t': 1388 w.write("\\t"); 1389 break; 1390 case '\n': 1391 w.write("\\n"); 1392 break; 1393 case '\f': 1394 w.write("\\f"); 1395 break; 1396 case '\r': 1397 w.write("\\r"); 1398 break; 1399 default: 1400 if (c < ' ' || (c >= '\u0080' && c < '\u00a0') 1401 || (c >= '\u2000' && c < '\u2100')) { 1402 w.write("\\u"); 1403 hhhh = Integer.toHexString(c); 1404 w.write("0000", 0, 4 - hhhh.length()); 1405 w.write(hhhh); 1406 } else { 1407 w.write(c); 1408 } 1409 } 1410 } 1411 w.write('"'); 1412 return w; 1413 } 1414 1415 /** 1416 * Remove a name and its value, if present. 1417 * 1418 * @param key 1419 * The name to be removed. 1420 * @return The value that was associated with the name, or null if there was 1421 * no value. 1422 */ 1423 public Object remove(String key) { 1424 return this.map.remove(key); 1425 } 1426 1427 /** 1428 * Determine if two JSONObjects are similar. 1429 * They must contain the same set of names which must be associated with 1430 * similar values. 1431 * 1432 * @param other The other JSONObject 1433 * @return true if they are equal 1434 */ 1435 public boolean similar(Object other) { 1436 try { 1437 if (!(other instanceof JSONObject)) { 1438 return false; 1439 } 1440 Set<String> set = this.keySet(); 1441 if (!set.equals(((JSONObject)other).keySet())) { 1442 return false; 1443 } 1444 Iterator<String> iterator = set.iterator(); 1445 while (iterator.hasNext()) { 1446 String name = iterator.next(); 1447 Object valueThis = this.get(name); 1448 Object valueOther = ((JSONObject)other).get(name); 1449 if (valueThis instanceof JSONObject) { 1450 if (!((JSONObject)valueThis).similar(valueOther)) { 1451 return false; 1452 } 1453 } else if (valueThis instanceof JSONArray) { 1454 if (!((JSONArray)valueThis).similar(valueOther)) { 1455 return false; 1456 } 1457 } else if (!valueThis.equals(valueOther)) { 1458 return false; 1459 } 1460 } 1461 return true; 1462 } catch (Throwable exception) { 1463 return false; 1464 } 1465 } 1466 1467 /** 1468 * Try to convert a string into a number, boolean, or null. If the string 1469 * can't be converted, return the string. 1470 * 1471 * @param string 1472 * A String. 1473 * @return A simple JSON value. 1474 */ 1475 public static Object stringToValue(String string) { 1476 if (string.equals("")) { 1477 return string; 1478 } 1479 if (string.equalsIgnoreCase("true")) { 1480 return Boolean.TRUE; 1481 } 1482 if (string.equalsIgnoreCase("false")) { 1483 return Boolean.FALSE; 1484 } 1485 if (string.equalsIgnoreCase("null")) { 1486 return JSONObject.NULL; 1487 } 1488 1489 /* 1490 * If it might be a number, try converting it. If a number cannot be 1491 * produced, then the value will just be a string. 1492 */ 1493 1494 char initial = string.charAt(0); 1495 if ((initial >= '0' && initial <= '9') || initial == '-') { 1496 try { 1497 if (string.indexOf('.') > -1 || string.indexOf('e') > -1 1498 || string.indexOf('E') > -1 1499 || "-0".equals(string)) { 1500 Double d = Double.valueOf(string); 1501 if (!d.isInfinite() && !d.isNaN()) { 1502 return d; 1503 } 1504 } else { 1505 Long myLong = new Long(string); 1506 if (string.equals(myLong.toString())) { 1507 if (myLong.longValue() == myLong.intValue()) { 1508 return Integer.valueOf(myLong.intValue()); 1509 } 1510 return myLong; 1511 } 1512 } 1513 } catch (Exception ignore) { 1514 } 1515 } 1516 return string; 1517 } 1518 1519 /** 1520 * Throw an exception if the object is a NaN or infinite number. 1521 * 1522 * @param o 1523 * The object to test. 1524 * @throws JSONException 1525 * If o is a non-finite number. 1526 */ 1527 public static void testValidity(Object o) throws JSONException { 1528 if (o != null) { 1529 if (o instanceof Double) { 1530 if (((Double) o).isInfinite() || ((Double) o).isNaN()) { 1531 throw new JSONException( 1532 "JSON does not allow non-finite numbers."); 1533 } 1534 } else if (o instanceof Float) { 1535 if (((Float) o).isInfinite() || ((Float) o).isNaN()) { 1536 throw new JSONException( 1537 "JSON does not allow non-finite numbers."); 1538 } 1539 } 1540 } 1541 } 1542 1543 /** 1544 * Produce a JSONArray containing the values of the members of this 1545 * JSONObject. 1546 * 1547 * @param names 1548 * A JSONArray containing a list of key strings. This determines 1549 * the sequence of the values in the result. 1550 * @return A JSONArray of values. 1551 * @throws JSONException 1552 * If any of the values are non-finite numbers. 1553 */ 1554 public JSONArray toJSONArray(JSONArray names) throws JSONException { 1555 if (names == null || names.length() == 0) { 1556 return null; 1557 } 1558 JSONArray ja = new JSONArray(); 1559 for (int i = 0; i < names.length(); i += 1) { 1560 ja.put(this.opt(names.getString(i))); 1561 } 1562 return ja; 1563 } 1564 1565 /** 1566 * Make a JSON text of this JSONObject. For compactness, no whitespace is 1567 * added. If this would not result in a syntactically correct JSON text, 1568 * then null will be returned instead. 1569 * <p> 1570 * Warning: This method assumes that the data structure is acyclical. 1571 * 1572 * @return a printable, displayable, portable, transmittable representation 1573 * of the object, beginning with <code>{</code> <small>(left 1574 * brace)</small> and ending with <code>}</code> <small>(right 1575 * brace)</small>. 1576 */ 1577 public String toString() { 1578 try { 1579 return this.toString(0); 1580 } catch (Exception e) { 1581 return null; 1582 } 1583 } 1584 1585 /** 1586 * Make a prettyprinted JSON text of this JSONObject. 1587 * <p> 1588 * Warning: This method assumes that the data structure is acyclical. 1589 * 1590 * @param indentFactor 1591 * The number of spaces to add to each level of indentation. 1592 * @return a printable, displayable, portable, transmittable representation 1593 * of the object, beginning with <code>{</code> <small>(left 1594 * brace)</small> and ending with <code>}</code> <small>(right 1595 * brace)</small>. 1596 * @throws JSONException 1597 * If the object contains an invalid number. 1598 */ 1599 public String toString(int indentFactor) throws JSONException { 1600 StringWriter w = new StringWriter(); 1601 synchronized (w.getBuffer()) { 1602 return this.write(w, indentFactor, 0).toString(); 1603 } 1604 } 1605 1606 /** 1607 * Make a JSON text of an Object value. If the object has an 1608 * value.toJSONString() method, then that method will be used to produce the 1609 * JSON text. The method is required to produce a strictly conforming text. 1610 * If the object does not contain a toJSONString method (which is the most 1611 * common case), then a text will be produced by other means. If the value 1612 * is an array or Collection, then a JSONArray will be made from it and its 1613 * toJSONString method will be called. If the value is a MAP, then a 1614 * JSONObject will be made from it and its toJSONString method will be 1615 * called. Otherwise, the value's toString method will be called, and the 1616 * result will be quoted. 1617 * 1618 * <p> 1619 * Warning: This method assumes that the data structure is acyclical. 1620 * 1621 * @param value 1622 * The value to be serialized. 1623 * @return a printable, displayable, transmittable representation of the 1624 * object, beginning with <code>{</code> <small>(left 1625 * brace)</small> and ending with <code>}</code> <small>(right 1626 * brace)</small>. 1627 * @throws JSONException 1628 * If the value is or contains an invalid number. 1629 */ 1630 public static String valueToString(Object value) throws JSONException { 1631 if (value == null || value.equals(null)) { 1632 return "null"; 1633 } 1634 if (value instanceof JSONString) { 1635 Object object; 1636 try { 1637 object = ((JSONString) value).toJSONString(); 1638 } catch (Exception e) { 1639 throw new JSONException(e); 1640 } 1641 if (object instanceof String) { 1642 return (String) object; 1643 } 1644 throw new JSONException("Bad value from toJSONString: " + object); 1645 } 1646 if (value instanceof Number) { 1647 return numberToString((Number) value); 1648 } 1649 if (value instanceof Boolean || value instanceof JSONObject 1650 || value instanceof JSONArray) { 1651 return value.toString(); 1652 } 1653 if (value instanceof Map) { 1654 Map<?, ?> map = (Map<?, ?>) value; 1655 return new JSONObject(map).toString(); 1656 } 1657 if (value instanceof Collection) { 1658 Collection<?> coll = (Collection<?>) value; 1659 return new JSONArray(coll).toString(); 1660 } 1661 if (value.getClass().isArray()) { 1662 return new JSONArray(value).toString(); 1663 } 1664 return quote(value.toString()); 1665 } 1666 1667 /** 1668 * Wrap an object, if necessary. If the object is null, return the NULL 1669 * object. If it is an array or collection, wrap it in a JSONArray. If it is 1670 * a map, wrap it in a JSONObject. If it is a standard property (Double, 1671 * String, et al) then it is already wrapped. Otherwise, if it comes from 1672 * one of the java packages, turn it into a string. And if it doesn't, try 1673 * to wrap it in a JSONObject. If the wrapping fails, then null is returned. 1674 * 1675 * @param object 1676 * The object to wrap 1677 * @return The wrapped value 1678 */ 1679 public static Object wrap(Object object) { 1680 try { 1681 if (object == null) { 1682 return NULL; 1683 } 1684 if (object instanceof JSONObject || object instanceof JSONArray 1685 || NULL.equals(object) || object instanceof JSONString 1686 || object instanceof Byte || object instanceof Character 1687 || object instanceof Short || object instanceof Integer 1688 || object instanceof Long || object instanceof Boolean 1689 || object instanceof Float || object instanceof Double 1690 || object instanceof String || object instanceof BigInteger 1691 || object instanceof BigDecimal) { 1692 return object; 1693 } 1694 1695 if (object instanceof Collection) { 1696 Collection<?> coll = (Collection<?>) object; 1697 return new JSONArray(coll); 1698 } 1699 if (object.getClass().isArray()) { 1700 return new JSONArray(object); 1701 } 1702 if (object instanceof Map) { 1703 Map<?, ?> map = (Map<?, ?>) object; 1704 return new JSONObject(map); 1705 } 1706 Package objectPackage = object.getClass().getPackage(); 1707 String objectPackageName = objectPackage != null ? objectPackage 1708 .getName() : ""; 1709 if (objectPackageName.startsWith("java.") 1710 || objectPackageName.startsWith("javax.") 1711 || object.getClass().getClassLoader() == null) { 1712 return object.toString(); 1713 } 1714 return new JSONObject(object); 1715 } catch (Exception exception) { 1716 return null; 1717 } 1718 } 1719 1720 /** 1721 * Write the contents of the JSONObject as JSON text to a writer. For 1722 * compactness, no whitespace is added. 1723 * <p> 1724 * Warning: This method assumes that the data structure is acyclical. 1725 * 1726 * @return The writer. 1727 * @throws JSONException 1728 */ 1729 public Writer write(Writer writer) throws JSONException { 1730 return this.write(writer, 0, 0); 1731 } 1732 1733 static final Writer writeValue(Writer writer, Object value, 1734 int indentFactor, int indent) throws JSONException, IOException { 1735 if (value == null || value.equals(null)) { 1736 writer.write("null"); 1737 } else if (value instanceof JSONObject) { 1738 ((JSONObject) value).write(writer, indentFactor, indent); 1739 } else if (value instanceof JSONArray) { 1740 ((JSONArray) value).write(writer, indentFactor, indent); 1741 } else if (value instanceof Map) { 1742 Map<?, ?> map = (Map<?, ?>) value; 1743 new JSONObject(map).write(writer, indentFactor, indent); 1744 } else if (value instanceof Collection) { 1745 Collection<?> coll = (Collection<?>) value; 1746 new JSONArray(coll).write(writer, indentFactor, indent); 1747 } else if (value.getClass().isArray()) { 1748 new JSONArray(value).write(writer, indentFactor, indent); 1749 } else if (value instanceof Number) { 1750 writer.write(numberToString((Number) value)); 1751 } else if (value instanceof Boolean) { 1752 writer.write(value.toString()); 1753 } else if (value instanceof JSONString) { 1754 Object o; 1755 try { 1756 o = ((JSONString) value).toJSONString(); 1757 } catch (Exception e) { 1758 throw new JSONException(e); 1759 } 1760 writer.write(o != null ? o.toString() : quote(value.toString())); 1761 } else { 1762 quote(value.toString(), writer); 1763 } 1764 return writer; 1765 } 1766 1767 static final void indent(Writer writer, int indent) throws IOException { 1768 for (int i = 0; i < indent; i += 1) { 1769 writer.write(' '); 1770 } 1771 } 1772 1773 /** 1774 * Write the contents of the JSONObject as JSON text to a writer. For 1775 * compactness, no whitespace is added. 1776 * <p> 1777 * Warning: This method assumes that the data structure is acyclical. 1778 * 1779 * @param writer 1780 * Writes the serialized JSON 1781 * @param indentFactor 1782 * The number of spaces to add to each level of indentation. 1783 * @param indent 1784 * The indention of the top level. 1785 * @return The writer. 1786 * @throws JSONException 1787 */ 1788 public Writer write(Writer writer, int indentFactor, int indent) 1789 throws JSONException { 1790 try { 1791 boolean commanate = false; 1792 final int length = this.length(); 1793 Iterator<String> keys = this.keys(); 1794 writer.write('{'); 1795 1796 if (length == 1) { 1797 Object key = keys.next(); 1798 writer.write(quote(key.toString())); 1799 writer.write(':'); 1800 if (indentFactor > 0) { 1801 writer.write(' '); 1802 } 1803 writeValue(writer, this.map.get(key), indentFactor, indent); 1804 } else if (length != 0) { 1805 final int newindent = indent + indentFactor; 1806 while (keys.hasNext()) { 1807 Object key = keys.next(); 1808 if (commanate) { 1809 writer.write(','); 1810 } 1811 if (indentFactor > 0) { 1812 writer.write('\n'); 1813 } 1814 indent(writer, newindent); 1815 writer.write(quote(key.toString())); 1816 writer.write(':'); 1817 if (indentFactor > 0) { 1818 writer.write(' '); 1819 } 1820 writeValue(writer, this.map.get(key), indentFactor, newindent); 1821 commanate = true; 1822 } 1823 if (indentFactor > 0) { 1824 writer.write('\n'); 1825 } 1826 indent(writer, indent); 1827 } 1828 writer.write('}'); 1829 return writer; 1830 } catch (IOException exception) { 1831 throw new JSONException(exception); 1832 } 1833 } 1834 1835 /** 1836 * Returns a java.util.Map containing all of the entrys in this object. 1837 * If an entry in the object is a JSONArray or JSONObject it will also 1838 * be converted. 1839 * <p> 1840 * Warning: This method assumes that the data structure is acyclical. 1841 * 1842 * @return a java.util.Map containing the entrys of this object 1843 */ 1844 public Map<String, Object> toMap() { 1845 Map<String, Object> results = new HashMap<>(); 1846 for (Entry<String, Object> entry : this.map.entrySet()) { 1847 Object value; 1848 if (entry.getValue() == null || NULL.equals(entry.getValue())) { 1849 value = null; 1850 } else if (entry.getValue() instanceof JSONObject) { 1851 value = ((JSONObject) entry.getValue()).toMap(); 1852 } else if (entry.getValue() instanceof JSONArray) { 1853 value = ((JSONArray) entry.getValue()).toList(); 1854 } else { 1855 value = entry.getValue(); 1856 } 1857 results.put(entry.getKey(), value); 1858 } 1859 return results; 1860 } 1861}