http://git-wip-us.apache.org/repos/asf/wicket/blob/0ba87f06/wicket-core/src/main/java/org/apache/wicket/ajax/json/JSONArray.java
----------------------------------------------------------------------
diff --git 
a/wicket-core/src/main/java/org/apache/wicket/ajax/json/JSONArray.java 
b/wicket-core/src/main/java/org/apache/wicket/ajax/json/JSONArray.java
old mode 100755
new mode 100644
index d328d0c..914f8a6
--- a/wicket-core/src/main/java/org/apache/wicket/ajax/json/JSONArray.java
+++ b/wicket-core/src/main/java/org/apache/wicket/ajax/json/JSONArray.java
@@ -1,907 +1,728 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
 package org.apache.wicket.ajax.json;
 
-/*
-Copyright (c) 2002 JSON.org
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-The Software shall be used for Good, not Evil.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
-*/
-
-import java.io.IOException;
-import java.io.StringWriter;
-import java.io.Writer;
 import java.lang.reflect.Array;
 import java.util.ArrayList;
 import java.util.Collection;
-import java.util.Iterator;
-import java.util.Map;
+import java.util.List;
+
+// Note: this class was written without inspecting the non-free org.json 
sourcecode.
 
 /**
- * A JSONArray is an ordered sequence of values. Its external text form is a
- * string wrapped in square brackets with commas separating the values. The
- * internal form is an object having <code>get</code> and <code>opt</code>
- * methods for accessing the values by index, and <code>put</code> methods for
- * adding or replacing values. The values can be any of these types:
- * <code>Boolean</code>, <code>JSONArray</code>, <code>JSONObject</code>,
- * <code>Number</code>, <code>String</code>, or the
- * <code>JSONObject.NULL object</code>.
- * <p>
- * The constructor can convert a JSON text into a Java object. The
- * <code>toString</code> method converts to JSON text.
- * <p>
- * A <code>get</code> method returns a value if one can be found, and throws an
- * exception if one cannot be found. An <code>opt</code> method returns a
- * default value instead of throwing an exception, and so is useful for
- * obtaining optional values.
- * <p>
- * The generic <code>get()</code> and <code>opt()</code> methods return an
- * object which you can cast or query for type. There are also typed
- * <code>get</code> and <code>opt</code> methods that do type checking and type
- * coercion for you.
- * <p>
- * The texts produced by the <code>toString</code> methods strictly conform to
- * JSON syntax rules. The constructors are more forgiving in the texts they 
will
- * accept:
- * <ul>
- * <li>An extra <code>,</code>&nbsp;<small>(comma)</small> may appear just
- * before the closing bracket.</li>
- * <li>The <code>null</code> value will be inserted when there is 
<code>,</code>
- * &nbsp;<small>(comma)</small> elision.</li>
- * <li>Strings may be quoted with <code>'</code>&nbsp;<small>(single
- * quote)</small>.</li>
- * <li>Strings do not need to be quoted at all if they do not begin with a 
quote
- * or single quote, and if they do not contain leading or trailing spaces, and
- * if they do not contain any of these characters:
- * <code>{ } [ ] / \ : , = ; #</code> and if they do not look like numbers and
- * if they are not the reserved words <code>true</code>, <code>false</code>, or
- * <code>null</code>.</li>
- * <li>Values can be separated by <code>;</code> <small>(semicolon)</small> as
- * well as by <code>,</code> <small>(comma)</small>.</li>
- * </ul>
+ * A dense indexed sequence of values. Values may be any mix of
+ * {@link JSONObject JSONObjects}, other {@link JSONArray JSONArrays}, Strings,
+ * Booleans, Integers, Longs, Doubles, {@code null} or {@link JSONObject#NULL}.
+ * Values may not be {@link Double#isNaN() NaNs}, {@link Double#isInfinite()
+ * infinities}, or of any type not listed here.
  *
- * @author JSON.org
- * @version 2012-04-20
+ * {@code JSONArray} has the same type coercion behavior and
+ * optional/mandatory accessors as {@link JSONObject}. See that class'
+ * documentation for details.
+ *
+ * <strong>Warning:</strong> this class represents null in two incompatible
+ * ways: the standard Java {@code null} reference, and the sentinel value 
{@link
+ * JSONObject#NULL}. In particular, {@code get} fails if the requested index
+ * holds the null reference, but succeeds if it holds {@code JSONObject.NULL}.
+ *
+ * Instances of this class are not thread safe. Although this class is
+ * non-final, it was not designed for inheritance and should not be subclassed.
+ * In particular, self-use by overridable methods is not specified. See
+ * <i>Effective Java</i> Item 17, "Design and Document or inheritance or else
+ * prohibit it" for further information.
  */
 public class JSONArray {
 
+    private final List<Object> values;
 
     /**
-     * The arrayList where the JSONArray's properties are kept.
-     */
-    private final ArrayList myArrayList;
-
-
-    /**
-     * Construct an empty JSONArray.
+     * Creates a {@code JSONArray} with no values.
      */
     public JSONArray() {
-        this.myArrayList = new ArrayList();
+        values = new ArrayList<Object>();
     }
 
     /**
-     * Construct a JSONArray from a JSONTokener.
-     * @param x A JSONTokener
-     * @throws JSONException If there is a syntax error.
+     * Creates a new {@code JSONArray} by copying all values from the given
+     * collection.
+     *
+     * @param copyFrom a collection whose values are of supported types.
+     *                 Unsupported values are not permitted and will yield an 
array in an
+     *                 inconsistent state.
      */
-    public JSONArray(JSONTokener x) throws JSONException {
+    /* Accept a raw type for API compatibility */
+    public JSONArray(Collection copyFrom) {
         this();
-        if (x.nextClean() != '[') {
-            throw x.syntaxError("A JSONArray text must start with '['");
-        }
-        if (x.nextClean() != ']') {
-            x.back();
-            for (;;) {
-                if (x.nextClean() == ',') {
-                    x.back();
-                    this.myArrayList.add(JSONObject.NULL);
-                } else {
-                    x.back();
-                    this.myArrayList.add(x.nextValue());
-                }
-                switch (x.nextClean()) {
-                case ';':
-                case ',':
-                    if (x.nextClean() == ']') {
-                        return;
-                    }
-                    x.back();
-                    break;
-                case ']':
-                    return;
-                default:
-                    throw x.syntaxError("Expected a ',' or ']'");
-                }
+        if (copyFrom != null) {
+            for (Object aCopyFrom : copyFrom) {
+                put(JSONObject.wrap(aCopyFrom));
             }
         }
     }
 
-
     /**
-     * Construct a JSONArray from a source JSON text.
-     * @param source     A string that begins with
-     * <code>[</code>&nbsp;<small>(left bracket)</small>
-     *  and ends with <code>]</code>&nbsp;<small>(right bracket)</small>.
-     *  @throws JSONException If there is a syntax error.
-     */
-    public JSONArray(String source) throws JSONException {
-        this(new JSONTokener(source));
+     * Creates a new {@code JSONArray} with values from the next array in the
+     * tokener.
+     *
+     * @param readFrom a tokener whose nextValue() method will yield a
+     *                 {@code JSONArray}.
+     * @throws JSONException if the parse fails or doesn't yield a
+     *                       {@code JSONArray}.
+     */
+    public JSONArray(JSONTokener readFrom) throws JSONException {
+        /*
+         * Getting the parser to populate this could get tricky. Instead, just
+         * parse to temporary JSONArray and then steal the data from that.
+         */
+        Object object = readFrom.nextValue();
+        if (object instanceof JSONArray) {
+            values = ((JSONArray) object).values;
+        } else {
+            throw JSON.typeMismatch(object, "JSONArray");
+        }
     }
 
-
     /**
-     * Construct a JSONArray from a Collection.
-     * @param collection     A Collection.
+     * Creates a new {@code JSONArray} with values from the JSON string.
+     *
+     * @param json a JSON-encoded string containing an array.
+     * @throws JSONException if the parse fails or doesn't yield a {@code
+     *                       JSONArray}.
      */
-    public JSONArray(Collection collection) {
-        this.myArrayList = new ArrayList();
-        if (collection != null) {
-            Iterator iter = collection.iterator();
-            while (iter.hasNext()) {
-                this.myArrayList.add(JSONObject.wrap(iter.next()));
-            }
-        }
+    public JSONArray(String json) throws JSONException {
+        this(new JSONTokener(json));
     }
 
-
     /**
-     * Construct a JSONArray from an array
-     * @throws JSONException If not an array.
+     * Creates a new {@code JSONArray} with values from the given primitive 
array.
+     *
+     * @param array The values to use.
+     * @throws JSONException if any of the values are non-finite double values 
(i.e. NaN or infinite)
      */
     public JSONArray(Object array) throws JSONException {
-        this();
-        if (array.getClass().isArray()) {
-            int length = Array.getLength(array);
-            for (int i = 0; i < length; i += 1) {
-                this.put(JSONObject.wrap(Array.get(array, i)));
-            }
-        } else {
-            throw new JSONException(
-"JSONArray initial value should be a string or collection or array.");
+        if (!array.getClass().isArray()) {
+            throw new JSONException("Not a primitive array: " + 
array.getClass());
         }
-    }
-
-
-    /**
-     * Get the object value associated with an index.
-     * @param index
-     *  The index must be between 0 and length() - 1.
-     * @return An object value.
-     * @throws JSONException If there is no value for the index.
-     */
-    public Object get(int index) throws JSONException {
-        Object object = this.opt(index);
-        if (object == null) {
-            throw new JSONException("JSONArray[" + index + "] not found.");
+        final int length = Array.getLength(array);
+        values = new ArrayList<Object>(length);
+        for (int i = 0; i < length; ++i) {
+            put(JSONObject.wrap(Array.get(array, i)));
         }
-        return object;
     }
 
-
     /**
-     * Get the boolean value associated with an index.
-     * The string values "true" and "false" are converted to boolean.
-     *
-     * @param index The index must be between 0 and length() - 1.
-     * @return      The truth.
-     * @throws JSONException If there is no value for the index or if the
-     *  value is not convertible to boolean.
+     * @return Returns the number of values in this array.
      */
-    public boolean getBoolean(int index) throws JSONException {
-        Object object = this.get(index);
-        if (object.equals(Boolean.FALSE) ||
-                (object instanceof String &&
-                ((String)object).equalsIgnoreCase("false"))) {
-            return false;
-        } else if (object.equals(Boolean.TRUE) ||
-                (object instanceof String &&
-                ((String)object).equalsIgnoreCase("true"))) {
-            return true;
-        }
-        throw new JSONException("JSONArray[" + index + "] is not a boolean.");
+    public int length() {
+        return values.size();
     }
 
-
     /**
-     * Get the double value associated with an index.
+     * Appends {@code value} to the end of this array.
      *
-     * @param index The index must be between 0 and length() - 1.
-     * @return      The value.
-     * @throws   JSONException If the key is not found or if the value cannot
-     *  be converted to a number.
+     * @param value The value to append.
+     * @return this array.
      */
-    public double getDouble(int index) throws JSONException {
-        Object object = this.get(index);
-        try {
-            return object instanceof Number
-                ? ((Number)object).doubleValue()
-                : Double.parseDouble((String)object);
-        } catch (Exception e) {
-            throw new JSONException("JSONArray[" + index +
-                "] is not a number.");
-        }
+    public JSONArray put(boolean value) {
+        values.add(value);
+        return this;
     }
 
-
     /**
-     * Get the int value associated with an index.
+     * Appends {@code value} to the end of this array.
      *
-     * @param index The index must be between 0 and length() - 1.
-     * @return      The value.
-     * @throws   JSONException If the key is not found or if the value is not 
a number.
+     * @param value a finite value. May not be {@link Double#isNaN() NaNs} or
+     *              {@link Double#isInfinite() infinities}.
+     * @return this array.
+     * @throws JSONException If the value is unacceptable.
      */
-    public int getInt(int index) throws JSONException {
-        Object object = this.get(index);
-        try {
-            return object instanceof Number
-                ? ((Number)object).intValue()
-                : Integer.parseInt((String)object);
-        } catch (Exception e) {
-            throw new JSONException("JSONArray[" + index +
-                "] is not a number.");
-        }
+    public JSONArray put(double value) throws JSONException {
+        values.add(JSON.checkDouble(value));
+        return this;
     }
 
-
     /**
-     * Get the JSONArray associated with an index.
-     * @param index The index must be between 0 and length() - 1.
-     * @return      A JSONArray value.
-     * @throws JSONException If there is no value for the index. or if the
-     * value is not a JSONArray
+     * Appends {@code value} to the end of this array.
+     *
+     * @param value The value to append.
+     * @return this array.
      */
-    public JSONArray getJSONArray(int index) throws JSONException {
-        Object object = this.get(index);
-        if (object instanceof JSONArray) {
-            return (JSONArray)object;
-        }
-        throw new JSONException("JSONArray[" + index +
-                "] is not a JSONArray.");
+    public JSONArray put(int value) {
+        values.add(value);
+        return this;
     }
 
-
     /**
-     * Get the JSONObject associated with an index.
-     * @param index subscript
-     * @return      A JSONObject value.
-     * @throws JSONException If there is no value for the index or if the
-     * value is not a JSONObject
+     * Appends {@code value} to the end of this array.
+     *
+     * @param value The value to append.
+     * @return this array.
      */
-    public JSONObject getJSONObject(int index) throws JSONException {
-        Object object = this.get(index);
-        if (object instanceof JSONObject) {
-            return (JSONObject)object;
-        }
-        throw new JSONException("JSONArray[" + index +
-            "] is not a JSONObject.");
+    public JSONArray put(long value) {
+        values.add(value);
+        return this;
     }
 
-
     /**
-     * Get the long value associated with an index.
+     * Appends {@code value} to the end of this array.
      *
-     * @param index The index must be between 0 and length() - 1.
-     * @return      The value.
-     * @throws   JSONException If the key is not found or if the value cannot
-     *  be converted to a number.
+     * @param value a {@link JSONObject}, {@link JSONArray}, String, Boolean,
+     *              Integer, Long, Double, {@link JSONObject#NULL}, or {@code 
null}. May
+     *              not be {@link Double#isNaN() NaNs} or {@link 
Double#isInfinite()
+     *              infinities}. Unsupported values are not permitted and will 
cause the
+     *              array to be in an inconsistent state.
+     * @return this array.
      */
-    public long getLong(int index) throws JSONException {
-        Object object = this.get(index);
-        try {
-            return object instanceof Number
-                ? ((Number)object).longValue()
-                : Long.parseLong((String)object);
-        } catch (Exception e) {
-            throw new JSONException("JSONArray[" + index +
-                "] is not a number.");
-        }
+    public JSONArray put(Object value) {
+        values.add(value);
+        return this;
     }
 
-
     /**
-     * Get the string associated with an index.
-     * @param index The index must be between 0 and length() - 1.
-     * @return      A string value.
-     * @throws JSONException If there is no string value for the index.
+     * Same as {@link #put}, with added validity checks.
+     *
+     * @param value The value to append.
      */
-    public String getString(int index) throws JSONException {
-        Object object = this.get(index);
-        if (object instanceof String) {
-            return (String)object;
+    void checkedPut(Object value) throws JSONException {
+        if (value instanceof Number) {
+            JSON.checkDouble(((Number) value).doubleValue());
         }
-        throw new JSONException("JSONArray[" + index + "] not a string.");
-    }
-
 
-    /**
-     * Determine if the value is null.
-     * @param index The index must be between 0 and length() - 1.
-     * @return true if the value at the index is null, or if there is no value.
-     */
-    public boolean isNull(int index) {
-        return JSONObject.NULL.equals(this.opt(index));
+        put(value);
     }
 
-
     /**
-     * Make a string from the contents of this JSONArray. The
-     * <code>separator</code> string is inserted between each element.
-     * Warning: This method assumes that the data structure is acyclical.
-     * @param separator A string that will be inserted between the elements.
-     * @return a string.
-     * @throws JSONException If the array contains an invalid number.
+     * Sets the value at {@code index} to {@code value}, null padding this 
array
+     * to the required length if necessary. If a value already exists at {@code
+     * index}, it will be replaced.
+     *
+     * @param index Where to put the value.
+     * @param value The value to set.
+     * @return this array.
+     * @throws JSONException This should never happen.
      */
-    public String join(String separator) throws JSONException {
-        int len = this.length();
-        StringBuffer sb = new StringBuffer();
-
-        for (int i = 0; i < len; i += 1) {
-            if (i > 0) {
-                sb.append(separator);
-            }
-            sb.append(JSONObject.valueToString(this.myArrayList.get(i)));
-        }
-        return sb.toString();
+    public JSONArray put(int index, boolean value) throws JSONException {
+        return put(index, (Boolean) value);
     }
 
-
     /**
-     * Get the number of elements in the JSONArray, included nulls.
+     * Sets the value at {@code index} to {@code value}, null padding this 
array
+     * to the required length if necessary. If a value already exists at {@code
+     * index}, it will be replaced.
      *
-     * @return The length (or size).
+     * @param index Where to put the value.
+     * @param value a finite value. May not be {@link Double#isNaN() NaNs} or
+     *              {@link Double#isInfinite() infinities}.
+     * @return this array.
+     * @throws JSONException If the value is not a finite value.
      */
-    public int length() {
-        return this.myArrayList.size();
+    public JSONArray put(int index, double value) throws JSONException {
+        return put(index, (Double) value);
     }
 
-
     /**
-     * Get the optional object value associated with an index.
-     * @param index The index must be between 0 and length() - 1.
-     * @return      An object value, or null if there is no
-     *              object at that index.
+     * Sets the value at {@code index} to {@code value}, null padding this 
array
+     * to the required length if necessary. If a value already exists at {@code
+     * index}, it will be replaced.
+     *
+     * @param index Where to put the value.
+     * @param value The value to set.
+     * @return this array.
+     * @throws JSONException Should never actually happen.
      */
-    public Object opt(int index) {
-        return (index < 0 || index >= this.length())
-            ? null
-            : this.myArrayList.get(index);
+    public JSONArray put(int index, int value) throws JSONException {
+        return put(index, (Integer) value);
     }
 
-
     /**
-     * Get the optional boolean value associated with an index.
-     * It returns false if there is no value at that index,
-     * or if the value is not Boolean.TRUE or the String "true".
+     * Sets the value at {@code index} to {@code value}, null padding this 
array
+     * to the required length if necessary. If a value already exists at {@code
+     * index}, it will be replaced.
      *
-     * @param index The index must be between 0 and length() - 1.
-     * @return      The truth.
+     * @param index Where to put the value.
+     * @param value The value to set.
+     * @return this array.
+     * @throws JSONException Should never actually happen.
      */
-    public boolean optBoolean(int index)  {
-        return this.optBoolean(index, false);
+    public JSONArray put(int index, long value) throws JSONException {
+        return put(index, (Long) value);
     }
 
-
     /**
-     * Get the optional boolean value associated with an index.
-     * It returns the defaultValue if there is no value at that index or if
-     * it is not a Boolean or the String "true" or "false" (case insensitive).
+     * Sets the value at {@code index} to {@code value}, null padding this 
array
+     * to the required length if necessary. If a value already exists at {@code
+     * index}, it will be replaced.
      *
-     * @param index The index must be between 0 and length() - 1.
-     * @param defaultValue     A boolean default.
-     * @return      The truth.
+     * @param index Where to put the value.
+     * @param value a {@link JSONObject}, {@link JSONArray}, String, Boolean,
+     *              Integer, Long, Double, {@link JSONObject#NULL}, or {@code 
null}. May
+     *              not be {@link Double#isNaN() NaNs} or {@link 
Double#isInfinite()
+     *              infinities}.
+     * @return this array.
+     * @throws JSONException If the value cannot be represented as a finite 
double value.
      */
-    public boolean optBoolean(int index, boolean defaultValue)  {
-        try {
-            return this.getBoolean(index);
-        } catch (Exception e) {
-            return defaultValue;
+    public JSONArray put(int index, Object value) throws JSONException {
+        if (value instanceof Number) {
+            // deviate from the original by checking all Numbers, not just 
floats & doubles
+            JSON.checkDouble(((Number) value).doubleValue());
         }
+        while (values.size() <= index) {
+            values.add(null);
+        }
+        values.set(index, value);
+        return this;
     }
 
-
     /**
-     * Get the optional double value associated with an index.
-     * NaN is returned if there is no value for the index,
-     * or if the value is not a number and cannot be converted to a number.
+     * Returns true if this array has no value at {@code index}, or if its 
value
+     * is the {@code null} reference or {@link JSONObject#NULL}.
      *
-     * @param index The index must be between 0 and length() - 1.
-     * @return      The value.
+     * @param index Which value to check.
+     * @return true if the value is null.
      */
-    public double optDouble(int index) {
-        return this.optDouble(index, Double.NaN);
+    public boolean isNull(int index) {
+        Object value = opt(index);
+        return value == null || value == JSONObject.NULL;
     }
 
-
     /**
-     * Get the optional double value associated with an index.
-     * The defaultValue is returned if there is no value for the index,
-     * or if the value is not a number and cannot be converted to a number.
+     * Returns the value at {@code index}.
      *
-     * @param index subscript
-     * @param defaultValue     The default value.
-     * @return      The value.
+     * @param index Which value to get.
+     * @return the value at the specified location.
+     * @throws JSONException if this array has no value at {@code index}, or if
+     *                       that value is the {@code null} reference. This 
method returns
+     *                       normally if the value is {@code JSONObject#NULL}.
      */
-    public double optDouble(int index, double defaultValue) {
+    public Object get(int index) throws JSONException {
         try {
-            return this.getDouble(index);
-        } catch (Exception e) {
-            return defaultValue;
+            Object value = values.get(index);
+            if (value == null) {
+                throw new JSONException("Value at " + index + " is null.");
+            }
+            return value;
+        } catch (IndexOutOfBoundsException e) {
+            throw new JSONException("Index " + index + " out of range [0.." + 
values.size() + ")");
         }
     }
 
-
     /**
-     * Get the optional int value associated with an index.
-     * Zero is returned if there is no value for the index,
-     * or if the value is not a number and cannot be converted to a number.
+     * Returns the value at {@code index}, or null if the array has no value
+     * at {@code index}.
      *
-     * @param index The index must be between 0 and length() - 1.
-     * @return      The value.
+     * @param index Which value to get.
+     * @return the value at the specified location.
      */
-    public int optInt(int index) {
-        return this.optInt(index, 0);
+    public Object opt(int index) {
+        if (index < 0 || index >= values.size()) {
+            return null;
+        }
+        return values.get(index);
     }
 
-
     /**
-     * Get the optional int value associated with an index.
-     * The defaultValue is returned if there is no value for the index,
-     * or if the value is not a number and cannot be converted to a number.
-     * @param index The index must be between 0 and length() - 1.
-     * @param defaultValue     The default value.
-     * @return      The value.
+     * Removes and returns the value at {@code index}, or null if the array 
has no value
+     * at {@code index}.
+     *
+     * @param index Which value to remove.
+     * @return The value previously at the specified location.
      */
-    public int optInt(int index, int defaultValue) {
-        try {
-            return this.getInt(index);
-        } catch (Exception e) {
-            return defaultValue;
+    public Object remove(int index) {
+        if (index < 0 || index >= values.size()) {
+            return null;
         }
+        return values.remove(index);
     }
 
-
     /**
-     * Get the optional JSONArray associated with an index.
-     * @param index subscript
-     * @return      A JSONArray value, or null if the index has no value,
-     * or if the value is not a JSONArray.
+     * Returns the value at {@code index} if it exists and is a boolean or can
+     * be coerced to a boolean.
+     *
+     * @param index Which value to get.
+     * @return the value at the specified location.
+     * @throws JSONException if the value at {@code index} doesn't exist or
+     *                       cannot be coerced to a boolean.
      */
-    public JSONArray optJSONArray(int index) {
-        Object o = this.opt(index);
-        return o instanceof JSONArray ? (JSONArray)o : null;
+    public boolean getBoolean(int index) throws JSONException {
+        Object object = get(index);
+        Boolean result = JSON.toBoolean(object);
+        if (result == null) {
+            throw JSON.typeMismatch(index, object, "boolean");
+        }
+        return result;
     }
 
-
     /**
-     * Get the optional JSONObject associated with an index.
-     * Null is returned if the key is not found, or null if the index has
-     * no value, or if the value is not a JSONObject.
+     * Returns the value at {@code index} if it exists and is a boolean or can
+     * be coerced to a boolean. Returns false otherwise.
      *
-     * @param index The index must be between 0 and length() - 1.
-     * @return      A JSONObject value.
+     * @param index Which value to get.
+     * @return the value at the specified location.
      */
-    public JSONObject optJSONObject(int index) {
-        Object o = this.opt(index);
-        return o instanceof JSONObject ? (JSONObject)o : null;
+    public boolean optBoolean(int index) {
+        return optBoolean(index, false);
     }
 
-
     /**
-     * Get the optional long value associated with an index.
-     * Zero is returned if there is no value for the index,
-     * or if the value is not a number and cannot be converted to a number.
+     * Returns the value at {@code index} if it exists and is a boolean or can
+     * be coerced to a boolean. Returns {@code fallback} otherwise.
      *
-     * @param index The index must be between 0 and length() - 1.
-     * @return      The value.
+     * @param index    Which value to get.
+     * @param fallback the fallback value to return if no value exists.
+     * @return the value at the specified location or the fallback value.
      */
-    public long optLong(int index) {
-        return this.optLong(index, 0);
+    public boolean optBoolean(int index, boolean fallback) {
+        Object object = opt(index);
+        Boolean result = JSON.toBoolean(object);
+        return result != null ? result : fallback;
     }
 
-
     /**
-     * Get the optional long value associated with an index.
-     * The defaultValue is returned if there is no value for the index,
-     * or if the value is not a number and cannot be converted to a number.
-     * @param index The index must be between 0 and length() - 1.
-     * @param defaultValue     The default value.
-     * @return      The value.
+     * Returns the value at {@code index} if it exists and is a double or can
+     * be coerced to a double.
+     *
+     * @param index Which value to get.
+     * @return the value at the specified location.
+     * @throws JSONException if the value at {@code index} doesn't exist or
+     *                       cannot be coerced to a double.
      */
-    public long optLong(int index, long defaultValue) {
-        try {
-            return this.getLong(index);
-        } catch (Exception e) {
-            return defaultValue;
+    public double getDouble(int index) throws JSONException {
+        Object object = get(index);
+        Double result = JSON.toDouble(object);
+        if (result == null) {
+            throw JSON.typeMismatch(index, object, "double");
         }
+        return result;
     }
 
-
     /**
-     * Get the optional string value associated with an index. It returns an
-     * empty string if there is no value at that index. If the value
-     * is not a string and is not null, then it is coverted to a string.
+     * Returns the value at {@code index} if it exists and is a double or can
+     * be coerced to a double. Returns {@code NaN} otherwise.
      *
-     * @param index The index must be between 0 and length() - 1.
-     * @return      A String value.
+     * @param index Which value to get.
+     * @return the value at the specified location.
      */
-    public String optString(int index) {
-        return this.optString(index, "");
+    public double optDouble(int index) {
+        return optDouble(index, Double.NaN);
     }
 
-
     /**
-     * Get the optional string associated with an index.
-     * The defaultValue is returned if the key is not found.
+     * Returns the value at {@code index} if it exists and is a double or can
+     * be coerced to a double. Returns {@code fallback} otherwise.
      *
-     * @param index The index must be between 0 and length() - 1.
-     * @param defaultValue     The default value.
-     * @return      A String value.
+     * @param index    Which value to get.
+     * @param fallback The fallback value to use if no value is at the 
specified location.
+     * @return the value at the specified location or the fallback value.
      */
-    public String optString(int index, String defaultValue) {
-        Object object = this.opt(index);
-        return JSONObject.NULL.equals(object)
- ? defaultValue : object
-                .toString();
+    public double optDouble(int index, double fallback) {
+        Object object = opt(index);
+        Double result = JSON.toDouble(object);
+        return result != null ? result : fallback;
     }
 
-
     /**
-     * Append a boolean value. This increases the array's length by one.
+     * Returns the value at {@code index} if it exists and is an int or
+     * can be coerced to an int.
      *
-     * @param value A boolean value.
-     * @return this.
+     * @param index Which value to get.
+     * @return the value at the specified location.
+     * @throws JSONException if the value at {@code index} doesn't exist or
+     *                       cannot be coerced to a int.
      */
-    public JSONArray put(boolean value) {
-        this.put(value ? Boolean.TRUE : Boolean.FALSE);
-        return this;
-    }
-
-
-    /**
-     * Put a value in the JSONArray, where the value will be a
-     * JSONArray which is produced from a Collection.
-     * @param value A Collection value.
-     * @return      this.
-     */
-    public JSONArray put(Collection value) {
-        this.put(new JSONArray(value));
-        return this;
+    public int getInt(int index) throws JSONException {
+        Object object = get(index);
+        Integer result = JSON.toInteger(object);
+        if (result == null) {
+            throw JSON.typeMismatch(index, object, "int");
+        }
+        return result;
     }
 
-
     /**
-     * Append a double value. This increases the array's length by one.
+     * Returns the value at {@code index} if it exists and is an int or
+     * can be coerced to an int. Returns 0 otherwise.
      *
-     * @param value A double value.
-     * @throws JSONException if the value is not finite.
-     * @return this.
+     * @param index Which value to get.
+     * @return the value at the specified location.
      */
-    public JSONArray put(double value) throws JSONException {
-        Double d = new Double(value);
-        JSONObject.testValidity(d);
-        this.put(d);
-        return this;
+    public int optInt(int index) {
+        return optInt(index, 0);
     }
 
-
     /**
-     * Append an int value. This increases the array's length by one.
+     * Returns the value at {@code index} if it exists and is an int or
+     * can be coerced to an int. Returns {@code fallback} otherwise.
      *
-     * @param value An int value.
-     * @return this.
+     * @param index    Which value to get.
+     * @param fallback The fallback value to use if no value is at the 
specified location.
+     * @return the value at the specified location or the fallback value.
      */
-    public JSONArray put(int value) {
-        this.put(new Integer(value));
-        return this;
+    public int optInt(int index, int fallback) {
+        Object object = opt(index);
+        Integer result = JSON.toInteger(object);
+        return result != null ? result : fallback;
     }
 
-
     /**
-     * Append an long value. This increases the array's length by one.
+     * Returns the value at {@code index} if it exists and is a long or
+     * can be coerced to a long.
      *
-     * @param value A long value.
-     * @return this.
+     * @param index Which value to get.
+     * @return the value at the specified location.
+     * @throws JSONException if the value at {@code index} doesn't exist or
+     *                       cannot be coerced to a long.
      */
-    public JSONArray put(long value) {
-        this.put(new Long(value));
-        return this;
-    }
-
-
-    /**
-     * Put a value in the JSONArray, where the value will be a
-     * JSONObject which is produced from a Map.
-     * @param value A Map value.
-     * @return      this.
-     */
-    public JSONArray put(Map value) {
-        this.put(new JSONObject(value));
-        return this;
+    public long getLong(int index) throws JSONException {
+        Object object = get(index);
+        Long result = JSON.toLong(object);
+        if (result == null) {
+            throw JSON.typeMismatch(index, object, "long");
+        }
+        return result;
     }
 
-
     /**
-     * Append an object value. This increases the array's length by one.
-     * @param value An object value.  The value should be a
-     *  Boolean, Double, Integer, JSONArray, JSONObject, Long, or String, or 
the
-     *  JSONObject.NULL object.
-     * @return this.
+     * Returns the value at {@code index} if it exists and is a long or
+     * can be coerced to a long. Returns 0 otherwise.
+     *
+     * @param index Which value to get.
+     * @return the value at the specified location.
      */
-    public JSONArray put(Object value) {
-        this.myArrayList.add(value);
-        return this;
+    public long optLong(int index) {
+        return optLong(index, 0L);
     }
 
-
     /**
-     * Put or replace a boolean value in the JSONArray. If the index is greater
-     * than the length of the JSONArray, then null elements will be added as
-     * necessary to pad it out.
-     * @param index The subscript.
-     * @param value A boolean value.
-     * @return this.
-     * @throws JSONException If the index is negative.
+     * Returns the value at {@code index} if it exists and is a long or
+     * can be coerced to a long. Returns {@code fallback} otherwise.
+     *
+     * @param index    Which value to get.
+     * @param fallback The fallback value to use if no value is at the 
specified location.
+     * @return the value at the specified location or the fallback value.
      */
-    public JSONArray put(int index, boolean value) throws JSONException {
-        this.put(index, value ? Boolean.TRUE : Boolean.FALSE);
-        return this;
+    public long optLong(int index, long fallback) {
+        Object object = opt(index);
+        Long result = JSON.toLong(object);
+        return result != null ? result : fallback;
     }
 
-
     /**
-     * Put a value in the JSONArray, where the value will be a
-     * JSONArray which is produced from a Collection.
-     * @param index The subscript.
-     * @param value A Collection value.
-     * @return      this.
-     * @throws JSONException If the index is negative or if the value is
-     * not finite.
+     * Returns the value at {@code index} if it exists, coercing it if
+     * necessary.
+     *
+     * @param index Which value to get.
+     * @return the value at the specified location.
+     * @throws JSONException if no such value exists.
      */
-    public JSONArray put(int index, Collection value) throws JSONException {
-        this.put(index, new JSONArray(value));
-        return this;
+    public String getString(int index) throws JSONException {
+        Object object = get(index);
+        String result = JSON.toString(object);
+        if (result == null) {
+            throw JSON.typeMismatch(index, object, "String");
+        }
+        return result;
     }
 
-
     /**
-     * Put or replace a double value. If the index is greater than the length 
of
-     *  the JSONArray, then null elements will be added as necessary to pad
-     *  it out.
-     * @param index The subscript.
-     * @param value A double value.
-     * @return this.
-     * @throws JSONException If the index is negative or if the value is
-     * not finite.
+     * Returns the value at {@code index} if it exists, coercing it if
+     * necessary. Returns the empty string if no such value exists.
+     *
+     * @param index Which value to get.
+     * @return the value at the specified location.
      */
-    public JSONArray put(int index, double value) throws JSONException {
-        this.put(index, new Double(value));
-        return this;
+    public String optString(int index) {
+        return optString(index, "");
     }
 
-
     /**
-     * Put or replace an int value. If the index is greater than the length of
-     *  the JSONArray, then null elements will be added as necessary to pad
-     *  it out.
-     * @param index The subscript.
-     * @param value An int value.
-     * @return this.
-     * @throws JSONException If the index is negative.
+     * Returns the value at {@code index} if it exists, coercing it if
+     * necessary. Returns {@code fallback} if no such value exists.
+     *
+     * @param index    Which value to get.
+     * @param fallback The fallback value to use if no value is at the 
specified location.
+     * @return the value at the specified location or the fallback value.
      */
-    public JSONArray put(int index, int value) throws JSONException {
-        this.put(index, new Integer(value));
-        return this;
+    public String optString(int index, String fallback) {
+        Object object = opt(index);
+        String result = JSON.toString(object);
+        return result != null ? result : fallback;
     }
 
-
     /**
-     * Put or replace a long value. If the index is greater than the length of
-     *  the JSONArray, then null elements will be added as necessary to pad
-     *  it out.
-     * @param index The subscript.
-     * @param value A long value.
-     * @return this.
-     * @throws JSONException If the index is negative.
+     * Returns the value at {@code index} if it exists and is a {@code
+     * JSONArray}.
+     *
+     * @param index Which value to get.
+     * @return the value at the specified location.
+     * @throws JSONException if the value doesn't exist or is not a {@code
+     *                       JSONArray}.
      */
-    public JSONArray put(int index, long value) throws JSONException {
-        this.put(index, new Long(value));
-        return this;
+    public JSONArray getJSONArray(int index) throws JSONException {
+        Object object = get(index);
+        if (object instanceof JSONArray) {
+            return (JSONArray) object;
+        } else {
+            throw JSON.typeMismatch(index, object, "JSONArray");
+        }
     }
 
-
     /**
-     * Put a value in the JSONArray, where the value will be a
-     * JSONObject that is produced from a Map.
-     * @param index The subscript.
-     * @param value The Map value.
-     * @return      this.
-     * @throws JSONException If the index is negative or if the the value is
-     *  an invalid number.
+     * Returns the value at {@code index} if it exists and is a {@code
+     * JSONArray}. Returns null otherwise.
+     *
+     * @param index Which value to get.
+     * @return the value at the specified location.
      */
-    public JSONArray put(int index, Map value) throws JSONException {
-        this.put(index, new JSONObject(value));
-        return this;
+    public JSONArray optJSONArray(int index) {
+        Object object = opt(index);
+        return object instanceof JSONArray ? (JSONArray) object : null;
     }
 
-
     /**
-     * Put or replace an object value in the JSONArray. If the index is greater
-     *  than the length of the JSONArray, then null elements will be added as
-     *  necessary to pad it out.
-     * @param index The subscript.
-     * @param value The value to put into the array. The value should be a
-     *  Boolean, Double, Integer, JSONArray, JSONObject, Long, or String, or 
the
-     *  JSONObject.NULL object.
-     * @return this.
-     * @throws JSONException If the index is negative or if the the value is
-     *  an invalid number.
+     * Returns the value at {@code index} if it exists and is a {@code
+     * JSONObject}.
+     *
+     * @param index Which value to get.
+     * @return the value at the specified location.
+     * @throws JSONException if the value doesn't exist or is not a {@code
+     *                       JSONObject}.
      */
-    public JSONArray put(int index, Object value) throws JSONException {
-        JSONObject.testValidity(value);
-        if (index < 0) {
-            throw new JSONException("JSONArray[" + index + "] not found.");
-        }
-        if (index < this.length()) {
-            this.myArrayList.set(index, value);
+    public JSONObject getJSONObject(int index) throws JSONException {
+        Object object = get(index);
+        if (object instanceof JSONObject) {
+            return (JSONObject) object;
         } else {
-            while (index != this.length()) {
-                this.put(JSONObject.NULL);
-            }
-            this.put(value);
+            throw JSON.typeMismatch(index, object, "JSONObject");
         }
-        return this;
     }
 
-
     /**
-     * Remove an index and close the hole.
-     * @param index The index of the element to be removed.
-     * @return The value that was associated with the index,
-     * or null if there was no value.
+     * Returns the value at {@code index} if it exists and is a {@code
+     * JSONObject}. Returns null otherwise.
+     *
+     * @param index Which value to get.
+     * @return the value at the specified location.
      */
-    public Object remove(int index) {
-        Object o = this.opt(index);
-        this.myArrayList.remove(index);
-        return o;
+    public JSONObject optJSONObject(int index) {
+        Object object = opt(index);
+        return object instanceof JSONObject ? (JSONObject) object : null;
     }
 
-
     /**
-     * Produce a JSONObject by combining a JSONArray of names with the values
-     * of this JSONArray.
-     * @param names A JSONArray containing a list of key strings. These will be
-     * paired with the values.
-     * @return A JSONObject, or null if there are no names or if this JSONArray
-     * has no values.
-     * @throws JSONException If any of the names are null.
+     * Returns a new object whose values are the values in this array, and 
whose
+     * names are the values in {@code names}. Names and values are paired up by
+     * index from 0 through to the shorter array's length. Names that are not
+     * strings will be coerced to strings. This method returns null if either
+     * array is empty.
+     *
+     * @param names The names to apply to the returned values.
+     * @return the newly constructed object.
+     * @throws JSONException Should not be possible.
      */
     public JSONObject toJSONObject(JSONArray names) throws JSONException {
-        if (names == null || names.length() == 0 || this.length() == 0) {
+        JSONObject result = new JSONObject();
+        int length = Math.min(names.length(), values.size());
+        if (length == 0) {
             return null;
         }
-        JSONObject jo = new JSONObject();
-        for (int i = 0; i < names.length(); i += 1) {
-            jo.put(names.getString(i), this.opt(i));
+        for (int i = 0; i < length; i++) {
+            String name = JSON.toString(names.opt(i));
+            result.put(name, opt(i));
         }
-        return jo;
+        return result;
     }
 
+    /**
+     * Returns a new string by alternating this array's values with {@code
+     * separator}. This array's string values are quoted and have their special
+     * characters escaped. For example, the array containing the strings '12"
+     * pizza', 'taco' and 'soda' joined on '+' returns this:
+     * <pre>"12\" pizza"+"taco"+"soda"</pre>
+     *
+     * @param separator The string used to separate the returned values.
+     * @return the conjoined values.
+     * @throws JSONException Only if there is a coding error.
+     */
+    public String join(String separator) throws JSONException {
+        JSONStringer stringer = new JSONStringer();
+        stringer.open(JSONStringer.Scope.NULL, "");
+        for (int i = 0, size = values.size(); i < size; i++) {
+            if (i > 0) {
+                stringer.out.append(separator);
+            }
+            stringer.value(values.get(i));
+        }
+        stringer.close(JSONStringer.Scope.NULL, JSONStringer.Scope.NULL, "");
+        return stringer.out.toString();
+    }
 
     /**
-     * Make a JSON text of this JSONArray. For compactness, no
-     * unnecessary whitespace is added. If it is not possible to produce a
-     * syntactically correct JSON text then null will be returned instead. This
-     * could occur if the array contains an invalid number.
-     * <p>
-     * Warning: This method assumes that the data structure is acyclical.
+     * Encodes this array as a compact JSON string, such as:
+     * <pre>[94043,90210]</pre>
      *
-     * @return a printable, displayable, transmittable
-     *  representation of the array.
+     * @return The string form of this array.
      */
     @Override
     public String toString() {
         try {
-            return '[' + this.join(",") + ']';
-        } catch (Exception e) {
+            JSONStringer stringer = new JSONStringer();
+            writeTo(stringer);
+            return stringer.toString();
+        } catch (JSONException e) {
             return null;
         }
     }
 
-
     /**
-     * Make a prettyprinted JSON text of this JSONArray.
-     * Warning: This method assumes that the data structure is acyclical.
-     * @param indentFactor The number of spaces to add to each level of
-     *  indentation.
-     * @return a printable, displayable, transmittable
-     *  representation of the object, beginning
-     *  with <code>[</code>&nbsp;<small>(left bracket)</small> and ending
-     *  with <code>]</code>&nbsp;<small>(right bracket)</small>.
-     * @throws JSONException
+     * Encodes this array as a human readable JSON string for debugging, such
+     * as:
+     * <pre>
+     * [
+     *     94043,
+     *     90210
+     * ]</pre>
+     *
+     * @param indentSpaces the number of spaces to indent for each level of
+     *                     nesting.
+     * @return The string form of this array.
+     * @throws JSONException Only if there is a coding error.
      */
-    public String toString(int indentFactor) throws JSONException {
-        StringWriter sw = new StringWriter();
-        synchronized (sw.getBuffer()) {
-            return this.write(sw, indentFactor, 0).toString();
+    public String toString(int indentSpaces) throws JSONException {
+        JSONStringer stringer = new JSONStringer(indentSpaces);
+        writeTo(stringer);
+        return stringer.toString();
+    }
+
+    void writeTo(JSONStringer stringer) throws JSONException {
+        stringer.array();
+        for (Object value : values) {
+            stringer.value(value);
         }
+        stringer.endArray();
     }
 
-    /**
-     * Write the contents of the JSONArray as JSON text to a writer. For
-     * compactness, no whitespace is added.
-     * <p>
-     * Warning: This method assumes that the data structure is acyclical.
-     *
-     * @return The writer.
-     * @throws JSONException
-     */
-    public Writer write(Writer writer) throws JSONException {
-        return this.write(writer, 0, 0);
+    @Override
+    public boolean equals(Object o) {
+        return o instanceof JSONArray && ((JSONArray) o).values.equals(values);
     }
 
-    /**
-     * Write the contents of the JSONArray as JSON text to a writer. For
-     * compactness, no whitespace is added.
-     * <p>
-     * Warning: This method assumes that the data structure is acyclical.
-     *
-     * @param indentFactor
-     *            The number of spaces to add to each level of indentation.
-     * @param indent
-     *            The indention of the top level.
-     * @return The writer.
-     * @throws JSONException
-     */
-    Writer write(Writer writer, int indentFactor, int indent)
-            throws JSONException {
-        try {
-            boolean commanate = false;
-            int length = this.length();
-            writer.write('[');
-
-            if (length == 1) {
-                JSONObject.writeValue(writer, this.myArrayList.get(0),
-                        indentFactor, indent);
-            } else if (length != 0) {
-                final int newindent = indent + indentFactor;
-
-                for (int i = 0; i < length; i += 1) {
-                    if (commanate) {
-                        writer.write(',');
-                    }
-                    if (indentFactor > 0) {
-                        writer.write('\n');
-                    }
-                    JSONObject.indent(writer, newindent);
-                    JSONObject.writeValue(writer, this.myArrayList.get(i),
-                            indentFactor, newindent);
-                    commanate = true;
-                }
-                if (indentFactor > 0) {
-                    writer.write('\n');
-                }
-                JSONObject.indent(writer, indent);
-            }
-            writer.write(']');
-            return writer;
-        } catch (IOException e) {
-           throw new JSONException(e);
-        }
+    @Override
+    public int hashCode() {
+        // diverge from the original, which doesn't implement hashCode
+        return values.hashCode();
     }
 }

http://git-wip-us.apache.org/repos/asf/wicket/blob/0ba87f06/wicket-core/src/main/java/org/apache/wicket/ajax/json/JSONException.java
----------------------------------------------------------------------
diff --git 
a/wicket-core/src/main/java/org/apache/wicket/ajax/json/JSONException.java 
b/wicket-core/src/main/java/org/apache/wicket/ajax/json/JSONException.java
old mode 100755
new mode 100644
index 10a52d7..d6530a3
--- a/wicket-core/src/main/java/org/apache/wicket/ajax/json/JSONException.java
+++ b/wicket-core/src/main/java/org/apache/wicket/ajax/json/JSONException.java
@@ -1,29 +1,57 @@
-package org.apache.wicket.ajax.json;
-
-/**
- * The JSONException is thrown by the JSON.org classes when things are amiss.
- * @author JSON.org
- * @version 2010-12-24
- */
-public class JSONException extends Exception {
-    private static final long serialVersionUID = 0;
-    private Throwable cause;
-
-    /**
-     * Constructs a JSONException with an explanatory message.
-     * @param message Detail about the reason for the exception.
-     */
-    public JSONException(String message) {
-        super(message);
-    }
-
-    public JSONException(Throwable cause) {
-        super(cause.getMessage());
-        this.cause = cause;
-    }
-
-    @Override
-    public Throwable getCause() {
-        return this.cause;
-    }
-}
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.wicket.ajax.json;
+
+// Note: this class was written without inspecting the non-free org.json 
sourcecode.
+
+/**
+ * Thrown to indicate a problem with the JSON API. Such problems include:
+ * <ul>
+ *   <li>Attempts to parse or construct malformed documents
+ *   <li>Use of null as a name
+ *   <li>Use of numeric types not available to JSON, such as {@link
+ *       Double#isNaN() NaNs} or {@link Double#isInfinite() infinities}.
+ *   <li>Lookups using an out of range index or nonexistent name
+ *   <li>Type mismatches on lookups
+ * </ul>
+ *
+ * <p>Although this is a checked exception, it is rarely recoverable. Most
+ * callers should simply wrap this exception in an unchecked exception and
+ * rethrow:
+ * <pre>  public JSONArray toJSONObject() {
+ *     try {
+ *         JSONObject result = new JSONObject();
+ *         ...
+ *     } catch (JSONException e) {
+ *         throw new RuntimeException(e);
+ *     }
+ * }</pre>
+ */
+public class JSONException extends RuntimeException {
+
+    public JSONException(String s) {
+        super(s);
+    }
+
+    public JSONException(Throwable cause) {
+        super(cause);
+    }
+
+    public JSONException(String message, Throwable cause) {
+        super(message, cause);
+    }
+}

http://git-wip-us.apache.org/repos/asf/wicket/blob/0ba87f06/wicket-core/src/main/java/org/apache/wicket/ajax/json/JSONML.java
----------------------------------------------------------------------
diff --git a/wicket-core/src/main/java/org/apache/wicket/ajax/json/JSONML.java 
b/wicket-core/src/main/java/org/apache/wicket/ajax/json/JSONML.java
deleted file mode 100755
index 4a2fe2e..0000000
--- a/wicket-core/src/main/java/org/apache/wicket/ajax/json/JSONML.java
+++ /dev/null
@@ -1,467 +0,0 @@
-package org.apache.wicket.ajax.json;
-
-/*
-Copyright (c) 2008 JSON.org
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-The Software shall be used for Good, not Evil.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
-*/
-
-import java.util.Iterator;
-
-
-/**
- * This provides static methods to convert an XML text into a JSONArray or
- * JSONObject, and to covert a JSONArray or JSONObject into an XML text using
- * the JsonML transform.
- * 
- * @author JSON.org
- * @version 2012-03-28
- */
-public class JSONML {
-
-    /**
-     * Parse XML values and store them in a JSONArray.
-     * @param x       The XMLTokener containing the source string.
-     * @param arrayForm true if array form, false if object form.
-     * @param ja      The JSONArray that is containing the current tag or null
-     *     if we are at the outermost level.
-     * @return A JSONArray if the value is the outermost tag, otherwise null.
-     * @throws JSONException
-     */
-    private static Object parse(
-        XMLTokener x,
-        boolean    arrayForm,
-        JSONArray  ja
-    ) throws JSONException {
-        String     attribute;
-        char       c;
-        String       closeTag = null;
-        int        i;
-        JSONArray  newja = null;
-        JSONObject newjo = null;
-        Object     token;
-        String       tagName = null;
-
-// Test for and skip past these forms:
-//      <!-- ... -->
-//      <![  ... ]]>
-//      <!   ...   >
-//      <?   ...  ?>
-
-        while (true) {
-            if (!x.more()) {
-                throw x.syntaxError("Bad XML");
-            }
-            token = x.nextContent();
-            if (token == XML.LT) {
-                token = x.nextToken();
-                if (token instanceof Character) {
-                    if (token == XML.SLASH) {
-
-// Close tag </
-
-                        token = x.nextToken();
-                        if (!(token instanceof String)) {
-                            throw new JSONException(
-                                    "Expected a closing name instead of '" +
-                                    token + "'.");
-                        }
-                        if (x.nextToken() != XML.GT) {
-                            throw x.syntaxError("Misshaped close tag");
-                        }
-                        return token;
-                    } else if (token == XML.BANG) {
-
-// <!
-
-                        c = x.next();
-                        if (c == '-') {
-                            if (x.next() == '-') {
-                                x.skipPast("-->");
-                            } else {
-                                x.back();
-                            }
-                        } else if (c == '[') {
-                            token = x.nextToken();
-                            if (token.equals("CDATA") && x.next() == '[') {
-                                if (ja != null) {
-                                    ja.put(x.nextCDATA());
-                                }
-                            } else {
-                                throw x.syntaxError("Expected 'CDATA['");
-                            }
-                        } else {
-                            i = 1;
-                            do {
-                                token = x.nextMeta();
-                                if (token == null) {
-                                    throw x.syntaxError("Missing '>' after 
'<!'.");
-                                } else if (token == XML.LT) {
-                                    i += 1;
-                                } else if (token == XML.GT) {
-                                    i -= 1;
-                                }
-                            } while (i > 0);
-                        }
-                    } else if (token == XML.QUEST) {
-
-// <?
-
-                        x.skipPast("?>");
-                    } else {
-                        throw x.syntaxError("Misshaped tag");
-                    }
-
-// Open tag <
-
-                } else {
-                    if (!(token instanceof String)) {
-                        throw x.syntaxError("Bad tagName '" + token + "'.");
-                    }
-                    tagName = (String)token;
-                    newja = new JSONArray();
-                    newjo = new JSONObject();
-                    if (arrayForm) {
-                        newja.put(tagName);
-                        if (ja != null) {
-                            ja.put(newja);
-                        }
-                    } else {
-                        newjo.put("tagName", tagName);
-                        if (ja != null) {
-                            ja.put(newjo);
-                        }
-                    }
-                    token = null;
-                    for (;;) {
-                        if (token == null) {
-                            token = x.nextToken();
-                        }
-                        if (token == null) {
-                            throw x.syntaxError("Misshaped tag");
-                        }
-                        if (!(token instanceof String)) {
-                            break;
-                        }
-
-// attribute = value
-
-                        attribute = (String)token;
-                        if (!arrayForm && ("tagName".equals(attribute) || 
"childNode".equals(attribute))) {
-                            throw x.syntaxError("Reserved attribute.");
-                        }
-                        token = x.nextToken();
-                        if (token == XML.EQ) {
-                            token = x.nextToken();
-                            if (!(token instanceof String)) {
-                                throw x.syntaxError("Missing value");
-                            }
-                            newjo.accumulate(attribute, 
XML.stringToValue((String)token));
-                            token = null;
-                        } else {
-                            newjo.accumulate(attribute, "");
-                        }
-                    }
-                    if (arrayForm && newjo.length() > 0) {
-                        newja.put(newjo);
-                    }
-
-// Empty tag <.../>
-
-                    if (token == XML.SLASH) {
-                        if (x.nextToken() != XML.GT) {
-                            throw x.syntaxError("Misshaped tag");
-                        }
-                        if (ja == null) {
-                            if (arrayForm) {
-                                return newja;
-                            } else {
-                                return newjo;
-                            }
-                        }
-
-// Content, between <...> and </...>
-
-                    } else {
-                        if (token != XML.GT) {
-                            throw x.syntaxError("Misshaped tag");
-                        }
-                        closeTag = (String)parse(x, arrayForm, newja);
-                        if (closeTag != null) {
-                            if (!closeTag.equals(tagName)) {
-                                throw x.syntaxError("Mismatched '" + tagName +
-                                        "' and '" + closeTag + "'");
-                            }
-                            tagName = null;
-                            if (!arrayForm && newja.length() > 0) {
-                                newjo.put("childNodes", newja);
-                            }
-                            if (ja == null) {
-                                if (arrayForm) {
-                                    return newja;
-                                } else {
-                                    return newjo;
-                                }
-                            }
-                        }
-                    }
-                }
-            } else {
-                if (ja != null) {
-                    ja.put(token instanceof String
-                        ? XML.stringToValue((String)token)
-                        : token);
-                }
-            }
-        }
-    }
-
-
-    /**
-     * Convert a well-formed (but not necessarily valid) XML string into a
-     * JSONArray using the JsonML transform. Each XML tag is represented as
-     * a JSONArray in which the first element is the tag name. If the tag has
-     * attributes, then the second element will be JSONObject containing the
-     * name/value pairs. If the tag contains children, then strings and
-     * JSONArrays will represent the child tags.
-     * Comments, prologs, DTDs, and <code>&lt;[ [ ]]></code> are ignored.
-     * @param string The source string.
-     * @return A JSONArray containing the structured data from the XML string.
-     * @throws JSONException
-     */
-    public static JSONArray toJSONArray(String string) throws JSONException {
-        return toJSONArray(new XMLTokener(string));
-    }
-
-
-    /**
-     * Convert a well-formed (but not necessarily valid) XML string into a
-     * JSONArray using the JsonML transform. Each XML tag is represented as
-     * a JSONArray in which the first element is the tag name. If the tag has
-     * attributes, then the second element will be JSONObject containing the
-     * name/value pairs. If the tag contains children, then strings and
-     * JSONArrays will represent the child content and tags.
-     * Comments, prologs, DTDs, and <code>&lt;[ [ ]]></code> are ignored.
-     * @param x An XMLTokener.
-     * @return A JSONArray containing the structured data from the XML string.
-     * @throws JSONException
-     */
-    public static JSONArray toJSONArray(XMLTokener x) throws JSONException {
-        return (JSONArray)parse(x, true, null);
-    }
-
-
-    /**
-     * Convert a well-formed (but not necessarily valid) XML string into a
-     * JSONObject using the JsonML transform. Each XML tag is represented as
-     * a JSONObject with a "tagName" property. If the tag has attributes, then
-     * the attributes will be in the JSONObject as properties. If the tag
-     * contains children, the object will have a "childNodes" property which
-     * will be an array of strings and JsonML JSONObjects.
-
-     * Comments, prologs, DTDs, and <code>&lt;[ [ ]]></code> are ignored.
-     * @param x An XMLTokener of the XML source text.
-     * @return A JSONObject containing the structured data from the XML string.
-     * @throws JSONException
-     */
-    public static JSONObject toJSONObject(XMLTokener x) throws JSONException {
-           return (JSONObject)parse(x, false, null);
-    }
-
-
-    /**
-     * Convert a well-formed (but not necessarily valid) XML string into a
-     * JSONObject using the JsonML transform. Each XML tag is represented as
-     * a JSONObject with a "tagName" property. If the tag has attributes, then
-     * the attributes will be in the JSONObject as properties. If the tag
-     * contains children, the object will have a "childNodes" property which
-     * will be an array of strings and JsonML JSONObjects.
-
-     * Comments, prologs, DTDs, and <code>&lt;[ [ ]]></code> are ignored.
-     * @param string The XML source text.
-     * @return A JSONObject containing the structured data from the XML string.
-     * @throws JSONException
-     */
-    public static JSONObject toJSONObject(String string) throws JSONException {
-        return toJSONObject(new XMLTokener(string));
-    }
-
-
-    /**
-     * Reverse the JSONML transformation, making an XML text from a JSONArray.
-     * @param ja A JSONArray.
-     * @return An XML string.
-     * @throws JSONException
-     */
-    public static String toString(JSONArray ja) throws JSONException {
-        int             i;
-        JSONObject   jo;
-        String       key;
-        Iterator     keys;
-        int             length;
-        Object         object;
-        StringBuffer sb = new StringBuffer();
-        String       tagName;
-        String       value;
-
-// Emit <tagName
-
-        tagName = ja.getString(0);
-        XML.noSpace(tagName);
-        tagName = XML.escape(tagName);
-        sb.append('<');
-        sb.append(tagName);
-
-        object = ja.opt(1);
-        if (object instanceof JSONObject) {
-            i = 2;
-            jo = (JSONObject)object;
-
-// Emit the attributes
-
-            keys = jo.keys();
-            while (keys.hasNext()) {
-                key = keys.next().toString();
-                XML.noSpace(key);
-                value = jo.optString(key);
-                if (value != null) {
-                    sb.append(' ');
-                    sb.append(XML.escape(key));
-                    sb.append('=');
-                    sb.append('"');
-                    sb.append(XML.escape(value));
-                    sb.append('"');
-                }
-            }
-        } else {
-            i = 1;
-        }
-
-//Emit content in body
-
-        length = ja.length();
-        if (i >= length) {
-            sb.append('/');
-            sb.append('>');
-        } else {
-            sb.append('>');
-            do {
-                object = ja.get(i);
-                i += 1;
-                if (object != null) {
-                    if (object instanceof String) {
-                        sb.append(XML.escape(object.toString()));
-                    } else if (object instanceof JSONObject) {
-                        sb.append(toString((JSONObject)object));
-                    } else if (object instanceof JSONArray) {
-                        sb.append(toString((JSONArray)object));
-                    }
-                }
-            } while (i < length);
-            sb.append('<');
-            sb.append('/');
-            sb.append(tagName);
-            sb.append('>');
-        }
-        return sb.toString();
-    }
-
-    /**
-     * Reverse the JSONML transformation, making an XML text from a JSONObject.
-     * The JSONObject must contain a "tagName" property. If it has children,
-     * then it must have a "childNodes" property containing an array of 
objects.
-     * The other properties are attributes with string values.
-     * @param jo A JSONObject.
-     * @return An XML string.
-     * @throws JSONException
-     */
-    public static String toString(JSONObject jo) throws JSONException {
-        StringBuffer sb = new StringBuffer();
-        int          i;
-        JSONArray    ja;
-        String       key;
-        Iterator     keys;
-        int          length;
-        Object         object;
-        String       tagName;
-        String       value;
-
-//Emit <tagName
-
-        tagName = jo.optString("tagName");
-        if (tagName == null) {
-            return XML.escape(jo.toString());
-        }
-        XML.noSpace(tagName);
-        tagName = XML.escape(tagName);
-        sb.append('<');
-        sb.append(tagName);
-
-//Emit the attributes
-
-        keys = jo.keys();
-        while (keys.hasNext()) {
-            key = keys.next().toString();
-            if (!"tagName".equals(key) && !"childNodes".equals(key)) {
-                XML.noSpace(key);
-                value = jo.optString(key);
-                if (value != null) {
-                    sb.append(' ');
-                    sb.append(XML.escape(key));
-                    sb.append('=');
-                    sb.append('"');
-                    sb.append(XML.escape(value));
-                    sb.append('"');
-                }
-            }
-        }
-
-//Emit content in body
-
-        ja = jo.optJSONArray("childNodes");
-        if (ja == null) {
-            sb.append('/');
-            sb.append('>');
-        } else {
-            sb.append('>');
-            length = ja.length();
-            for (i = 0; i < length; i += 1) {
-                object = ja.get(i);
-                if (object != null) {
-                    if (object instanceof String) {
-                        sb.append(XML.escape(object.toString()));
-                    } else if (object instanceof JSONObject) {
-                        sb.append(toString((JSONObject)object));
-                    } else if (object instanceof JSONArray) {
-                        sb.append(toString((JSONArray)object));
-                    } else {
-                        sb.append(object.toString());
-                    }
-                }
-            }
-            sb.append('<');
-            sb.append('/');
-            sb.append(tagName);
-            sb.append('>');
-        }
-        return sb.toString();
-    }
-}

Reply via email to