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