JAL-4045 - don't apply distribution dependent scale factor to the axis lines!
[jalview.git] / src / 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 if
76  * 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-08/15
82  */
83 public class JSONArray implements Iterable<Object>
84 {
85
86   /**
87    * The arrayList where the JSONArray's properties are kept.
88    */
89   private final ArrayList<Object> myArrayList;
90
91   /**
92    * Construct an empty JSONArray.
93    */
94   public JSONArray()
95   {
96     this.myArrayList = new ArrayList<Object>();
97   }
98
99   /**
100    * Construct a JSONArray from a JSONTokener.
101    *
102    * @param x
103    *          A JSONTokener
104    * @throws JSONException
105    *           If there is a syntax error.
106    */
107   public JSONArray(JSONTokener x) throws JSONException
108   {
109     this();
110     if (x.nextClean() != '[')
111     {
112       throw x.syntaxError("A JSONArray text must start with '['");
113     }
114
115     char nextChar = x.nextClean();
116     if (nextChar == 0)
117     {
118       // array is unclosed. No ']' found, instead EOF
119       throw x.syntaxError("Expected a ',' or ']'");
120     }
121     if (nextChar != ']')
122     {
123       x.back();
124       for (;;)
125       {
126         if (x.nextClean() == ',')
127         {
128           x.back();
129           this.myArrayList.add(JSONObject.NULL);
130         }
131         else
132         {
133           x.back();
134           this.myArrayList.add(x.nextValue());
135         }
136         switch (x.nextClean())
137         {
138         case 0:
139           // array is unclosed. No ']' found, instead EOF
140           throw x.syntaxError("Expected a ',' or ']'");
141         case ',':
142           nextChar = x.nextClean();
143           if (nextChar == 0)
144           {
145             // array is unclosed. No ']' found, instead EOF
146             throw x.syntaxError("Expected a ',' or ']'");
147           }
148           if (nextChar == ']')
149           {
150             return;
151           }
152           x.back();
153           break;
154         case ']':
155           return;
156         default:
157           throw x.syntaxError("Expected a ',' or ']'");
158         }
159       }
160     }
161   }
162
163   /**
164    * Construct a JSONArray from a source JSON text.
165    *
166    * @param source
167    *          A string that begins with <code>[</code>&nbsp;<small>(left
168    *          bracket)</small> and ends with <code>]</code> &nbsp;<small>(right
169    *          bracket)</small>.
170    * @throws JSONException
171    *           If there is a syntax error.
172    */
173   public JSONArray(String source) throws JSONException
174   {
175     this(new JSONTokener(source));
176   }
177
178   /**
179    * Construct a JSONArray from a Collection.
180    *
181    * @param collection
182    *          A Collection.
183    */
184   public JSONArray(Collection<?> collection)
185   {
186     if (collection == null)
187     {
188       this.myArrayList = new ArrayList<Object>();
189     }
190     else
191     {
192       this.myArrayList = new ArrayList<Object>(collection.size());
193       for (Object o : collection)
194       {
195         this.myArrayList.add(JSONObject.wrap(o));
196       }
197     }
198   }
199
200   /**
201    * Construct a JSONArray from an array
202    *
203    * @throws JSONException
204    *           If not an array or if an array value is non-finite number.
205    */
206   public JSONArray(Object array) throws JSONException
207   {
208     this();
209     if (array.getClass().isArray())
210     {
211       int length = Array.getLength(array);
212       this.myArrayList.ensureCapacity(length);
213       for (int i = 0; i < length; i += 1)
214       {
215         this.put(JSONObject.wrap(Array.get(array, i)));
216       }
217     }
218     else
219     {
220       throw new JSONException(
221               "JSONArray initial value should be a string or collection or array.");
222     }
223   }
224
225   @Override
226   public Iterator<Object> iterator()
227   {
228     return this.myArrayList.iterator();
229   }
230
231   /**
232    * Get the object value associated with an index.
233    *
234    * @param index
235    *          The index must be between 0 and length() - 1.
236    * @return An object value.
237    * @throws JSONException
238    *           If there is no value for the index.
239    */
240   public Object get(int index) throws JSONException
241   {
242     Object object = this.opt(index);
243     if (object == null)
244     {
245       throw new JSONException("JSONArray[" + index + "] not found.");
246     }
247     return object;
248   }
249
250   /**
251    * Get the boolean value associated with an index. The string values "true"
252    * and "false" are converted to boolean.
253    *
254    * @param index
255    *          The index must be between 0 and length() - 1.
256    * @return The truth.
257    * @throws JSONException
258    *           If there is no value for the index or if the value is not
259    *           convertible to boolean.
260    */
261   public boolean getBoolean(int index) throws JSONException
262   {
263     Object object = this.get(index);
264     if (object.equals(Boolean.FALSE) || (object instanceof String
265             && ((String) object).equalsIgnoreCase("false")))
266     {
267       return false;
268     }
269     else if (object.equals(Boolean.TRUE) || (object instanceof String
270             && ((String) object).equalsIgnoreCase("true")))
271     {
272       return true;
273     }
274     throw new JSONException("JSONArray[" + index + "] is not a boolean.");
275   }
276
277   /**
278    * Get the double value associated with an index.
279    *
280    * @param index
281    *          The index must be between 0 and length() - 1.
282    * @return The value.
283    * @throws JSONException
284    *           If the key is not found or if the value cannot be converted to a
285    *           number.
286    */
287   public double getDouble(int index) throws JSONException
288   {
289     Object object = this.get(index);
290     try
291     {
292       return object instanceof Number ? ((Number) object).doubleValue()
293               : Double.parseDouble((String) object);
294     } catch (Exception e)
295     {
296       throw new JSONException("JSONArray[" + index + "] is not a number.",
297               e);
298     }
299   }
300
301   /**
302    * Get the float value associated with a key.
303    *
304    * @param index
305    *          The index must be between 0 and length() - 1.
306    * @return The numeric value.
307    * @throws JSONException
308    *           if the key is not found or if the value is not a Number object
309    *           and cannot be converted to a number.
310    */
311   public float getFloat(int index) throws JSONException
312   {
313     Object object = this.get(index);
314     try
315     {
316       return object instanceof Number ? ((Number) object).floatValue()
317               : Float.parseFloat(object.toString());
318     } catch (Exception e)
319     {
320       throw new JSONException("JSONArray[" + index + "] is not a number.",
321               e);
322     }
323   }
324
325   /**
326    * Get the Number value associated with a key.
327    *
328    * @param index
329    *          The index must be between 0 and length() - 1.
330    * @return The numeric value.
331    * @throws JSONException
332    *           if the key is not found or if the value is not a Number object
333    *           and cannot be converted to a number.
334    */
335   public Number getNumber(int index) throws JSONException
336   {
337     Object object = this.get(index);
338     try
339     {
340       if (object instanceof Number)
341       {
342         return (Number) object;
343       }
344       return JSONObject.stringToNumber(object.toString());
345     } catch (Exception e)
346     {
347       throw new JSONException("JSONArray[" + index + "] is not a number.",
348               e);
349     }
350   }
351
352   /**
353    * Get the enum value associated with an index.
354    * 
355    * @param clazz
356    *          The type of enum to retrieve.
357    * @param index
358    *          The index must be between 0 and length() - 1.
359    * @return The enum value at the index location
360    * @throws JSONException
361    *           if the key is not found or if the value cannot be converted to an
362    *           enum.
363    */
364   public <E extends Enum<E>> E getEnum(Class<E> clazz, int index)
365           throws JSONException
366   {
367     E val = optEnum(clazz, index);
368     if (val == null)
369     {
370       // JSONException should really take a throwable argument.
371       // If it did, I would re-implement this with the Enum.valueOf
372       // method and place any thrown exception in the JSONException
373       throw new JSONException(
374               "JSONArray[" + index + "] is not an enum of type "
375                       + JSONObject.quote(clazz.getSimpleName()) + ".");
376     }
377     return val;
378   }
379
380   /**
381    * Get the BigDecimal value associated with an index.
382    *
383    * @param index
384    *          The index must be between 0 and length() - 1.
385    * @return The value.
386    * @throws JSONException
387    *           If the key is not found or if the value cannot be converted to a
388    *           BigDecimal.
389    */
390   public BigDecimal getBigDecimal(int index) throws JSONException
391   {
392     Object object = this.get(index);
393     try
394     {
395       return new BigDecimal(object.toString());
396     } catch (Exception e)
397     {
398       throw new JSONException(
399               "JSONArray[" + index + "] could not convert to BigDecimal.",
400               e);
401     }
402   }
403
404   /**
405    * Get the BigInteger value associated with an index.
406    *
407    * @param index
408    *          The index must be between 0 and length() - 1.
409    * @return The value.
410    * @throws JSONException
411    *           If the key is not found or if the value cannot be converted to a
412    *           BigInteger.
413    */
414   public BigInteger getBigInteger(int index) throws JSONException
415   {
416     Object object = this.get(index);
417     try
418     {
419       return new BigInteger(object.toString());
420     } catch (Exception e)
421     {
422       throw new JSONException(
423               "JSONArray[" + index + "] could not convert to BigInteger.",
424               e);
425     }
426   }
427
428   /**
429    * Get the int value associated with an index.
430    *
431    * @param index
432    *          The index must be between 0 and length() - 1.
433    * @return The value.
434    * @throws JSONException
435    *           If the key is not found or if the value is not a number.
436    */
437   public int getInt(int index) throws JSONException
438   {
439     Object object = this.get(index);
440     try
441     {
442       return object instanceof Number ? ((Number) object).intValue()
443               : Integer.parseInt((String) object);
444     } catch (Exception e)
445     {
446       throw new JSONException("JSONArray[" + index + "] is not a number.",
447               e);
448     }
449   }
450
451   /**
452    * Get the JSONArray associated with an index.
453    *
454    * @param index
455    *          The index must be between 0 and length() - 1.
456    * @return A JSONArray value.
457    * @throws JSONException
458    *           If there is no value for the index. or if the value is not a
459    *           JSONArray
460    */
461   public JSONArray getJSONArray(int index) throws JSONException
462   {
463     Object object = this.get(index);
464     if (object instanceof JSONArray)
465     {
466       return (JSONArray) object;
467     }
468     throw new JSONException("JSONArray[" + index + "] is not a JSONArray.");
469   }
470
471   /**
472    * Get the JSONObject associated with an index.
473    *
474    * @param index
475    *          subscript
476    * @return A JSONObject value.
477    * @throws JSONException
478    *           If there is no value for the index or if the value is not a
479    *           JSONObject
480    */
481   public JSONObject getJSONObject(int index) throws JSONException
482   {
483     Object object = this.get(index);
484     if (object instanceof JSONObject)
485     {
486       return (JSONObject) object;
487     }
488     throw new JSONException(
489             "JSONArray[" + index + "] is not a JSONObject.");
490   }
491
492   /**
493    * Get the long value associated with an index.
494    *
495    * @param index
496    *          The index must be between 0 and length() - 1.
497    * @return The value.
498    * @throws JSONException
499    *           If the key is not found or if the value cannot be converted to a
500    *           number.
501    */
502   public long getLong(int index) throws JSONException
503   {
504     Object object = this.get(index);
505     try
506     {
507       return object instanceof Number ? ((Number) object).longValue()
508               : Long.parseLong((String) object);
509     } catch (Exception e)
510     {
511       throw new JSONException("JSONArray[" + index + "] is not a number.",
512               e);
513     }
514   }
515
516   /**
517    * Get the string associated with an index.
518    *
519    * @param index
520    *          The index must be between 0 and length() - 1.
521    * @return A string value.
522    * @throws JSONException
523    *           If there is no string value for the index.
524    */
525   public String getString(int index) throws JSONException
526   {
527     Object object = this.get(index);
528     if (object instanceof String)
529     {
530       return (String) object;
531     }
532     throw new JSONException("JSONArray[" + index + "] not a string.");
533   }
534
535   /**
536    * Determine if the value is <code>null</code>.
537    *
538    * @param index
539    *          The index must be between 0 and length() - 1.
540    * @return true if the value at the index is <code>null</code>, or if there is
541    *         no value.
542    */
543   public boolean isNull(int index)
544   {
545     return JSONObject.NULL.equals(this.opt(index));
546   }
547
548   /**
549    * Make a string from the contents of this JSONArray. The
550    * <code>separator</code> string is inserted between each element. Warning:
551    * This method assumes that the data structure is acyclical.
552    *
553    * @param separator
554    *          A string that will be inserted between the elements.
555    * @return a string.
556    * @throws JSONException
557    *           If the array contains an invalid number.
558    */
559   public String join(String separator) throws JSONException
560   {
561     int len = this.length();
562     StringBuilder sb = new StringBuilder();
563
564     for (int i = 0; i < len; i += 1)
565     {
566       if (i > 0)
567       {
568         sb.append(separator);
569       }
570       sb.append(JSONObject.valueToString(this.myArrayList.get(i)));
571     }
572     return sb.toString();
573   }
574
575   /**
576    * Get the number of elements in the JSONArray, included nulls.
577    *
578    * @return The length (or size).
579    */
580   public int length()
581   {
582     return this.myArrayList.size();
583   }
584
585   /**
586    * Get the optional object value associated with an index.
587    *
588    * @param index
589    *          The index must be between 0 and length() - 1. If not, null is
590    *          returned.
591    * @return An object value, or null if there is no object at that index.
592    */
593   public Object opt(int index)
594   {
595     return (index < 0 || index >= this.length()) ? null
596             : this.myArrayList.get(index);
597   }
598
599   /**
600    * Get the optional boolean value associated with an index. It returns false
601    * if there is no value at that index, or if the value is not Boolean.TRUE or
602    * the String "true".
603    *
604    * @param index
605    *          The index must be between 0 and length() - 1.
606    * @return The truth.
607    */
608   public boolean optBoolean(int index)
609   {
610     return this.optBoolean(index, false);
611   }
612
613   /**
614    * Get the optional boolean value associated with an index. It returns the
615    * defaultValue if there is no value at that index or if it is not a Boolean
616    * or the String "true" or "false" (case insensitive).
617    *
618    * @param index
619    *          The index must be between 0 and length() - 1.
620    * @param defaultValue
621    *          A boolean default.
622    * @return The truth.
623    */
624   public boolean optBoolean(int index, boolean defaultValue)
625   {
626     try
627     {
628       return this.getBoolean(index);
629     } catch (Exception e)
630     {
631       return defaultValue;
632     }
633   }
634
635   /**
636    * Get the optional double value associated with an index. NaN is returned if
637    * there is no value for the index, or if the value is not a number and cannot
638    * be converted to a number.
639    *
640    * @param index
641    *          The index must be between 0 and length() - 1.
642    * @return The value.
643    */
644   public double optDouble(int index)
645   {
646     return this.optDouble(index, Double.NaN);
647   }
648
649   /**
650    * Get the optional double value associated with an index. The defaultValue is
651    * returned if there is no value for the index, or if the value is not a
652    * number and cannot be converted to a number.
653    *
654    * @param index
655    *          subscript
656    * @param defaultValue
657    *          The default value.
658    * @return The value.
659    */
660   public double optDouble(int index, double defaultValue)
661   {
662     Object val = this.opt(index);
663     if (JSONObject.NULL.equals(val))
664     {
665       return defaultValue;
666     }
667     if (val instanceof Number)
668     {
669       return ((Number) val).doubleValue();
670     }
671     if (val instanceof String)
672     {
673       try
674       {
675         return Double.parseDouble((String) val);
676       } catch (Exception e)
677       {
678         return defaultValue;
679       }
680     }
681     return defaultValue;
682   }
683
684   /**
685    * Get the optional float value associated with an index. NaN is returned if
686    * there is no value for the index, or if the value is not a number and cannot
687    * be converted to a number.
688    *
689    * @param index
690    *          The index must be between 0 and length() - 1.
691    * @return The value.
692    */
693   public float optFloat(int index)
694   {
695     return this.optFloat(index, Float.NaN);
696   }
697
698   /**
699    * Get the optional float value associated with an index. The defaultValue is
700    * returned if there is no value for the index, or if the value is not a
701    * number and cannot be converted to a number.
702    *
703    * @param index
704    *          subscript
705    * @param defaultValue
706    *          The default value.
707    * @return The value.
708    */
709   public float optFloat(int index, float defaultValue)
710   {
711     Object val = this.opt(index);
712     if (JSONObject.NULL.equals(val))
713     {
714       return defaultValue;
715     }
716     if (val instanceof Number)
717     {
718       return ((Number) val).floatValue();
719     }
720     if (val instanceof String)
721     {
722       try
723       {
724         return Float.parseFloat((String) val);
725       } catch (Exception e)
726       {
727         return defaultValue;
728       }
729     }
730     return defaultValue;
731   }
732
733   /**
734    * Get the optional int value associated with an index. Zero is returned if
735    * there is no value for the index, or if the value is not a number and cannot
736    * be converted to a number.
737    *
738    * @param index
739    *          The index must be between 0 and length() - 1.
740    * @return The value.
741    */
742   public int optInt(int index)
743   {
744     return this.optInt(index, 0);
745   }
746
747   /**
748    * Get the optional int value associated with an index. The defaultValue is
749    * returned if there is no value for the index, or if the value is not a
750    * number and cannot be converted to a number.
751    *
752    * @param index
753    *          The index must be between 0 and length() - 1.
754    * @param defaultValue
755    *          The default value.
756    * @return The value.
757    */
758   public int optInt(int index, int defaultValue)
759   {
760     Object val = this.opt(index);
761     if (JSONObject.NULL.equals(val))
762     {
763       return defaultValue;
764     }
765     if (val instanceof Number)
766     {
767       return ((Number) val).intValue();
768     }
769
770     if (val instanceof String)
771     {
772       try
773       {
774         return new BigDecimal(val.toString()).intValue();
775       } catch (Exception e)
776       {
777         return defaultValue;
778       }
779     }
780     return defaultValue;
781   }
782
783   /**
784    * Get the enum value associated with a key.
785    * 
786    * @param clazz
787    *          The type of enum to retrieve.
788    * @param index
789    *          The index must be between 0 and length() - 1.
790    * @return The enum value at the index location or null if not found
791    */
792   public <E extends Enum<E>> E optEnum(Class<E> clazz, int index)
793   {
794     return this.optEnum(clazz, index, null);
795   }
796
797   /**
798    * Get the enum value associated with a key.
799    * 
800    * @param clazz
801    *          The type of enum to retrieve.
802    * @param index
803    *          The index must be between 0 and length() - 1.
804    * @param defaultValue
805    *          The default in case the value is not found
806    * @return The enum value at the index location or defaultValue if the value
807    *         is not found or cannot be assigned to clazz
808    */
809   public <E extends Enum<E>> E optEnum(Class<E> clazz, int index,
810           E defaultValue)
811   {
812     try
813     {
814       Object val = this.opt(index);
815       if (JSONObject.NULL.equals(val))
816       {
817         return defaultValue;
818       }
819       if (clazz.isAssignableFrom(val.getClass()))
820       {
821         // we just checked it!
822         @SuppressWarnings("unchecked")
823         E myE = (E) val;
824         return myE;
825       }
826       return Enum.valueOf(clazz, val.toString());
827     } catch (IllegalArgumentException e)
828     {
829       return defaultValue;
830     } catch (NullPointerException e)
831     {
832       return defaultValue;
833     }
834   }
835
836   /**
837    * Get the optional BigInteger value associated with an index. The
838    * defaultValue is returned if there is no value for the index, or if the
839    * value is not a number and cannot be converted to a number.
840    *
841    * @param index
842    *          The index must be between 0 and length() - 1.
843    * @param defaultValue
844    *          The default value.
845    * @return The value.
846    */
847   public BigInteger optBigInteger(int index, BigInteger defaultValue)
848   {
849     Object val = this.opt(index);
850     if (JSONObject.NULL.equals(val))
851     {
852       return defaultValue;
853     }
854     if (val instanceof BigInteger)
855     {
856       return (BigInteger) val;
857     }
858     if (val instanceof BigDecimal)
859     {
860       return ((BigDecimal) val).toBigInteger();
861     }
862     if (val instanceof Double || val instanceof Float)
863     {
864       return new BigDecimal(((Number) val).doubleValue()).toBigInteger();
865     }
866     if (val instanceof Long || val instanceof Integer
867             || val instanceof Short || val instanceof Byte)
868     {
869       return BigInteger.valueOf(((Number) val).longValue());
870     }
871     try
872     {
873       final String valStr = val.toString();
874       if (JSONObject.isDecimalNotation(valStr))
875       {
876         return new BigDecimal(valStr).toBigInteger();
877       }
878       return new BigInteger(valStr);
879     } catch (Exception e)
880     {
881       return defaultValue;
882     }
883   }
884
885   /**
886    * Get the optional BigDecimal value associated with an index. The
887    * defaultValue is returned if there is no value for the index, or if the
888    * value is not a number and cannot be converted to a number.
889    *
890    * @param index
891    *          The index must be between 0 and length() - 1.
892    * @param defaultValue
893    *          The default value.
894    * @return The value.
895    */
896   public BigDecimal optBigDecimal(int index, BigDecimal defaultValue)
897   {
898     Object val = this.opt(index);
899     if (JSONObject.NULL.equals(val))
900     {
901       return defaultValue;
902     }
903     if (val instanceof BigDecimal)
904     {
905       return (BigDecimal) val;
906     }
907     if (val instanceof BigInteger)
908     {
909       return new BigDecimal((BigInteger) val);
910     }
911     if (val instanceof Double || val instanceof Float)
912     {
913       return new BigDecimal(((Number) val).doubleValue());
914     }
915     if (val instanceof Long || val instanceof Integer
916             || val instanceof Short || val instanceof Byte)
917     {
918       return new BigDecimal(((Number) val).longValue());
919     }
920     try
921     {
922       return new BigDecimal(val.toString());
923     } catch (Exception e)
924     {
925       return defaultValue;
926     }
927   }
928
929   /**
930    * Get the optional JSONArray associated with an index.
931    *
932    * @param index
933    *          subscript
934    * @return A JSONArray value, or null if the index has no value, or if the
935    *         value is not a JSONArray.
936    */
937   public JSONArray optJSONArray(int index)
938   {
939     Object o = this.opt(index);
940     return o instanceof JSONArray ? (JSONArray) o : null;
941   }
942
943   /**
944    * Get the optional JSONObject associated with an index. Null is returned if
945    * the key is not found, or null if the index has no value, or if the value is
946    * not a JSONObject.
947    *
948    * @param index
949    *          The index must be between 0 and length() - 1.
950    * @return A JSONObject value.
951    */
952   public JSONObject optJSONObject(int index)
953   {
954     Object o = this.opt(index);
955     return o instanceof JSONObject ? (JSONObject) o : null;
956   }
957
958   /**
959    * Get the optional long value associated with an index. Zero is returned if
960    * there is no value for the index, or if the value is not a number and cannot
961    * be converted to a number.
962    *
963    * @param index
964    *          The index must be between 0 and length() - 1.
965    * @return The value.
966    */
967   public long optLong(int index)
968   {
969     return this.optLong(index, 0);
970   }
971
972   /**
973    * Get the optional long value associated with an index. The defaultValue is
974    * returned if there is no value for the index, or if the value is not a
975    * number and cannot be converted to a number.
976    *
977    * @param index
978    *          The index must be between 0 and length() - 1.
979    * @param defaultValue
980    *          The default value.
981    * @return The value.
982    */
983   public long optLong(int index, long defaultValue)
984   {
985     Object val = this.opt(index);
986     if (JSONObject.NULL.equals(val))
987     {
988       return defaultValue;
989     }
990     if (val instanceof Number)
991     {
992       return ((Number) val).longValue();
993     }
994
995     if (val instanceof String)
996     {
997       try
998       {
999         return new BigDecimal(val.toString()).longValue();
1000       } catch (Exception e)
1001       {
1002         return defaultValue;
1003       }
1004     }
1005     return defaultValue;
1006   }
1007
1008   /**
1009    * Get an optional {@link Number} value associated with a key, or
1010    * <code>null</code> if there is no such key or if the value is not a number.
1011    * If the value is a string, an attempt will be made to evaluate it as a
1012    * number ({@link BigDecimal}). This method would be used in cases where type
1013    * coercion of the number value is unwanted.
1014    *
1015    * @param index
1016    *          The index must be between 0 and length() - 1.
1017    * @return An object which is the value.
1018    */
1019   public Number optNumber(int index)
1020   {
1021     return this.optNumber(index, null);
1022   }
1023
1024   /**
1025    * Get an optional {@link Number} value associated with a key, or the default
1026    * if there is no such key or if the value is not a number. If the value is a
1027    * string, an attempt will be made to evaluate it as a number
1028    * ({@link BigDecimal}). This method would be used in cases where type
1029    * coercion of the number value is unwanted.
1030    *
1031    * @param index
1032    *          The index must be between 0 and length() - 1.
1033    * @param defaultValue
1034    *          The default.
1035    * @return An object which is the value.
1036    */
1037   public Number optNumber(int index, Number defaultValue)
1038   {
1039     Object val = this.opt(index);
1040     if (JSONObject.NULL.equals(val))
1041     {
1042       return defaultValue;
1043     }
1044     if (val instanceof Number)
1045     {
1046       return (Number) val;
1047     }
1048
1049     if (val instanceof String)
1050     {
1051       try
1052       {
1053         return JSONObject.stringToNumber((String) val);
1054       } catch (Exception e)
1055       {
1056         return defaultValue;
1057       }
1058     }
1059     return defaultValue;
1060   }
1061
1062   /**
1063    * Get the optional string value associated with an index. It returns an empty
1064    * string if there is no value at that index. If the value is not a string and
1065    * is not null, then it is converted to a string.
1066    *
1067    * @param index
1068    *          The index must be between 0 and length() - 1.
1069    * @return A String value.
1070    */
1071   public String optString(int index)
1072   {
1073     return this.optString(index, "");
1074   }
1075
1076   /**
1077    * Get the optional string associated with an index. The defaultValue is
1078    * returned if the key is not found.
1079    *
1080    * @param index
1081    *          The index must be between 0 and length() - 1.
1082    * @param defaultValue
1083    *          The default value.
1084    * @return A String value.
1085    */
1086   public String optString(int index, String defaultValue)
1087   {
1088     Object object = this.opt(index);
1089     return JSONObject.NULL.equals(object) ? defaultValue
1090             : object.toString();
1091   }
1092
1093   /**
1094    * Append a boolean value. This increases the array's length by one.
1095    *
1096    * @param value
1097    *          A boolean value.
1098    * @return this.
1099    */
1100   public JSONArray put(boolean value)
1101   {
1102     return this.put(value ? Boolean.TRUE : Boolean.FALSE);
1103   }
1104
1105   /**
1106    * Put a value in the JSONArray, where the value will be a JSONArray which is
1107    * produced from a Collection.
1108    *
1109    * @param value
1110    *          A Collection value.
1111    * @return this.
1112    * @throws JSONException
1113    *           If the value is non-finite number.
1114    */
1115   public JSONArray put(Collection<?> value)
1116   {
1117     return this.put(new JSONArray(value));
1118   }
1119
1120   /**
1121    * Append a double value. This increases the array's length by one.
1122    *
1123    * @param value
1124    *          A double value.
1125    * @return this.
1126    * @throws JSONException
1127    *           if the value is not finite.
1128    */
1129   public JSONArray put(double value) throws JSONException
1130   {
1131     return this.put(Double.valueOf(value));
1132   }
1133
1134   /**
1135    * Append a float value. This increases the array's length by one.
1136    *
1137    * @param value
1138    *          A float value.
1139    * @return this.
1140    * @throws JSONException
1141    *           if the value is not finite.
1142    */
1143   public JSONArray put(float value) throws JSONException
1144   {
1145     return this.put(Float.valueOf(value));
1146   }
1147
1148   /**
1149    * Append an int value. This increases the array's length by one.
1150    *
1151    * @param value
1152    *          An int value.
1153    * @return this.
1154    */
1155   public JSONArray put(int value)
1156   {
1157     return this.put(Integer.valueOf(value));
1158   }
1159
1160   /**
1161    * Append an long value. This increases the array's length by one.
1162    *
1163    * @param value
1164    *          A long value.
1165    * @return this.
1166    */
1167   public JSONArray put(long value)
1168   {
1169     return this.put(Long.valueOf(value));
1170   }
1171
1172   /**
1173    * Put a value in the JSONArray, where the value will be a JSONObject which is
1174    * produced from a Map.
1175    *
1176    * @param value
1177    *          A Map value.
1178    * @return this.
1179    * @throws JSONException
1180    *           If a value in the map is non-finite number.
1181    * @throws NullPointerException
1182    *           If a key in the map is <code>null</code>
1183    */
1184   public JSONArray put(Map<?, ?> value)
1185   {
1186     return this.put(new JSONObject(value));
1187   }
1188
1189   /**
1190    * Append an object value. This increases the array's length by one.
1191    *
1192    * @param value
1193    *          An object value. The value should be a Boolean, Double, Integer,
1194    *          JSONArray, JSONObject, Long, or String, or the JSONObject.NULL
1195    *          object.
1196    * @return this.
1197    * @throws JSONException
1198    *           If the value is non-finite number.
1199    */
1200   public JSONArray put(Object value)
1201   {
1202     JSONObject.testValidity(value);
1203     this.myArrayList.add(value);
1204     return this;
1205   }
1206
1207   /**
1208    * Put or replace a boolean value in the JSONArray. If the index is greater
1209    * than the length of the JSONArray, then null elements will be added as
1210    * necessary to pad it out.
1211    *
1212    * @param index
1213    *          The subscript.
1214    * @param value
1215    *          A boolean value.
1216    * @return this.
1217    * @throws JSONException
1218    *           If the index is negative.
1219    */
1220   public JSONArray put(int index, boolean value) throws JSONException
1221   {
1222     return this.put(index, value ? Boolean.TRUE : Boolean.FALSE);
1223   }
1224
1225   /**
1226    * Put a value in the JSONArray, where the value will be a JSONArray which is
1227    * produced from a Collection.
1228    *
1229    * @param index
1230    *          The subscript.
1231    * @param value
1232    *          A Collection value.
1233    * @return this.
1234    * @throws JSONException
1235    *           If the index is negative or if the value is non-finite.
1236    */
1237   public JSONArray put(int index, Collection<?> value) throws JSONException
1238   {
1239     return this.put(index, new JSONArray(value));
1240   }
1241
1242   /**
1243    * Put or replace a double value. If the index is greater than the length of
1244    * the JSONArray, then null elements will be added as necessary to pad it out.
1245    *
1246    * @param index
1247    *          The subscript.
1248    * @param value
1249    *          A double value.
1250    * @return this.
1251    * @throws JSONException
1252    *           If the index is negative or if the value is non-finite.
1253    */
1254   public JSONArray put(int index, double value) throws JSONException
1255   {
1256     return this.put(index, Double.valueOf(value));
1257   }
1258
1259   /**
1260    * Put or replace a float value. If the index is greater than the length of
1261    * the JSONArray, then null elements will be added as necessary to pad it out.
1262    *
1263    * @param index
1264    *          The subscript.
1265    * @param value
1266    *          A float value.
1267    * @return this.
1268    * @throws JSONException
1269    *           If the index is negative or if the value is non-finite.
1270    */
1271   public JSONArray put(int index, float value) throws JSONException
1272   {
1273     return this.put(index, Float.valueOf(value));
1274   }
1275
1276   /**
1277    * Put or replace an int value. If the index is greater than the length of the
1278    * JSONArray, then null elements will be added as necessary to pad it out.
1279    *
1280    * @param index
1281    *          The subscript.
1282    * @param value
1283    *          An int value.
1284    * @return this.
1285    * @throws JSONException
1286    *           If the index is negative.
1287    */
1288   public JSONArray put(int index, int value) throws JSONException
1289   {
1290     return this.put(index, Integer.valueOf(value));
1291   }
1292
1293   /**
1294    * Put or replace a long value. If the index is greater than the length of the
1295    * JSONArray, then null elements will be added as necessary to pad it out.
1296    *
1297    * @param index
1298    *          The subscript.
1299    * @param value
1300    *          A long value.
1301    * @return this.
1302    * @throws JSONException
1303    *           If the index is negative.
1304    */
1305   public JSONArray put(int index, long value) throws JSONException
1306   {
1307     return this.put(index, Long.valueOf(value));
1308   }
1309
1310   /**
1311    * Put a value in the JSONArray, where the value will be a JSONObject that is
1312    * produced from a Map.
1313    *
1314    * @param index
1315    *          The subscript.
1316    * @param value
1317    *          The Map value.
1318    * @return this.
1319    * @throws JSONException
1320    *           If the index is negative or if the the value is an invalid
1321    *           number.
1322    * @throws NullPointerException
1323    *           If a key in the map is <code>null</code>
1324    */
1325   public JSONArray put(int index, Map<?, ?> value) throws JSONException
1326   {
1327     this.put(index, new JSONObject(value));
1328     return this;
1329   }
1330
1331   /**
1332    * Put or replace an object value in the JSONArray. If the index is greater
1333    * than the length of the JSONArray, then null elements will be added as
1334    * necessary to pad it out.
1335    *
1336    * @param index
1337    *          The subscript.
1338    * @param value
1339    *          The value to put into the array. The value should be a Boolean,
1340    *          Double, Integer, JSONArray, JSONObject, Long, or String, or the
1341    *          JSONObject.NULL object.
1342    * @return this.
1343    * @throws JSONException
1344    *           If the index is negative or if the the value is an invalid
1345    *           number.
1346    */
1347   public JSONArray put(int index, Object value) throws JSONException
1348   {
1349     if (index < 0)
1350     {
1351       throw new JSONException("JSONArray[" + index + "] not found.");
1352     }
1353     if (index < this.length())
1354     {
1355       JSONObject.testValidity(value);
1356       this.myArrayList.set(index, value);
1357       return this;
1358     }
1359     if (index == this.length())
1360     {
1361       // simple append
1362       return this.put(value);
1363     }
1364     // if we are inserting past the length, we want to grow the array all at
1365     // once
1366     // instead of incrementally.
1367     this.myArrayList.ensureCapacity(index + 1);
1368     while (index != this.length())
1369     {
1370       // we don't need to test validity of NULL objects
1371       this.myArrayList.add(JSONObject.NULL);
1372     }
1373     return this.put(value);
1374   }
1375
1376   /**
1377    * Creates a JSONPointer using an initialization string and tries to match it
1378    * to an item within this JSONArray. For example, given a JSONArray
1379    * initialized with this document:
1380    * 
1381    * <pre>
1382    * [
1383    *     {"b":"c"}
1384    * ]
1385    * </pre>
1386    * 
1387    * and this JSONPointer string:
1388    * 
1389    * <pre>
1390    * "/0/b"
1391    * </pre>
1392    * 
1393    * Then this method will return the String "c" A JSONPointerException may be
1394    * thrown from code called by this method.
1395    *
1396    * @param jsonPointer
1397    *          string that can be used to create a JSONPointer
1398    * @return the item matched by the JSONPointer, otherwise null
1399    */
1400   public Object query(String jsonPointer)
1401   {
1402     return query(new JSONPointer(jsonPointer));
1403   }
1404
1405   /**
1406    * Uses a uaer initialized JSONPointer and tries to match it to an item
1407    * whithin this JSONArray. For example, given a JSONArray initialized with
1408    * this document:
1409    * 
1410    * <pre>
1411    * [
1412    *     {"b":"c"}
1413    * ]
1414    * </pre>
1415    * 
1416    * and this JSONPointer:
1417    * 
1418    * <pre>
1419    * "/0/b"
1420    * </pre>
1421    * 
1422    * Then this method will return the String "c" A JSONPointerException may be
1423    * thrown from code called by this method.
1424    *
1425    * @param jsonPointer
1426    *          string that can be used to create a JSONPointer
1427    * @return the item matched by the JSONPointer, otherwise null
1428    */
1429   public Object query(JSONPointer jsonPointer)
1430   {
1431     return jsonPointer.queryFrom(this);
1432   }
1433
1434   /**
1435    * Queries and returns a value from this object using {@code jsonPointer}, or
1436    * returns null if the query fails due to a missing key.
1437    * 
1438    * @param jsonPointer
1439    *          the string representation of the JSON pointer
1440    * @return the queried value or {@code null}
1441    * @throws IllegalArgumentException
1442    *           if {@code jsonPointer} has invalid syntax
1443    */
1444   public Object optQuery(String jsonPointer)
1445   {
1446     return optQuery(new JSONPointer(jsonPointer));
1447   }
1448
1449   /**
1450    * Queries and returns a value from this object using {@code jsonPointer}, or
1451    * returns null if the query fails due to a missing key.
1452    * 
1453    * @param jsonPointer
1454    *          The JSON pointer
1455    * @return the queried value or {@code null}
1456    * @throws IllegalArgumentException
1457    *           if {@code jsonPointer} has invalid syntax
1458    */
1459   public Object optQuery(JSONPointer jsonPointer)
1460   {
1461     try
1462     {
1463       return jsonPointer.queryFrom(this);
1464     } catch (JSONPointerException e)
1465     {
1466       return null;
1467     }
1468   }
1469
1470   /**
1471    * Remove an index and close the hole.
1472    *
1473    * @param index
1474    *          The index of the element to be removed.
1475    * @return The value that was associated with the index, or null if there was
1476    *         no value.
1477    */
1478   public Object remove(int index)
1479   {
1480     return index >= 0 && index < this.length()
1481             ? this.myArrayList.remove(index)
1482             : null;
1483   }
1484
1485   /**
1486    * Determine if two JSONArrays are similar. They must contain similar
1487    * sequences.
1488    *
1489    * @param other
1490    *          The other JSONArray
1491    * @return true if they are equal
1492    */
1493   public boolean similar(Object other)
1494   {
1495     if (!(other instanceof JSONArray))
1496     {
1497       return false;
1498     }
1499     int len = this.length();
1500     if (len != ((JSONArray) other).length())
1501     {
1502       return false;
1503     }
1504     for (int i = 0; i < len; i += 1)
1505     {
1506       Object valueThis = this.myArrayList.get(i);
1507       Object valueOther = ((JSONArray) other).myArrayList.get(i);
1508       if (valueThis == valueOther)
1509       {
1510         continue;
1511       }
1512       if (valueThis == null)
1513       {
1514         return false;
1515       }
1516       if (valueThis instanceof JSONObject)
1517       {
1518         if (!((JSONObject) valueThis).similar(valueOther))
1519         {
1520           return false;
1521         }
1522       }
1523       else if (valueThis instanceof JSONArray)
1524       {
1525         if (!((JSONArray) valueThis).similar(valueOther))
1526         {
1527           return false;
1528         }
1529       }
1530       else if (!valueThis.equals(valueOther))
1531       {
1532         return false;
1533       }
1534     }
1535     return true;
1536   }
1537
1538   /**
1539    * Produce a JSONObject by combining a JSONArray of names with the values of
1540    * this JSONArray.
1541    *
1542    * @param names
1543    *          A JSONArray containing a list of key strings. These will be paired
1544    *          with the values.
1545    * @return A JSONObject, or null if there are no names or if this JSONArray
1546    *         has no values.
1547    * @throws JSONException
1548    *           If any of the names are null.
1549    */
1550   public JSONObject toJSONObject(JSONArray names) throws JSONException
1551   {
1552     if (names == null || names.isEmpty() || this.isEmpty())
1553     {
1554       return null;
1555     }
1556     JSONObject jo = new JSONObject(names.length());
1557     for (int i = 0; i < names.length(); i += 1)
1558     {
1559       jo.put(names.getString(i), this.opt(i));
1560     }
1561     return jo;
1562   }
1563
1564   /**
1565    * Make a JSON text of this JSONArray. For compactness, no unnecessary
1566    * whitespace is added. If it is not possible to produce a syntactically
1567    * correct JSON text then null will be returned instead. This could occur if
1568    * the array contains an invalid number.
1569    * <p>
1570    * <b> Warning: This method assumes that the data structure is acyclical. </b>
1571    *
1572    * @return a printable, displayable, transmittable representation of the
1573    *         array.
1574    */
1575   @Override
1576   public String toString()
1577   {
1578     try
1579     {
1580       return this.toString(0);
1581     } catch (Exception e)
1582     {
1583       return null;
1584     }
1585   }
1586
1587   /**
1588    * Make a pretty-printed JSON text of this JSONArray.
1589    * 
1590    * <p>
1591    * If <code>indentFactor > 0</code> and the {@link JSONArray} has only one
1592    * element, then the array will be output on a single line:
1593    * 
1594    * <pre>
1595    * {@code [1]}
1596    * </pre>
1597    * 
1598    * <p>
1599    * If an array has 2 or more elements, then it will be output across multiple
1600    * lines:
1601    * 
1602    * <pre>
1603    * {@code
1604    * [
1605    * 1,
1606    * "value 2",
1607    * 3
1608    * ]
1609    * }
1610    * </pre>
1611    * <p>
1612    * <b> Warning: This method assumes that the data structure is acyclical. </b>
1613    * 
1614    * @param indentFactor
1615    *          The number of spaces to add to each level of indentation.
1616    * @return a printable, displayable, transmittable representation of the
1617    *         object, beginning with <code>[</code>&nbsp;<small>(left
1618    *         bracket)</small> and ending with <code>]</code> &nbsp;<small>(right
1619    *         bracket)</small>.
1620    * @throws JSONException
1621    */
1622   public String toString(int indentFactor) throws JSONException
1623   {
1624     StringWriter sw = new StringWriter();
1625     synchronized (sw.getBuffer())
1626     {
1627       return this.write(sw, indentFactor, 0).toString();
1628     }
1629   }
1630
1631   /**
1632    * Write the contents of the JSONArray as JSON text to a writer. For
1633    * compactness, no whitespace is added.
1634    * <p>
1635    * <b> Warning: This method assumes that the data structure is acyclical. </b>
1636    *
1637    * @return The writer.
1638    * @throws JSONException
1639    */
1640   public Writer write(Writer writer) throws JSONException
1641   {
1642     return this.write(writer, 0, 0);
1643   }
1644
1645   /**
1646    * Write the contents of the JSONArray as JSON text to a writer.
1647    * 
1648    * <p>
1649    * If <code>indentFactor > 0</code> and the {@link JSONArray} has only one
1650    * element, then the array will be output on a single line:
1651    * 
1652    * <pre>
1653    * {@code [1]}
1654    * </pre>
1655    * 
1656    * <p>
1657    * If an array has 2 or more elements, then it will be output across multiple
1658    * lines:
1659    * 
1660    * <pre>
1661    * {@code
1662    * [
1663    * 1,
1664    * "value 2",
1665    * 3
1666    * ]
1667    * }
1668    * </pre>
1669    * <p>
1670    * <b> Warning: This method assumes that the data structure is acyclical. </b>
1671    *
1672    * @param writer
1673    *          Writes the serialized JSON
1674    * @param indentFactor
1675    *          The number of spaces to add to each level of indentation.
1676    * @param indent
1677    *          The indentation of the top level.
1678    * @return The writer.
1679    * @throws JSONException
1680    */
1681   public Writer write(Writer writer, int indentFactor, int indent)
1682           throws JSONException
1683   {
1684     try
1685     {
1686       boolean commanate = false;
1687       int length = this.length();
1688       writer.write('[');
1689
1690       if (length == 1)
1691       {
1692         try
1693         {
1694           JSONObject.writeValue(writer, this.myArrayList.get(0),
1695                   indentFactor, indent);
1696         } catch (Exception e)
1697         {
1698           throw new JSONException(
1699                   "Unable to write JSONArray value at index: 0", e);
1700         }
1701       }
1702       else if (length != 0)
1703       {
1704         final int newindent = indent + indentFactor;
1705
1706         for (int i = 0; i < length; i += 1)
1707         {
1708           if (commanate)
1709           {
1710             writer.write(',');
1711           }
1712           if (indentFactor > 0)
1713           {
1714             writer.write('\n');
1715           }
1716           JSONObject.indent(writer, newindent);
1717           try
1718           {
1719             JSONObject.writeValue(writer, this.myArrayList.get(i),
1720                     indentFactor, newindent);
1721           } catch (Exception e)
1722           {
1723             throw new JSONException(
1724                     "Unable to write JSONArray value at index: " + i, e);
1725           }
1726           commanate = true;
1727         }
1728         if (indentFactor > 0)
1729         {
1730           writer.write('\n');
1731         }
1732         JSONObject.indent(writer, indent);
1733       }
1734       writer.write(']');
1735       return writer;
1736     } catch (IOException e)
1737     {
1738       throw new JSONException(e);
1739     }
1740   }
1741
1742   /**
1743    * Returns a java.util.List containing all of the elements in this array. If
1744    * an element in the array is a JSONArray or JSONObject it will also be
1745    * converted.
1746    * <p>
1747    * Warning: This method assumes that the data structure is acyclical.
1748    *
1749    * @return a java.util.List containing the elements of this array
1750    */
1751   public List<Object> toList()
1752   {
1753     List<Object> results = new ArrayList<Object>(this.myArrayList.size());
1754     for (Object element : this.myArrayList)
1755     {
1756       if (element == null || JSONObject.NULL.equals(element))
1757       {
1758         results.add(null);
1759       }
1760       else if (element instanceof JSONArray)
1761       {
1762         results.add(((JSONArray) element).toList());
1763       }
1764       else if (element instanceof JSONObject)
1765       {
1766         results.add(((JSONObject) element).toMap());
1767       }
1768       else
1769       {
1770         results.add(element);
1771       }
1772     }
1773     return results;
1774   }
1775
1776   /**
1777    * Check if JSONArray is empty.
1778    *
1779    * @return true if JSONArray is empty, otherwise false.
1780    */
1781   public boolean isEmpty()
1782   {
1783     return myArrayList.isEmpty();
1784   }
1785
1786 }