View Javadoc

1   /*
2    * $Id: JSONArray.java,v 1.1 2007/10/22 16:23:08 oeuillot Exp $
3    */
4   package org.rcfaces.core.internal.util.json;
5   
6   /*
7    * Copyright (c) 2002 JSON.org
8    * 
9    * Permission is hereby granted, free of charge, to any person obtaining a copy
10   * of this software and associated documentation files (the "Software"), to deal
11   * in the Software without restriction, including without limitation the rights
12   * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13   * copies of the Software, and to permit persons to whom the Software is
14   * furnished to do so, subject to the following conditions:
15   * 
16   * The above copyright notice and this permission notice shall be included in
17   * all copies or substantial portions of the Software.
18   * 
19   * The Software shall be used for Good, not Evil.
20   * 
21   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22   * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23   * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24   * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25   * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26   * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
27   * SOFTWARE.
28   */
29  
30  import java.io.IOException;
31  import java.io.Writer;
32  import java.lang.reflect.Array;
33  import java.util.ArrayList;
34  import java.util.Collection;
35  import java.util.List;
36  import java.util.Map;
37  
38  /**
39   * A JSONArray is an ordered sequence of values. Its external text form is a
40   * string wrapped in square brackets with commas separating the values. The
41   * internal form is an object having <code>get</code> and <code>opt</code>
42   * methods for accessing the values by index, and <code>put</code> methods for
43   * adding or replacing values. The values can be any of these types:
44   * <code>Boolean</code>, <code>JSONArray</code>, <code>JSONObject</code>,
45   * <code>Number</code>, <code>String</code>, or the
46   * <code>JSONObject.NULL object</code>.
47   * <p>
48   * The constructor can convert a JSON text into a Java object. The
49   * <code>toString</code> method converts to JSON text.
50   * <p>
51   * A <code>get</code> method returns a value if one can be found, and throws
52   * an 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
59   * type coersion for you.
60   * <p>
61   * The texts produced by the <code>toString</code> methods strictly conform to
62   * JSON syntax rules. The constructors are more forgiving in the texts they will
63   * accept:
64   * <ul>
65   * <li>An extra <code>,</code>&nbsp;<small>(comma)</small> may appear just
66   * before the closing bracket.</li>
67   * <li>The <code>null</code> value will be inserted when there is
68   * <code>,</code>&nbsp;<small>(comma)</small> elision.</li>
69   * <li>Strings may be quoted with <code>'</code>&nbsp;<small>(single quote)</small>.</li>
70   * <li>Strings do not need to be quoted at all if they do not begin with a
71   * quote or single quote, and if they do not contain leading or trailing spaces,
72   * and if they do not contain any of these characters:
73   * <code>{ } [ ] / \ : , = ; #</code> and if they do not look like numbers and
74   * if they are not the reserved words <code>true</code>, <code>false</code>,
75   * or <code>null</code>.</li>
76   * <li>Values can be separated by <code>;</code> <small>(semicolon)</small>
77   * as well as by <code>,</code> <small>(comma)</small>.</li>
78   * <li>Numbers may have the <code>0-</code> <small>(octal)</small> or
79   * <code>0x-</code> <small>(hex)</small> prefix.</li>
80   * <li>Comments written in the slashshlash, slashstar, and hash conventions
81   * will be ignored.</li>
82   * </ul>
83   * 
84   * @author JSON.org
85   * @version 2
86   */
87  public class JSONArray {
88  
89      /**
90       * The arrayList where the JSONArray's properties are kept.
91       */
92      private List myArrayList;
93  
94      /**
95       * Construct an empty JSONArray.
96       */
97      public JSONArray() {
98          this.myArrayList = new ArrayList();
99      }
100 
101     /**
102      * Construct a JSONArray from a JSONTokener.
103      * 
104      * @param x
105      *            A JSONTokener
106      * @throws JSONException
107      *             If there is a syntax error.
108      */
109     public JSONArray(JSONTokener x) throws JSONException {
110         this();
111         if (x.nextClean() != '[') {
112             throw x.syntaxError("A JSONArray text must start with '['");
113         }
114         if (x.nextClean() == ']') {
115             return;
116         }
117         x.back();
118         for (;;) {
119             if (x.nextClean() == ',') {
120                 x.back();
121                 this.myArrayList.add(null);
122             } else {
123                 x.back();
124                 this.myArrayList.add(x.nextValue());
125             }
126             switch (x.nextClean()) {
127             case ';':
128             case ',':
129                 if (x.nextClean() == ']') {
130                     return;
131                 }
132                 x.back();
133                 break;
134             case ']':
135                 return;
136             default:
137                 throw x.syntaxError("Expected a ',' or ']'");
138             }
139         }
140     }
141 
142     /**
143      * Construct a JSONArray from a source JSON text.
144      * 
145      * @param source
146      *            A string that begins with <code>[</code>&nbsp;<small>(left
147      *            bracket)</small> and ends with <code>]</code>&nbsp;<small>(right
148      *            bracket)</small>.
149      * @throws JSONException
150      *             If there is a syntax error.
151      */
152     public JSONArray(String source) throws JSONException {
153         this(new JSONTokener(source));
154     }
155 
156     /**
157      * Construct a JSONArray from a Collection.
158      * 
159      * @param collection
160      *            A Collection.
161      */
162     public JSONArray(Collection collection) {
163         this.myArrayList = (collection == null) ? new ArrayList()
164                 : new ArrayList(collection);
165     }
166 
167     /**
168      * Construct a JSONArray from an array
169      * 
170      * @throws JSONException
171      *             If not an array.
172      */
173     public JSONArray(Object array) throws JSONException {
174         this();
175         if (array.getClass().isArray()) {
176             int length = Array.getLength(array);
177             for (int i = 0; i < length; i += 1) {
178                 this.put(Array.get(array, i));
179             }
180         } else {
181             throw new JSONException(
182                     "JSONArray initial value should be a string or collection or array.");
183         }
184     }
185 
186     /**
187      * Get the object value associated with an index.
188      * 
189      * @param index
190      *            The index must be between 0 and length() - 1.
191      * @return An object value.
192      * @throws JSONException
193      *             If there is no value for the index.
194      */
195     public Object get(int index) throws JSONException {
196         Object o = opt(index);
197         if (o == null) {
198             throw new JSONException("JSONArray[" + index + "] not found.");
199         }
200         return o;
201     }
202 
203     /**
204      * Get the boolean value associated with an index. The string values "true"
205      * and "false" are converted to boolean.
206      * 
207      * @param index
208      *            The index must be between 0 and length() - 1.
209      * @return The truth.
210      * @throws JSONException
211      *             If there is no value for the index or if the value is not
212      *             convertable to boolean.
213      */
214     public boolean getBoolean(int index) throws JSONException {
215         Object o = get(index);
216         if (o.equals(Boolean.FALSE)
217                 || (o instanceof String && ((String) o)
218                         .equalsIgnoreCase("false"))) {
219             return false;
220         } else if (o.equals(Boolean.TRUE)
221                 || (o instanceof String && ((String) o)
222                         .equalsIgnoreCase("true"))) {
223             return true;
224         }
225         throw new JSONException("JSONArray[" + index + "] is not a Boolean.");
226     }
227 
228     /**
229      * Get the double value associated with an index.
230      * 
231      * @param index
232      *            The index must be between 0 and length() - 1.
233      * @return The value.
234      * @throws JSONException
235      *             If the key is not found or if the value cannot be converted
236      *             to a number.
237      */
238     public double getDouble(int index) throws JSONException {
239         Object o = get(index);
240         try {
241             return o instanceof Number ? ((Number) o).doubleValue() : Double
242                     .valueOf((String) o).doubleValue();
243         } catch (Exception e) {
244             throw new JSONException("JSONArray[" + index + "] is not a number.");
245         }
246     }
247 
248     /**
249      * Get the int value associated with an index.
250      * 
251      * @param index
252      *            The index must be between 0 and length() - 1.
253      * @return The value.
254      * @throws JSONException
255      *             If the key is not found or if the value cannot be converted
256      *             to a number. if the value cannot be converted to a number.
257      */
258     public int getInt(int index) throws JSONException {
259         Object o = get(index);
260         return o instanceof Number ? ((Number) o).intValue()
261                 : (int) getDouble(index);
262     }
263 
264     /**
265      * Get the JSONArray associated with an index.
266      * 
267      * @param index
268      *            The index must be between 0 and length() - 1.
269      * @return A JSONArray value.
270      * @throws JSONException
271      *             If there is no value for the index. or if the value is not a
272      *             JSONArray
273      */
274     public JSONArray getJSONArray(int index) throws JSONException {
275         Object o = get(index);
276         if (o instanceof JSONArray) {
277             return (JSONArray) o;
278         }
279         throw new JSONException("JSONArray[" + index + "] is not a JSONArray.");
280     }
281 
282     /**
283      * Get the JSONObject associated with an index.
284      * 
285      * @param index
286      *            subscript
287      * @return A JSONObject value.
288      * @throws JSONException
289      *             If there is no value for the index or if the value is not a
290      *             JSONObject
291      */
292     public JSONObject getJSONObject(int index) throws JSONException {
293         Object o = get(index);
294         if (o instanceof JSONObject) {
295             return (JSONObject) o;
296         }
297         throw new JSONException("JSONArray[" + index + "] is not a JSONObject.");
298     }
299 
300     /**
301      * Get the long value associated with an index.
302      * 
303      * @param index
304      *            The index must be between 0 and length() - 1.
305      * @return The value.
306      * @throws JSONException
307      *             If the key is not found or if the value cannot be converted
308      *             to a number.
309      */
310     public long getLong(int index) throws JSONException {
311         Object o = get(index);
312         return o instanceof Number ? ((Number) o).longValue()
313                 : (long) getDouble(index);
314     }
315 
316     /**
317      * Get the string associated with an index.
318      * 
319      * @param index
320      *            The index must be between 0 and length() - 1.
321      * @return A string value.
322      * @throws JSONException
323      *             If there is no value for the index.
324      */
325     public String getString(int index) throws JSONException {
326         return get(index).toString();
327     }
328 
329     /**
330      * Determine if the value is null.
331      * 
332      * @param index
333      *            The index must be between 0 and length() - 1.
334      * @return true if the value at the index is null, or if there is no value.
335      */
336     public boolean isNull(int index) {
337         return JSONObject.NULL.equals(opt(index));
338     }
339 
340     /**
341      * Make a string from the contents of this JSONArray. The
342      * <code>separator</code> string is inserted between each element.
343      * Warning: This method assumes that the data structure is acyclical.
344      * 
345      * @param separator
346      *            A string that will be inserted between the elements.
347      * @return a string.
348      * @throws JSONException
349      *             If the array contains an invalid number.
350      */
351     public String join(String separator) throws JSONException {
352         int len = length();
353         StringBuffer sb = new StringBuffer();
354 
355         for (int i = 0; i < len; i += 1) {
356             if (i > 0) {
357                 sb.append(separator);
358             }
359             sb.append(JSONObject.valueToString(this.myArrayList.get(i)));
360         }
361         return sb.toString();
362     }
363 
364     /**
365      * Get the number of elements in the JSONArray, included nulls.
366      * 
367      * @return The length (or size).
368      */
369     public int length() {
370         return this.myArrayList.size();
371     }
372 
373     /**
374      * Get the optional object value associated with an index.
375      * 
376      * @param index
377      *            The index must be between 0 and length() - 1.
378      * @return An object value, or null if there is no object at that index.
379      */
380     public Object opt(int index) {
381         return (index < 0 || index >= length()) ? null : this.myArrayList
382                 .get(index);
383     }
384 
385     /**
386      * Get the optional boolean value associated with an index. It returns false
387      * if there is no value at that index, or if the value is not Boolean.TRUE
388      * or the String "true".
389      * 
390      * @param index
391      *            The index must be between 0 and length() - 1.
392      * @return The truth.
393      */
394     public boolean optBoolean(int index) {
395         return optBoolean(index, false);
396     }
397 
398     /**
399      * Get the optional boolean value associated with an index. It returns the
400      * defaultValue if there is no value at that index or if it is not a Boolean
401      * or the String "true" or "false" (case insensitive).
402      * 
403      * @param index
404      *            The index must be between 0 and length() - 1.
405      * @param defaultValue
406      *            A boolean default.
407      * @return The truth.
408      */
409     public boolean optBoolean(int index, boolean defaultValue) {
410         try {
411             return getBoolean(index);
412         } catch (Exception e) {
413             return defaultValue;
414         }
415     }
416 
417     /**
418      * Get the optional double value associated with an index. NaN is returned
419      * if there is no value for the index, or if the value is not a number and
420      * cannot be converted to a number.
421      * 
422      * @param index
423      *            The index must be between 0 and length() - 1.
424      * @return The value.
425      */
426     public double optDouble(int index) {
427         return optDouble(index, Double.NaN);
428     }
429 
430     /**
431      * Get the optional double value associated with an index. The defaultValue
432      * is returned if there is no value for the index, or if the value is not a
433      * number and cannot be converted to a number.
434      * 
435      * @param index
436      *            subscript
437      * @param defaultValue
438      *            The default value.
439      * @return The value.
440      */
441     public double optDouble(int index, double defaultValue) {
442         try {
443             return getDouble(index);
444         } catch (Exception e) {
445             return defaultValue;
446         }
447     }
448 
449     /**
450      * Get the optional int value associated with an index. Zero is returned if
451      * there is no value for the index, or if the value is not a number and
452      * cannot be converted to a number.
453      * 
454      * @param index
455      *            The index must be between 0 and length() - 1.
456      * @return The value.
457      */
458     public int optInt(int index) {
459         return optInt(index, 0);
460     }
461 
462     /**
463      * Get the optional int value associated with an index. The defaultValue is
464      * returned if there is no value for the index, or if the value is not a
465      * number and cannot be converted to a number.
466      * 
467      * @param index
468      *            The index must be between 0 and length() - 1.
469      * @param defaultValue
470      *            The default value.
471      * @return The value.
472      */
473     public int optInt(int index, int defaultValue) {
474         try {
475             return getInt(index);
476         } catch (Exception e) {
477             return defaultValue;
478         }
479     }
480 
481     /**
482      * Get the optional JSONArray associated with an index.
483      * 
484      * @param index
485      *            subscript
486      * @return A JSONArray value, or null if the index has no value, or if the
487      *         value is not a JSONArray.
488      */
489     public JSONArray optJSONArray(int index) {
490         Object o = opt(index);
491         return o instanceof JSONArray ? (JSONArray) o : null;
492     }
493 
494     /**
495      * Get the optional JSONObject associated with an index. Null is returned if
496      * the key is not found, or null if the index has no value, or if the value
497      * is not a JSONObject.
498      * 
499      * @param index
500      *            The index must be between 0 and length() - 1.
501      * @return A JSONObject value.
502      */
503     public JSONObject optJSONObject(int index) {
504         Object o = opt(index);
505         return o instanceof JSONObject ? (JSONObject) o : null;
506     }
507 
508     /**
509      * Get the optional long value associated with an index. Zero is returned if
510      * there is no value for the index, or if the value is not a number and
511      * cannot be converted to a number.
512      * 
513      * @param index
514      *            The index must be between 0 and length() - 1.
515      * @return The value.
516      */
517     public long optLong(int index) {
518         return optLong(index, 0);
519     }
520 
521     /**
522      * Get the optional long value associated with an index. The defaultValue is
523      * returned if there is no value for the index, or if the value is not a
524      * number and cannot be converted to a number.
525      * 
526      * @param index
527      *            The index must be between 0 and length() - 1.
528      * @param defaultValue
529      *            The default value.
530      * @return The value.
531      */
532     public long optLong(int index, long defaultValue) {
533         try {
534             return getLong(index);
535         } catch (Exception e) {
536             return defaultValue;
537         }
538     }
539 
540     /**
541      * Get the optional string value associated with an index. It returns an
542      * empty string if there is no value at that index. If the value is not a
543      * string and is not null, then it is coverted to a string.
544      * 
545      * @param index
546      *            The index must be between 0 and length() - 1.
547      * @return A String value.
548      */
549     public String optString(int index) {
550         return optString(index, "");
551     }
552 
553     /**
554      * Get the optional string associated with an index. The defaultValue is
555      * returned if the key is not found.
556      * 
557      * @param index
558      *            The index must be between 0 and length() - 1.
559      * @param defaultValue
560      *            The default value.
561      * @return A String value.
562      */
563     public String optString(int index, String defaultValue) {
564         Object o = opt(index);
565         return o != null ? o.toString() : defaultValue;
566     }
567 
568     /**
569      * Append a boolean value. This increases the array's length by one.
570      * 
571      * @param value
572      *            A boolean value.
573      * @return this.
574      */
575     public JSONArray put(boolean value) {
576         put(value ? Boolean.TRUE : Boolean.FALSE);
577         return this;
578     }
579 
580     /**
581      * Put a value in the JSONArray, where the value will be a JSONArray which
582      * is produced from a Collection.
583      * 
584      * @param value
585      *            A Collection value.
586      * @return this.
587      */
588     public JSONArray put(Collection value) {
589         put(new JSONArray(value));
590         return this;
591     }
592 
593     /**
594      * Append a double value. This increases the array's length by one.
595      * 
596      * @param value
597      *            A double value.
598      * @throws JSONException
599      *             if the value is not finite.
600      * @return this.
601      */
602     public JSONArray put(double value) throws JSONException {
603         Double d = new Double(value);
604         JSONObject.testValidity(d);
605         put(d);
606         return this;
607     }
608 
609     /**
610      * Append an int value. This increases the array's length by one.
611      * 
612      * @param value
613      *            An int value.
614      * @return this.
615      */
616     public JSONArray put(int value) {
617         put(new Integer(value));
618         return this;
619     }
620 
621     /**
622      * Append an long value. This increases the array's length by one.
623      * 
624      * @param value
625      *            A long value.
626      * @return this.
627      */
628     public JSONArray put(long value) {
629         put(new Long(value));
630         return this;
631     }
632 
633     /**
634      * Put a value in the JSONArray, where the value will be a JSONObject which
635      * is produced from a Map.
636      * 
637      * @param value
638      *            A Map value.
639      * @return this.
640      */
641     public JSONArray put(Map value) {
642         put(new JSONObject(value));
643         return this;
644     }
645 
646     /**
647      * Append an object value. This increases the array's length by one.
648      * 
649      * @param value
650      *            An object value. The value should be a Boolean, Double,
651      *            Integer, JSONArray, JSONObject, Long, or String, or the
652      *            JSONObject.NULL object.
653      * @return this.
654      */
655     public JSONArray put(Object value) {
656         this.myArrayList.add(value);
657         return this;
658     }
659 
660     /**
661      * Put or replace a boolean value in the JSONArray. If the index is greater
662      * than the length of the JSONArray, then null elements will be added as
663      * necessary to pad it out.
664      * 
665      * @param index
666      *            The subscript.
667      * @param value
668      *            A boolean value.
669      * @return this.
670      * @throws JSONException
671      *             If the index is negative.
672      */
673     public JSONArray put(int index, boolean value) throws JSONException {
674         put(index, value ? Boolean.TRUE : Boolean.FALSE);
675         return this;
676     }
677 
678     /**
679      * Put a value in the JSONArray, where the value will be a JSONArray which
680      * is produced from a Collection.
681      * 
682      * @param index
683      *            The subscript.
684      * @param value
685      *            A Collection value.
686      * @return this.
687      * @throws JSONException
688      *             If the index is negative or if the value is not finite.
689      */
690     public JSONArray put(int index, Collection value) throws JSONException {
691         put(index, new JSONArray(value));
692         return this;
693     }
694 
695     /**
696      * Put or replace a double value. If the index is greater than the length of
697      * the JSONArray, then null elements will be added as necessary to pad it
698      * out.
699      * 
700      * @param index
701      *            The subscript.
702      * @param value
703      *            A double value.
704      * @return this.
705      * @throws JSONException
706      *             If the index is negative or if the value is not finite.
707      */
708     public JSONArray put(int index, double value) throws JSONException {
709         put(index, new Double(value));
710         return this;
711     }
712 
713     /**
714      * Put or replace an int value. If the index is greater than the length of
715      * the JSONArray, then null elements will be added as necessary to pad it
716      * out.
717      * 
718      * @param index
719      *            The subscript.
720      * @param value
721      *            An int value.
722      * @return this.
723      * @throws JSONException
724      *             If the index is negative.
725      */
726     public JSONArray put(int index, int value) throws JSONException {
727         put(index, new Integer(value));
728         return this;
729     }
730 
731     /**
732      * Put or replace a long value. If the index is greater than the length of
733      * the JSONArray, then null elements will be added as necessary to pad it
734      * out.
735      * 
736      * @param index
737      *            The subscript.
738      * @param value
739      *            A long value.
740      * @return this.
741      * @throws JSONException
742      *             If the index is negative.
743      */
744     public JSONArray put(int index, long value) throws JSONException {
745         put(index, new Long(value));
746         return this;
747     }
748 
749     /**
750      * Put a value in the JSONArray, where the value will be a JSONObject which
751      * is produced from a Map.
752      * 
753      * @param index
754      *            The subscript.
755      * @param value
756      *            The Map value.
757      * @return this.
758      * @throws JSONException
759      *             If the index is negative or if the the value is an invalid
760      *             number.
761      */
762     public JSONArray put(int index, Map value) throws JSONException {
763         put(index, new JSONObject(value));
764         return this;
765     }
766 
767     /**
768      * Put or replace an object value in the JSONArray. If the index is greater
769      * than the length of the JSONArray, then null elements will be added as
770      * necessary to pad it out.
771      * 
772      * @param index
773      *            The subscript.
774      * @param value
775      *            The value to put into the array. The value should be a
776      *            Boolean, Double, Integer, JSONArray, JSONObject, Long, or
777      *            String, or the JSONObject.NULL object.
778      * @return this.
779      * @throws JSONException
780      *             If the index is negative or if the the value is an invalid
781      *             number.
782      */
783     public JSONArray put(int index, Object value) throws JSONException {
784         JSONObject.testValidity(value);
785         if (index < 0) {
786             throw new JSONException("JSONArray[" + index + "] not found.");
787         }
788         if (index < length()) {
789             this.myArrayList.set(index, value);
790         } else {
791             while (index != length()) {
792                 put(JSONObject.NULL);
793             }
794             put(value);
795         }
796         return this;
797     }
798 
799     /**
800      * Produce a JSONObject by combining a JSONArray of names with the values of
801      * this JSONArray.
802      * 
803      * @param names
804      *            A JSONArray containing a list of key strings. These will be
805      *            paired with the values.
806      * @return A JSONObject, or null if there are no names or if this JSONArray
807      *         has no values.
808      * @throws JSONException
809      *             If any of the names are null.
810      */
811     public JSONObject toJSONObject(JSONArray names) throws JSONException {
812         if (names == null || names.length() == 0 || length() == 0) {
813             return null;
814         }
815         JSONObject jo = new JSONObject();
816         for (int i = 0; i < names.length(); i += 1) {
817             jo.put(names.getString(i), this.opt(i));
818         }
819         return jo;
820     }
821 
822     /**
823      * Make a JSON text of this JSONArray. For compactness, no unnecessary
824      * whitespace is added. If it is not possible to produce a syntactically
825      * correct JSON text then null will be returned instead. This could occur if
826      * the array contains an invalid number.
827      * <p>
828      * Warning: This method assumes that the data structure is acyclical.
829      * 
830      * @return a printable, displayable, transmittable representation of the
831      *         array.
832      */
833     public String toString() {
834         try {
835             return '[' + join(",") + ']';
836         } catch (Exception e) {
837             return null;
838         }
839     }
840 
841     /**
842      * Make a prettyprinted JSON text of this JSONArray. Warning: This method
843      * assumes that the data structure is acyclical.
844      * 
845      * @param indentFactor
846      *            The number of spaces to add to each level of indentation.
847      * @return a printable, displayable, transmittable representation of the
848      *         object, beginning with <code>[</code>&nbsp;<small>(left
849      *         bracket)</small> and ending with <code>]</code>&nbsp;<small>(right
850      *         bracket)</small>.
851      * @throws JSONException
852      */
853     public String toString(int indentFactor) throws JSONException {
854         return toString(indentFactor, 0);
855     }
856 
857     /**
858      * Make a prettyprinted JSON text of this JSONArray. Warning: This method
859      * assumes that the data structure is acyclical.
860      * 
861      * @param indentFactor
862      *            The number of spaces to add to each level of indentation.
863      * @param indent
864      *            The indention of the top level.
865      * @return a printable, displayable, transmittable representation of the
866      *         array.
867      * @throws JSONException
868      */
869     String toString(int indentFactor, int indent) throws JSONException {
870         int len = length();
871         if (len == 0) {
872             return "[]";
873         }
874         int i;
875         StringBuffer sb = new StringBuffer("[");
876         if (len == 1) {
877             sb.append(JSONObject.valueToString(this.myArrayList.get(0),
878                     indentFactor, indent));
879         } else {
880             int newindent = indent + indentFactor;
881             sb.append('\n');
882             for (i = 0; i < len; i += 1) {
883                 if (i > 0) {
884                     sb.append(",\n");
885                 }
886                 for (int j = 0; j < newindent; j += 1) {
887                     sb.append(' ');
888                 }
889                 sb.append(JSONObject.valueToString(this.myArrayList.get(i),
890                         indentFactor, newindent));
891             }
892             sb.append('\n');
893             for (i = 0; i < indent; i += 1) {
894                 sb.append(' ');
895             }
896         }
897         sb.append(']');
898         return sb.toString();
899     }
900 
901     /**
902      * Write the contents of the JSONArray as JSON text to a writer. For
903      * compactness, no whitespace is added.
904      * <p>
905      * Warning: This method assumes that the data structure is acyclical.
906      * 
907      * @return The writer.
908      * @throws JSONException
909      */
910     public Writer write(Writer writer) throws JSONException {
911         try {
912             boolean b = false;
913             int len = length();
914 
915             writer.write('[');
916 
917             for (int i = 0; i < len; i += 1) {
918                 if (b) {
919                     writer.write(',');
920                 }
921                 Object v = this.myArrayList.get(i);
922                 if (v instanceof JSONObject) {
923                     ((JSONObject) v).write(writer);
924                 } else if (v instanceof JSONArray) {
925                     ((JSONArray) v).write(writer);
926                 } else {
927                     writer.write(JSONObject.valueToString(v));
928                 }
929                 b = true;
930             }
931             writer.write(']');
932             return writer;
933         } catch (IOException e) {
934             throw new JSONException(e);
935         }
936     }
937 }