001package org.json; 002 003/* 004 Copyright (c) 2002 JSON.org 005 006 Permission is hereby granted, free of charge, to any person obtaining a copy 007 of this software and associated documentation files (the "Software"), to deal 008 in the Software without restriction, including without limitation the rights 009 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 010 copies of the Software, and to permit persons to whom the Software is 011 furnished to do so, subject to the following conditions: 012 013 The above copyright notice and this permission notice shall be included in all 014 copies or substantial portions of the Software. 015 016 The Software shall be used for Good, not Evil. 017 018 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 019 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 020 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 021 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 022 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 023 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 024 SOFTWARE. 025 */ 026 027import java.io.IOException; 028import java.io.StringWriter; 029import java.io.Writer; 030import java.lang.reflect.Array; 031import java.math.BigDecimal; 032import java.math.BigInteger; 033import java.util.*; 034 035/** 036 * A JSONArray is an ordered sequence of values. Its external text form is a 037 * string wrapped in square brackets with commas separating the values. The 038 * internal form is an object having <code>get</code> and <code>opt</code> 039 * methods for accessing the values by index, and <code>put</code> methods for 040 * adding or replacing values. The values can be any of these types: 041 * <code>Boolean</code>, <code>JSONArray</code>, <code>JSONObject</code>, 042 * <code>Number</code>, <code>String</code>, or the 043 * <code>JSONObject.NULL object</code>. 044 * <p> 045 * The constructor can convert a JSON text into a Java object. The 046 * <code>toString</code> method converts to JSON text. 047 * <p> 048 * A <code>get</code> method returns a value if one can be found, and throws an 049 * exception if one cannot be found. An <code>opt</code> method returns a 050 * default value instead of throwing an exception, and so is useful for 051 * obtaining optional values. 052 * <p> 053 * The generic <code>get()</code> and <code>opt()</code> methods return an 054 * object which you can cast or query for type. There are also typed 055 * <code>get</code> and <code>opt</code> methods that do type checking and type 056 * coercion for you. 057 * <p> 058 * The texts produced by the <code>toString</code> methods strictly conform to 059 * JSON syntax rules. The constructors are more forgiving in the texts they will 060 * accept: 061 * <ul> 062 * <li>An extra <code>,</code> <small>(comma)</small> may appear just 063 * before the closing bracket.</li> 064 * <li>The <code>null</code> value will be inserted when there is <code>,</code> 065 * <small>(comma)</small> elision.</li> 066 * <li>Strings may be quoted with <code>'</code> <small>(single 067 * quote)</small>.</li> 068 * <li>Strings do not need to be quoted at all if they do not begin with a quote 069 * or single quote, and if they do not contain leading or trailing spaces, and 070 * if they do not contain any of these characters: 071 * <code>{ } [ ] / \ : , #</code> and if they do not look like numbers and 072 * if they are not the reserved words <code>true</code>, <code>false</code>, or 073 * <code>null</code>.</li> 074 * </ul> 075 * 076 * @author JSON.org 077 * @version 2016-03-05 078 */ 079public class JSONArray implements Iterable<Object> { 080 081 /** 082 * The arrayList where the JSONArray's properties are kept. 083 */ 084 private final ArrayList<Object> myArrayList; 085 086 /** 087 * Construct an empty JSONArray. 088 */ 089 public JSONArray() { 090 this.myArrayList = new ArrayList<Object>(); 091 } 092 093 /** 094 * Construct a JSONArray from a JSONTokener. 095 * 096 * @param x 097 * A JSONTokener 098 * @throws JSONException 099 * If there is a syntax error. 100 */ 101 public JSONArray(JSONTokener x) throws JSONException { 102 this(); 103 if (x.nextClean() != '[') { 104 throw x.syntaxError("A JSONArray text must start with '['"); 105 } 106 if (x.nextClean() != ']') { 107 x.back(); 108 for (;;) { 109 if (x.nextClean() == ',') { 110 x.back(); 111 this.myArrayList.add(JSONObject.NULL); 112 } else { 113 x.back(); 114 this.myArrayList.add(x.nextValue()); 115 } 116 switch (x.nextClean()) { 117 case ',': 118 if (x.nextClean() == ']') { 119 return; 120 } 121 x.back(); 122 break; 123 case ']': 124 return; 125 default: 126 throw x.syntaxError("Expected a ',' or ']'"); 127 } 128 } 129 } 130 } 131 132 /** 133 * Construct a JSONArray from a source JSON text. 134 * 135 * @param source 136 * A string that begins with <code>[</code> <small>(left 137 * bracket)</small> and ends with <code>]</code> 138 * <small>(right bracket)</small>. 139 * @throws JSONException 140 * If there is a syntax error. 141 */ 142 public JSONArray(String source) throws JSONException { 143 this(new JSONTokener(source)); 144 } 145 146 /** 147 * Construct a JSONArray from a Collection. 148 * 149 * @param collection 150 * A Collection. 151 */ 152 public JSONArray(Collection<?> collection) { 153 this.myArrayList = new ArrayList<Object>(); 154 if (collection != null) { 155 for (Object o: collection){ 156 this.myArrayList.add(JSONObject.wrap(o)); 157 } 158 } 159 } 160 161 /** 162 * Construct a JSONArray from an array 163 * 164 * @throws JSONException 165 * If not an array. 166 */ 167 public JSONArray(Object array) throws JSONException { 168 this(); 169 if (array.getClass().isArray()) { 170 int length = Array.getLength(array); 171 for (int i = 0; i < length; i += 1) { 172 this.put(JSONObject.wrap(Array.get(array, i))); 173 } 174 } else { 175 throw new JSONException( 176 "JSONArray initial value should be a string or collection or array."); 177 } 178 } 179 180 @Override 181 public Iterator<Object> iterator() { 182 return myArrayList.iterator(); 183 } 184 185 /** 186 * Get the object value associated with an index. 187 * 188 * @param index 189 * The index must be between 0 and length() - 1. 190 * @return An object value. 191 * @throws JSONException 192 * If there is no value for the index. 193 */ 194 public Object get(int index) throws JSONException { 195 Object object = this.opt(index); 196 if (object == null) { 197 throw new JSONException("JSONArray[" + index + "] not found."); 198 } 199 return object; 200 } 201 202 /** 203 * Get the boolean value associated with an index. The string values "true" 204 * and "false" are converted to boolean. 205 * 206 * @param index 207 * The index must be between 0 and length() - 1. 208 * @return The truth. 209 * @throws JSONException 210 * If there is no value for the index or if the value is not 211 * convertible to boolean. 212 */ 213 public boolean getBoolean(int index) throws JSONException { 214 Object object = this.get(index); 215 if (object.equals(Boolean.FALSE) 216 || (object instanceof String && ((String) object) 217 .equalsIgnoreCase("false"))) { 218 return false; 219 } else if (object.equals(Boolean.TRUE) 220 || (object instanceof String && ((String) object) 221 .equalsIgnoreCase("true"))) { 222 return true; 223 } 224 throw new JSONException("JSONArray[" + index + "] is not a boolean."); 225 } 226 227 /** 228 * Get the double value associated with an index. 229 * 230 * @param index 231 * The index must be between 0 and length() - 1. 232 * @return The value. 233 * @throws JSONException 234 * If the key is not found or if the value cannot be converted 235 * to a number. 236 */ 237 public double getDouble(int index) throws JSONException { 238 Object object = this.get(index); 239 try { 240 return object instanceof Number ? ((Number) object).doubleValue() 241 : Double.parseDouble((String) object); 242 } catch (Exception e) { 243 throw new JSONException("JSONArray[" + index + "] is not a number."); 244 } 245 } 246 247 /** 248 * Get the enum value associated with an index. 249 * 250 * @param clazz 251 * The type of enum to retrieve. 252 * @param index 253 * The index must be between 0 and length() - 1. 254 * @return The enum value at the index location 255 * @throws JSONException 256 * if the key is not found or if the value cannot be converted 257 * to an enum. 258 */ 259 public <E extends Enum<E>> E getEnum(Class<E> clazz, int index) throws JSONException { 260 E val = optEnum(clazz, index); 261 if(val==null) { 262 // JSONException should really take a throwable argument. 263 // If it did, I would re-implement this with the Enum.valueOf 264 // method and place any thrown exception in the JSONException 265 throw new JSONException("JSONObject[" + JSONObject.quote(Integer.toString(index)) 266 + "] is not an enum of type " + JSONObject.quote(clazz.getSimpleName()) 267 + "."); 268 } 269 return val; 270 } 271 272 /** 273 * Get the BigDecimal value associated with an index. 274 * 275 * @param index 276 * The index must be between 0 and length() - 1. 277 * @return The value. 278 * @throws JSONException 279 * If the key is not found or if the value cannot be converted 280 * to a BigDecimal. 281 */ 282 public BigDecimal getBigDecimal (int index) throws JSONException { 283 Object object = this.get(index); 284 try { 285 return new BigDecimal(object.toString()); 286 } catch (Exception e) { 287 throw new JSONException("JSONArray[" + index + 288 "] could not convert to BigDecimal."); 289 } 290 } 291 292 /** 293 * Get the BigInteger value associated with an index. 294 * 295 * @param index 296 * The index must be between 0 and length() - 1. 297 * @return The value. 298 * @throws JSONException 299 * If the key is not found or if the value cannot be converted 300 * to a BigInteger. 301 */ 302 public BigInteger getBigInteger (int index) throws JSONException { 303 Object object = this.get(index); 304 try { 305 return new BigInteger(object.toString()); 306 } catch (Exception e) { 307 throw new JSONException("JSONArray[" + index + 308 "] could not convert to BigInteger."); 309 } 310 } 311 312 /** 313 * Get the int value associated with an index. 314 * 315 * @param index 316 * The index must be between 0 and length() - 1. 317 * @return The value. 318 * @throws JSONException 319 * If the key is not found or if the value is not a number. 320 */ 321 public int getInt(int index) throws JSONException { 322 Object object = this.get(index); 323 try { 324 return object instanceof Number ? ((Number) object).intValue() 325 : Integer.parseInt((String) object); 326 } catch (Exception e) { 327 throw new JSONException("JSONArray[" + index + "] is not a number."); 328 } 329 } 330 331 /** 332 * Get the JSONArray associated with an index. 333 * 334 * @param index 335 * The index must be between 0 and length() - 1. 336 * @return A JSONArray value. 337 * @throws JSONException 338 * If there is no value for the index. or if the value is not a 339 * JSONArray 340 */ 341 public JSONArray getJSONArray(int index) throws JSONException { 342 Object object = this.get(index); 343 if (object instanceof JSONArray) { 344 return (JSONArray) object; 345 } 346 throw new JSONException("JSONArray[" + index + "] is not a JSONArray."); 347 } 348 349 /** 350 * Get the JSONObject associated with an index. 351 * 352 * @param index 353 * subscript 354 * @return A JSONObject value. 355 * @throws JSONException 356 * If there is no value for the index or if the value is not a 357 * JSONObject 358 */ 359 public JSONObject getJSONObject(int index) throws JSONException { 360 Object object = this.get(index); 361 if (object instanceof JSONObject) { 362 return (JSONObject) object; 363 } 364 throw new JSONException("JSONArray[" + index + "] is not a JSONObject."); 365 } 366 367 /** 368 * Get the long value associated with an index. 369 * 370 * @param index 371 * The index must be between 0 and length() - 1. 372 * @return The value. 373 * @throws JSONException 374 * If the key is not found or if the value cannot be converted 375 * to a number. 376 */ 377 public long getLong(int index) throws JSONException { 378 Object object = this.get(index); 379 try { 380 return object instanceof Number ? ((Number) object).longValue() 381 : Long.parseLong((String) object); 382 } catch (Exception e) { 383 throw new JSONException("JSONArray[" + index + "] is not a number."); 384 } 385 } 386 387 /** 388 * Get the string associated with an index. 389 * 390 * @param index 391 * The index must be between 0 and length() - 1. 392 * @return A string value. 393 * @throws JSONException 394 * If there is no string value for the index. 395 */ 396 public String getString(int index) throws JSONException { 397 Object object = this.get(index); 398 if (object instanceof String) { 399 return (String) object; 400 } 401 throw new JSONException("JSONArray[" + index + "] not a string."); 402 } 403 404 /** 405 * Determine if the value is null. 406 * 407 * @param index 408 * The index must be between 0 and length() - 1. 409 * @return true if the value at the index is null, or if there is no value. 410 */ 411 public boolean isNull(int index) { 412 return JSONObject.NULL.equals(this.opt(index)); 413 } 414 415 /** 416 * Make a string from the contents of this JSONArray. The 417 * <code>separator</code> string is inserted between each element. Warning: 418 * This method assumes that the data structure is acyclical. 419 * 420 * @param separator 421 * A string that will be inserted between the elements. 422 * @return a string. 423 * @throws JSONException 424 * If the array contains an invalid number. 425 */ 426 public String join(String separator) throws JSONException { 427 int len = this.length(); 428 StringBuilder sb = new StringBuilder(); 429 430 for (int i = 0; i < len; i += 1) { 431 if (i > 0) { 432 sb.append(separator); 433 } 434 sb.append(JSONObject.valueToString(this.myArrayList.get(i))); 435 } 436 return sb.toString(); 437 } 438 439 /** 440 * Get the number of elements in the JSONArray, included nulls. 441 * 442 * @return The length (or size). 443 */ 444 public int length() { 445 return this.myArrayList.size(); 446 } 447 448 /** 449 * Get the optional object value associated with an index. 450 * 451 * @param index 452 * The index must be between 0 and length() - 1. 453 * @return An object value, or null if there is no object at that index. 454 */ 455 public Object opt(int index) { 456 return (index < 0 || index >= this.length()) ? null : this.myArrayList 457 .get(index); 458 } 459 460 /** 461 * Get the optional boolean value associated with an index. It returns false 462 * if there is no value at that index, or if the value is not Boolean.TRUE 463 * or the String "true". 464 * 465 * @param index 466 * The index must be between 0 and length() - 1. 467 * @return The truth. 468 */ 469 public boolean optBoolean(int index) { 470 return this.optBoolean(index, false); 471 } 472 473 /** 474 * Get the optional boolean value associated with an index. It returns the 475 * defaultValue if there is no value at that index or if it is not a Boolean 476 * or the String "true" or "false" (case insensitive). 477 * 478 * @param index 479 * The index must be between 0 and length() - 1. 480 * @param defaultValue 481 * A boolean default. 482 * @return The truth. 483 */ 484 public boolean optBoolean(int index, boolean defaultValue) { 485 try { 486 return this.getBoolean(index); 487 } catch (Exception e) { 488 return defaultValue; 489 } 490 } 491 492 /** 493 * Get the optional double value associated with an index. NaN is returned 494 * if there is no value for the index, or if the value is not a number and 495 * cannot be converted to a number. 496 * 497 * @param index 498 * The index must be between 0 and length() - 1. 499 * @return The value. 500 */ 501 public double optDouble(int index) { 502 return this.optDouble(index, Double.NaN); 503 } 504 505 /** 506 * Get the optional double value associated with an index. The defaultValue 507 * is returned if there is no value for the index, or if the value is not a 508 * number and cannot be converted to a number. 509 * 510 * @param index 511 * subscript 512 * @param defaultValue 513 * The default value. 514 * @return The value. 515 */ 516 public double optDouble(int index, double defaultValue) { 517 try { 518 return this.getDouble(index); 519 } catch (Exception e) { 520 return defaultValue; 521 } 522 } 523 524 /** 525 * Get the optional int value associated with an index. Zero is returned if 526 * there is no value for the index, or if the value is not a number and 527 * cannot be converted to a number. 528 * 529 * @param index 530 * The index must be between 0 and length() - 1. 531 * @return The value. 532 */ 533 public int optInt(int index) { 534 return this.optInt(index, 0); 535 } 536 537 /** 538 * Get the optional int value associated with an index. The defaultValue is 539 * returned if there is no value for the index, or if the value is not a 540 * number and cannot be converted to a number. 541 * 542 * @param index 543 * The index must be between 0 and length() - 1. 544 * @param defaultValue 545 * The default value. 546 * @return The value. 547 */ 548 public int optInt(int index, int defaultValue) { 549 try { 550 return this.getInt(index); 551 } catch (Exception e) { 552 return defaultValue; 553 } 554 } 555 556 /** 557 * Get the enum value associated with a key. 558 * 559 * @param clazz 560 * The type of enum to retrieve. 561 * @param index 562 * The index must be between 0 and length() - 1. 563 * @return The enum value at the index location or null if not found 564 */ 565 public <E extends Enum<E>> E optEnum(Class<E> clazz, int index) { 566 return this.optEnum(clazz, index, null); 567 } 568 569 /** 570 * Get the enum value associated with a key. 571 * 572 * @param clazz 573 * The type of enum to retrieve. 574 * @param index 575 * The index must be between 0 and length() - 1. 576 * @param defaultValue 577 * The default in case the value is not found 578 * @return The enum value at the index location or defaultValue if 579 * the value is not found or cannot be assigned to clazz 580 */ 581 public <E extends Enum<E>> E optEnum(Class<E> clazz, int index, E defaultValue) { 582 try { 583 Object val = this.opt(index); 584 if (JSONObject.NULL.equals(val)) { 585 return defaultValue; 586 } 587 if (clazz.isAssignableFrom(val.getClass())) { 588 // we just checked it! 589 @SuppressWarnings("unchecked") 590 E myE = (E) val; 591 return myE; 592 } 593 return Enum.valueOf(clazz, val.toString()); 594 } catch (IllegalArgumentException e) { 595 return defaultValue; 596 } catch (NullPointerException e) { 597 return defaultValue; 598 } 599 } 600 601 602 /** 603 * Get the optional BigInteger value associated with an index. The 604 * defaultValue is returned if there is no value for the index, or if the 605 * value is not a number and cannot be converted to a number. 606 * 607 * @param index 608 * The index must be between 0 and length() - 1. 609 * @param defaultValue 610 * The default value. 611 * @return The value. 612 */ 613 public BigInteger optBigInteger(int index, BigInteger defaultValue) { 614 try { 615 return this.getBigInteger(index); 616 } catch (Exception e) { 617 return defaultValue; 618 } 619 } 620 621 /** 622 * Get the optional BigDecimal value associated with an index. The 623 * defaultValue is returned if there is no value for the index, or if the 624 * value is not a number and cannot be converted to a number. 625 * 626 * @param index 627 * The index must be between 0 and length() - 1. 628 * @param defaultValue 629 * The default value. 630 * @return The value. 631 */ 632 public BigDecimal optBigDecimal(int index, BigDecimal defaultValue) { 633 try { 634 return this.getBigDecimal(index); 635 } catch (Exception e) { 636 return defaultValue; 637 } 638 } 639 640 /** 641 * Get the optional JSONArray associated with an index. 642 * 643 * @param index 644 * subscript 645 * @return A JSONArray value, or null if the index has no value, or if the 646 * value is not a JSONArray. 647 */ 648 public JSONArray optJSONArray(int index) { 649 Object o = this.opt(index); 650 return o instanceof JSONArray ? (JSONArray) o : null; 651 } 652 653 /** 654 * Get the optional JSONObject associated with an index. Null is returned if 655 * the key is not found, or null if the index has no value, or if the value 656 * is not a JSONObject. 657 * 658 * @param index 659 * The index must be between 0 and length() - 1. 660 * @return A JSONObject value. 661 */ 662 public JSONObject optJSONObject(int index) { 663 Object o = this.opt(index); 664 return o instanceof JSONObject ? (JSONObject) o : null; 665 } 666 667 /** 668 * Get the optional long value associated with an index. Zero is returned if 669 * there is no value for the index, or if the value is not a number and 670 * cannot be converted to a number. 671 * 672 * @param index 673 * The index must be between 0 and length() - 1. 674 * @return The value. 675 */ 676 public long optLong(int index) { 677 return this.optLong(index, 0); 678 } 679 680 /** 681 * Get the optional long value associated with an index. The defaultValue is 682 * returned if there is no value for the index, or if the value is not a 683 * number and cannot be converted to a number. 684 * 685 * @param index 686 * The index must be between 0 and length() - 1. 687 * @param defaultValue 688 * The default value. 689 * @return The value. 690 */ 691 public long optLong(int index, long defaultValue) { 692 try { 693 return this.getLong(index); 694 } catch (Exception e) { 695 return defaultValue; 696 } 697 } 698 699 /** 700 * Get the optional string value associated with an index. It returns an 701 * empty string if there is no value at that index. If the value is not a 702 * string and is not null, then it is coverted to a string. 703 * 704 * @param index 705 * The index must be between 0 and length() - 1. 706 * @return A String value. 707 */ 708 public String optString(int index) { 709 return this.optString(index, ""); 710 } 711 712 /** 713 * Get the optional string associated with an index. The defaultValue is 714 * returned if the key is not found. 715 * 716 * @param index 717 * The index must be between 0 and length() - 1. 718 * @param defaultValue 719 * The default value. 720 * @return A String value. 721 */ 722 public String optString(int index, String defaultValue) { 723 Object object = this.opt(index); 724 return JSONObject.NULL.equals(object) ? defaultValue : object 725 .toString(); 726 } 727 728 /** 729 * Append a boolean value. This increases the array's length by one. 730 * 731 * @param value 732 * A boolean value. 733 * @return this. 734 */ 735 public JSONArray put(boolean value) { 736 this.put(value ? Boolean.TRUE : Boolean.FALSE); 737 return this; 738 } 739 740 /** 741 * Put a value in the JSONArray, where the value will be a JSONArray which 742 * is produced from a Collection. 743 * 744 * @param value 745 * A Collection value. 746 * @return this. 747 */ 748 public JSONArray put(Collection<?> value) { 749 this.put(new JSONArray(value)); 750 return this; 751 } 752 753 /** 754 * Append a double value. This increases the array's length by one. 755 * 756 * @param value 757 * A double value. 758 * @throws JSONException 759 * if the value is not finite. 760 * @return this. 761 */ 762 public JSONArray put(double value) throws JSONException { 763 Double d = new Double(value); 764 JSONObject.testValidity(d); 765 this.put(d); 766 return this; 767 } 768 769 /** 770 * Append an int value. This increases the array's length by one. 771 * 772 * @param value 773 * An int value. 774 * @return this. 775 */ 776 public JSONArray put(int value) { 777 this.put(new Integer(value)); 778 return this; 779 } 780 781 /** 782 * Append an long value. This increases the array's length by one. 783 * 784 * @param value 785 * A long value. 786 * @return this. 787 */ 788 public JSONArray put(long value) { 789 this.put(new Long(value)); 790 return this; 791 } 792 793 /** 794 * Put a value in the JSONArray, where the value will be a JSONObject which 795 * is produced from a Map. 796 * 797 * @param value 798 * A Map value. 799 * @return this. 800 */ 801 public JSONArray put(Map<?, ?> value) { 802 this.put(new JSONObject(value)); 803 return this; 804 } 805 806 /** 807 * Append an object value. This increases the array's length by one. 808 * 809 * @param value 810 * An object value. The value should be a Boolean, Double, 811 * Integer, JSONArray, JSONObject, Long, or String, or the 812 * JSONObject.NULL object. 813 * @return this. 814 */ 815 public JSONArray put(Object value) { 816 this.myArrayList.add(value); 817 return this; 818 } 819 820 /** 821 * Put or replace a boolean value in the JSONArray. If the index is greater 822 * than the length of the JSONArray, then null elements will be added as 823 * necessary to pad it out. 824 * 825 * @param index 826 * The subscript. 827 * @param value 828 * A boolean value. 829 * @return this. 830 * @throws JSONException 831 * If the index is negative. 832 */ 833 public JSONArray put(int index, boolean value) throws JSONException { 834 this.put(index, value ? Boolean.TRUE : Boolean.FALSE); 835 return this; 836 } 837 838 /** 839 * Put a value in the JSONArray, where the value will be a JSONArray which 840 * is produced from a Collection. 841 * 842 * @param index 843 * The subscript. 844 * @param value 845 * A Collection value. 846 * @return this. 847 * @throws JSONException 848 * If the index is negative or if the value is not finite. 849 */ 850 public JSONArray put(int index, Collection<?> value) throws JSONException { 851 this.put(index, new JSONArray(value)); 852 return this; 853 } 854 855 /** 856 * Put or replace a double value. If the index is greater than the length of 857 * the JSONArray, then null elements will be added as necessary to pad it 858 * out. 859 * 860 * @param index 861 * The subscript. 862 * @param value 863 * A double value. 864 * @return this. 865 * @throws JSONException 866 * If the index is negative or if the value is not finite. 867 */ 868 public JSONArray put(int index, double value) throws JSONException { 869 this.put(index, new Double(value)); 870 return this; 871 } 872 873 /** 874 * Put or replace an int value. If the index is greater than the length of 875 * the JSONArray, then null elements will be added as necessary to pad it 876 * out. 877 * 878 * @param index 879 * The subscript. 880 * @param value 881 * An int value. 882 * @return this. 883 * @throws JSONException 884 * If the index is negative. 885 */ 886 public JSONArray put(int index, int value) throws JSONException { 887 this.put(index, new Integer(value)); 888 return this; 889 } 890 891 /** 892 * Put or replace a long value. If the index is greater than the length of 893 * the JSONArray, then null elements will be added as necessary to pad it 894 * out. 895 * 896 * @param index 897 * The subscript. 898 * @param value 899 * A long value. 900 * @return this. 901 * @throws JSONException 902 * If the index is negative. 903 */ 904 public JSONArray put(int index, long value) throws JSONException { 905 this.put(index, new Long(value)); 906 return this; 907 } 908 909 /** 910 * Put a value in the JSONArray, where the value will be a JSONObject that 911 * is produced from a Map. 912 * 913 * @param index 914 * The subscript. 915 * @param value 916 * The Map value. 917 * @return this. 918 * @throws JSONException 919 * If the index is negative or if the the value is an invalid 920 * number. 921 */ 922 public JSONArray put(int index, Map<?, ?> value) throws JSONException { 923 this.put(index, new JSONObject(value)); 924 return this; 925 } 926 927 /** 928 * Put or replace an object value in the JSONArray. If the index is greater 929 * than the length of the JSONArray, then null elements will be added as 930 * necessary to pad it out. 931 * 932 * @param index 933 * The subscript. 934 * @param value 935 * The value to put into the array. The value should be a 936 * Boolean, Double, Integer, JSONArray, JSONObject, Long, or 937 * String, or the JSONObject.NULL object. 938 * @return this. 939 * @throws JSONException 940 * If the index is negative or if the the value is an invalid 941 * number. 942 */ 943 public JSONArray put(int index, Object value) throws JSONException { 944 JSONObject.testValidity(value); 945 if (index < 0) { 946 throw new JSONException("JSONArray[" + index + "] not found."); 947 } 948 if (index < this.length()) { 949 this.myArrayList.set(index, value); 950 } else { 951 while (index != this.length()) { 952 this.put(JSONObject.NULL); 953 } 954 this.put(value); 955 } 956 return this; 957 } 958 959 /** 960 * Remove an index and close the hole. 961 * 962 * @param index 963 * The index of the element to be removed. 964 * @return The value that was associated with the index, or null if there 965 * was no value. 966 */ 967 public Object remove(int index) { 968 return index >= 0 && index < this.length() 969 ? this.myArrayList.remove(index) 970 : null; 971 } 972 973 /** 974 * Determine if two JSONArrays are similar. 975 * They must contain similar sequences. 976 * 977 * @param other The other JSONArray 978 * @return true if they are equal 979 */ 980 public boolean similar(Object other) { 981 if (!(other instanceof JSONArray)) { 982 return false; 983 } 984 int len = this.length(); 985 if (len != ((JSONArray)other).length()) { 986 return false; 987 } 988 for (int i = 0; i < len; i += 1) { 989 Object valueThis = this.get(i); 990 Object valueOther = ((JSONArray)other).get(i); 991 if (valueThis instanceof JSONObject) { 992 if (!((JSONObject)valueThis).similar(valueOther)) { 993 return false; 994 } 995 } else if (valueThis instanceof JSONArray) { 996 if (!((JSONArray)valueThis).similar(valueOther)) { 997 return false; 998 } 999 } else if (!valueThis.equals(valueOther)) { 1000 return false; 1001 } 1002 } 1003 return true; 1004 } 1005 1006 /** 1007 * Produce a JSONObject by combining a JSONArray of names with the values of 1008 * this JSONArray. 1009 * 1010 * @param names 1011 * A JSONArray containing a list of key strings. These will be 1012 * paired with the values. 1013 * @return A JSONObject, or null if there are no names or if this JSONArray 1014 * has no values. 1015 * @throws JSONException 1016 * If any of the names are null. 1017 */ 1018 public JSONObject toJSONObject(JSONArray names) throws JSONException { 1019 if (names == null || names.length() == 0 || this.length() == 0) { 1020 return null; 1021 } 1022 JSONObject jo = new JSONObject(); 1023 for (int i = 0; i < names.length(); i += 1) { 1024 jo.put(names.getString(i), this.opt(i)); 1025 } 1026 return jo; 1027 } 1028 1029 /** 1030 * Make a JSON text of this JSONArray. For compactness, no unnecessary 1031 * whitespace is added. If it is not possible to produce a syntactically 1032 * correct JSON text then null will be returned instead. This could occur if 1033 * the array contains an invalid number. 1034 * <p> 1035 * Warning: This method assumes that the data structure is acyclical. 1036 * 1037 * @return a printable, displayable, transmittable representation of the 1038 * array. 1039 */ 1040 public String toString() { 1041 try { 1042 return this.toString(0); 1043 } catch (Exception e) { 1044 return null; 1045 } 1046 } 1047 1048 /** 1049 * Make a prettyprinted JSON text of this JSONArray. Warning: This method 1050 * assumes that the data structure is acyclical. 1051 * 1052 * @param indentFactor 1053 * The number of spaces to add to each level of indentation. 1054 * @return a printable, displayable, transmittable representation of the 1055 * object, beginning with <code>[</code> <small>(left 1056 * bracket)</small> and ending with <code>]</code> 1057 * <small>(right bracket)</small>. 1058 * @throws JSONException 1059 */ 1060 public String toString(int indentFactor) throws JSONException { 1061 StringWriter sw = new StringWriter(); 1062 synchronized (sw.getBuffer()) { 1063 return this.write(sw, indentFactor, 0).toString(); 1064 } 1065 } 1066 1067 /** 1068 * Write the contents of the JSONArray as JSON text to a writer. For 1069 * compactness, no whitespace is added. 1070 * <p> 1071 * Warning: This method assumes that the data structure is acyclical. 1072 * 1073 * @return The writer. 1074 * @throws JSONException 1075 */ 1076 public Writer write(Writer writer) throws JSONException { 1077 return this.write(writer, 0, 0); 1078 } 1079 1080 /** 1081 * Write the contents of the JSONArray as JSON text to a writer. For 1082 * compactness, no whitespace is added. 1083 * <p> 1084 * Warning: This method assumes that the data structure is acyclical. 1085 * 1086 * @param writer 1087 * Writes the serialized JSON 1088 * @param indentFactor 1089 * The number of spaces to add to each level of indentation. 1090 * @param indent 1091 * The indention of the top level. 1092 * @return The writer. 1093 * @throws JSONException 1094 */ 1095 public Writer write(Writer writer, int indentFactor, int indent) 1096 throws JSONException { 1097 try { 1098 boolean commanate = false; 1099 int length = this.length(); 1100 writer.write('['); 1101 1102 if (length == 1) { 1103 JSONObject.writeValue(writer, this.myArrayList.get(0), 1104 indentFactor, indent); 1105 } else if (length != 0) { 1106 final int newindent = indent + indentFactor; 1107 1108 for (int i = 0; i < length; i += 1) { 1109 if (commanate) { 1110 writer.write(','); 1111 } 1112 if (indentFactor > 0) { 1113 writer.write('\n'); 1114 } 1115 JSONObject.indent(writer, newindent); 1116 JSONObject.writeValue(writer, this.myArrayList.get(i), 1117 indentFactor, newindent); 1118 commanate = true; 1119 } 1120 if (indentFactor > 0) { 1121 writer.write('\n'); 1122 } 1123 JSONObject.indent(writer, indent); 1124 } 1125 writer.write(']'); 1126 return writer; 1127 } catch (IOException e) { 1128 throw new JSONException(e); 1129 } 1130 } 1131 1132 /** 1133 * Returns a java.util.List containing all of the elements in this array. 1134 * If an element in the array is a JSONArray or JSONObject it will also 1135 * be converted. 1136 * <p> 1137 * Warning: This method assumes that the data structure is acyclical. 1138 * 1139 * @return a java.util.List containing the elements of this array 1140 */ 1141 public List<Object> toList() { 1142 List<Object> results = new ArrayList<Object>(this.myArrayList.size()); 1143 for (Object element : this.myArrayList) { 1144 if (element == null || JSONObject.NULL.equals(element)) { 1145 results.add(null); 1146 } else if (element instanceof JSONArray) { 1147 results.add(((JSONArray) element).toList()); 1148 } else if (element instanceof JSONObject) { 1149 results.add(((JSONObject) element).toMap()); 1150 } else { 1151 results.add(element); 1152 } 1153 } 1154 return results; 1155 } 1156}