1 package org
.gaixie
.jibu
.json
;
4 Copyright (c) 2002 JSON.org
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:
13 The above copyright notice and this permission notice shall be included in all
14 copies or substantial portions of the Software.
16 The Software shall be used for Good, not Evil.
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
27 import java
.io
.IOException
;
28 import java
.io
.Writer
;
29 import java
.lang
.reflect
.Array
;
30 import java
.util
.ArrayList
;
31 import java
.util
.Collection
;
32 import java
.util
.Iterator
;
36 * A JSONArray is an ordered sequence of values. Its external text form is a
37 * string wrapped in square brackets with commas separating the values. The
38 * internal form is an object having <code>get</code> and <code>opt</code>
39 * methods for accessing the values by index, and <code>put</code> methods for
40 * adding or replacing values. The values can be any of these types:
41 * <code>Boolean</code>, <code>JSONArray</code>, <code>JSONObject</code>,
42 * <code>Number</code>, <code>String</code>, or the
43 * <code>JSONObject.NULL object</code>.
45 * The constructor can convert a JSON text into a Java object. The
46 * <code>toString</code> method converts to JSON text.
48 * A <code>get</code> method returns a value if one can be found, and throws an
49 * exception if one cannot be found. An <code>opt</code> method returns a
50 * default value instead of throwing an exception, and so is useful for
51 * obtaining optional values.
53 * The generic <code>get()</code> and <code>opt()</code> methods return an
54 * object which you can cast or query for type. There are also typed
55 * <code>get</code> and <code>opt</code> methods that do type checking and type
58 * The texts produced by the <code>toString</code> methods strictly conform to
59 * JSON syntax rules. The constructors are more forgiving in the texts they will
62 * <li>An extra <code>,</code> <small>(comma)</small> may appear just
63 * before the closing bracket.</li>
64 * <li>The <code>null</code> value will be inserted when there
65 * is <code>,</code> <small>(comma)</small> elision.</li>
66 * <li>Strings may be quoted with <code>'</code> <small>(single
67 * quote)</small>.</li>
68 * <li>Strings do not need to be quoted at all if they do not begin with a quote
69 * or single quote, and if they do not contain leading or trailing spaces,
70 * and if they do not contain any of these characters:
71 * <code>{ } [ ] / \ : , = ; #</code> and if they do not look like numbers
72 * and if they are not the reserved words <code>true</code>,
73 * <code>false</code>, or <code>null</code>.</li>
74 * <li>Values can be separated by <code>;</code> <small>(semicolon)</small> as
75 * well as by <code>,</code> <small>(comma)</small>.</li>
76 * <li>Numbers may have the <code>0-</code> <small>(octal)</small> or
77 * <code>0x-</code> <small>(hex)</small> prefix.</li>
83 public class JSONArray
{
87 * The arrayList where the JSONArray's properties are kept.
89 private ArrayList myArrayList
;
93 * Construct an empty JSONArray.
96 this.myArrayList
= new ArrayList();
100 * Construct a JSONArray from a JSONTokener.
101 * @param x A JSONTokener
102 * @throws JSONException If there is a syntax error.
104 public JSONArray(JSONTokener x
) throws JSONException
{
106 char c
= x
.nextClean();
110 } else if (c
== '(') {
113 throw x
.syntaxError("A JSONArray text must start with '['");
115 if (x
.nextClean() == ']') {
120 if (x
.nextClean() == ',') {
122 this.myArrayList
.add(null);
125 this.myArrayList
.add(x
.nextValue());
131 if (x
.nextClean() == ']') {
139 throw x
.syntaxError("Expected a '" + new Character(q
) + "'");
143 throw x
.syntaxError("Expected a ',' or ']'");
150 * Construct a JSONArray from a source JSON text.
151 * @param source A string that begins with
152 * <code>[</code> <small>(left bracket)</small>
153 * and ends with <code>]</code> <small>(right bracket)</small>.
154 * @throws JSONException If there is a syntax error.
156 public JSONArray(String source
) throws JSONException
{
157 this(new JSONTokener(source
));
162 * Construct a JSONArray from a Collection.
163 * @param collection A Collection.
165 public JSONArray(Collection collection
) {
166 this.myArrayList
= (collection
== null) ?
168 new ArrayList(collection
);
172 * Construct a JSONArray from a collection of beans.
173 * The collection should have Java Beans.
175 * @throws JSONException If not an array.
178 public JSONArray(Collection collection
, boolean includeSuperClass
) {
179 this.myArrayList
= new ArrayList();
180 if (collection
!= null) {
181 Iterator iter
= collection
.iterator();;
182 while (iter
.hasNext()) {
183 Object o
= iter
.next();
184 if (o
instanceof Map
) {
185 this.myArrayList
.add(new JSONObject((Map
)o
, includeSuperClass
));
186 } else if (!JSONObject
.isStandardProperty(o
.getClass())) {
187 this.myArrayList
.add(new JSONObject(o
, includeSuperClass
));
189 this.myArrayList
.add(o
);
197 * Construct a JSONArray from an array
198 * @throws JSONException If not an array.
200 public JSONArray(Object array
) throws JSONException
{
202 if (array
.getClass().isArray()) {
203 int length
= Array
.getLength(array
);
204 for (int i
= 0; i
< length
; i
+= 1) {
205 this.put(Array
.get(array
, i
));
208 throw new JSONException("JSONArray initial value should be a string or collection or array.");
213 * Construct a JSONArray from an array with a bean.
214 * The array should have Java Beans.
216 * @throws JSONException If not an array.
218 public JSONArray(Object array
,boolean includeSuperClass
) throws JSONException
{
220 if (array
.getClass().isArray()) {
221 int length
= Array
.getLength(array
);
222 for (int i
= 0; i
< length
; i
+= 1) {
223 Object o
= Array
.get(array
, i
);
224 if (JSONObject
.isStandardProperty(o
.getClass())) {
225 this.myArrayList
.add(o
);
227 this.myArrayList
.add(new JSONObject(o
,includeSuperClass
));
231 throw new JSONException("JSONArray initial value should be a string or collection or array.");
238 * Get the object value associated with an index.
240 * The index must be between 0 and length() - 1.
241 * @return An object value.
242 * @throws JSONException If there is no value for the index.
244 public Object
get(int index
) throws JSONException
{
245 Object o
= opt(index
);
247 throw new JSONException("JSONArray[" + index
+ "] not found.");
254 * Get the boolean value associated with an index.
255 * The string values "true" and "false" are converted to boolean.
257 * @param index The index must be between 0 and length() - 1.
259 * @throws JSONException If there is no value for the index or if the
260 * value is not convertable to boolean.
262 public boolean getBoolean(int index
) throws JSONException
{
263 Object o
= get(index
);
264 if (o
.equals(Boolean
.FALSE
) ||
265 (o
instanceof String
&&
266 ((String
)o
).equalsIgnoreCase("false"))) {
268 } else if (o
.equals(Boolean
.TRUE
) ||
269 (o
instanceof String
&&
270 ((String
)o
).equalsIgnoreCase("true"))) {
273 throw new JSONException("JSONArray[" + index
+ "] is not a Boolean.");
278 * Get the double value associated with an index.
280 * @param index The index must be between 0 and length() - 1.
282 * @throws JSONException If the key is not found or if the value cannot
283 * be converted to a number.
285 public double getDouble(int index
) throws JSONException
{
286 Object o
= get(index
);
288 return o
instanceof Number ?
289 ((Number
)o
).doubleValue() :
290 Double
.valueOf((String
)o
).doubleValue();
291 } catch (Exception e
) {
292 throw new JSONException("JSONArray[" + index
+
293 "] is not a number.");
299 * Get the int value associated with an index.
301 * @param index The index must be between 0 and length() - 1.
303 * @throws JSONException If the key is not found or if the value cannot
304 * be converted to a number.
305 * if the value cannot be converted to a number.
307 public int getInt(int index
) throws JSONException
{
308 Object o
= get(index
);
309 return o
instanceof Number ?
310 ((Number
)o
).intValue() : (int)getDouble(index
);
315 * Get the JSONArray associated with an index.
316 * @param index The index must be between 0 and length() - 1.
317 * @return A JSONArray value.
318 * @throws JSONException If there is no value for the index. or if the
319 * value is not a JSONArray
321 public JSONArray
getJSONArray(int index
) throws JSONException
{
322 Object o
= get(index
);
323 if (o
instanceof JSONArray
) {
326 throw new JSONException("JSONArray[" + index
+
327 "] is not a JSONArray.");
332 * Get the JSONObject associated with an index.
333 * @param index subscript
334 * @return A JSONObject value.
335 * @throws JSONException If there is no value for the index or if the
336 * value is not a JSONObject
338 public JSONObject
getJSONObject(int index
) throws JSONException
{
339 Object o
= get(index
);
340 if (o
instanceof JSONObject
) {
341 return (JSONObject
)o
;
343 throw new JSONException("JSONArray[" + index
+
344 "] is not a JSONObject.");
349 * Get the long value associated with an index.
351 * @param index The index must be between 0 and length() - 1.
353 * @throws JSONException If the key is not found or if the value cannot
354 * be converted to a number.
356 public long getLong(int index
) throws JSONException
{
357 Object o
= get(index
);
358 return o
instanceof Number ?
359 ((Number
)o
).longValue() : (long)getDouble(index
);
364 * Get the string associated with an index.
365 * @param index The index must be between 0 and length() - 1.
366 * @return A string value.
367 * @throws JSONException If there is no value for the index.
369 public String
getString(int index
) throws JSONException
{
370 return get(index
).toString();
375 * Determine if the value is null.
376 * @param index The index must be between 0 and length() - 1.
377 * @return true if the value at the index is null, or if there is no value.
379 public boolean isNull(int index
) {
380 return JSONObject
.NULL
.equals(opt(index
));
385 * Make a string from the contents of this JSONArray. The
386 * <code>separator</code> string is inserted between each element.
387 * Warning: This method assumes that the data structure is acyclical.
388 * @param separator A string that will be inserted between the elements.
390 * @throws JSONException If the array contains an invalid number.
392 public String
join(String separator
) throws JSONException
{
394 StringBuffer sb
= new StringBuffer();
396 for (int i
= 0; i
< len
; i
+= 1) {
398 sb
.append(separator
);
400 sb
.append(JSONObject
.valueToString(this.myArrayList
.get(i
)));
402 return sb
.toString();
407 * Get the number of elements in the JSONArray, included nulls.
409 * @return The length (or size).
411 public int length() {
412 return this.myArrayList
.size();
417 * Get the optional object value associated with an index.
418 * @param index The index must be between 0 and length() - 1.
419 * @return An object value, or null if there is no
420 * object at that index.
422 public Object
opt(int index
) {
423 return (index
< 0 || index
>= length()) ?
424 null : this.myArrayList
.get(index
);
429 * Get the optional boolean value associated with an index.
430 * It returns false if there is no value at that index,
431 * or if the value is not Boolean.TRUE or the String "true".
433 * @param index The index must be between 0 and length() - 1.
436 public boolean optBoolean(int index
) {
437 return optBoolean(index
, false);
442 * Get the optional boolean value associated with an index.
443 * It returns the defaultValue if there is no value at that index or if
444 * it is not a Boolean or the String "true" or "false" (case insensitive).
446 * @param index The index must be between 0 and length() - 1.
447 * @param defaultValue A boolean default.
450 public boolean optBoolean(int index
, boolean defaultValue
) {
452 return getBoolean(index
);
453 } catch (Exception e
) {
460 * Get the optional double value associated with an index.
461 * NaN is returned if there is no value for the index,
462 * or if the value is not a number and cannot be converted to a number.
464 * @param index The index must be between 0 and length() - 1.
467 public double optDouble(int index
) {
468 return optDouble(index
, Double
.NaN
);
473 * Get the optional double value associated with an index.
474 * The defaultValue is returned if there is no value for the index,
475 * or if the value is not a number and cannot be converted to a number.
477 * @param index subscript
478 * @param defaultValue The default value.
481 public double optDouble(int index
, double defaultValue
) {
483 return getDouble(index
);
484 } catch (Exception e
) {
491 * Get the optional int value associated with an index.
492 * Zero is returned if there is no value for the index,
493 * or if the value is not a number and cannot be converted to a number.
495 * @param index The index must be between 0 and length() - 1.
498 public int optInt(int index
) {
499 return optInt(index
, 0);
504 * Get the optional int value associated with an index.
505 * The defaultValue is returned if there is no value for the index,
506 * or if the value is not a number and cannot be converted to a number.
507 * @param index The index must be between 0 and length() - 1.
508 * @param defaultValue The default value.
511 public int optInt(int index
, int defaultValue
) {
513 return getInt(index
);
514 } catch (Exception e
) {
521 * Get the optional JSONArray associated with an index.
522 * @param index subscript
523 * @return A JSONArray value, or null if the index has no value,
524 * or if the value is not a JSONArray.
526 public JSONArray
optJSONArray(int index
) {
527 Object o
= opt(index
);
528 return o
instanceof JSONArray ?
(JSONArray
)o
: null;
533 * Get the optional JSONObject associated with an index.
534 * Null is returned if the key is not found, or null if the index has
535 * no value, or if the value is not a JSONObject.
537 * @param index The index must be between 0 and length() - 1.
538 * @return A JSONObject value.
540 public JSONObject
optJSONObject(int index
) {
541 Object o
= opt(index
);
542 return o
instanceof JSONObject ?
(JSONObject
)o
: null;
547 * Get the optional long value associated with an index.
548 * Zero is returned if there is no value for the index,
549 * or if the value is not a number and cannot be converted to a number.
551 * @param index The index must be between 0 and length() - 1.
554 public long optLong(int index
) {
555 return optLong(index
, 0);
560 * Get the optional long value associated with an index.
561 * The defaultValue is returned if there is no value for the index,
562 * or if the value is not a number and cannot be converted to a number.
563 * @param index The index must be between 0 and length() - 1.
564 * @param defaultValue The default value.
567 public long optLong(int index
, long defaultValue
) {
569 return getLong(index
);
570 } catch (Exception e
) {
577 * Get the optional string value associated with an index. It returns an
578 * empty string if there is no value at that index. If the value
579 * is not a string and is not null, then it is coverted to a string.
581 * @param index The index must be between 0 and length() - 1.
582 * @return A String value.
584 public String
optString(int index
) {
585 return optString(index
, "");
590 * Get the optional string associated with an index.
591 * The defaultValue is returned if the key is not found.
593 * @param index The index must be between 0 and length() - 1.
594 * @param defaultValue The default value.
595 * @return A String value.
597 public String
optString(int index
, String defaultValue
) {
598 Object o
= opt(index
);
599 return o
!= null ? o
.toString() : defaultValue
;
604 * Append a boolean value. This increases the array's length by one.
606 * @param value A boolean value.
609 public JSONArray
put(boolean value
) {
610 put(value ? Boolean
.TRUE
: Boolean
.FALSE
);
616 * Put a value in the JSONArray, where the value will be a
617 * JSONArray which is produced from a Collection.
618 * @param value A Collection value.
621 public JSONArray
put(Collection value
) {
622 put(new JSONArray(value
));
628 * Append a double value. This increases the array's length by one.
630 * @param value A double value.
631 * @throws JSONException if the value is not finite.
634 public JSONArray
put(double value
) throws JSONException
{
635 Double d
= new Double(value
);
636 JSONObject
.testValidity(d
);
643 * Append an int value. This increases the array's length by one.
645 * @param value An int value.
648 public JSONArray
put(int value
) {
649 put(new Integer(value
));
655 * Append an long value. This increases the array's length by one.
657 * @param value A long value.
660 public JSONArray
put(long value
) {
661 put(new Long(value
));
667 * Put a value in the JSONArray, where the value will be a
668 * JSONObject which is produced from a Map.
669 * @param value A Map value.
672 public JSONArray
put(Map value
) {
673 put(new JSONObject(value
));
679 * Append an object value. This increases the array's length by one.
680 * @param value An object value. The value should be a
681 * Boolean, Double, Integer, JSONArray, JSONObject, Long, or String, or the
682 * JSONObject.NULL object.
685 public JSONArray
put(Object value
) {
686 this.myArrayList
.add(value
);
692 * Put or replace a boolean value in the JSONArray. If the index is greater
693 * than the length of the JSONArray, then null elements will be added as
694 * necessary to pad it out.
695 * @param index The subscript.
696 * @param value A boolean value.
698 * @throws JSONException If the index is negative.
700 public JSONArray
put(int index
, boolean value
) throws JSONException
{
701 put(index
, value ? Boolean
.TRUE
: Boolean
.FALSE
);
707 * Put a value in the JSONArray, where the value will be a
708 * JSONArray which is produced from a Collection.
709 * @param index The subscript.
710 * @param value A Collection value.
712 * @throws JSONException If the index is negative or if the value is
715 public JSONArray
put(int index
, Collection value
) throws JSONException
{
716 put(index
, new JSONArray(value
));
722 * Put or replace a double value. If the index is greater than the length of
723 * the JSONArray, then null elements will be added as necessary to pad
725 * @param index The subscript.
726 * @param value A double value.
728 * @throws JSONException If the index is negative or if the value is
731 public JSONArray
put(int index
, double value
) throws JSONException
{
732 put(index
, new Double(value
));
738 * Put or replace an int value. If the index is greater than the length of
739 * the JSONArray, then null elements will be added as necessary to pad
741 * @param index The subscript.
742 * @param value An int value.
744 * @throws JSONException If the index is negative.
746 public JSONArray
put(int index
, int value
) throws JSONException
{
747 put(index
, new Integer(value
));
753 * Put or replace a long value. If the index is greater than the length of
754 * the JSONArray, then null elements will be added as necessary to pad
756 * @param index The subscript.
757 * @param value A long value.
759 * @throws JSONException If the index is negative.
761 public JSONArray
put(int index
, long value
) throws JSONException
{
762 put(index
, new Long(value
));
768 * Put a value in the JSONArray, where the value will be a
769 * JSONObject which is produced from a Map.
770 * @param index The subscript.
771 * @param value The Map value.
773 * @throws JSONException If the index is negative or if the the value is
776 public JSONArray
put(int index
, Map value
) throws JSONException
{
777 put(index
, new JSONObject(value
));
783 * Put or replace an object value in the JSONArray. If the index is greater
784 * than the length of the JSONArray, then null elements will be added as
785 * necessary to pad it out.
786 * @param index The subscript.
787 * @param value The value to put into the array. The value should be a
788 * Boolean, Double, Integer, JSONArray, JSONObject, Long, or String, or the
789 * JSONObject.NULL object.
791 * @throws JSONException If the index is negative or if the the value is
794 public JSONArray
put(int index
, Object value
) throws JSONException
{
795 JSONObject
.testValidity(value
);
797 throw new JSONException("JSONArray[" + index
+ "] not found.");
799 if (index
< length()) {
800 this.myArrayList
.set(index
, value
);
802 while (index
!= length()) {
803 put(JSONObject
.NULL
);
812 * Remove an index and close the hole.
813 * @param index The index of the element to be removed.
814 * @return The value that was associated with the index,
815 * or null if there was no value.
817 public Object
remove(int index
) {
818 Object o
= opt(index
);
819 this.myArrayList
.remove(index
);
825 * Produce a JSONObject by combining a JSONArray of names with the values
827 * @param names A JSONArray containing a list of key strings. These will be
828 * paired with the values.
829 * @return A JSONObject, or null if there are no names or if this JSONArray
831 * @throws JSONException If any of the names are null.
833 public JSONObject
toJSONObject(JSONArray names
) throws JSONException
{
834 if (names
== null || names
.length() == 0 || length() == 0) {
837 JSONObject jo
= new JSONObject();
838 for (int i
= 0; i
< names
.length(); i
+= 1) {
839 jo
.put(names
.getString(i
), this.opt(i
));
846 * Make a JSON text of this JSONArray. For compactness, no
847 * unnecessary whitespace is added. If it is not possible to produce a
848 * syntactically correct JSON text then null will be returned instead. This
849 * could occur if the array contains an invalid number.
851 * Warning: This method assumes that the data structure is acyclical.
853 * @return a printable, displayable, transmittable
854 * representation of the array.
856 public String
toString() {
858 return '[' + join(",") + ']';
859 } catch (Exception e
) {
866 * Make a prettyprinted JSON text of this JSONArray.
867 * Warning: This method assumes that the data structure is acyclical.
868 * @param indentFactor The number of spaces to add to each level of
870 * @return a printable, displayable, transmittable
871 * representation of the object, beginning
872 * with <code>[</code> <small>(left bracket)</small> and ending
873 * with <code>]</code> <small>(right bracket)</small>.
874 * @throws JSONException
876 public String
toString(int indentFactor
) throws JSONException
{
877 return toString(indentFactor
, 0);
882 * Make a prettyprinted JSON text of this JSONArray.
883 * Warning: This method assumes that the data structure is acyclical.
884 * @param indentFactor The number of spaces to add to each level of
886 * @param indent The indention of the top level.
887 * @return a printable, displayable, transmittable
888 * representation of the array.
889 * @throws JSONException
891 String
toString(int indentFactor
, int indent
) throws JSONException
{
897 StringBuffer sb
= new StringBuffer("[");
899 sb
.append(JSONObject
.valueToString(this.myArrayList
.get(0),
900 indentFactor
, indent
));
902 int newindent
= indent
+ indentFactor
;
904 for (i
= 0; i
< len
; i
+= 1) {
908 for (int j
= 0; j
< newindent
; j
+= 1) {
911 sb
.append(JSONObject
.valueToString(this.myArrayList
.get(i
),
912 indentFactor
, newindent
));
915 for (i
= 0; i
< indent
; i
+= 1) {
920 return sb
.toString();
925 * Write the contents of the JSONArray as JSON text to a writer.
926 * For compactness, no whitespace is added.
928 * Warning: This method assumes that the data structure is acyclical.
930 * @return The writer.
931 * @throws JSONException
933 public Writer
write(Writer writer
) throws JSONException
{
940 for (int i
= 0; i
< len
; i
+= 1) {
944 Object v
= this.myArrayList
.get(i
);
945 if (v
instanceof JSONObject
) {
946 ((JSONObject
)v
).write(writer
);
947 } else if (v
instanceof JSONArray
) {
948 ((JSONArray
)v
).write(writer
);
950 writer
.write(JSONObject
.valueToString(v
));
956 } catch (IOException e
) {
957 throw new JSONException(e
);