001package org.json; 002 003/* 004Copyright (c) 2002 JSON.org 005 006Permission is hereby granted, free of charge, to any person obtaining a copy 007of this software and associated documentation files (the "Software"), to deal 008in the Software without restriction, including without limitation the rights 009to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 010copies of the Software, and to permit persons to whom the Software is 011furnished to do so, subject to the following conditions: 012 013The above copyright notice and this permission notice shall be included in all 014copies or substantial portions of the Software. 015 016The Software shall be used for Good, not Evil. 017 018THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 019IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 020FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 021AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 022LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 023OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 024SOFTWARE. 025 */ 026import java.io.IOException; 027import java.io.Writer; 028import java.lang.reflect.Field; 029import java.lang.reflect.Method; 030import java.lang.reflect.Modifier; 031import java.util.Collection; 032import java.util.HashMap; 033import java.util.Iterator; 034import java.util.Locale; 035import java.util.Map; 036import java.util.TreeSet; 037 038/** 039 * A JSONObject is an unordered collection of name/value pairs. Its 040 * external form is a string wrapped in curly braces with colons between the 041 * names and values, and commas between the values and names. The internal form 042 * is an object having <code>get</code> and <code>opt</code> methods for 043 * accessing the values by name, and <code>put</code> methods for adding or 044 * replacing values by name. The values can be any of these types: 045 * <code>Boolean</code>, <code>JSONArray</code>, <code>JSONObject</code>, 046 * <code>Number</code>, <code>String</code>, or the <code>JSONObject.NULL</code> 047 * object. A JSONObject constructor can be used to convert an external form 048 * JSON text 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. 051 * A <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. 060 * <p> 061 * The <code>put</code> methods adds values to an object. For example, <pre> 062 * myString = new JSONObject().put("JSON", "Hello, World!").toString();</pre> 063 * produces the string <code>{"JSON": "Hello, World"}</code>. 064 * <p> 065 * The texts produced by the <code>toString</code> methods strictly conform to 066 * the JSON syntax rules. 067 * The constructors are more forgiving in the texts they will accept: 068 * <ul> 069 * <li>An extra <code>,</code> <small>(comma)</small> may appear just 070 * before the closing brace.</li> 071 * <li>Strings may be quoted with <code>'</code> <small>(single 072 * quote)</small>.</li> 073 * <li>Strings do not need to be quoted at all if they do not begin with a quote 074 * or single quote, and if they do not contain leading or trailing spaces, 075 * and if they do not contain any of these characters: 076 * <code>{ } [ ] / \ : , = ; #</code> and if they do not look like numbers 077 * and if they are not the reserved words <code>true</code>, 078 * <code>false</code>, or <code>null</code>.</li> 079 * <li>Keys can be followed by <code>=</code> or <code>=></code> as well as 080 * by <code>:</code>.</li> 081 * <li>Values can be followed by <code>;</code> <small>(semicolon)</small> as 082 * well as by <code>,</code> <small>(comma)</small>.</li> 083 * <li>Numbers may have the <code>0x-</code> <small>(hex)</small> prefix.</li> 084 * </ul> 085 * @author JSON.org 086@version $Id$ 087@since Ptolemy II 10.0 088 * @version 2010-05-17 089 */ 090public class JSONObject { 091 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 * @return NULL. 103 */ 104 @Override 105 protected final Object clone() { 106 return this; 107 } 108 109 /** 110 * A Null object is equal to the null value and to itself. 111 * @param object An object to test for nullness. 112 * @return true if the object parameter is the JSONObject.NULL object 113 * or null. 114 */ 115 @Override 116 public boolean equals(Object object) { 117 return object == null || object == this; 118 } 119 120 /** 121 * Get the "null" string value. 122 * @return The string "null". 123 */ 124 @Override 125 public String toString() { 126 return "null"; 127 } 128 } 129 130 /** 131 * The map where the JSONObject's properties are kept. 132 */ 133 private Map map; 134 135 /** 136 * It is sometimes more convenient and less ambiguous to have a 137 * <code>NULL</code> object than to use Java's <code>null</code> value. 138 * <code>JSONObject.NULL.equals(null)</code> returns <code>true</code>. 139 * <code>JSONObject.NULL.toString()</code> returns <code>"null"</code>. 140 */ 141 public static final Object NULL = new Null(); 142 143 /** 144 * Construct an empty JSONObject. 145 */ 146 public JSONObject() { 147 this.map = new HashMap(); 148 } 149 150 /** 151 * Construct a JSONObject from a subset of another JSONObject. 152 * An array of strings is used to identify the keys that should be copied. 153 * Missing keys are ignored. 154 * @param jo A JSONObject. 155 * @param names An array of strings. 156 */ 157 public JSONObject(JSONObject jo, String[] names) { 158 this(); 159 for (String name : names) { 160 try { 161 putOnce(name, jo.opt(name)); 162 } catch (Exception ignore) { 163 // FIXME: It is wrong to ignore exceptions, this should be logged. 164 } 165 } 166 } 167 168 /** 169 * Construct a JSONObject from a JSONTokener. 170 * @param x A JSONTokener object containing the source string. 171 * @exception JSONException If there is a syntax error in the source string 172 * or a duplicated key. 173 */ 174 public JSONObject(JSONTokener x) throws JSONException { 175 this(); 176 char c; 177 String key; 178 179 if (x.nextClean() != '{') { 180 throw x.syntaxError("A JSONObject text must begin with '{'"); 181 } 182 for (;;) { 183 c = x.nextClean(); 184 switch (c) { 185 case 0: 186 throw x.syntaxError("A JSONObject text must end with '}'"); 187 case '}': 188 return; 189 default: 190 x.back(); 191 key = x.nextValue().toString(); 192 } 193 194 /* 195 * The key is followed by ':'. We will also tolerate '=' or '=>'. 196 */ 197 198 c = x.nextClean(); 199 if (c == '=') { 200 if (x.next() != '>') { 201 x.back(); 202 } 203 } else if (c != ':') { 204 throw x.syntaxError("Expected a ':' after a key"); 205 } 206 putOnce(key, x.nextValue()); 207 208 /* 209 * Pairs are separated by ','. We will also tolerate ';'. 210 */ 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 A map object that can be used to initialize the contents of 232 * the JSONObject. 233 */ 234 public JSONObject(Map map) { 235 this.map = new HashMap(); 236 if (map != null) { 237 Iterator i = map.entrySet().iterator(); 238 while (i.hasNext()) { 239 Map.Entry e = (Map.Entry) i.next(); 240 map.put(e.getKey(), wrap(e.getValue())); 241 } 242 } 243 } 244 245 /** 246 * Construct a JSONObject from an Object using bean getters. 247 * It reflects on all of the public methods of the object. 248 * For each of the methods with no parameters and a name starting 249 * with <code>"get"</code> or <code>"is"</code> followed by an uppercase letter, 250 * the method is invoked, and a key and the value returned from the getter method 251 * are put into the new JSONObject. 252 * 253 * The key is formed by removing the <code>"get"</code> or <code>"is"</code> prefix. 254 * If the second remaining character is not upper case, then the first 255 * character is converted to lower case. 256 * 257 * For example, if an object has a method named <code>"getName"</code>, and 258 * if the result of calling <code>object.getName()</code> is <code>"Larry Fine"</code>, 259 * then the JSONObject will contain <code>"name": "Larry Fine"</code>. 260 * 261 * @param bean An object that has getter methods that should be used 262 * to make a JSONObject. 263 */ 264 public JSONObject(Object bean) { 265 this(); 266 populateMap(bean); 267 } 268 269 /** 270 * Construct a JSONObject from an Object, using reflection to find the 271 * public members. The resulting JSONObject's keys will be the strings 272 * from the names array, and the values will be the field values associated 273 * with those keys in the object. If a key is not found or not visible, 274 * then it will not be copied into the new JSONObject. 275 * @param object An object that has fields that should be used to make a 276 * JSONObject. 277 * @param names An array of strings, the names of the fields to be obtained 278 * from the object. 279 */ 280 public JSONObject(Object object, String names[]) { 281 this(); 282 Class c = object.getClass(); 283 for (String name : names) { 284 try { 285 putOpt(name, c.getField(name).get(object)); 286 } catch (Exception ignore) { 287 } 288 } 289 } 290 291 /** 292 * Construct a JSONObject from a source JSON text string. 293 * This is the most commonly used JSONObject constructor. 294 * @param source A string beginning 295 * with <code>{</code> <small>(left brace)</small> and ending 296 * with <code>}</code> <small>(right brace)</small>. 297 * @exception JSONException If there is a syntax error in the source 298 * string or a duplicated key. 299 */ 300 public JSONObject(String source) throws JSONException { 301 this(new JSONTokener(source)); 302 } 303 304 /** 305 * Accumulate values under a key. It is similar to the put method except 306 * that if there is already an object stored under the key then a 307 * JSONArray is stored under the key to hold all of the accumulated values. 308 * If there is already a JSONArray, then the new value is appended to it. 309 * In contrast, the put method replaces the previous value. 310 * @param key A key string. 311 * @param value An object to be accumulated under the key. 312 * @return this. 313 * @exception JSONException If the value is an invalid number 314 * or if the key is null. 315 */ 316 public JSONObject accumulate(String key, Object value) 317 throws JSONException { 318 testValidity(value); 319 Object o = opt(key); 320 if (o == null) { 321 put(key, value instanceof JSONArray ? new JSONArray().put(value) 322 : value); 323 } else if (o instanceof JSONArray) { 324 ((JSONArray) o).put(value); 325 } else { 326 put(key, new JSONArray().put(o).put(value)); 327 } 328 return this; 329 } 330 331 /** 332 * Append values to the array under a key. If the key does not exist in the 333 * JSONObject, then the key is put in the JSONObject with its value being a 334 * JSONArray containing the value parameter. If the key was already 335 * associated with a JSONArray, then the value parameter is appended to it. 336 * @param key A key string. 337 * @param value An object to be accumulated under the key. 338 * @return this. 339 * @exception JSONException If the key is null or if the current value 340 * associated with the key is not a JSONArray. 341 */ 342 public JSONObject append(String key, Object value) throws JSONException { 343 testValidity(value); 344 Object o = opt(key); 345 if (o == null) { 346 put(key, new JSONArray().put(value)); 347 } else if (o instanceof JSONArray) { 348 put(key, ((JSONArray) o).put(value)); 349 } else { 350 throw new JSONException( 351 "JSONObject[" + key + "] is not a JSONArray."); 352 } 353 return this; 354 } 355 356 /** 357 * Produce a string from a double. The string "null" will be returned if 358 * the number is not finite. 359 * @param d A double. 360 * @return A String. 361 */ 362 static public String doubleToString(double d) { 363 if (Double.isInfinite(d) || Double.isNaN(d)) { 364 return "null"; 365 } 366 367 // Shave off trailing zeros and decimal point, if possible. 368 369 String s = Double.toString(d); 370 if (s.indexOf('.') > 0 && s.indexOf('e') < 0 && s.indexOf('E') < 0) { 371 while (s.endsWith("0")) { 372 s = s.substring(0, s.length() - 1); 373 } 374 if (s.endsWith(".")) { 375 s = s.substring(0, s.length() - 1); 376 } 377 } 378 return s; 379 } 380 381 /** 382 * Get the value object associated with a key. 383 * 384 * @param key A key string. 385 * @return The object associated with the key. 386 * @exception JSONException if the key is not found. 387 */ 388 public Object get(String key) throws JSONException { 389 Object o = opt(key); 390 if (o == null) { 391 throw new JSONException( 392 "JSONObject[" + quote(key) + "] not found."); 393 } 394 return o; 395 } 396 397 /** 398 * Get the boolean value associated with a key. 399 * 400 * @param key A key string. 401 * @return The truth. 402 * @exception JSONException 403 * if the value is not a Boolean or the String "true" or "false". 404 */ 405 public boolean getBoolean(String key) throws JSONException { 406 Object o = get(key); 407 if (o.equals(Boolean.FALSE) || o instanceof String 408 && ((String) o).equalsIgnoreCase("false")) { 409 return false; 410 } else if (o.equals(Boolean.TRUE) || o instanceof String 411 && ((String) o).equalsIgnoreCase("true")) { 412 return true; 413 } 414 throw new JSONException( 415 "JSONObject[" + quote(key) + "] is not a Boolean."); 416 } 417 418 /** 419 * Get the double value associated with a key. 420 * @param key A key string. 421 * @return The numeric value. 422 * @exception JSONException if the key is not found or 423 * if the value is not a Number object and cannot be converted to a number. 424 */ 425 public double getDouble(String key) throws JSONException { 426 Object o = get(key); 427 try { 428 return o instanceof Number ? ((Number) o).doubleValue() 429 : Double.valueOf((String) o).doubleValue(); 430 } catch (Exception e) { 431 throw new JSONException( 432 "JSONObject[" + quote(key) + "] is not a number."); 433 } 434 } 435 436 /** 437 * Get the int value associated with a key. 438 * 439 * @param key A key string. 440 * @return The integer value. 441 * @exception JSONException if the key is not found or if the value cannot 442 * be converted to an integer. 443 */ 444 public int getInt(String key) throws JSONException { 445 Object o = get(key); 446 try { 447 return o instanceof Number ? ((Number) o).intValue() 448 : Integer.parseInt((String) o); 449 } catch (Exception e) { 450 throw new JSONException( 451 "JSONObject[" + quote(key) + "] is not an int."); 452 } 453 } 454 455 /** 456 * Get the JSONArray value associated with a key. 457 * 458 * @param key A key string. 459 * @return A JSONArray which is the value. 460 * @exception JSONException if the key is not found or 461 * if the value is not a JSONArray. 462 */ 463 public JSONArray getJSONArray(String key) throws JSONException { 464 Object o = get(key); 465 if (o instanceof JSONArray) { 466 return (JSONArray) o; 467 } 468 throw new JSONException( 469 "JSONObject[" + quote(key) + "] is not a JSONArray."); 470 } 471 472 /** 473 * Get the JSONObject value associated with a key. 474 * 475 * @param key A key string. 476 * @return A JSONObject which is the value. 477 * @exception JSONException if the key is not found or 478 * if the value is not a JSONObject. 479 */ 480 public JSONObject getJSONObject(String key) throws JSONException { 481 Object o = get(key); 482 if (o instanceof JSONObject) { 483 return (JSONObject) o; 484 } 485 throw new JSONException( 486 "JSONObject[" + quote(key) + "] is not a JSONObject."); 487 } 488 489 /** 490 * Get the long value associated with a key. 491 * 492 * @param key A key string. 493 * @return The long value. 494 * @exception JSONException if the key is not found or if the value cannot 495 * be converted to a long. 496 */ 497 public long getLong(String key) throws JSONException { 498 Object o = get(key); 499 try { 500 return o instanceof Number ? ((Number) o).longValue() 501 : Long.parseLong((String) o); 502 } catch (Exception e) { 503 throw new JSONException( 504 "JSONObject[" + quote(key) + "] is not a long."); 505 } 506 } 507 508 /** 509 * Get an array of field names from a JSONObject. 510 * 511 * @return An array of field names, or null if there are no names. 512 */ 513 public static String[] getNames(JSONObject jo) { 514 int length = jo.length(); 515 if (length == 0) { 516 return null; 517 } 518 Iterator i = jo.keys(); 519 String[] names = new String[length]; 520 int j = 0; 521 while (i.hasNext()) { 522 names[j] = (String) i.next(); 523 j += 1; 524 } 525 return names; 526 } 527 528 /** 529 * Get an array of field names from an Object. 530 * 531 * @return An array of field names, or null if there are no names. 532 */ 533 public static String[] getNames(Object object) { 534 if (object == null) { 535 return null; 536 } 537 Class klass = object.getClass(); 538 Field[] fields = klass.getFields(); 539 int length = fields.length; 540 if (length == 0) { 541 return null; 542 } 543 String[] names = new String[length]; 544 for (int i = 0; i < length; i += 1) { 545 names[i] = fields[i].getName(); 546 } 547 return names; 548 } 549 550 /** 551 * Get the string associated with a key. 552 * 553 * @param key A key string. 554 * @return A string which is the value. 555 * @exception JSONException if the key is not found. 556 */ 557 public String getString(String key) throws JSONException { 558 return get(key).toString(); 559 } 560 561 /** 562 * Determine if the JSONObject contains a specific key. 563 * @param key A key string. 564 * @return true if the key exists in the JSONObject. 565 */ 566 public boolean has(String key) { 567 return this.map.containsKey(key); 568 } 569 570 /** 571 * Increment a property of a JSONObject. If there is no such property, 572 * create one with a value of 1. If there is such a property, and if 573 * it is an Integer, Long, Double, or Float, then add one to it. 574 * @param key A key string. 575 * @return this. 576 * @exception JSONException If there is already a property with this name 577 * that is not an Integer, Long, Double, or Float. 578 */ 579 public JSONObject increment(String key) throws JSONException { 580 Object value = opt(key); 581 if (value == null) { 582 put(key, 1); 583 } else { 584 if (value instanceof Integer) { 585 put(key, ((Integer) value).intValue() + 1); 586 } else if (value instanceof Long) { 587 put(key, ((Long) value).longValue() + 1); 588 } else if (value instanceof Double) { 589 put(key, ((Double) value).doubleValue() + 1); 590 } else if (value instanceof Float) { 591 put(key, ((Float) value).floatValue() + 1); 592 } else { 593 throw new JSONException("Unable to increment [" + key + "]."); 594 } 595 } 596 return this; 597 } 598 599 /** 600 * Determine if the value associated with the key is null or if there is 601 * no value. 602 * @param key A key string. 603 * @return true if there is no value associated with the key or if 604 * the value is the JSONObject.NULL object. 605 */ 606 public boolean isNull(String key) { 607 return JSONObject.NULL.equals(opt(key)); 608 } 609 610 /** 611 * Get an enumeration of the keys of the JSONObject. 612 * 613 * @return An iterator of the keys. 614 */ 615 public Iterator keys() { 616 return this.map.keySet().iterator(); 617 } 618 619 /** 620 * Get the number of keys stored in the JSONObject. 621 * 622 * @return The number of keys in the JSONObject. 623 */ 624 public int length() { 625 return this.map.size(); 626 } 627 628 /** 629 * Produce a JSONArray containing the names of the elements of this 630 * JSONObject. 631 * @return A JSONArray containing the key strings, or null if the JSONObject 632 * is empty. 633 */ 634 public JSONArray names() { 635 JSONArray ja = new JSONArray(); 636 Iterator keys = keys(); 637 while (keys.hasNext()) { 638 ja.put(keys.next()); 639 } 640 return ja.length() == 0 ? null : ja; 641 } 642 643 /** 644 * Produce a string from a Number. 645 * @param n A Number 646 * @return A String. 647 * @exception JSONException If n is a non-finite number. 648 */ 649 static public String numberToString(Number n) throws JSONException { 650 if (n == null) { 651 throw new JSONException("Null pointer"); 652 } 653 testValidity(n); 654 655 // Shave off trailing zeros and decimal point, if possible. 656 657 String s = n.toString(); 658 if (s.indexOf('.') > 0 && s.indexOf('e') < 0 && s.indexOf('E') < 0) { 659 while (s.endsWith("0")) { 660 s = s.substring(0, s.length() - 1); 661 } 662 if (s.endsWith(".")) { 663 s = s.substring(0, s.length() - 1); 664 } 665 } 666 return s; 667 } 668 669 /** 670 * Get an optional value associated with a key. 671 * @param key A key string. 672 * @return An object which is the value, or null if there is no value. 673 */ 674 public Object opt(String key) { 675 return key == null ? null : this.map.get(key); 676 } 677 678 /** 679 * Get an optional boolean associated with a key. 680 * It returns false if there is no such key, or if the value is not 681 * Boolean.TRUE or the String "true". 682 * 683 * @param key A key string. 684 * @return The truth. 685 */ 686 public boolean optBoolean(String key) { 687 return optBoolean(key, false); 688 } 689 690 /** 691 * Get an optional boolean associated with a key. 692 * It returns the defaultValue if there is no such key, or if it is not 693 * a Boolean or the String "true" or "false" (case insensitive). 694 * 695 * @param key A key string. 696 * @param defaultValue The default. 697 * @return The truth. 698 */ 699 public boolean optBoolean(String key, boolean defaultValue) { 700 try { 701 return getBoolean(key); 702 } catch (Exception e) { 703 return defaultValue; 704 } 705 } 706 707 /** 708 * Get an optional double associated with a key, 709 * or NaN if there is no such key or if its value is not a number. 710 * If the value is a string, an attempt will be made to evaluate it as 711 * a number. 712 * 713 * @param key A string which is the key. 714 * @return An object which is the value. 715 */ 716 public double optDouble(String key) { 717 return optDouble(key, Double.NaN); 718 } 719 720 /** 721 * Get an optional double associated with a key, or the 722 * defaultValue if there is no such key or if its value is not a number. 723 * If the value is a string, an attempt will be made to evaluate it as 724 * a number. 725 * 726 * @param key A key string. 727 * @param defaultValue The default. 728 * @return An object which is the value. 729 */ 730 public double optDouble(String key, double defaultValue) { 731 try { 732 Object o = opt(key); 733 return o instanceof Number ? ((Number) o).doubleValue() 734 : new Double((String) o).doubleValue(); 735 } catch (Exception e) { 736 return defaultValue; 737 } 738 } 739 740 /** 741 * Get an optional int value associated with a key, 742 * or zero if there is no such key or if the value is not a number. 743 * If the value is a string, an attempt will be made to evaluate it as 744 * a number. 745 * 746 * @param key A key string. 747 * @return An object which is the value. 748 */ 749 public int optInt(String key) { 750 return optInt(key, 0); 751 } 752 753 /** 754 * Get an optional int value associated with a key, 755 * or the default if there is no such key or if the value is not a number. 756 * If the value is a string, an attempt will be made to evaluate it as 757 * a number. 758 * 759 * @param key A key string. 760 * @param defaultValue The default. 761 * @return An object which is the value. 762 */ 763 public int optInt(String key, int defaultValue) { 764 try { 765 return getInt(key); 766 } catch (Exception e) { 767 return defaultValue; 768 } 769 } 770 771 /** 772 * Get an optional JSONArray associated with a key. 773 * It returns null if there is no such key, or if its value is not a 774 * JSONArray. 775 * 776 * @param key A key string. 777 * @return A JSONArray which is the value. 778 */ 779 public JSONArray optJSONArray(String key) { 780 Object o = opt(key); 781 return o instanceof JSONArray ? (JSONArray) o : null; 782 } 783 784 /** 785 * Get an optional JSONObject associated with a key. 786 * It returns null if there is no such key, or if its value is not a 787 * JSONObject. 788 * 789 * @param key A key string. 790 * @return A JSONObject which is the value. 791 */ 792 public JSONObject optJSONObject(String key) { 793 Object o = opt(key); 794 return o instanceof JSONObject ? (JSONObject) o : null; 795 } 796 797 /** 798 * Get an optional long value associated with a key, 799 * or zero if there is no such key or if the value is not a number. 800 * If the value is a string, an attempt will be made to evaluate it as 801 * a number. 802 * 803 * @param key A key string. 804 * @return An object which is the value. 805 */ 806 public long optLong(String key) { 807 return optLong(key, 0); 808 } 809 810 /** 811 * Get an optional long value associated with a key, 812 * or the default if there is no such key or if the value is not a number. 813 * If the value is a string, an attempt will be made to evaluate it as 814 * a number. 815 * 816 * @param key A key string. 817 * @param defaultValue The default. 818 * @return An object which is the value. 819 */ 820 public long optLong(String key, long defaultValue) { 821 try { 822 return getLong(key); 823 } catch (Exception e) { 824 return defaultValue; 825 } 826 } 827 828 /** 829 * Get an optional string associated with a key. 830 * It returns an empty string if there is no such key. If the value is not 831 * a string and is not null, then it is converted to a string. 832 * 833 * @param key A key string. 834 * @return A string which is the value. 835 */ 836 public String optString(String key) { 837 return optString(key, ""); 838 } 839 840 /** 841 * Get an optional string associated with a key. 842 * It returns the defaultValue if there is no such key. 843 * 844 * @param key A key string. 845 * @param defaultValue The default. 846 * @return A string which is the value. 847 */ 848 public String optString(String key, String defaultValue) { 849 Object o = opt(key); 850 return o != null ? o.toString() : defaultValue; 851 } 852 853 private void populateMap(Object bean) { 854 Class klass = bean.getClass(); 855 856 // If klass is a System class then set includeSuperClass to false. 857 858 boolean includeSuperClass = klass.getClassLoader() != null; 859 860 Method[] methods = includeSuperClass ? klass.getMethods() 861 : klass.getDeclaredMethods(); 862 for (Method method : methods) { 863 try { 864 if (Modifier.isPublic(method.getModifiers())) { 865 String name = method.getName(); 866 String key = ""; 867 if (name.startsWith("get")) { 868 if (name.equals("getClass") 869 || name.equals("getDeclaringClass")) { 870 key = ""; 871 } else { 872 key = name.substring(3); 873 } 874 } else if (name.startsWith("is")) { 875 key = name.substring(2); 876 } 877 if (key.length() > 0 && Character.isUpperCase(key.charAt(0)) 878 && method.getParameterTypes().length == 0) { 879 if (key.length() == 1) { 880 key = key.toLowerCase(Locale.getDefault()); 881 } else if (!Character.isUpperCase(key.charAt(1))) { 882 key = key.substring(0, 1).toLowerCase( 883 Locale.getDefault()) + key.substring(1); 884 } 885 886 Object result = method.invoke(bean, (Object[]) null); 887 888 map.put(key, wrap(result)); 889 } 890 } 891 } catch (Exception ignore) { 892 } 893 } 894 } 895 896 /** 897 * Put a key/boolean pair in the JSONObject. 898 * 899 * @param key A key string. 900 * @param value A boolean which is the value. 901 * @return this. 902 * @exception JSONException If the key is null. 903 */ 904 public JSONObject put(String key, boolean value) throws JSONException { 905 put(key, value ? Boolean.TRUE : Boolean.FALSE); 906 return this; 907 } 908 909 /** 910 * Put a key/value pair in the JSONObject, where the value will be a 911 * JSONArray which is produced from a Collection. 912 * @param key A key string. 913 * @param value A Collection value. 914 * @return this. 915 * @exception JSONException 916 */ 917 public JSONObject put(String key, Collection value) throws JSONException { 918 put(key, new JSONArray(value)); 919 return this; 920 } 921 922 /** 923 * Put a key/double pair in the JSONObject. 924 * 925 * @param key A key string. 926 * @param value A double which is the value. 927 * @return this. 928 * @exception JSONException If the key is null or if the number is invalid. 929 */ 930 public JSONObject put(String key, double value) throws JSONException { 931 put(key, new Double(value)); 932 return this; 933 } 934 935 /** 936 * Put a key/int pair in the JSONObject. 937 * 938 * @param key A key string. 939 * @param value An int which is the value. 940 * @return this. 941 * @exception JSONException If the key is null. 942 */ 943 public JSONObject put(String key, int value) throws JSONException { 944 put(key, new Integer(value)); 945 return this; 946 } 947 948 /** 949 * Put a key/long pair in the JSONObject. 950 * 951 * @param key A key string. 952 * @param value A long which is the value. 953 * @return this. 954 * @exception JSONException If the key is null. 955 */ 956 public JSONObject put(String key, long value) throws JSONException { 957 put(key, new Long(value)); 958 return this; 959 } 960 961 /** 962 * Put a key/value pair in the JSONObject, where the value will be a 963 * JSONObject which is produced from a Map. 964 * @param key A key string. 965 * @param value A Map value. 966 * @return this. 967 * @exception JSONException 968 */ 969 public JSONObject put(String key, Map value) throws JSONException { 970 put(key, new JSONObject(value)); 971 return this; 972 } 973 974 /** 975 * Put a key/value pair in the JSONObject. If the value is null, 976 * then the key will be removed from the JSONObject if it is present. 977 * @param key A key string. 978 * @param value An object which is the value. It should be of one of these 979 * types: Boolean, Double, Integer, JSONArray, JSONObject, Long, String, 980 * or the JSONObject.NULL object. 981 * @return this. 982 * @exception JSONException If the value is non-finite number 983 * or if the key is null. 984 */ 985 public JSONObject put(String key, Object value) throws JSONException { 986 if (key == null) { 987 throw new JSONException("Null key."); 988 } 989 if (value != null) { 990 testValidity(value); 991 this.map.put(key, value); 992 } else { 993 remove(key); 994 } 995 return this; 996 } 997 998 /** 999 * Put a key/value pair in the JSONObject, but only if the key and the 1000 * value are both non-null, and only if there is not already a member 1001 * with that name. 1002 * @param key 1003 * @param value 1004 * @return his. 1005 * @exception JSONException if the key is a duplicate 1006 */ 1007 public JSONObject putOnce(String key, Object value) throws JSONException { 1008 if (key != null && value != null) { 1009 if (opt(key) != null) { 1010 throw new JSONException("Duplicate key \"" + key + "\""); 1011 } 1012 put(key, value); 1013 } 1014 return this; 1015 } 1016 1017 /** 1018 * Put a key/value pair in the JSONObject, but only if the 1019 * key and the value are both non-null. 1020 * @param key A key string. 1021 * @param value An object which is the value. It should be of one of these 1022 * types: Boolean, Double, Integer, JSONArray, JSONObject, Long, String, 1023 * or the JSONObject.NULL object. 1024 * @return this. 1025 * @exception JSONException If the value is a non-finite number. 1026 */ 1027 public JSONObject putOpt(String key, Object value) throws JSONException { 1028 if (key != null && value != null) { 1029 put(key, value); 1030 } 1031 return this; 1032 } 1033 1034 /** 1035 * Produce a string in double quotes with backslash sequences in all the 1036 * right places. A backslash will be inserted within </, allowing JSON 1037 * text to be delivered in HTML. In JSON text, a string cannot contain a 1038 * control character or an unescaped quote or backslash. 1039 * @param string A String 1040 * @return A String correctly formatted for insertion in a JSON text. 1041 */ 1042 public static String quote(String string) { 1043 if (string == null || string.length() == 0) { 1044 return "\"\""; 1045 } 1046 1047 char b; 1048 char c = 0; 1049 int i; 1050 int len = string.length(); 1051 StringBuffer sb = new StringBuffer(len + 4); 1052 String t; 1053 1054 sb.append('"'); 1055 for (i = 0; i < len; i += 1) { 1056 b = c; 1057 c = string.charAt(i); 1058 switch (c) { 1059 case '\\': 1060 case '"': 1061 sb.append('\\'); 1062 sb.append(c); 1063 break; 1064 case '/': 1065 if (b == '<') { 1066 sb.append('\\'); 1067 } 1068 sb.append(c); 1069 break; 1070 case '\b': 1071 sb.append("\\b"); 1072 break; 1073 case '\t': 1074 sb.append("\\t"); 1075 break; 1076 case '\n': 1077 sb.append("\\n"); 1078 break; 1079 case '\f': 1080 sb.append("\\f"); 1081 break; 1082 case '\r': 1083 sb.append("\\r"); 1084 break; 1085 default: 1086 if (c < ' ' || c >= '\u0080' && c < '\u00a0' 1087 || c >= '\u2000' && c < '\u2100') { 1088 t = "000" + Integer.toHexString(c); 1089 sb.append("\\u" + t.substring(t.length() - 4)); 1090 } else { 1091 sb.append(c); 1092 } 1093 } 1094 } 1095 sb.append('"'); 1096 return sb.toString(); 1097 } 1098 1099 /** 1100 * Remove a name and its value, if present. 1101 * @param key The name to be removed. 1102 * @return The value that was associated with the name, 1103 * or null if there was no value. 1104 */ 1105 public Object remove(String key) { 1106 return this.map.remove(key); 1107 } 1108 1109 /** 1110 * Get an enumeration of the keys of the JSONObject. 1111 * The keys will be sorted alphabetically. 1112 * 1113 * @return An iterator of the keys. 1114 */ 1115 public Iterator sortedKeys() { 1116 return new TreeSet(this.map.keySet()).iterator(); 1117 } 1118 1119 /** 1120 * Try to convert a string into a number, boolean, or null. If the string 1121 * can't be converted, return the string. 1122 * @param s A String. 1123 * @return A simple JSON value. 1124 */ 1125 static public Object stringToValue(String s) { 1126 if (s.equals("")) { 1127 return s; 1128 } 1129 if (s.equalsIgnoreCase("true")) { 1130 return Boolean.TRUE; 1131 } 1132 if (s.equalsIgnoreCase("false")) { 1133 return Boolean.FALSE; 1134 } 1135 if (s.equalsIgnoreCase("null")) { 1136 return JSONObject.NULL; 1137 } 1138 1139 /* 1140 * If it might be a number, try converting it. 1141 * We support the non-standard 0x- convention. 1142 * If a number cannot be produced, then the value will just 1143 * be a string. Note that the 0x-, plus, and implied string 1144 * conventions are non-standard. A JSON parser may accept 1145 * non-JSON forms as long as it accepts all correct JSON forms. 1146 */ 1147 1148 char b = s.charAt(0); 1149 if (b >= '0' && b <= '9' || b == '.' || b == '-' || b == '+') { 1150 if (b == '0' && s.length() > 2 1151 && (s.charAt(1) == 'x' || s.charAt(1) == 'X')) { 1152 try { 1153 return new Integer(Integer.parseInt(s.substring(2), 16)); 1154 } catch (Exception ignore) { 1155 } 1156 } 1157 try { 1158 if (s.indexOf('.') > -1 || s.indexOf('e') > -1 1159 || s.indexOf('E') > -1) { 1160 return Double.valueOf(s); 1161 } else { 1162 Long myLong = new Long(s); 1163 if (myLong.longValue() == myLong.intValue()) { 1164 return new Integer(myLong.intValue()); 1165 } else { 1166 return myLong; 1167 } 1168 } 1169 } catch (Exception ignore) { 1170 } 1171 } 1172 return s; 1173 } 1174 1175 /** 1176 * Throw an exception if the object is an NaN or infinite number. 1177 * @param o The object to test. 1178 * @exception JSONException If o is a non-finite number. 1179 */ 1180 static void testValidity(Object o) throws JSONException { 1181 if (o != null) { 1182 if (o instanceof Double) { 1183 if (((Double) o).isInfinite() || ((Double) o).isNaN()) { 1184 throw new JSONException( 1185 "JSON does not allow non-finite numbers."); 1186 } 1187 } else if (o instanceof Float) { 1188 if (((Float) o).isInfinite() || ((Float) o).isNaN()) { 1189 throw new JSONException( 1190 "JSON does not allow non-finite numbers."); 1191 } 1192 } 1193 } 1194 } 1195 1196 /** 1197 * Produce a JSONArray containing the values of the members of this 1198 * JSONObject. 1199 * @param names A JSONArray containing a list of key strings. This 1200 * determines the sequence of the values in the result. 1201 * @return A JSONArray of values. 1202 * @exception JSONException If any of the values are non-finite numbers. 1203 */ 1204 public JSONArray toJSONArray(JSONArray names) throws JSONException { 1205 if (names == null || names.length() == 0) { 1206 return null; 1207 } 1208 JSONArray ja = new JSONArray(); 1209 for (int i = 0; i < names.length(); i += 1) { 1210 ja.put(this.opt(names.getString(i))); 1211 } 1212 return ja; 1213 } 1214 1215 /** 1216 * Make a JSON text of this JSONObject. For compactness, no whitespace 1217 * is added. If this would not result in a syntactically correct JSON text, 1218 * then null will be returned instead. 1219 * <p> 1220 * Warning: This method assumes that the data structure is acyclical. 1221 * 1222 * @return a printable, displayable, portable, transmittable 1223 * representation of the object, beginning 1224 * with <code>{</code> <small>(left brace)</small> and ending 1225 * with <code>}</code> <small>(right brace)</small>. 1226 */ 1227 @Override 1228 public String toString() { 1229 try { 1230 Iterator keys = keys(); 1231 StringBuffer sb = new StringBuffer("{"); 1232 1233 while (keys.hasNext()) { 1234 if (sb.length() > 1) { 1235 sb.append(','); 1236 } 1237 Object o = keys.next(); 1238 sb.append(quote(o.toString())); 1239 sb.append(':'); 1240 sb.append(valueToString(this.map.get(o))); 1241 } 1242 sb.append('}'); 1243 return sb.toString(); 1244 } catch (Exception e) { 1245 return null; 1246 } 1247 } 1248 1249 /** 1250 * Make a prettyprinted JSON text of this JSONObject. 1251 * <p> 1252 * Warning: This method assumes that the data structure is acyclical. 1253 * @param indentFactor The number of spaces to add to each level of 1254 * indentation. 1255 * @return a printable, displayable, portable, transmittable 1256 * representation of the object, beginning 1257 * with <code>{</code> <small>(left brace)</small> and ending 1258 * with <code>}</code> <small>(right brace)</small>. 1259 * @exception JSONException If the object contains an invalid number. 1260 */ 1261 public String toString(int indentFactor) throws JSONException { 1262 return toString(indentFactor, 0); 1263 } 1264 1265 /** 1266 * Make a prettyprinted JSON text of this JSONObject. 1267 * <p> 1268 * Warning: This method assumes that the data structure is acyclical. 1269 * @param indentFactor The number of spaces to add to each level of 1270 * indentation. 1271 * @param indent The indentation of the top level. 1272 * @return a printable, displayable, transmittable 1273 * representation of the object, beginning 1274 * with <code>{</code> <small>(left brace)</small> and ending 1275 * with <code>}</code> <small>(right brace)</small>. 1276 * @exception JSONException If the object contains an invalid number. 1277 */ 1278 String toString(int indentFactor, int indent) throws JSONException { 1279 int j; 1280 int n = length(); 1281 if (n == 0) { 1282 return "{}"; 1283 } 1284 Iterator keys = sortedKeys(); 1285 StringBuffer sb = new StringBuffer("{"); 1286 int newindent = indent + indentFactor; 1287 Object o; 1288 if (n == 1) { 1289 o = keys.next(); 1290 sb.append(quote(o.toString())); 1291 sb.append(": "); 1292 sb.append(valueToString(this.map.get(o), indentFactor, indent)); 1293 } else { 1294 while (keys.hasNext()) { 1295 o = keys.next(); 1296 if (sb.length() > 1) { 1297 sb.append(",\n"); 1298 } else { 1299 sb.append('\n'); 1300 } 1301 for (j = 0; j < newindent; j += 1) { 1302 sb.append(' '); 1303 } 1304 sb.append(quote(o.toString())); 1305 sb.append(": "); 1306 sb.append(valueToString(this.map.get(o), indentFactor, 1307 newindent)); 1308 } 1309 if (sb.length() > 1) { 1310 sb.append('\n'); 1311 for (j = 0; j < indent; j += 1) { 1312 sb.append(' '); 1313 } 1314 } 1315 } 1316 sb.append('}'); 1317 return sb.toString(); 1318 } 1319 1320 /** 1321 * Make a JSON text of an Object value. If the object has an 1322 * value.toJSONString() method, then that method will be used to produce 1323 * the JSON text. The method is required to produce a strictly 1324 * conforming text. If the object does not contain a toJSONString 1325 * method (which is the most common case), then a text will be 1326 * produced by other means. If the value is an array or Collection, 1327 * then a JSONArray will be made from it and its toJSONString method 1328 * will be called. If the value is a MAP, then a JSONObject will be made 1329 * from it and its toJSONString method will be called. Otherwise, the 1330 * value's toString method will be called, and the result will be quoted. 1331 * 1332 * <p> 1333 * Warning: This method assumes that the data structure is acyclical. 1334 * @param value The value to be serialized. 1335 * @return a printable, displayable, transmittable 1336 * representation of the object, beginning 1337 * with <code>{</code> <small>(left brace)</small> and ending 1338 * with <code>}</code> <small>(right brace)</small>. 1339 * @exception JSONException If the value is or contains an invalid number. 1340 */ 1341 static String valueToString(Object value) throws JSONException { 1342 if (value == null || value.equals(null)) { 1343 return "null"; 1344 } 1345 if (value instanceof JSONString) { 1346 Object o; 1347 try { 1348 o = ((JSONString) value).toJSONString(); 1349 } catch (Exception e) { 1350 throw new JSONException(e); 1351 } 1352 if (o instanceof String) { 1353 return (String) o; 1354 } 1355 throw new JSONException("Bad value from toJSONString: " + o); 1356 } 1357 if (value instanceof Number) { 1358 return numberToString((Number) value); 1359 } 1360 if (value instanceof Boolean || value instanceof JSONObject 1361 || value instanceof JSONArray) { 1362 return value.toString(); 1363 } 1364 if (value instanceof Map) { 1365 return new JSONObject((Map) value).toString(); 1366 } 1367 if (value instanceof Collection) { 1368 return new JSONArray((Collection) value).toString(); 1369 } 1370 if (value.getClass().isArray()) { 1371 return new JSONArray(value).toString(); 1372 } 1373 return quote(value.toString()); 1374 } 1375 1376 /** 1377 * Make a prettyprinted JSON text of an object value. 1378 * <p> 1379 * Warning: This method assumes that the data structure is acyclical. 1380 * @param value The value to be serialized. 1381 * @param indentFactor The number of spaces to add to each level of 1382 * indentation. 1383 * @param indent The indentation of the top level. 1384 * @return a printable, displayable, transmittable 1385 * representation of the object, beginning 1386 * with <code>{</code> <small>(left brace)</small> and ending 1387 * with <code>}</code> <small>(right brace)</small>. 1388 * @exception JSONException If the object contains an invalid number. 1389 */ 1390 static String valueToString(Object value, int indentFactor, int indent) 1391 throws JSONException { 1392 if (value == null || value.equals(null)) { 1393 return "null"; 1394 } 1395 try { 1396 if (value instanceof JSONString) { 1397 Object o = ((JSONString) value).toJSONString(); 1398 if (o instanceof String) { 1399 return (String) o; 1400 } 1401 } 1402 } catch (Exception ignore) { 1403 } 1404 if (value instanceof Number) { 1405 return numberToString((Number) value); 1406 } 1407 if (value instanceof Boolean) { 1408 return value.toString(); 1409 } 1410 if (value instanceof JSONObject) { 1411 return ((JSONObject) value).toString(indentFactor, indent); 1412 } 1413 if (value instanceof JSONArray) { 1414 return ((JSONArray) value).toString(indentFactor, indent); 1415 } 1416 if (value instanceof Map) { 1417 return new JSONObject((Map) value).toString(indentFactor, indent); 1418 } 1419 if (value instanceof Collection) { 1420 return new JSONArray((Collection) value).toString(indentFactor, 1421 indent); 1422 } 1423 if (value.getClass().isArray()) { 1424 return new JSONArray(value).toString(indentFactor, indent); 1425 } 1426 return quote(value.toString()); 1427 } 1428 1429 /** 1430 * Wrap an object, if necessary. If the object is null, return the NULL 1431 * object. If it is an array or collection, wrap it in a JSONArray. If 1432 * it is a map, wrap it in a JSONObject. If it is a standard property 1433 * (Double, String, et al) then it is already wrapped. Otherwise, if it 1434 * comes from one of the java packages, turn it into a string. And if 1435 * it doesn't, try to wrap it in a JSONObject. If the wrapping fails, 1436 * then null is returned. 1437 * 1438 * @param object The object to wrap 1439 * @return The wrapped value 1440 */ 1441 static Object wrap(Object object) { 1442 try { 1443 if (object == null) { 1444 return NULL; 1445 } 1446 if (object instanceof JSONObject || object instanceof JSONArray 1447 || NULL.equals(object) || object instanceof JSONString 1448 || object instanceof Byte || object instanceof Character 1449 || object instanceof Short || object instanceof Integer 1450 || object instanceof Long || object instanceof Boolean 1451 || object instanceof Float || object instanceof Double 1452 || object instanceof String) { 1453 return object; 1454 } 1455 1456 if (object instanceof Collection) { 1457 return new JSONArray((Collection) object); 1458 } 1459 if (object.getClass().isArray()) { 1460 return new JSONArray(object); 1461 } 1462 if (object instanceof Map) { 1463 return new JSONObject((Map) object); 1464 } 1465 Package objectPackage = object.getClass().getPackage(); 1466 String objectPackageName = objectPackage != null 1467 ? objectPackage.getName() 1468 : ""; 1469 if (objectPackageName.startsWith("java.") 1470 || objectPackageName.startsWith("javax.") 1471 || object.getClass().getClassLoader() == null) { 1472 return object.toString(); 1473 } 1474 return new JSONObject(object); 1475 } catch (Exception exception) { 1476 return null; 1477 } 1478 } 1479 1480 /** 1481 * Write the contents of the JSONObject as JSON text to a writer. 1482 * For compactness, no whitespace is added. 1483 * <p> 1484 * Warning: This method assumes that the data structure is acyclical. 1485 * 1486 * @return The writer. 1487 * @exception JSONException 1488 */ 1489 public Writer write(Writer writer) throws JSONException { 1490 try { 1491 boolean b = false; 1492 Iterator keys = keys(); 1493 writer.write('{'); 1494 1495 while (keys.hasNext()) { 1496 if (b) { 1497 writer.write(','); 1498 } 1499 Object k = keys.next(); 1500 writer.write(quote(k.toString())); 1501 writer.write(':'); 1502 Object v = this.map.get(k); 1503 if (v instanceof JSONObject) { 1504 ((JSONObject) v).write(writer); 1505 } else if (v instanceof JSONArray) { 1506 ((JSONArray) v).write(writer); 1507 } else { 1508 writer.write(valueToString(v)); 1509 } 1510 b = true; 1511 } 1512 writer.write('}'); 1513 return writer; 1514 } catch (IOException exception) { 1515 throw new JSONException(exception); 1516 } 1517 } 1518}