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