You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@geode.apache.org by ud...@apache.org on 2017/02/17 21:58:09 UTC

[1/8] geode git commit: Revert "GEODE-2142: Spotless"

Repository: geode
Updated Branches:
  refs/heads/develop 2e3a88f7b -> 0805036e8


http://git-wip-us.apache.org/repos/asf/geode/blob/1253d780/geode-json/src/main/java/org/json/JSONTokener.java
----------------------------------------------------------------------
diff --git a/geode-json/src/main/java/org/json/JSONTokener.java b/geode-json/src/main/java/org/json/JSONTokener.java
index 21c9fb0..59eb4bc 100755
--- a/geode-json/src/main/java/org/json/JSONTokener.java
+++ b/geode-json/src/main/java/org/json/JSONTokener.java
@@ -1,15 +1,17 @@
 /*
  * 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
+ * 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
+ *      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.
+ * 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.json;
@@ -20,620 +22,637 @@ import java.io.IOException;
 import java.io.Reader;
 
 /**
- * Parses a JSON (<a href="http://www.ietf.org/rfc/rfc4627.txt">RFC 4627</a>) encoded string into
- * the corresponding object. Most clients of this class will use only need the
- * {@link #JSONTokener(String) constructor} and {@link #nextValue} method. Example usage:
- * 
- * <pre>
- * String json = "{" + "  \"query\": \"Pizza\", " + "  \"locations\": [ 94043, 90210 ] " + "}";
+ * Parses a JSON (<a href="http://www.ietf.org/rfc/rfc4627.txt">RFC 4627</a>)
+ * encoded string into the corresponding object. Most clients of
+ * this class will use only need the {@link #JSONTokener(String) constructor}
+ * and {@link #nextValue} method. Example usage: <pre>
+ * String json = "{"
+ *         + "  \"query\": \"Pizza\", "
+ *         + "  \"locations\": [ 94043, 90210 ] "
+ *         + "}";
  *
  * JSONObject object = (JSONObject) new JSONTokener(json).nextValue();
  * String query = object.getString("query");
- * JSONArray locations = object.getJSONArray("locations");
- * </pre>
+ * JSONArray locations = object.getJSONArray("locations");</pre>
  *
- * <p>
- * For best interoperability and performance use JSON that complies with RFC 4627, such as that
- * generated by {@link JSONStringer}. For legacy reasons this parser is lenient, so a successful
- * parse does not indicate that the input string was valid JSON. All of the following syntax errors
- * will be ignored:
+ * <p>For best interoperability and performance use JSON that complies with
+ * RFC 4627, such as that generated by {@link JSONStringer}. For legacy reasons
+ * this parser is lenient, so a successful parse does not indicate that the
+ * input string was valid JSON. All of the following syntax errors will be
+ * ignored:
  * <ul>
- * <li>End of line comments starting with {@code //} or {@code #} and ending with a newline
- * character.
- * <li>C-style comments starting with {@code /*} and ending with {@code *}{@code /}. Such comments
- * may not be nested.
+ * <li>End of line comments starting with {@code //} or {@code #} and ending
+ * with a newline character.
+ * <li>C-style comments starting with {@code /*} and ending with
+ * {@code *}{@code /}. Such comments may not be nested.
  * <li>Strings that are unquoted or {@code 'single quoted'}.
  * <li>Hexadecimal integers prefixed with {@code 0x} or {@code 0X}.
  * <li>Octal integers prefixed with {@code 0}.
  * <li>Array elements separated by {@code ;}.
- * <li>Unnecessary array separators. These are interpreted as if null was the omitted value.
+ * <li>Unnecessary array separators. These are interpreted as if null was the
+ * omitted value.
  * <li>Key-value pairs separated by {@code =} or {@code =>}.
  * <li>Key-value pairs separated by {@code ;}.
  * </ul>
  *
- * <p>
- * Each tokener may be used to parse a single JSON string. Instances of this class are not thread
- * safe. Although this class is nonfinal, it was not designed for inheritance and should not be
- * subclassed. In particular, self-use by overrideable methods is not specified. See <i>Effective
- * Java</i> Item 17, "Design and Document or inheritance or else prohibit it" for further
+ * <p>Each tokener may be used to parse a single JSON string. Instances of this
+ * class are not thread safe. Although this class is nonfinal, it was not
+ * designed for inheritance and should not be subclassed. In particular,
+ * self-use by overrideable 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 JSONTokener {
 
-  /**
-   * The input JSON.
-   */
-  private final String in;
-
-  /**
-   * The index of the next character to be returned by {@link #next}. When the input is exhausted,
-   * this equals the input's length.
-   */
-  private int pos;
-
-  /**
-   * @param in JSON encoded string. Null is not permitted and will yield a tokener that throws
-   *        {@code NullPointerExceptions} when methods are called.
-   */
-  public JSONTokener(String in) {
-    // consume an optional byte order mark (BOM) if it exists
-    if (in != null && in.startsWith("\ufeff")) {
-      in = in.substring(1);
-    }
-    this.in = in;
-  }
-
-  public JSONTokener(Reader input) throws IOException {
-    StringBuilder s = new StringBuilder();
-    char[] readBuf = new char[102400];
-    int n = input.read(readBuf);
-    while (n >= 0) {
-      s.append(readBuf, 0, n);
-      n = input.read(readBuf);
+    /**
+     * The input JSON.
+     */
+    private final String in;
+
+    /**
+     * The index of the next character to be returned by {@link #next}. When
+     * the input is exhausted, this equals the input's length.
+     */
+    private int pos;
+
+    /**
+     * @param in JSON encoded string. Null is not permitted and will yield a
+     *           tokener that throws {@code NullPointerExceptions} when methods are
+     *           called.
+     */
+    public JSONTokener(String in) {
+        // consume an optional byte order mark (BOM) if it exists
+        if (in != null && in.startsWith("\ufeff")) {
+            in = in.substring(1);
+        }
+        this.in = in;
     }
-    in = s.toString();
-    pos = 0;
-  }
-
-  /**
-   * Returns the next value from the input.
-   *
-   * @return a {@link JSONObject}, {@link JSONArray}, String, Boolean, Integer, Long, Double or
-   *         {@link JSONObject#NULL}.
-   * @throws JSONException if the input is malformed.
-   */
-  public Object nextValue() throws JSONException {
-    int c = nextCleanInternal();
-    switch (c) {
-      case -1:
-        throw syntaxError("End of input");
-
-      case '{':
-        return readObject();
-
-      case '[':
-        return readArray();
-
-      case '\'':
-      case '"':
-        return nextString((char) c);
-
-      default:
-        pos--;
-        return readLiteral();
+
+    public JSONTokener(Reader input) throws IOException {
+        StringBuilder s = new StringBuilder();
+        char[] readBuf = new char[102400];
+        int n = input.read(readBuf);
+        while (n >= 0) {
+            s.append(readBuf, 0, n);
+            n = input.read(readBuf);
+        }
+        in = s.toString();
+        pos = 0;
     }
-  }
-
-  private int nextCleanInternal() throws JSONException {
-    while (pos < in.length()) {
-      int c = in.charAt(pos++);
-      switch (c) {
-        case '\t':
-        case ' ':
-        case '\n':
-        case '\r':
-          continue;
-
-        case '/':
-          if (pos == in.length()) {
-            return c;
-          }
-
-          char peek = in.charAt(pos);
-          switch (peek) {
-            case '*':
-              // skip a /* c-style comment */
-              pos++;
-              int commentEnd = in.indexOf("*/", pos);
-              if (commentEnd == -1) {
-                throw syntaxError("Unterminated comment");
-              }
-              pos = commentEnd + 2;
-              continue;
-
-            case '/':
-              // skip a // end-of-line comment
-              pos++;
-              skipToEndOfLine();
-              continue;
+
+    /**
+     * Returns the next value from the input.
+     *
+     * @return a {@link JSONObject}, {@link JSONArray}, String, Boolean,
+     * Integer, Long, Double or {@link JSONObject#NULL}.
+     * @throws JSONException if the input is malformed.
+     */
+    public Object nextValue() throws JSONException {
+        int c = nextCleanInternal();
+        switch (c) {
+            case -1:
+                throw syntaxError("End of input");
+
+            case '{':
+                return readObject();
+
+            case '[':
+                return readArray();
+
+            case '\'':
+            case '"':
+                return nextString((char) c);
 
             default:
-              return c;
-          }
-
-        case '#':
-          /*
-           * Skip a # hash end-of-line comment. The JSON RFC doesn't specify this behavior, but it's
-           * required to parse existing documents. See http://b/2571423.
-           */
-          skipToEndOfLine();
-          continue;
-
-        default:
-          return c;
-      }
+                pos--;
+                return readLiteral();
+        }
     }
 
-    return -1;
-  }
-
-  /**
-   * Advances the position until after the next newline character. If the line is terminated by
-   * "\r\n", the '\n' must be consumed as whitespace by the caller.
-   */
-  private void skipToEndOfLine() {
-    for (; pos < in.length(); pos++) {
-      char c = in.charAt(pos);
-      if (c == '\r' || c == '\n') {
-        pos++;
-        break;
-      }
+    private int nextCleanInternal() throws JSONException {
+        while (pos < in.length()) {
+            int c = in.charAt(pos++);
+            switch (c) {
+                case '\t':
+                case ' ':
+                case '\n':
+                case '\r':
+                    continue;
+
+                case '/':
+                    if (pos == in.length()) {
+                        return c;
+                    }
+
+                    char peek = in.charAt(pos);
+                    switch (peek) {
+                        case '*':
+                            // skip a /* c-style comment */
+                            pos++;
+                            int commentEnd = in.indexOf("*/", pos);
+                            if (commentEnd == -1) {
+                                throw syntaxError("Unterminated comment");
+                            }
+                            pos = commentEnd + 2;
+                            continue;
+
+                        case '/':
+                            // skip a // end-of-line comment
+                            pos++;
+                            skipToEndOfLine();
+                            continue;
+
+                        default:
+                            return c;
+                    }
+
+                case '#':
+                    /*
+                     * Skip a # hash end-of-line comment. The JSON RFC doesn't
+                     * specify this behavior, but it's required to parse
+                     * existing documents. See http://b/2571423.
+                     */
+                    skipToEndOfLine();
+                    continue;
+
+                default:
+                    return c;
+            }
+        }
+
+        return -1;
     }
-  }
-
-  /**
-   * Returns the string up to but not including {@code quote}, unescaping any character escape
-   * sequences encountered along the way. The opening quote should have already been read. This
-   * consumes the closing quote, but does not include it in the returned string.
-   *
-   * @param quote either ' or ".
-   * @return The unescaped string.
-   * @throws JSONException if the string isn't terminated by a closing quote correctly.
-   */
-  public String nextString(char quote) throws JSONException {
-    /*
-     * For strings that are free of escape sequences, we can just extract the result as a substring
-     * of the input. But if we encounter an escape sequence, we need to use a StringBuilder to
-     * compose the result.
+
+    /**
+     * Advances the position until after the next newline character. If the line
+     * is terminated by "\r\n", the '\n' must be consumed as whitespace by the
+     * caller.
      */
-    StringBuilder builder = null;
-
-    /* the index of the first character not yet appended to the builder. */
-    int start = pos;
-
-    while (pos < in.length()) {
-      int c = in.charAt(pos++);
-      if (c == quote) {
-        if (builder == null) {
-          // a new string avoids leaking memory
-          // noinspection RedundantStringConstructorCall
-          return new String(in.substring(start, pos - 1));
-        } else {
-          builder.append(in, start, pos - 1);
-          return builder.toString();
+    private void skipToEndOfLine() {
+        for (; pos < in.length(); pos++) {
+            char c = in.charAt(pos);
+            if (c == '\r' || c == '\n') {
+                pos++;
+                break;
+            }
         }
-      }
+    }
 
-      if (c == '\\') {
-        if (pos == in.length()) {
-          throw syntaxError("Unterminated escape sequence");
+    /**
+     * Returns the string up to but not including {@code quote}, unescaping any
+     * character escape sequences encountered along the way. The opening quote
+     * should have already been read. This consumes the closing quote, but does
+     * not include it in the returned string.
+     *
+     * @param quote either ' or ".
+     * @return The unescaped string.
+     * @throws JSONException if the string isn't terminated by a closing quote correctly.
+     */
+    public String nextString(char quote) throws JSONException {
+        /*
+         * For strings that are free of escape sequences, we can just extract
+         * the result as a substring of the input. But if we encounter an escape
+         * sequence, we need to use a StringBuilder to compose the result.
+         */
+        StringBuilder builder = null;
+
+        /* the index of the first character not yet appended to the builder. */
+        int start = pos;
+
+        while (pos < in.length()) {
+            int c = in.charAt(pos++);
+            if (c == quote) {
+                if (builder == null) {
+                    // a new string avoids leaking memory
+                    //noinspection RedundantStringConstructorCall
+                    return new String(in.substring(start, pos - 1));
+                } else {
+                    builder.append(in, start, pos - 1);
+                    return builder.toString();
+                }
+            }
+
+            if (c == '\\') {
+                if (pos == in.length()) {
+                    throw syntaxError("Unterminated escape sequence");
+                }
+                if (builder == null) {
+                    builder = new StringBuilder();
+                }
+                builder.append(in, start, pos - 1);
+                builder.append(readEscapeCharacter());
+                start = pos;
+            }
         }
-        if (builder == null) {
-          builder = new StringBuilder();
+
+        throw syntaxError("Unterminated string");
+    }
+
+    /**
+     * Unescapes the character identified by the character or characters that
+     * immediately follow a backslash. The backslash '\' should have already
+     * been read. This supports both unicode escapes "u000A" and two-character
+     * escapes "\n".
+     */
+    private char readEscapeCharacter() throws JSONException {
+        char escaped = in.charAt(pos++);
+        switch (escaped) {
+            case 'u':
+                if (pos + 4 > in.length()) {
+                    throw syntaxError("Unterminated escape sequence");
+                }
+                String hex = in.substring(pos, pos + 4);
+                pos += 4;
+                try {
+                    return (char) Integer.parseInt(hex, 16);
+                } catch (NumberFormatException nfe) {
+                    throw syntaxError("Invalid escape sequence: " + hex);
+                }
+
+            case 't':
+                return '\t';
+
+            case 'b':
+                return '\b';
+
+            case 'n':
+                return '\n';
+
+            case 'r':
+                return '\r';
+
+            case 'f':
+                return '\f';
+
+            case '\'':
+            case '"':
+            case '\\':
+            default:
+                return escaped;
         }
-        builder.append(in, start, pos - 1);
-        builder.append(readEscapeCharacter());
-        start = pos;
-      }
     }
 
-    throw syntaxError("Unterminated string");
-  }
-
-  /**
-   * Unescapes the character identified by the character or characters that immediately follow a
-   * backslash. The backslash '\' should have already been read. This supports both unicode escapes
-   * "u000A" and two-character escapes "\n".
-   */
-  private char readEscapeCharacter() throws JSONException {
-    char escaped = in.charAt(pos++);
-    switch (escaped) {
-      case 'u':
-        if (pos + 4 > in.length()) {
-          throw syntaxError("Unterminated escape sequence");
+    /**
+     * Reads a null, boolean, numeric or unquoted string literal value. Numeric
+     * values will be returned as an Integer, Long, or Double, in that order of
+     * preference.
+     */
+    private Object readLiteral() throws JSONException {
+        String literal = nextToInternal("{}[]/\\:,=;# \t\f");
+
+        if (literal.length() == 0) {
+            throw syntaxError("Expected literal value");
+        } else if ("null".equalsIgnoreCase(literal)) {
+            return JSONObject.NULL;
+        } else if ("true".equalsIgnoreCase(literal)) {
+            return Boolean.TRUE;
+        } else if ("false".equalsIgnoreCase(literal)) {
+            return Boolean.FALSE;
+        }
+
+        /* try to parse as an integral type... */
+        if (literal.indexOf('.') == -1) {
+            int base = 10;
+            String number = literal;
+            if (number.startsWith("0x") || number.startsWith("0X")) {
+                number = number.substring(2);
+                base = 16;
+            } else if (number.startsWith("0") && number.length() > 1) {
+                number = number.substring(1);
+                base = 8;
+            }
+            try {
+                long longValue = Long.parseLong(number, base);
+                if (longValue <= Integer.MAX_VALUE && longValue >= Integer.MIN_VALUE) {
+                    return (int) longValue;
+                } else {
+                    return longValue;
+                }
+            } catch (NumberFormatException e) {
+                /*
+                 * This only happens for integral numbers greater than
+                 * Long.MAX_VALUE, numbers in exponential form (5e-10) and
+                 * unquoted strings. Fall through to try floating point.
+                 */
+            }
         }
-        String hex = in.substring(pos, pos + 4);
-        pos += 4;
+
+        /* ...next try to parse as a floating point... */
         try {
-          return (char) Integer.parseInt(hex, 16);
-        } catch (NumberFormatException nfe) {
-          throw syntaxError("Invalid escape sequence: " + hex);
+            return Double.valueOf(literal);
+        } catch (NumberFormatException ignored) {
         }
 
-      case 't':
-        return '\t';
+        /* ... finally give up. We have an unquoted string */
+        //noinspection RedundantStringConstructorCall
+        return new String(literal); // a new string avoids leaking memory
+    }
 
-      case 'b':
-        return '\b';
+    /**
+     * Returns the string up to but not including any of the given characters or
+     * a newline character. This does not consume the excluded character.
+     */
+    private String nextToInternal(String excluded) {
+        int start = pos;
+        for (; pos < in.length(); pos++) {
+            char c = in.charAt(pos);
+            if (c == '\r' || c == '\n' || excluded.indexOf(c) != -1) {
+                return in.substring(start, pos);
+            }
+        }
+        return in.substring(start);
+    }
 
-      case 'n':
-        return '\n';
+    /**
+     * Reads a sequence of key/value pairs and the trailing closing brace '}' of
+     * an object. The opening brace '{' should have already been read.
+     */
+    private JSONObject readObject() throws JSONException {
+        JSONObject result = new JSONObject();
+
+        /* Peek to see if this is the empty object. */
+        int first = nextCleanInternal();
+        if (first == '}') {
+            return result;
+        } else if (first != -1) {
+            pos--;
+        }
 
-      case 'r':
-        return '\r';
+        while (true) {
+            Object name = nextValue();
+            if (!(name instanceof String)) {
+                if (name == null) {
+                    throw syntaxError("Names cannot be null");
+                } else {
+                    throw syntaxError("Names must be strings, but " + name
+                            + " is of type " + name.getClass().getName());
+                }
+            }
+
+            /*
+             * Expect the name/value separator to be either a colon ':', an
+             * equals sign '=', or an arrow "=>". The last two are bogus but we
+             * include them because that's what the original implementation did.
+             */
+            int separator = nextCleanInternal();
+            if (separator != ':' && separator != '=') {
+                throw syntaxError("Expected ':' after " + name);
+            }
+            if (pos < in.length() && in.charAt(pos) == '>') {
+                pos++;
+            }
+
+            result.put((String) name, nextValue());
+
+            switch (nextCleanInternal()) {
+                case '}':
+                    return result;
+                case ';':
+                case ',':
+                    continue;
+                default:
+                    throw syntaxError("Unterminated object");
+            }
+        }
+    }
 
-      case 'f':
-        return '\f';
+    /**
+     * Reads a sequence of values and the trailing closing brace ']' of an
+     * array. The opening brace '[' should have already been read. Note that
+     * "[]" yields an empty array, but "[,]" returns a two-element array
+     * equivalent to "[null,null]".
+     */
+    private JSONArray readArray() throws JSONException {
+        JSONArray result = new JSONArray();
+
+        /* to cover input that ends with ",]". */
+        boolean hasTrailingSeparator = false;
+
+        while (true) {
+            switch (nextCleanInternal()) {
+                case -1:
+                    throw syntaxError("Unterminated array");
+                case ']':
+                    if (hasTrailingSeparator) {
+                        result.put(null);
+                    }
+                    return result;
+                case ',':
+                case ';':
+                    /* A separator without a value first means "null". */
+                    result.put(null);
+                    hasTrailingSeparator = true;
+                    continue;
+                default:
+                    pos--;
+            }
+
+            result.put(nextValue());
+
+            switch (nextCleanInternal()) {
+                case ']':
+                    return result;
+                case ',':
+                case ';':
+                    hasTrailingSeparator = true;
+                    continue;
+                default:
+                    throw syntaxError("Unterminated array");
+            }
+        }
+    }
 
-      case '\'':
-      case '"':
-      case '\\':
-      default:
-        return escaped;
+    /**
+     * Returns an exception containing the given message plus the current
+     * position and the entire input string.
+     *
+     * @param message The message we want to include.
+     * @return An exception that we can throw.
+     */
+    public JSONException syntaxError(String message) {
+        return new JSONException(message + this);
     }
-  }
-
-  /**
-   * Reads a null, boolean, numeric or unquoted string literal value. Numeric values will be
-   * returned as an Integer, Long, or Double, in that order of preference.
-   */
-  private Object readLiteral() throws JSONException {
-    String literal = nextToInternal("{}[]/\\:,=;# \t\f");
-
-    if (literal.length() == 0) {
-      throw syntaxError("Expected literal value");
-    } else if ("null".equalsIgnoreCase(literal)) {
-      return JSONObject.NULL;
-    } else if ("true".equalsIgnoreCase(literal)) {
-      return Boolean.TRUE;
-    } else if ("false".equalsIgnoreCase(literal)) {
-      return Boolean.FALSE;
+
+    /**
+     * Returns the current position and the entire input string.
+     */
+    @Override
+    public String toString() {
+        // consistent with the original implementation
+        return " at character " + pos + " of " + in;
     }
 
-    /* try to parse as an integral type... */
-    if (literal.indexOf('.') == -1) {
-      int base = 10;
-      String number = literal;
-      if (number.startsWith("0x") || number.startsWith("0X")) {
-        number = number.substring(2);
-        base = 16;
-      } else if (number.startsWith("0") && number.length() > 1) {
-        number = number.substring(1);
-        base = 8;
-      }
-      try {
-        long longValue = Long.parseLong(number, base);
-        if (longValue <= Integer.MAX_VALUE && longValue >= Integer.MIN_VALUE) {
-          return (int) longValue;
-        } else {
-          return longValue;
-        }
-      } catch (NumberFormatException e) {
-        /*
-         * This only happens for integral numbers greater than Long.MAX_VALUE, numbers in
-         * exponential form (5e-10) and unquoted strings. Fall through to try floating point.
-         */
-      }
+    /*
+     * Legacy APIs.
+     *
+     * None of the methods below are on the critical path of parsing JSON
+     * documents. They exist only because they were exposed by the original
+     * implementation and may be used by some clients.
+     */
+
+    /**
+     * Returns true until the input has been exhausted.
+     *
+     * @return true if more input exists.
+     */
+    public boolean more() {
+        return pos < in.length();
     }
 
-    /* ...next try to parse as a floating point... */
-    try {
-      return Double.valueOf(literal);
-    } catch (NumberFormatException ignored) {
+    /**
+     * Returns the next available character, or the null character '\0' if all
+     * input has been exhausted. The return value of this method is ambiguous
+     * for JSON strings that contain the character '\0'.
+     *
+     * @return the next character.
+     */
+    public char next() {
+        return pos < in.length() ? in.charAt(pos++) : '\0';
     }
 
-    /* ... finally give up. We have an unquoted string */
-    // noinspection RedundantStringConstructorCall
-    return new String(literal); // a new string avoids leaking memory
-  }
-
-  /**
-   * Returns the string up to but not including any of the given characters or a newline character.
-   * This does not consume the excluded character.
-   */
-  private String nextToInternal(String excluded) {
-    int start = pos;
-    for (; pos < in.length(); pos++) {
-      char c = in.charAt(pos);
-      if (c == '\r' || c == '\n' || excluded.indexOf(c) != -1) {
-        return in.substring(start, pos);
-      }
+    /**
+     * Returns the next available character if it equals {@code c}. Otherwise an
+     * exception is thrown.
+     *
+     * @param c The character we are looking for.
+     * @return the next character.
+     * @throws JSONException If the next character isn't {@code c}
+     */
+    public char next(char c) throws JSONException {
+        char result = next();
+        if (result != c) {
+            throw syntaxError("Expected " + c + " but was " + result);
+        }
+        return result;
     }
-    return in.substring(start);
-  }
-
-  /**
-   * Reads a sequence of key/value pairs and the trailing closing brace '}' of an object. The
-   * opening brace '{' should have already been read.
-   */
-  private JSONObject readObject() throws JSONException {
-    JSONObject result = new JSONObject();
-
-    /* Peek to see if this is the empty object. */
-    int first = nextCleanInternal();
-    if (first == '}') {
-      return result;
-    } else if (first != -1) {
-      pos--;
+
+    /**
+     * Returns the next character that is not whitespace and does not belong to
+     * a comment. If the input is exhausted before such a character can be
+     * found, the null character '\0' is returned. The return value of this
+     * method is ambiguous for JSON strings that contain the character '\0'.
+     *
+     * @return The next non-whitespace character.
+     * @throws JSONException Should not be possible.
+     */
+    public char nextClean() throws JSONException {
+        int nextCleanInt = nextCleanInternal();
+        return nextCleanInt == -1 ? '\0' : (char) nextCleanInt;
     }
 
-    while (true) {
-      Object name = nextValue();
-      if (!(name instanceof String)) {
-        if (name == null) {
-          throw syntaxError("Names cannot be null");
-        } else {
-          throw syntaxError(
-              "Names must be strings, but " + name + " is of type " + name.getClass().getName());
+    /**
+     * Returns the next {@code length} characters of the input.
+     *
+     * <p>The returned string shares its backing character array with this
+     * tokener's input string. If a reference to the returned string may be held
+     * indefinitely, you should use {@code new String(result)} to copy it first
+     * to avoid memory leaks.
+     *
+     * @param length The desired number of characters to return.
+     * @return The next few characters.
+     * @throws JSONException if the remaining input is not long enough to
+     *                       satisfy this request.
+     */
+    public String next(int length) throws JSONException {
+        if (pos + length > in.length()) {
+            throw syntaxError(length + " is out of bounds");
         }
-      }
-
-      /*
-       * Expect the name/value separator to be either a colon ':', an equals sign '=', or an arrow
-       * "=>". The last two are bogus but we include them because that's what the original
-       * implementation did.
-       */
-      int separator = nextCleanInternal();
-      if (separator != ':' && separator != '=') {
-        throw syntaxError("Expected ':' after " + name);
-      }
-      if (pos < in.length() && in.charAt(pos) == '>') {
-        pos++;
-      }
-
-      result.put((String) name, nextValue());
-
-      switch (nextCleanInternal()) {
-        case '}':
-          return result;
-        case ';':
-        case ',':
-          continue;
-        default:
-          throw syntaxError("Unterminated object");
-      }
-    }
-  }
-
-  /**
-   * Reads a sequence of values and the trailing closing brace ']' of an array. The opening brace
-   * '[' should have already been read. Note that "[]" yields an empty array, but "[,]" returns a
-   * two-element array equivalent to "[null,null]".
-   */
-  private JSONArray readArray() throws JSONException {
-    JSONArray result = new JSONArray();
-
-    /* to cover input that ends with ",]". */
-    boolean hasTrailingSeparator = false;
-
-    while (true) {
-      switch (nextCleanInternal()) {
-        case -1:
-          throw syntaxError("Unterminated array");
-        case ']':
-          if (hasTrailingSeparator) {
-            result.put(null);
-          }
-          return result;
-        case ',':
-        case ';':
-          /* A separator without a value first means "null". */
-          result.put(null);
-          hasTrailingSeparator = true;
-          continue;
-        default:
-          pos--;
-      }
-
-      result.put(nextValue());
-
-      switch (nextCleanInternal()) {
-        case ']':
-          return result;
-        case ',':
-        case ';':
-          hasTrailingSeparator = true;
-          continue;
-        default:
-          throw syntaxError("Unterminated array");
-      }
+        String result = in.substring(pos, pos + length);
+        pos += length;
+        return result;
     }
-  }
-
-  /**
-   * Returns an exception containing the given message plus the current position and the entire
-   * input string.
-   *
-   * @param message The message we want to include.
-   * @return An exception that we can throw.
-   */
-  public JSONException syntaxError(String message) {
-    return new JSONException(message + this);
-  }
-
-  /**
-   * Returns the current position and the entire input string.
-   */
-  @Override
-  public String toString() {
-    // consistent with the original implementation
-    return " at character " + pos + " of " + in;
-  }
-
-  /*
-   * Legacy APIs.
-   *
-   * None of the methods below are on the critical path of parsing JSON documents. They exist only
-   * because they were exposed by the original implementation and may be used by some clients.
-   */
-
-  /**
-   * Returns true until the input has been exhausted.
-   *
-   * @return true if more input exists.
-   */
-  public boolean more() {
-    return pos < in.length();
-  }
-
-  /**
-   * Returns the next available character, or the null character '\0' if all input has been
-   * exhausted. The return value of this method is ambiguous for JSON strings that contain the
-   * character '\0'.
-   *
-   * @return the next character.
-   */
-  public char next() {
-    return pos < in.length() ? in.charAt(pos++) : '\0';
-  }
-
-  /**
-   * Returns the next available character if it equals {@code c}. Otherwise an exception is thrown.
-   *
-   * @param c The character we are looking for.
-   * @return the next character.
-   * @throws JSONException If the next character isn't {@code c}
-   */
-  public char next(char c) throws JSONException {
-    char result = next();
-    if (result != c) {
-      throw syntaxError("Expected " + c + " but was " + result);
+
+    /**
+     * Returns the {@link String#trim trimmed} string holding the characters up
+     * to but not including the first of:
+     * <ul>
+     * <li>any character in {@code excluded}
+     * <li>a newline character '\n'
+     * <li>a carriage return '\r'
+     * </ul>
+     *
+     * <p>The returned string shares its backing character array with this
+     * tokener's input string. If a reference to the returned string may be held
+     * indefinitely, you should use {@code new String(result)} to copy it first
+     * to avoid memory leaks.
+     *
+     * @param excluded The limiting string where the search should stop.
+     * @return a possibly-empty string
+     */
+    public String nextTo(String excluded) {
+        if (excluded == null) {
+            throw new NullPointerException("excluded == null");
+        }
+        return nextToInternal(excluded).trim();
     }
-    return result;
-  }
-
-  /**
-   * Returns the next character that is not whitespace and does not belong to a comment. If the
-   * input is exhausted before such a character can be found, the null character '\0' is returned.
-   * The return value of this method is ambiguous for JSON strings that contain the character '\0'.
-   *
-   * @return The next non-whitespace character.
-   * @throws JSONException Should not be possible.
-   */
-  public char nextClean() throws JSONException {
-    int nextCleanInt = nextCleanInternal();
-    return nextCleanInt == -1 ? '\0' : (char) nextCleanInt;
-  }
-
-  /**
-   * Returns the next {@code length} characters of the input.
-   *
-   * <p>
-   * The returned string shares its backing character array with this tokener's input string. If a
-   * reference to the returned string may be held indefinitely, you should use
-   * {@code new String(result)} to copy it first to avoid memory leaks.
-   *
-   * @param length The desired number of characters to return.
-   * @return The next few characters.
-   * @throws JSONException if the remaining input is not long enough to satisfy this request.
-   */
-  public String next(int length) throws JSONException {
-    if (pos + length > in.length()) {
-      throw syntaxError(length + " is out of bounds");
+
+    /**
+     * Equivalent to {@code nextTo(String.valueOf(excluded))}.
+     *
+     * @param excluded The limiting character.
+     * @return a possibly-empty string
+     */
+    public String nextTo(char excluded) {
+        return nextToInternal(String.valueOf(excluded)).trim();
     }
-    String result = in.substring(pos, pos + length);
-    pos += length;
-    return result;
-  }
-
-  /**
-   * Returns the {@link String#trim trimmed} string holding the characters up to but not including
-   * the first of:
-   * <ul>
-   * <li>any character in {@code excluded}
-   * <li>a newline character '\n'
-   * <li>a carriage return '\r'
-   * </ul>
-   *
-   * <p>
-   * The returned string shares its backing character array with this tokener's input string. If a
-   * reference to the returned string may be held indefinitely, you should use
-   * {@code new String(result)} to copy it first to avoid memory leaks.
-   *
-   * @param excluded The limiting string where the search should stop.
-   * @return a possibly-empty string
-   */
-  public String nextTo(String excluded) {
-    if (excluded == null) {
-      throw new NullPointerException("excluded == null");
+
+    /**
+     * Advances past all input up to and including the next occurrence of
+     * {@code thru}. If the remaining input doesn't contain {@code thru}, the
+     * input is exhausted.
+     *
+     * @param thru The string to skip over.
+     */
+    public void skipPast(String thru) {
+        int thruStart = in.indexOf(thru, pos);
+        pos = thruStart == -1 ? in.length() : (thruStart + thru.length());
     }
-    return nextToInternal(excluded).trim();
-  }
-
-  /**
-   * Equivalent to {@code nextTo(String.valueOf(excluded))}.
-   *
-   * @param excluded The limiting character.
-   * @return a possibly-empty string
-   */
-  public String nextTo(char excluded) {
-    return nextToInternal(String.valueOf(excluded)).trim();
-  }
-
-  /**
-   * Advances past all input up to and including the next occurrence of {@code thru}. If the
-   * remaining input doesn't contain {@code thru}, the input is exhausted.
-   *
-   * @param thru The string to skip over.
-   */
-  public void skipPast(String thru) {
-    int thruStart = in.indexOf(thru, pos);
-    pos = thruStart == -1 ? in.length() : (thruStart + thru.length());
-  }
-
-  /**
-   * Advances past all input up to but not including the next occurrence of {@code to}. If the
-   * remaining input doesn't contain {@code to}, the input is unchanged.
-   *
-   * @param to The character we want to skip to.
-   * @return The value of {@code to} or null.
-   */
-  public char skipTo(char to) {
-    int index = in.indexOf(to, pos);
-    if (index != -1) {
-      pos = index;
-      return to;
-    } else {
-      return '\0';
+
+    /**
+     * Advances past all input up to but not including the next occurrence of
+     * {@code to}. If the remaining input doesn't contain {@code to}, the input
+     * is unchanged.
+     *
+     * @param to The character we want to skip to.
+     * @return The value of {@code to} or null.
+     */
+    public char skipTo(char to) {
+        int index = in.indexOf(to, pos);
+        if (index != -1) {
+            pos = index;
+            return to;
+        } else {
+            return '\0';
+        }
     }
-  }
-
-  /**
-   * Unreads the most recent character of input. If no input characters have been read, the input is
-   * unchanged.
-   */
-  public void back() {
-    if (--pos == -1) {
-      pos = 0;
+
+    /**
+     * Unreads the most recent character of input. If no input characters have
+     * been read, the input is unchanged.
+     */
+    public void back() {
+        if (--pos == -1) {
+            pos = 0;
+        }
     }
-  }
-
-  /**
-   * Returns the integer [0..15] value for the given hex character, or -1 for non-hex input.
-   *
-   * @param hex a character in the ranges [0-9], [A-F] or [a-f]. Any other character will yield a -1
-   *        result.
-   * @return The decoded integer.
-   */
-  public static int dehexchar(char hex) {
-    if (hex >= '0' && hex <= '9') {
-      return hex - '0';
-    } else if (hex >= 'A' && hex <= 'F') {
-      return hex - 'A' + 10;
-    } else if (hex >= 'a' && hex <= 'f') {
-      return hex - 'a' + 10;
-    } else {
-      return -1;
+
+    /**
+     * Returns the integer [0..15] value for the given hex character, or -1
+     * for non-hex input.
+     *
+     * @param hex a character in the ranges [0-9], [A-F] or [a-f]. Any other
+     *            character will yield a -1 result.
+     * @return The decoded integer.
+     */
+    public static int dehexchar(char hex) {
+        if (hex >= '0' && hex <= '9') {
+            return hex - '0';
+        } else if (hex >= 'A' && hex <= 'F') {
+            return hex - 'A' + 10;
+        } else if (hex >= 'a' && hex <= 'f') {
+            return hex - 'a' + 10;
+        } else {
+            return -1;
+        }
     }
-  }
 }


[7/8] geode git commit: Revert "GEODE-2142: Removal of non-compliant org.json implementation."

Posted by ud...@apache.org.
http://git-wip-us.apache.org/repos/asf/geode/blob/0805036e/geode-json/src/main/java/org/json/JSONArray.java
----------------------------------------------------------------------
diff --git a/geode-json/src/main/java/org/json/JSONArray.java b/geode-json/src/main/java/org/json/JSONArray.java
old mode 100755
new mode 100644
index 074624d..edaefa4
--- a/geode-json/src/main/java/org/json/JSONArray.java
+++ b/geode-json/src/main/java/org/json/JSONArray.java
@@ -1,759 +1,868 @@
+package org.json;
+
 /*
- * 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.
+ * 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.
  */
 
-package org.json;
-
+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.List;
-
-// Note: this class was written without inspecting the non-free org.json sourcecode.
+import java.util.Iterator;
+import java.util.Map;
 
 /**
- * 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.
- *
- * {@code JSONArray} has the same type coercion behavior and
- * optional/mandatory accessors as {@link JSONObject}. See that class'
- * documentation for details.
+ * 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>
  *
- * <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.
+ * @author JSON.org
+ * @version 2012-04-20
  */
 public class JSONArray {
 
-    private final List<Object> values;
-
-    /**
-     * Creates a {@code JSONArray} with no values.
-     */
-    public JSONArray() {
-        values = new ArrayList<Object>();
-    }
-
-    /**
-     * 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.
-     */
-    /* Accept a raw type for API compatibility */
-    public JSONArray(Collection<?> copyFrom) {
-        this();
-        if (copyFrom != null) {
-            for (Object aCopyFrom : copyFrom) {
-                put(JSONObject.wrap(aCopyFrom));
-            }
-        }
-    }
-
-    /**
-     * 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");
-        }
-    }
-
-    /**
-     * 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(String json) throws JSONException {
-        this(new JSONTokener(json));
-    }
-
-    /**
-     * 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 {
-        if (!array.getClass().isArray()) {
-            throw new JSONException("Not a primitive array: " + array.getClass());
-        }
-        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 Returns the number of values in this array.
-     */
-    public int length() {
-        return values.size();
-    }
-
-    /**
-     * Appends {@code value} to the end of this array.
-     *
-     * @param value The value to append.
-     * @return this array.
-     */
-    public JSONArray put(boolean value) {
-        values.add(value);
-        return this;
-    }
-
-    /**
-     * Appends {@code value} to the end of this array.
-     *
-     * @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 JSONArray put(double value) throws JSONException {
-        values.add(JSON.checkDouble(value));
-        return this;
-    }
-
-    /**
-     * Appends {@code value} to the end of this array.
-     *
-     * @param value The value to append.
-     * @return this array.
-     */
-    public JSONArray put(int value) {
-        values.add(value);
-        return this;
-    }
-
-    /**
-     * Appends {@code value} to the end of this array.
-     *
-     * @param value The value to append.
-     * @return this array.
-     */
-    public JSONArray put(long value) {
-        values.add(value);
-        return this;
-    }
-
-    /**
-     * Appends {@code value} wrapped by {@link JSONArray} to the end of this array.
-     *
-     * @param value any collection.
-     * @return this array.
-     */
-    public JSONArray put(Collection<?> value) {
-        if (value == null) {
-            return put((Object)null);
-        }
-        values.add(new JSONArray(value));
-        return this;
-    }
-
-    /**
-     * Appends {@code value} to the end of this array.
-     *
-     * @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 JSONArray put(Object value) {
-        values.add(value);
-        return this;
-    }
-
-    /**
-     * Same as {@link #put}, with added validity checks.
-     *
-     * @param value The value to append.
-     */
-    void checkedPut(Object value) throws JSONException {
-        if (value instanceof Number) {
-            JSON.checkDouble(((Number) value).doubleValue());
-        }
-
-        put(value);
-    }
-
-    /**
-     * 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 JSONArray put(int index, boolean value) throws JSONException {
-        return put(index, (Boolean) value);
-    }
-
-    /**
-     * 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 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 JSONArray put(int index, double value) throws JSONException {
-        return put(index, (Double) value);
-    }
-
-    /**
-     * 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 JSONArray put(int index, int value) throws JSONException {
-        return put(index, (Integer) value);
-    }
-
-    /**
-     * 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 JSONArray put(int index, long value) throws JSONException {
-        return put(index, (Long) value);
-    }
-
-    /**
-     * Sets the value at {@code index} to {@code value} wrapped into {@link JSONArray},
-     * 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 JSONArray put(int index, Collection<?> value) throws JSONException {
-        if (value == null) {
-            return put(index, (Object)null);
-        }
-        return put(index, new JSONArray(value));
-    }
-
-    /**
-     * 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 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 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;
-    }
-
-    /**
-     * 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 Which value to check.
-     * @return true if the value is null.
-     */
-    public boolean isNull(int index) {
-        Object value = opt(index);
-        return value == null || value == JSONObject.NULL;
-    }
-
-    /**
-     * Returns the value at {@code index}.
-     *
-     * @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 Object get(int index) throws JSONException {
-        try {
-            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() + ")");
-        }
-    }
-
-    /**
-     * Returns the value at {@code index}, or null if the array has no value
-     * at {@code index}.
-     *
-     * @param index Which value to get.
-     * @return the value at the specified location.
-     */
-    public Object opt(int index) {
-        if (index < 0 || index >= values.size()) {
-            return null;
-        }
-        return values.get(index);
-    }
-
-    /**
-     * 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 Object remove(int index) {
-        if (index < 0 || index >= values.size()) {
-            return null;
-        }
-        return values.remove(index);
-    }
-
-    /**
-     * 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 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;
-    }
-
-    /**
-     * 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 Which value to get.
-     * @return the value at the specified location.
-     */
-    public boolean optBoolean(int index) {
-        return optBoolean(index, false);
-    }
-
-    /**
-     * 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    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 boolean optBoolean(int index, boolean fallback) {
-        Object object = opt(index);
-        Boolean result = JSON.toBoolean(object);
-        return result != null ? result : fallback;
-    }
-
-    /**
-     * 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 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;
-    }
-
-    /**
-     * 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 Which value to get.
-     * @return the value at the specified location.
-     */
-    public double optDouble(int index) {
-        return optDouble(index, Double.NaN);
-    }
-
-    /**
-     * 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    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 double optDouble(int index, double fallback) {
-        Object object = opt(index);
-        Double result = JSON.toDouble(object);
-        return result != null ? result : fallback;
-    }
-
-    /**
-     * Returns the value at {@code index} if it exists and is an int or
-     * can be coerced to an int.
-     *
-     * @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 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;
-    }
-
-    /**
-     * Returns the value at {@code index} if it exists and is an int or
-     * can be coerced to an int. Returns 0 otherwise.
-     *
-     * @param index Which value to get.
-     * @return the value at the specified location.
-     */
-    public int optInt(int index) {
-        return optInt(index, 0);
-    }
-
-    /**
-     * 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 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 int optInt(int index, int fallback) {
-        Object object = opt(index);
-        Integer result = JSON.toInteger(object);
-        return result != null ? result : fallback;
-    }
-
-    /**
-     * Returns the value at {@code index} if it exists and is a long or
-     * can be coerced to a long.
-     *
-     * @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 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;
-    }
-
-    /**
-     * 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 long optLong(int index) {
-        return optLong(index, 0L);
-    }
-
-    /**
-     * 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 long optLong(int index, long fallback) {
-        Object object = opt(index);
-        Long result = JSON.toLong(object);
-        return result != null ? result : fallback;
-    }
 
-    /**
-     * 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 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;
-    }
-
-    /**
-     * 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 String optString(int index) {
-        return optString(index, "");
-    }
-
-    /**
-     * 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 String optString(int index, String fallback) {
-        Object object = opt(index);
-        String result = JSON.toString(object);
-        return result != null ? result : fallback;
-    }
-
-    /**
-     * 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 getJSONArray(int index) throws JSONException {
-        Object object = get(index);
-        if (object instanceof JSONArray) {
-            return (JSONArray) object;
+  /**
+   * The arrayList where the JSONArray's properties are kept.
+   */
+  private final ArrayList myArrayList;
+
+
+  /**
+   * Construct an empty JSONArray.
+   */
+  public JSONArray() {
+    this.myArrayList = new ArrayList();
+  }
+
+  /**
+   * Construct a JSONArray from a JSONTokener.
+   * 
+   * @param x A JSONTokener
+   * @throws JSONException If there is a syntax error.
+   */
+  public JSONArray(JSONTokener x) throws JSONException {
+    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 {
-            throw JSON.typeMismatch(index, object, "JSONArray");
+          x.back();
+          this.myArrayList.add(x.nextValue());
         }
-    }
-
-    /**
-     * 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 optJSONArray(int index) {
-        Object object = opt(index);
-        return object instanceof JSONArray ? (JSONArray) object : null;
-    }
-
-    /**
-     * 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 JSONObject getJSONObject(int index) throws JSONException {
-        Object object = get(index);
-        if (object instanceof JSONObject) {
-            return (JSONObject) object;
-        } else {
-            throw JSON.typeMismatch(index, object, "JSONObject");
-        }
-    }
-
-    /**
-     * 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 JSONObject optJSONObject(int index) {
-        Object object = opt(index);
-        return object instanceof JSONObject ? (JSONObject) object : 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 {
-        JSONObject result = new JSONObject();
-        int length = Math.min(names.length(), values.size());
-        if (length == 0) {
-            return null;
-        }
-        for (int i = 0; i < length; i++) {
-            String name = JSON.toString(names.opt(i));
-            result.put(name, opt(i));
-        }
-        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);
+        switch (x.nextClean()) {
+          case ';':
+          case ',':
+            if (x.nextClean() == ']') {
+              return;
             }
-            stringer.value(values.get(i));
+            x.back();
+            break;
+          case ']':
+            return;
+          default:
+            throw x.syntaxError("Expected a ',' or ']'");
         }
-        stringer.close(JSONStringer.Scope.NULL, JSONStringer.Scope.NULL, "");
-        return stringer.out.toString();
-    }
-
-    /**
-     * Encodes this array as a compact JSON string, such as:
-     * <pre>[94043,90210]</pre>
-     *
-     * @return The string form of this array.
-     */
-    @Override
-    public String toString() {
-        try {
-            JSONStringer stringer = new JSONStringer();
-            writeTo(stringer);
-            return stringer.toString();
-        } catch (JSONException e) {
-            return null;
+      }
+    }
+  }
+
+
+  /**
+   * 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));
+  }
+
+
+  /**
+   * Construct a JSONArray from a Collection.
+   * 
+   * @param collection A Collection.
+   */
+  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()));
+      }
+    }
+  }
+
+
+  /**
+   * Construct a JSONArray from an array
+   * 
+   * @throws JSONException If not an array.
+   */
+  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.");
+    }
+  }
+
+
+  /**
+   * 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.");
+    }
+    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.
+   */
+  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.");
+  }
+
+
+  /**
+   * Get the double value associated with an index.
+   *
+   * @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.
+   */
+  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.");
+    }
+  }
+
+
+  /**
+   * Get the int value associated with an index.
+   *
+   * @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.
+   */
+  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.");
+    }
+  }
+
+
+  /**
+   * 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
+   */
+  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.");
+  }
+
+
+  /**
+   * 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
+   */
+  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.");
+  }
+
+
+  /**
+   * Get the long value associated with an index.
+   *
+   * @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.
+   */
+  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.");
+    }
+  }
+
+
+  /**
+   * 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.
+   */
+  public String getString(int index) throws JSONException {
+    Object object = this.get(index);
+    if (object instanceof String) {
+      return (String) object;
+    }
+    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));
+  }
+
+
+  /**
+   * 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.
+   */
+  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();
+  }
+
+
+  /**
+   * Get the number of elements in the JSONArray, included nulls.
+   *
+   * @return The length (or size).
+   */
+  public int length() {
+    return this.myArrayList.size();
+  }
+
+
+  /**
+   * 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.
+   */
+  public Object opt(int index) {
+    return (index < 0 || index >= this.length()) ? null : this.myArrayList.get(index);
+  }
+
+
+  /**
+   * 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".
+   *
+   * @param index The index must be between 0 and length() - 1.
+   * @return The truth.
+   */
+  public boolean optBoolean(int index) {
+    return this.optBoolean(index, false);
+  }
+
+
+  /**
+   * 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).
+   *
+   * @param index The index must be between 0 and length() - 1.
+   * @param defaultValue A boolean default.
+   * @return The truth.
+   */
+  public boolean optBoolean(int index, boolean defaultValue) {
+    try {
+      return this.getBoolean(index);
+    } catch (Exception e) {
+      return defaultValue;
+    }
+  }
+
+
+  /**
+   * 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.
+   *
+   * @param index The index must be between 0 and length() - 1.
+   * @return The value.
+   */
+  public double optDouble(int index) {
+    return this.optDouble(index, Double.NaN);
+  }
+
+
+  /**
+   * 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.
+   *
+   * @param index subscript
+   * @param defaultValue The default value.
+   * @return The value.
+   */
+  public double optDouble(int index, double defaultValue) {
+    try {
+      return this.getDouble(index);
+    } catch (Exception e) {
+      return defaultValue;
+    }
+  }
+
+
+  /**
+   * 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.
+   *
+   * @param index The index must be between 0 and length() - 1.
+   * @return The value.
+   */
+  public int optInt(int index) {
+    return this.optInt(index, 0);
+  }
+
+
+  /**
+   * 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.
+   */
+  public int optInt(int index, int defaultValue) {
+    try {
+      return this.getInt(index);
+    } catch (Exception e) {
+      return defaultValue;
+    }
+  }
+
+
+  /**
+   * 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.
+   */
+  public JSONArray optJSONArray(int index) {
+    Object o = this.opt(index);
+    return o instanceof JSONArray ? (JSONArray) o : null;
+  }
+
+
+  /**
+   * 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.
+   *
+   * @param index The index must be between 0 and length() - 1.
+   * @return A JSONObject value.
+   */
+  public JSONObject optJSONObject(int index) {
+    Object o = this.opt(index);
+    return o instanceof JSONObject ? (JSONObject) o : null;
+  }
+
+
+  /**
+   * 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.
+   *
+   * @param index The index must be between 0 and length() - 1.
+   * @return The value.
+   */
+  public long optLong(int index) {
+    return this.optLong(index, 0);
+  }
+
+
+  /**
+   * 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.
+   */
+  public long optLong(int index, long defaultValue) {
+    try {
+      return this.getLong(index);
+    } catch (Exception e) {
+      return defaultValue;
+    }
+  }
+
+
+  /**
+   * 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.
+   *
+   * @param index The index must be between 0 and length() - 1.
+   * @return A String value.
+   */
+  public String optString(int index) {
+    return this.optString(index, "");
+  }
+
+
+  /**
+   * Get the optional string associated with an index. The defaultValue is returned if the key is
+   * not found.
+   *
+   * @param index The index must be between 0 and length() - 1.
+   * @param defaultValue The default value.
+   * @return A String value.
+   */
+  public String optString(int index, String defaultValue) {
+    Object object = this.opt(index);
+    return JSONObject.NULL.equals(object) ? defaultValue : object.toString();
+  }
+
+
+  /**
+   * Append a boolean value. This increases the array's length by one.
+   *
+   * @param value A boolean value.
+   * @return this.
+   */
+  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;
+  }
+
+
+  /**
+   * Append a double value. This increases the array's length by one.
+   *
+   * @param value A double value.
+   * @throws JSONException if the value is not finite.
+   * @return this.
+   */
+  public JSONArray put(double value) throws JSONException {
+    Double d = new Double(value);
+    JSONObject.testValidity(d);
+    this.put(d);
+    return this;
+  }
+
+
+  /**
+   * Append an int value. This increases the array's length by one.
+   *
+   * @param value An int value.
+   * @return this.
+   */
+  public JSONArray put(int value) {
+    this.put(new Integer(value));
+    return this;
+  }
+
+
+  /**
+   * Append an long value. This increases the array's length by one.
+   *
+   * @param value A long value.
+   * @return this.
+   */
+  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;
+  }
+
+
+  /**
+   * 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.
+   */
+  public JSONArray put(Object value) {
+    this.myArrayList.add(value);
+    return this;
+  }
+
+
+  /**
+   * 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.
+   */
+  public JSONArray put(int index, boolean value) throws JSONException {
+    this.put(index, 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 index The subscript.
+   * @param value A Collection value.
+   * @return this.
+   * @throws JSONException If the index is negative or if the value is not finite.
+   */
+  public JSONArray put(int index, Collection value) throws JSONException {
+    this.put(index, new JSONArray(value));
+    return this;
+  }
+
+
+  /**
+   * 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.
+   */
+  public JSONArray put(int index, double value) throws JSONException {
+    this.put(index, new Double(value));
+    return this;
+  }
+
+
+  /**
+   * 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.
+   */
+  public JSONArray put(int index, int value) throws JSONException {
+    this.put(index, new Integer(value));
+    return this;
+  }
+
+
+  /**
+   * 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.
+   */
+  public JSONArray put(int index, long value) throws JSONException {
+    this.put(index, new Long(value));
+    return this;
+  }
+
+
+  /**
+   * 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.
+   */
+  public JSONArray put(int index, Map value) throws JSONException {
+    this.put(index, new JSONObject(value));
+    return this;
+  }
+
+
+  /**
+   * 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.
+   */
+  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);
+    } else {
+      while (index != this.length()) {
+        this.put(JSONObject.NULL);
+      }
+      this.put(value);
+    }
+    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.
+   */
+  public Object remove(int index) {
+    Object o = this.opt(index);
+    this.myArrayList.remove(index);
+    return o;
+  }
+
+
+  /**
+   * 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.
+   */
+  public JSONObject toJSONObject(JSONArray names) throws JSONException {
+    if (names == null || names.length() == 0 || this.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));
+    }
+    return jo;
+  }
+
+
+  /**
+   * 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.
+   *
+   * @return a printable, displayable, transmittable representation of the array.
+   */
+  public String toString() {
+    try {
+      return '[' + this.join(",") + ']';
+    } catch (Exception 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
+   */
+  public String toString(int indentFactor) throws JSONException {
+    StringWriter sw = new StringWriter();
+    synchronized (sw.getBuffer()) {
+      return this.write(sw, indentFactor, 0).toString();
+    }
+  }
+
+  /**
+   * 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);
+  }
+
+  /**
+   * 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;
         }
-    }
-
-    /**
-     * 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 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);
+        if (indentFactor > 0) {
+          writer.write('\n');
         }
-        stringer.endArray();
-    }
-
-    @Override
-    public boolean equals(Object o) {
-        return o instanceof JSONArray && ((JSONArray) o).values.equals(values);
-    }
-
-    @Override
-    public int hashCode() {
-        // diverge from the original, which doesn't implement hashCode
-        return values.hashCode();
-    }
+        JSONObject.indent(writer, indent);
+      }
+      writer.write(']');
+      return writer;
+    } catch (IOException e) {
+      throw new JSONException(e);
+    }
+  }
 }

http://git-wip-us.apache.org/repos/asf/geode/blob/0805036e/geode-json/src/main/java/org/json/JSONException.java
----------------------------------------------------------------------
diff --git a/geode-json/src/main/java/org/json/JSONException.java b/geode-json/src/main/java/org/json/JSONException.java
index 1292e86..b65efe2 100755
--- a/geode-json/src/main/java/org/json/JSONException.java
+++ b/geode-json/src/main/java/org/json/JSONException.java
@@ -1,57 +1,30 @@
-/*
- * 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.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>
+ * The JSONException is thrown by the JSON.org classes when things are amiss.
+ * 
+ * @author JSON.org
+ * @version 2010-12-24
  */
-public class JSONException extends RuntimeException {
+public class JSONException extends Exception {
+  private static final long serialVersionUID = 0;
+  private Throwable cause;
 
-    public JSONException(String s) {
-        super(s);
-    }
+  /**
+   * 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);
-    }
+  public JSONException(Throwable cause) {
+    super(cause.getMessage());
+    this.cause = cause;
+  }
 
-    public JSONException(String message, Throwable cause) {
-        super(message, cause);
-    }
+  public Throwable getCause() {
+    return this.cause;
+  }
 }

http://git-wip-us.apache.org/repos/asf/geode/blob/0805036e/geode-json/src/main/java/org/json/JSONML.java
----------------------------------------------------------------------
diff --git a/geode-json/src/main/java/org/json/JSONML.java b/geode-json/src/main/java/org/json/JSONML.java
new file mode 100755
index 0000000..b535614
--- /dev/null
+++ b/geode-json/src/main/java/org/json/JSONML.java
@@ -0,0 +1,454 @@
+package org.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();
+  }
+}


[6/8] geode git commit: Revert "GEODE-2142: Removal of non-compliant org.json implementation."

Posted by ud...@apache.org.
http://git-wip-us.apache.org/repos/asf/geode/blob/0805036e/geode-json/src/main/java/org/json/JSONObject.java
----------------------------------------------------------------------
diff --git a/geode-json/src/main/java/org/json/JSONObject.java b/geode-json/src/main/java/org/json/JSONObject.java
index d5de19f..a2c6d8b 100755
--- a/geode-json/src/main/java/org/json/JSONObject.java
+++ b/geode-json/src/main/java/org/json/JSONObject.java
@@ -1,1005 +1,1525 @@
+package org.json;
+
 /*
- * 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.
+ * 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.
  */
 
-package org.json;
-
-import java.beans.IntrospectionException;
-import java.beans.Introspector;
-import java.beans.PropertyDescriptor;
-import java.lang.reflect.InvocationTargetException;
+import java.io.IOException;
+import java.io.StringWriter;
+import java.io.Writer;
+import java.lang.reflect.Field;
 import java.lang.reflect.Method;
 import java.lang.reflect.Modifier;
-import java.util.ArrayList;
 import java.util.Collection;
+import java.util.Enumeration;
 import java.util.Iterator;
 import java.util.LinkedHashMap;
+import java.util.Locale;
 import java.util.Map;
+import java.util.ResourceBundle;
 import java.util.Set;
-import java.util.TreeMap;
-
-// Note: this class was written without inspecting the non-free org.json sourcecode.
 
 /**
- * A modifiable set of name/value mappings. Names are unique, non-null strings.
- * Values may be any mix of {@link JSONObject JSONObjects}, {@link JSONArray
- * JSONArrays}, Strings, Booleans, Integers, Longs, Doubles or {@link #NULL}.
- * Values may not be {@code null}, {@link Double#isNaN() NaNs}, {@link
- * Double#isInfinite() infinities}, or of any type not listed here.
+ * A JSONObject is an unordered collection of name/value pairs. Its external form is a string
+ * wrapped in curly braces with colons between the names and values, and commas between the values
+ * and names. The internal form is an object having <code>get</code> and <code>opt</code> methods
+ * for accessing the values by name, and <code>put</code> methods for adding or replacing values by
+ * name. 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</code> object. A JSONObject constructor can be used to convert an external
+ * form JSON text into an internal form whose values can be retrieved with the <code>get</code> and
+ * <code>opt</code> methods, or to convert values into a JSON text using the <code>put</code> and
+ * <code>toString</code> methods. 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. The opt methods differ from the get methods in that
+ * they do not throw. Instead, they return a specified value, such as null.
+ * <p>
+ * The <code>put</code> methods add or replace values in an object. For example,
  *
- * <p>This class can coerce values to another type when requested.
- * <ul>
- * <li>When the requested type is a boolean, strings will be coerced using a
- * case-insensitive comparison to "true" and "false".
- * <li>When the requested type is a double, other {@link Number} types will
- * be coerced using {@link Number#doubleValue() doubleValue}. Strings
- * that can be coerced using {@link Double#valueOf(String)} will be.
- * <li>When the requested type is an int, other {@link Number} types will
- * be coerced using {@link Number#intValue() intValue}. Strings
- * that can be coerced using {@link Double#valueOf(String)} will be,
- * and then cast to int.
- * <li><a name="lossy">When the requested type is a long, other {@link Number} types will
- * be coerced using {@link Number#longValue() longValue}. Strings
- * that can be coerced using {@link Double#valueOf(String)} will be,
- * and then cast to long. This two-step conversion is lossy for very
- * large values. For example, the string "9223372036854775806" yields the
- * long 9223372036854775807.</a>
- * <li>When the requested type is a String, other non-null values will be
- * coerced using {@link String#valueOf(Object)}. Although null cannot be
- * coerced, the sentinel value {@link JSONObject#NULL} is coerced to the
- * string "null".
- * </ul>
+ * <pre>
+ * myString = new JSONObject().put(&quot;JSON&quot;, &quot;Hello, World!&quot;).toString();
+ * </pre>
  *
- * <p>This class can look up both mandatory and optional values:
+ * produces the string <code>{"JSON": "Hello, World"}</code>.
+ * <p>
+ * The texts produced by the <code>toString</code> methods strictly conform to the JSON syntax
+ * rules. The constructors are more forgiving in the texts they will accept:
  * <ul>
- * <li>Use <code>get<i>Type</i>()</code> to retrieve a mandatory value. This
- * fails with a {@code JSONException} if the requested name has no value
- * or if the value cannot be coerced to the requested type.
- * <li>Use <code>opt<i>Type</i>()</code> to retrieve an optional value. This
- * returns a system- or user-supplied default if the requested name has no
- * value or if the value cannot be coerced to the requested type.
+ * <li>An extra <code>,</code>&nbsp;<small>(comma)</small> may appear just before the closing
+ * brace.</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>Keys can be followed by <code>=</code> or <code>=></code> as well as by <code>:</code>.</li>
+ * <li>Values can be followed by <code>;</code> <small>(semicolon)</small> as well as by
+ * <code>,</code> <small>(comma)</small>.</li>
  * </ul>
  *
- * <p><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, calling {@code put(name, null)} removes the
- * named entry from the object but {@code put(name, JSONObject.NULL)} stores an
- * entry whose value is {@code JSONObject.NULL}.
- *
- * <p>Instances of this class are not thread safe. Although this class is
- * nonfinal, it was not designed for inheritance and should not be subclassed.
- * In particular, self-use by overrideable methods is not specified. See
- * <i>Effective Java</i> Item 17, "Design and Document or inheritance or else
- * prohibit it" for further information.
+ * @author JSON.org
+ * @version 2012-05-29
  */
 public class JSONObject {
-
-  private static final Double NEGATIVE_ZERO = -0d;
-
-  public static ThreadLocal<Set> cyclicDependencySet = new ThreadLocal();
-  public static ThreadLocal<Boolean> cyclicDepChkEnabled = new ThreadLocal();
-
   /**
-   * A sentinel value used to explicitly define a name with no value. Unlike
-   * {@code null}, names with this value:
-   * <ul>
-   * <li>show up in the {@link #names} array
-   * <li>show up in the {@link #keys} iterator
-   * <li>return {@code true} for {@link #has(String)}
-   * <li>do not throw on {@link #get(String)}
-   * <li>are included in the encoded JSON string.
-   * </ul>
-   *
-   * <p>This value violates the general contract of {@link Object#equals} by
-   * returning true when compared to {@code null}. Its {@link #toString}
-   * method returns "null".
+   * JSONObject.NULL is equivalent to the value that JavaScript calls null, whilst Java's null is
+   * equivalent to the value that JavaScript calls undefined.
    */
-  public static final Object NULL = new Object() {
-    @SuppressWarnings("EqualsWhichDoesntCheckParameterClass")
-    @Override
-    public boolean equals(Object o) {
-      return o == this || o == null; // API specifies this broken equals implementation
+  private static final class Null {
+
+    /**
+     * There is only intended to be a single instance of the NULL object, so the clone method
+     * returns itself.
+     * 
+     * @return NULL.
+     */
+    protected final Object clone() {
+      return this;
     }
 
-    // at least make the broken equals(null) consistent with Objects.hashCode(null).
-    @Override
-    public int hashCode() {
-      return 0;
+    /**
+     * A Null object is equal to the null value and to itself.
+     * 
+     * @param object An object to test for nullness.
+     * @return true if the object parameter is the JSONObject.NULL object or null.
+     */
+    public boolean equals(Object object) {
+      return object == null || object == this;
     }
 
-    @Override
+    /**
+     * Get the "null" string value.
+     * 
+     * @return The string "null".
+     */
     public String toString() {
       return "null";
     }
-  };
+  }
+
+
+  /**
+   * The map where the JSONObject's properties are kept.
+   */
+  private final Map map;
+
+
+  /**
+   * It is sometimes more convenient and less ambiguous to have a <code>NULL</code> object than to
+   * use Java's <code>null</code> value. <code>JSONObject.NULL.equals(null)</code> returns
+   * <code>true</code>. <code>JSONObject.NULL.toString()</code> returns <code>"null"</code>.
+   */
+  public static final Object NULL = new Null();
+
+
+  public static ThreadLocal<Set> cyclicDependencySet = new ThreadLocal();
+  public static ThreadLocal<Boolean> cyclicDepChkEnabled = new ThreadLocal();
 
-  private final LinkedHashMap<String, Object> nameValuePairs;
 
   /**
-   * Creates a {@code JSONObject} with no name/value mappings.
+   * Construct an empty JSONObject.
    */
   public JSONObject() {
-    nameValuePairs = new LinkedHashMap<String, Object>();
+    this.map = new LinkedHashMap();
   }
 
+
   /**
-   * Creates a new {@code JSONObject} by copying all name/value mappings from
-   * the given map.
-   * @param copyFrom a map whose keys are of type {@link String} and whose values are of supported
-   * types.
-   * @throws NullPointerException if any of the map's keys are null.
+   * Construct a JSONObject from a subset of another JSONObject. An array of strings is used to
+   * identify the keys that should be copied. Missing keys are ignored.
+   * 
+   * @param jo A JSONObject.
+   * @param names An array of strings.
    */
-    /* (accept a raw type for API compatibility) */
-  public JSONObject(Map copyFrom) {
+  public JSONObject(JSONObject jo, String[] names) {
     this();
-    Map<?, ?> contentsTyped = (Map<?, ?>) copyFrom;
-    for (Map.Entry<?, ?> entry : contentsTyped.entrySet()) {
-            /*
-             * Deviate from the original by checking that keys are non-null and
-             * of the proper type. (We still defer validating the values).
-             */
-      String key = (String) entry.getKey();
-      if (key == null) {
-        throw new NullPointerException("key == null");
+    for (int i = 0; i < names.length; i += 1) {
+      try {
+        this.putOnce(names[i], jo.opt(names[i]));
+      } catch (Exception ignore) {
       }
-      nameValuePairs.put(key, wrap(entry.getValue()));
     }
   }
 
+
   /**
-   * Creates a new {@code JSONObject} with name/value mappings from the next
-   * object in the tokener.
-   * @param readFrom a tokener whose nextValue() method will yield a {@code JSONObject}.
-   * @throws JSONException if the parse fails or doesn't yield a {@code JSONObject}.
+   * Construct a JSONObject from a JSONTokener.
+   * 
+   * @param x A JSONTokener object containing the source string.
+   * @throws JSONException If there is a syntax error in the source string or a duplicated key.
    */
-  public JSONObject(JSONTokener readFrom) throws JSONException {
-        /*
-         * Getting the parser to populate this could get tricky. Instead, just
-         * parse to temporary JSONObject and then steal the data from that.
-         */
-    Object object = readFrom.nextValue();
-    if (object instanceof JSONObject) {
-      this.nameValuePairs = ((JSONObject) object).nameValuePairs;
-    } else {
-      throw JSON.typeMismatch(object, "JSONObject");
+  public JSONObject(JSONTokener x) throws JSONException {
+    this();
+    char c;
+    String key;
+
+    if (x.nextClean() != '{') {
+      throw x.syntaxError("A JSONObject text must begin with '{'");
     }
-  }
+    for (;;) {
+      c = x.nextClean();
+      switch (c) {
+        case 0:
+          throw x.syntaxError("A JSONObject text must end with '}'");
+        case '}':
+          return;
+        default:
+          x.back();
+          key = x.nextValue().toString();
+      }
 
-  /**
-   * Creates a new {@code JSONObject} with name/value mappings from the JSON
-   * string.
-   * @param json a JSON-encoded string containing an object.
-   * @throws JSONException if the parse fails or doesn't yield a {@code JSONObject}.
-   */
-  public JSONObject(String json) throws JSONException {
-    this(new JSONTokener(json));
+      // The key is followed by ':'. We will also tolerate '=' or '=>'.
+
+      c = x.nextClean();
+      if (c == '=') {
+        if (x.next() != '>') {
+          x.back();
+        }
+      } else if (c != ':') {
+        throw x.syntaxError("Expected a ':' after a key");
+      }
+      this.putOnce(key, x.nextValue());
+
+      // Pairs are separated by ','. We will also tolerate ';'.
+
+      switch (x.nextClean()) {
+        case ';':
+        case ',':
+          if (x.nextClean() == '}') {
+            return;
+          }
+          x.back();
+          break;
+        case '}':
+          return;
+        default:
+          throw x.syntaxError("Expected a ',' or '}'");
+      }
+    }
   }
 
+
   /**
-   * Creates a new {@code JSONObject} by copying mappings for the listed names
-   * from the given object. Names that aren't present in {@code copyFrom} will
-   * be skipped.
-   * @param copyFrom The source object.
-   * @param names The names of the fields to copy.
-   * @throws JSONException On internal errors. Shouldn't happen.
+   * Construct a JSONObject from a Map.
+   *
+   * @param map A map object that can be used to initialize the contents of the JSONObject.
    */
-  public JSONObject(JSONObject copyFrom, String[] names) throws JSONException {
-    this();
-    for (String name : names) {
-      Object value = copyFrom.opt(name);
-      if (value != null) {
-        nameValuePairs.put(name, value);
+  public JSONObject(Map map) {
+    this.map = new LinkedHashMap();
+    if (map != null) {
+      Iterator i = map.entrySet().iterator();
+      while (i.hasNext()) {
+        Map.Entry e = (Map.Entry) i.next();
+        Object value = e.getValue();
+        if (value != null) {
+          this.map.put(e.getKey(), wrap(value));
+        }
       }
     }
   }
 
+
   /**
-   * Creates a json object from a bean
-   * @param bean the bean to create the json object from
-   * @throws JSONException If there is an exception while reading the bean
+   * Construct a JSONObject from an Object using bean getters. It reflects on all of the public
+   * methods of the object. For each of the methods with no parameters and a name starting with
+   * <code>"get"</code> or <code>"is"</code> followed by an uppercase letter, the method is invoked,
+   * and a key and the value returned from the getter method are put into the new JSONObject.
+   *
+   * The key is formed by removing the <code>"get"</code> or <code>"is"</code> prefix. If the second
+   * remaining character is not upper case, then the first character is converted to lower case.
+   *
+   * For example, if an object has a method named <code>"getName"</code>, and if the result of
+   * calling <code>object.getName()</code> is <code>"Larry Fine"</code>, then the JSONObject will
+   * contain <code>"name": "Larry Fine"</code>.
+   *
+   * @param bean An object that has getter methods that should be used to make a JSONObject.
    */
-  public JSONObject(Object bean) throws JSONException {
-    this(propertiesAsMap(bean));
+  public JSONObject(Object bean) {
+    this();
+    this.populateMap(bean);
   }
 
-  //This is custom properties mapping specific for GEODE
-  private static Map<String, Object> propertiesAsMap(Object bean) {
-    Map<String, Object> props = new TreeMap();
-    Class klass = bean.getClass();
-
-    // If klass is a System class then set includeSuperClass to false.
-
-    boolean includeSuperClass = klass.getClassLoader() != null;
 
-    Method[] methods = includeSuperClass ? klass.getMethods() : klass.getDeclaredMethods();
-    for (int i = 0; i < methods.length; i += 1) {
+  /**
+   * Construct a JSONObject from an Object, using reflection to find the public members. The
+   * resulting JSONObject's keys will be the strings from the names array, and the values will be
+   * the field values associated with those keys in the object. If a key is not found or not
+   * visible, then it will not be copied into the new JSONObject.
+   * 
+   * @param object An object that has fields that should be used to make a JSONObject.
+   * @param names An array of strings, the names of the fields to be obtained from the object.
+   */
+  public JSONObject(Object object, String names[]) {
+    this();
+    Class c = object.getClass();
+    for (int i = 0; i < names.length; i += 1) {
+      String name = names[i];
       try {
-        Method method = methods[i];
-        if (Modifier.isPublic(method.getModifiers()) && !Modifier.isStatic(method.getModifiers())) {
-          String name = method.getName();
-          String key = "";
-          if (name.startsWith("get")) {
-            if ("getClass".equals(name) || "getDeclaringClass".equals(name)) {
-              key = "";
-            } else {
-              key = name.substring(3);
-            }
-          } else if (name.startsWith("is")) {
-            key = name.substring(2);
-          }
-          if (key.length() > 0 && Character.isUpperCase(key.charAt(0))
-              && method.getParameterTypes().length == 0) {
-            if (key.length() == 1) {
-              key = key.toLowerCase();
-            } else if (!Character.isUpperCase(key.charAt(1))) {
-              key = key.substring(0, 1).toLowerCase() + key.substring(1);
-            }
-            Object result = method.invoke(bean, (Object[]) null);
-            if (result != null) {
-              props.put(key, wrap(result));
-            } else if (!method.getReturnType().isArray()) {
-              props.put(key, JSONObject.NULL);
-            }
-          }
-        }
+        this.putOpt(name, c.getField(name).get(object));
       } catch (Exception ignore) {
       }
     }
-    props.put("type-class", klass.getCanonicalName());
-    return props;
   }
 
-  public static String[] getNames(JSONObject x) {
-    Set<String> names = x.keySet();
-    String[] r = new String[names.size()];
-    int i = 0;
-    for (String name : names) {
-      r[i++] = name;
-    }
-    return r;
-  }
 
   /**
-   * Returns the number of name/value mappings in this object.
-   * @return the length of this.
+   * Construct a JSONObject from a source JSON text string. This is the most commonly used
+   * JSONObject constructor.
+   * 
+   * @param source A string beginning with <code>{</code>&nbsp;<small>(left brace)</small> and
+   *        ending with <code>}</code>&nbsp;<small>(right brace)</small>.
+   * @exception JSONException If there is a syntax error in the source string or a duplicated key.
    */
-  public int length() {
-    return nameValuePairs.size();
+  public JSONObject(String source) throws JSONException {
+    this(new JSONTokener(source));
   }
 
+
   /**
-   * Maps {@code name} to {@code value}, clobbering any existing name/value
-   * mapping with the same name.
-   * @param name The name of the value to insert.
-   * @param value The value to insert.
-   * @return this object.
-   * @throws JSONException Should not be possible.
+   * Construct a JSONObject from a ResourceBundle.
+   * 
+   * @param baseName The ResourceBundle base name.
+   * @param locale The Locale to load the ResourceBundle for.
+   * @throws JSONException If any JSONExceptions are detected.
    */
-  public JSONObject put(String name, boolean value) throws JSONException {
-    nameValuePairs.put(checkName(name), value);
-    return this;
+  public JSONObject(String baseName, Locale locale) throws JSONException {
+    this();
+    ResourceBundle bundle =
+        ResourceBundle.getBundle(baseName, locale, Thread.currentThread().getContextClassLoader());
+
+    // Iterate through the keys in the bundle.
+
+    Enumeration keys = bundle.getKeys();
+    while (keys.hasMoreElements()) {
+      Object key = keys.nextElement();
+      if (key instanceof String) {
+
+        // Go through the path, ensuring that there is a nested JSONObject for each
+        // segment except the last. Add the value using the last segment's name into
+        // the deepest nested JSONObject.
+
+        String[] path = ((String) key).split("\\.");
+        int last = path.length - 1;
+        JSONObject target = this;
+        for (int i = 0; i < last; i += 1) {
+          String segment = path[i];
+          JSONObject nextTarget = target.optJSONObject(segment);
+          if (nextTarget == null) {
+            nextTarget = new JSONObject();
+            target.put(segment, nextTarget);
+          }
+          target = nextTarget;
+        }
+        target.put(path[last], bundle.getString((String) key));
+      }
+    }
   }
 
+
   /**
-   * Maps {@code name} to {@code value}, clobbering any existing name/value
-   * mapping with the same name.
-   * @param name The name for the new value.
-   * @param value a finite value. May not be {@link Double#isNaN() NaNs} or {@link
-   * Double#isInfinite() infinities}.
-   * @return this object.
-   * @throws JSONException if value is NaN or infinite.
+   * Accumulate values under a key. It is similar to the put method except that if there is already
+   * an object stored under the key then a JSONArray is stored under the key to hold all of the
+   * accumulated values. If there is already a JSONArray, then the new value is appended to it. In
+   * contrast, the put method replaces the previous value.
+   *
+   * If only one value is accumulated that is not a JSONArray, then the result will be the same as
+   * using put. But if multiple values are accumulated, then the result will be like append.
+   * 
+   * @param key A key string.
+   * @param value An object to be accumulated under the key.
+   * @return this.
+   * @throws JSONException If the value is an invalid number or if the key is null.
    */
-  public JSONObject put(String name, double value) throws JSONException {
-    nameValuePairs.put(checkName(name), JSON.checkDouble(value));
+  public JSONObject accumulate(String key, Object value) throws JSONException {
+    testValidity(value);
+    Object object = this.opt(key);
+    if (object == null) {
+      this.put(key, value instanceof JSONArray ? new JSONArray().put(value) : value);
+    } else if (object instanceof JSONArray) {
+      ((JSONArray) object).put(value);
+    } else {
+      this.put(key, new JSONArray().put(object).put(value));
+    }
     return this;
   }
 
+
   /**
-   * Maps {@code name} to {@code value}, clobbering any existing name/value
-   * mapping with the same name.
-   * @param name The name for the new value.
-   * @param value The new value.
-   * @return this object.
-   * @throws JSONException Should not be possible.
+   * Append values to the array under a key. If the key does not exist in the JSONObject, then the
+   * key is put in the JSONObject with its value being a JSONArray containing the value parameter.
+   * If the key was already associated with a JSONArray, then the value parameter is appended to it.
+   * 
+   * @param key A key string.
+   * @param value An object to be accumulated under the key.
+   * @return this.
+   * @throws JSONException If the key is null or if the current value associated with the key is not
+   *         a JSONArray.
    */
-  public JSONObject put(String name, int value) throws JSONException {
-    nameValuePairs.put(checkName(name), value);
+  public JSONObject append(String key, Object value) throws JSONException {
+    testValidity(value);
+    Object object = this.opt(key);
+    if (object == null) {
+      this.put(key, new JSONArray().put(value));
+    } else if (object instanceof JSONArray) {
+      this.put(key, ((JSONArray) object).put(value));
+    } else {
+      throw new JSONException("JSONObject[" + key + "] is not a JSONArray.");
+    }
     return this;
   }
 
+
   /**
-   * Maps {@code name} to {@code value}, clobbering any existing name/value
-   * mapping with the same name.
-   * @param name The name of the new value.
-   * @param value The new value to insert.
-   * @return this object.
-   * @throws JSONException Should not be possible.
+   * Produce a string from a double. The string "null" will be returned if the number is not finite.
+   * 
+   * @param d A double.
+   * @return A String.
    */
-  public JSONObject put(String name, long value) throws JSONException {
-    nameValuePairs.put(checkName(name), value);
-    return this;
+  public static String doubleToString(double d) {
+    if (Double.isInfinite(d) || Double.isNaN(d)) {
+      return "null";
+    }
+
+    // Shave off trailing zeros and decimal point, if possible.
+
+    String string = Double.toString(d);
+    if (string.indexOf('.') > 0 && string.indexOf('e') < 0 && string.indexOf('E') < 0) {
+      while (string.endsWith("0")) {
+        string = string.substring(0, string.length() - 1);
+      }
+      if (string.endsWith(".")) {
+        string = string.substring(0, string.length() - 1);
+      }
+    }
+    return string;
   }
 
+
   /**
-   * Maps {@code name} to {@code value}, clobbering any existing name/value
-   * mapping with the same name. If the value is {@code null}, any existing
-   * mapping for {@code name} is removed.
-   * @param name The name of the new value.
-   * @param value a {@link JSONObject}, {@link JSONArray}, String, Boolean, Integer, Long, Double,
-   * {@link #NULL}, or {@code null}. May not be {@link Double#isNaN() NaNs} or {@link
-   * Double#isInfinite() infinities}.
-   * @return this object.
-   * @throws JSONException if the value is an invalid double (infinite or NaN).
+   * Get the value object associated with a key.
+   *
+   * @param key A key string.
+   * @return The object associated with the key.
+   * @throws JSONException if the key is not found.
    */
-  public JSONObject put(String name, Object value) throws JSONException {
-    if (value == null) {
-      nameValuePairs.remove(name);
-      return this;
+  public Object get(String key) throws JSONException {
+    if (key == null) {
+      throw new JSONException("Null key.");
     }
-    if (value instanceof Number) {
-      // deviate from the original by checking all Numbers, not just floats & doubles
-      JSON.checkDouble(((Number) value).doubleValue());
+    Object object = this.opt(key);
+    if (object == null) {
+      throw new JSONException("JSONObject[" + quote(key) + "] not found.");
     }
-    nameValuePairs.put(checkName(name), value);
-    return this;
+    return object;
   }
 
+
   /**
-   * Put a key/value pair in the JSONObject, where the value will be a JSONArray which is produced
-   * from a Collection.
+   * Get the boolean value associated with a key.
    *
    * @param key A key string.
-   * @param value A Collection value.
-   * @return this.
-   * @throws JSONException
+   * @return The truth.
+   * @throws JSONException if the value is not a Boolean or the String "true" or "false".
    */
-  public JSONObject put(String key, Collection value) throws JSONException {
-    this.put(key, new JSONArray(value));
-    return this;
+  public boolean getBoolean(String key) throws JSONException {
+    Object object = this.get(key);
+    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("JSONObject[" + quote(key) + "] is not a Boolean.");
   }
 
+
   /**
-   * Equivalent to {@code put(name, value)} when both parameters are non-null;
-   * does nothing otherwise.
-   * @param name The name of the value to insert.
-   * @param value The value to insert.
-   * @return this object.
-   * @throws JSONException if the value is an invalid double (infinite or NaN).
+   * Get the double value associated with a key.
+   * 
+   * @param key A key string.
+   * @return The numeric value.
+   * @throws JSONException if the key is not found or if the value is not a Number object and cannot
+   *         be converted to a number.
    */
-  public JSONObject putOpt(String name, Object value) throws JSONException {
-    if (name == null || value == null) {
-      return this;
+  public double getDouble(String key) throws JSONException {
+    Object object = this.get(key);
+    try {
+      return object instanceof Number ? ((Number) object).doubleValue()
+          : Double.parseDouble((String) object);
+    } catch (Exception e) {
+      throw new JSONException("JSONObject[" + quote(key) + "] is not a number.");
     }
-    return put(name, value);
   }
 
+
   /**
-   * Appends {@code value} to the array already mapped to {@code name}. If
-   * this object has no mapping for {@code name}, this inserts a new mapping.
-   * If the mapping exists but its value is not an array, the existing
-   * and new values are inserted in order into a new array which is itself
-   * mapped to {@code name}. In aggregate, this allows values to be added to a
-   * mapping one at a time.
+   * Get the int value associated with a key.
    *
-   * Note that {@code append(String, Object)} provides better semantics.
-   * In particular, the mapping for {@code name} will <b>always</b> be a
-   * {@link JSONArray}. Using {@code accumulate} will result in either a
-   * {@link JSONArray} or a mapping whose type is the type of {@code value}
-   * depending on the number of calls to it.
-   * @param name The name of the field to change.
-   * @param value a {@link JSONObject}, {@link JSONArray}, String, Boolean, Integer, Long, Double,
-   * {@link #NULL} or null. May not be {@link Double#isNaN() NaNs} or {@link Double#isInfinite()
-   * infinities}.
-   * @return this object after mutation.
-   * @throws JSONException If the object being added is an invalid number.
+   * @param key A key string.
+   * @return The integer value.
+   * @throws JSONException if the key is not found or if the value cannot be converted to an
+   *         integer.
    */
-  // TODO: Change {@code append) to {@link #append} when append is
-  // unhidden.
-  public JSONObject accumulate(String name, Object value) throws JSONException {
-    Object current = nameValuePairs.get(checkName(name));
-    if (current == null) {
-      return put(name, value);
+  public int getInt(String key) throws JSONException {
+    Object object = this.get(key);
+    try {
+      return object instanceof Number ? ((Number) object).intValue()
+          : Integer.parseInt((String) object);
+    } catch (Exception e) {
+      throw new JSONException("JSONObject[" + quote(key) + "] is not an int.");
     }
+  }
 
-    if (current instanceof JSONArray) {
-      JSONArray array = (JSONArray) current;
-      array.checkedPut(value);
-    } else {
-      JSONArray array = new JSONArray();
-      array.checkedPut(current);
-      array.checkedPut(value);
-      nameValuePairs.put(name, array);
+
+  /**
+   * Get the JSONArray value associated with a key.
+   *
+   * @param key A key string.
+   * @return A JSONArray which is the value.
+   * @throws JSONException if the key is not found or if the value is not a JSONArray.
+   */
+  public JSONArray getJSONArray(String key) throws JSONException {
+    Object object = this.get(key);
+    if (object instanceof JSONArray) {
+      return (JSONArray) object;
     }
-    return this;
+    throw new JSONException("JSONObject[" + quote(key) + "] is not a JSONArray.");
   }
 
+
   /**
-   * Appends values to the array mapped to {@code name}. A new {@link JSONArray}
-   * mapping for {@code name} will be inserted if no mapping exists. If the existing
-   * mapping for {@code name} is not a {@link JSONArray}, a {@link JSONException}
-   * will be thrown.
-   * @param name The name of the array to which the value should be appended.
-   * @param value The value to append.
-   * @return this object.
-   * @throws JSONException if {@code name} is {@code null} or if the mapping for {@code name} is
-   * non-null and is not a {@link JSONArray}.
+   * Get the JSONObject value associated with a key.
+   *
+   * @param key A key string.
+   * @return A JSONObject which is the value.
+   * @throws JSONException if the key is not found or if the value is not a JSONObject.
    */
-  public JSONObject append(String name, Object value) throws JSONException {
-    Object current = nameValuePairs.get(checkName(name));
-
-    final JSONArray array;
-    if (current instanceof JSONArray) {
-      array = (JSONArray) current;
-    } else if (current == null) {
-      JSONArray newArray = new JSONArray();
-      nameValuePairs.put(name, newArray);
-      array = newArray;
-    } else {
-      throw new JSONException("Key " + name + " is not a JSONArray");
+  public JSONObject getJSONObject(String key) throws JSONException {
+    Object object = this.get(key);
+    if (object instanceof JSONObject) {
+      return (JSONObject) object;
     }
+    throw new JSONException("JSONObject[" + quote(key) + "] is not a JSONObject.");
+  }
 
-    array.checkedPut(value);
 
-    return this;
+  /**
+   * Get the long value associated with a key.
+   *
+   * @param key A key string.
+   * @return The long value.
+   * @throws JSONException if the key is not found or if the value cannot be converted to a long.
+   */
+  public long getLong(String key) throws JSONException {
+    Object object = this.get(key);
+    try {
+      return object instanceof Number ? ((Number) object).longValue()
+          : Long.parseLong((String) object);
+    } catch (Exception e) {
+      throw new JSONException("JSONObject[" + quote(key) + "] is not a long.");
+    }
   }
 
-  String checkName(String name) throws JSONException {
-    if (name == null) {
-      throw new JSONException("Names must be non-null");
+
+  /**
+   * Get an array of field names from a JSONObject.
+   *
+   * @return An array of field names, or null if there are no names.
+   */
+  public static String[] getNames(JSONObject jo) {
+    int length = jo.length();
+    if (length == 0) {
+      return null;
     }
-    return name;
+    Iterator iterator = jo.keys();
+    String[] names = new String[length];
+    int i = 0;
+    while (iterator.hasNext()) {
+      names[i] = (String) iterator.next();
+      i += 1;
+    }
+    return names;
   }
 
+
   /**
-   * Removes the named mapping if it exists; does nothing otherwise.
-   * @param name The name of the mapping to remove.
-   * @return the value previously mapped by {@code name}, or null if there was no such mapping.
+   * Get an array of field names from an Object.
+   *
+   * @return An array of field names, or null if there are no names.
    */
-  public Object remove(String name) {
-    return nameValuePairs.remove(name);
+  public static String[] getNames(Object object) {
+    if (object == null) {
+      return null;
+    }
+    Class klass = object.getClass();
+    Field[] fields = klass.getFields();
+    int length = fields.length;
+    if (length == 0) {
+      return null;
+    }
+    String[] names = new String[length];
+    for (int i = 0; i < length; i += 1) {
+      names[i] = fields[i].getName();
+    }
+    return names;
   }
 
+
   /**
-   * Returns true if this object has no mapping for {@code name} or if it has
-   * a mapping whose value is {@link #NULL}.
-   * @param name The name of the value to check on.
-   * @return true if the field doesn't exist or is null.
+   * Get the string associated with a key.
+   *
+   * @param key A key string.
+   * @return A string which is the value.
+   * @throws JSONException if there is no string value for the key.
    */
-  public boolean isNull(String name) {
-    Object value = nameValuePairs.get(name);
-    return value == null || value == NULL;
+  public String getString(String key) throws JSONException {
+    Object object = this.get(key);
+    if (object instanceof String) {
+      return (String) object;
+    }
+    throw new JSONException("JSONObject[" + quote(key) + "] not a string.");
   }
 
+
   /**
-   * Returns true if this object has a mapping for {@code name}. The mapping
-   * may be {@link #NULL}.
-   * @param name The name of the value to check on.
-   * @return true if this object has a field named {@code name}
+   * Determine if the JSONObject contains a specific key.
+   * 
+   * @param key A key string.
+   * @return true if the key exists in the JSONObject.
    */
-  public boolean has(String name) {
-    return nameValuePairs.containsKey(name);
+  public boolean has(String key) {
+    return this.map.containsKey(key);
   }
 
+
   /**
-   * Returns the value mapped by {@code name}, or throws if no such mapping exists.
-   * @param name The name of the value to get.
-   * @return The value.
-   * @throws JSONException if no such mapping exists.
+   * Increment a property of a JSONObject. If there is no such property, create one with a value of
+   * 1. If there is such a property, and if it is an Integer, Long, Double, or Float, then add one
+   * to it.
+   * 
+   * @param key A key string.
+   * @return this.
+   * @throws JSONException If there is already a property with this name that is not an Integer,
+   *         Long, Double, or Float.
    */
-  public Object get(String name) throws JSONException {
-    Object result = nameValuePairs.get(name);
-    if (result == null) {
-      throw new JSONException("No value for " + name);
+  public JSONObject increment(String key) throws JSONException {
+    Object value = this.opt(key);
+    if (value == null) {
+      this.put(key, 1);
+    } else if (value instanceof Integer) {
+      this.put(key, ((Integer) value).intValue() + 1);
+    } else if (value instanceof Long) {
+      this.put(key, ((Long) value).longValue() + 1);
+    } else if (value instanceof Double) {
+      this.put(key, ((Double) value).doubleValue() + 1);
+    } else if (value instanceof Float) {
+      this.put(key, ((Float) value).floatValue() + 1);
+    } else {
+      throw new JSONException("Unable to increment [" + quote(key) + "].");
     }
-    return result;
+    return this;
   }
 
+
   /**
-   * Returns the value mapped by {@code name}, or null if no such mapping
-   * exists.
-   * @param name The name of the value to get.
-   * @return The value.
+   * Determine if the value associated with the key is null or if there is no value.
+   * 
+   * @param key A key string.
+   * @return true if there is no value associated with the key or if the value is the
+   *         JSONObject.NULL object.
    */
-  public Object opt(String name) {
-    return nameValuePairs.get(name);
+  public boolean isNull(String key) {
+    return JSONObject.NULL.equals(this.opt(key));
   }
 
+
   /**
-   * Returns the value mapped by {@code name} if it exists and is a boolean or
-   * can be coerced to a boolean, or throws otherwise.
-   * @param name The name of the field we want.
-   * @return The selected value if it exists.
-   * @throws JSONException if the mapping doesn't exist or cannot be coerced to a boolean.
+   * Get an enumeration of the keys of the JSONObject.
+   *
+   * @return An iterator of the keys.
    */
-  public boolean getBoolean(String name) throws JSONException {
-    Object object = get(name);
-    Boolean result = JSON.toBoolean(object);
-    if (result == null) {
-      throw JSON.typeMismatch(name, object, "boolean");
-    }
-    return result;
+  public Iterator keys() {
+    return this.map.keySet().iterator();
   }
 
+
   /**
-   * Returns the value mapped by {@code name} if it exists and is a boolean or
-   * can be coerced to a boolean, or false otherwise.
-   * @param name The name of the field we want.
-   * @return The selected value if it exists.
+   * Get the number of keys stored in the JSONObject.
+   *
+   * @return The number of keys in the JSONObject.
    */
-  public boolean optBoolean(String name) {
-    return optBoolean(name, false);
+  public int length() {
+    return this.map.size();
   }
 
+
   /**
-   * Returns the value mapped by {@code name} if it exists and is a boolean or
-   * can be coerced to a boolean, or {@code fallback} otherwise.
-   * @param name The name of the field we want.
-   * @param fallback The value to return if the field isn't there.
-   * @return The selected value or the fallback.
+   * Produce a JSONArray containing the names of the elements of this JSONObject.
+   * 
+   * @return A JSONArray containing the key strings, or null if the JSONObject is empty.
    */
-  public boolean optBoolean(String name, boolean fallback) {
-    Object object = opt(name);
-    Boolean result = JSON.toBoolean(object);
-    return result != null ? result : fallback;
+  public JSONArray names() {
+    JSONArray ja = new JSONArray();
+    Iterator keys = this.keys();
+    while (keys.hasNext()) {
+      ja.put(keys.next());
+    }
+    return ja.length() == 0 ? null : ja;
   }
 
   /**
-   * Returns the value mapped by {@code name} if it exists and is a double or
-   * can be coerced to a double, or throws otherwise.
-   * @param name The name of the field we want.
-   * @return The selected value if it exists.
-   * @throws JSONException if the mapping doesn't exist or cannot be coerced to a double.
+   * Produce a string from a Number.
+   * 
+   * @param number A Number
+   * @return A String.
+   * @throws JSONException If n is a non-finite number.
    */
-  public double getDouble(String name) throws JSONException {
-    Object object = get(name);
-    Double result = JSON.toDouble(object);
-    if (result == null) {
-      throw JSON.typeMismatch(name, object, "double");
+  public static String numberToString(Number number) throws JSONException {
+    if (number == null) {
+      throw new JSONException("Null pointer");
     }
-    return result;
+    testValidity(number);
+
+    // Shave off trailing zeros and decimal point, if possible.
+
+    String string = number.toString();
+    if (string.indexOf('.') > 0 && string.indexOf('e') < 0 && string.indexOf('E') < 0) {
+      while (string.endsWith("0")) {
+        string = string.substring(0, string.length() - 1);
+      }
+      if (string.endsWith(".")) {
+        string = string.substring(0, string.length() - 1);
+      }
+    }
+    return string;
   }
 
+
   /**
-   * Returns the value mapped by {@code name} if it exists and is a double or
-   * can be coerced to a double, or {@code NaN} otherwise.
-   * @param name The name of the field we want.
-   * @return The selected value if it exists.
+   * Get an optional value associated with a key.
+   * 
+   * @param key A key string.
+   * @return An object which is the value, or null if there is no value.
    */
-  public double optDouble(String name) {
-    return optDouble(name, Double.NaN);
+  public Object opt(String key) {
+    return key == null ? null : this.map.get(key);
   }
 
+
   /**
-   * Returns the value mapped by {@code name} if it exists and is a double or
-   * can be coerced to a double, or {@code fallback} otherwise.
-   * @param name The name of the field we want.
-   * @param fallback The value to return if the field isn't there.
-   * @return The selected value or the fallback.
+   * Get an optional boolean associated with a key. It returns false if there is no such key, or if
+   * the value is not Boolean.TRUE or the String "true".
+   *
+   * @param key A key string.
+   * @return The truth.
    */
-  public double optDouble(String name, double fallback) {
-    Object object = opt(name);
-    Double result = JSON.toDouble(object);
-    return result != null ? result : fallback;
+  public boolean optBoolean(String key) {
+    return this.optBoolean(key, false);
   }
 
+
   /**
-   * Returns the value mapped by {@code name} if it exists and is an int or
-   * can be coerced to an int, or throws otherwise.
-   * @param name The name of the field we want.
-   * @return The selected value if it exists.
-   * @throws JSONException if the mapping doesn't exist or cannot be coerced to an int.
+   * Get an optional boolean associated with a key. It returns the defaultValue if there is no such
+   * key, or if it is not a Boolean or the String "true" or "false" (case insensitive).
+   *
+   * @param key A key string.
+   * @param defaultValue The default.
+   * @return The truth.
    */
-  public int getInt(String name) throws JSONException {
-    Object object = get(name);
-    Integer result = JSON.toInteger(object);
-    if (result == null) {
-      throw JSON.typeMismatch(name, object, "int");
+  public boolean optBoolean(String key, boolean defaultValue) {
+    try {
+      return this.getBoolean(key);
+    } catch (Exception e) {
+      return defaultValue;
     }
-    return result;
   }
 
-  /**
-   * Returns the value mapped by {@code name} if it exists and is an int or
-   * can be coerced to an int, or 0 otherwise.
-   * @param name The name of the field we want.
-   * @return The selected value if it exists.
-   */
-  public int optInt(String name) {
-    return optInt(name, 0);
-  }
 
   /**
-   * Returns the value mapped by {@code name} if it exists and is an int or
-   * can be coerced to an int, or {@code fallback} otherwise.
-   * @param name The name of the field we want.
-   * @param fallback The value to return if the field isn't there.
-   * @return The selected value or the fallback.
+   * Get an optional double associated with a key, or NaN if there is no such key or if its value is
+   * not a number. If the value is a string, an attempt will be made to evaluate it as a number.
+   *
+   * @param key A string which is the key.
+   * @return An object which is the value.
    */
-  public int optInt(String name, int fallback) {
-    Object object = opt(name);
-    Integer result = JSON.toInteger(object);
-    return result != null ? result : fallback;
+  public double optDouble(String key) {
+    return this.optDouble(key, Double.NaN);
   }
 
+
   /**
-   * Returns the value mapped by {@code name} if it exists and is a long or
-   * can be coerced to a long, or throws otherwise.
-   * Note that JSON represents numbers as doubles,
+   * Get an optional double associated with a key, or the defaultValue if there is no such key or if
+   * its value is not a number. If the value is a string, an attempt will be made to evaluate it as
+   * a number.
    *
-   * so this is <a href="#lossy">lossy</a>; use strings to transfer numbers
-   * via JSON without loss.
-   * @param name The name of the field that we want.
-   * @return The value of the field.
-   * @throws JSONException if the mapping doesn't exist or cannot be coerced to a long.
+   * @param key A key string.
+   * @param defaultValue The default.
+   * @return An object which is the value.
    */
-  public long getLong(String name) throws JSONException {
-    Object object = get(name);
-    Long result = JSON.toLong(object);
-    if (result == null) {
-      throw JSON.typeMismatch(name, object, "long");
+  public double optDouble(String key, double defaultValue) {
+    try {
+      return this.getDouble(key);
+    } catch (Exception e) {
+      return defaultValue;
     }
-    return result;
   }
 
+
   /**
-   * Returns the value mapped by {@code name} if it exists and is a long or
-   * can be coerced to a long, or 0 otherwise. Note that JSON represents numbers as doubles,
-   * so this is <a href="#lossy">lossy</a>; use strings to transfer numbers via JSON.
-   * @param name The name of the field we want.
-   * @return The selected value.
+   * Get an optional int value associated with a key, or zero if there is no such key or if the
+   * value is not a number. If the value is a string, an attempt will be made to evaluate it as a
+   * number.
+   *
+   * @param key A key string.
+   * @return An object which is the value.
    */
-  public long optLong(String name) {
-    return optLong(name, 0L);
+  public int optInt(String key) {
+    return this.optInt(key, 0);
   }
 
+
   /**
-   * Returns the value mapped by {@code name} if it exists and is a long or
-   * can be coerced to a long, or {@code fallback} otherwise. Note that JSON represents
-   * numbers as doubles, so this is <a href="#lossy">lossy</a>; use strings to transfer
-   * numbers via JSON.
-   * @param name The name of the field we want.
-   * @param fallback The value to return if the field isn't there.
-   * @return The selected value or the fallback.
+   * Get an optional int value associated with a key, or the default if there is no such key or if
+   * the value is not a number. If the value is a string, an attempt will be made to evaluate it as
+   * a number.
+   *
+   * @param key A key string.
+   * @param defaultValue The default.
+   * @return An object which is the value.
    */
-  public long optLong(String name, long fallback) {
-    Object object = opt(name);
-    Long result = JSON.toLong(object);
-    return result != null ? result : fallback;
+  public int optInt(String key, int defaultValue) {
+    try {
+      return this.getInt(key);
+    } catch (Exception e) {
+      return defaultValue;
+    }
   }
 
+
   /**
-   * Returns the value mapped by {@code name} if it exists, coercing it if
-   * necessary, or throws if no such mapping exists.
-   * @param name The name of the field we want.
-   * @return The value of the field.
-   * @throws JSONException if no such mapping exists.
+   * Get an optional JSONArray associated with a key. It returns null if there is no such key, or if
+   * its value is not a JSONArray.
+   *
+   * @param key A key string.
+   * @return A JSONArray which is the value.
    */
-  public String getString(String name) throws JSONException {
-    Object object = get(name);
-    String result = JSON.toString(object);
-    if (result == null) {
-      throw JSON.typeMismatch(name, object, "String");
-    }
-    return result;
+  public JSONArray optJSONArray(String key) {
+    Object o = this.opt(key);
+    return o instanceof JSONArray ? (JSONArray) o : null;
   }
 
+
   /**
-   * Returns the value mapped by {@code name} if it exists, coercing it if
-   * necessary, or the empty string if no such mapping exists.
-   * @param name The name of the field we want.
-   * @return The value of the field.
+   * Get an optional JSONObject associated with a key. It returns null if there is no such key, or
+   * if its value is not a JSONObject.
+   *
+   * @param key A key string.
+   * @return A JSONObject which is the value.
    */
-  public String optString(String name) {
-    return optString(name, "");
+  public JSONObject optJSONObject(String key) {
+    Object object = this.opt(key);
+    return object instanceof JSONObject ? (JSONObject) object : null;
   }
 
+
   /**
-   * Returns the value mapped by {@code name} if it exists, coercing it if
-   * necessary, or {@code fallback} if no such mapping exists.
-   * @param name The name of the field that we want.
-   * @param fallback The value to return if the field doesn't exist.
-   * @return The value of the field or fallback.
+   * Get an optional long value associated with a key, or zero if there is no such key or if the
+   * value is not a number. If the value is a string, an attempt will be made to evaluate it as a
+   * number.
+   *
+   * @param key A key string.
+   * @return An object which is the value.
    */
-  public String optString(String name, String fallback) {
-    Object object = opt(name);
-    String result = JSON.toString(object);
-    return result != null ? result : fallback;
+  public long optLong(String key) {
+    return this.optLong(key, 0);
   }
 
+
   /**
-   * Returns the value mapped by {@code name} if it exists and is a {@code
-   * JSONArray}, or throws otherwise.
-   * @param name The field we want to get.
-   * @return The value of the field (if it is a JSONArray.
-   * @throws JSONException if the mapping doesn't exist or is not a {@code JSONArray}.
+   * Get an optional long value associated with a key, or the default if there is no such key or if
+   * the value is not a number. If the value is a string, an attempt will be made to evaluate it as
+   * a number.
+   *
+   * @param key A key string.
+   * @param defaultValue The default.
+   * @return An object which is the value.
    */
-  public JSONArray getJSONArray(String name) throws JSONException {
-    Object object = get(name);
-    if (object instanceof JSONArray) {
-      return (JSONArray) object;
-    } else {
-      throw JSON.typeMismatch(name, object, "JSONArray");
+  public long optLong(String key, long defaultValue) {
+    try {
+      return this.getLong(key);
+    } catch (Exception e) {
+      return defaultValue;
     }
   }
 
+
   /**
-   * Returns the value mapped by {@code name} if it exists and is a {@code
-   * JSONArray}, or null otherwise.
-   * @param name The name of the field we want.
-   * @return The value of the specified field (assuming it is a JSNOArray
+   * Get an optional string associated with a key. It returns an empty string if there is no such
+   * key. If the value is not a string and is not null, then it is converted to a string.
+   *
+   * @param key A key string.
+   * @return A string which is the value.
    */
-  public JSONArray optJSONArray(String name) {
-    Object object = opt(name);
-    return object instanceof JSONArray ? (JSONArray) object : null;
+  public String optString(String key) {
+    return this.optString(key, "");
   }
 
+
   /**
-   * Returns the value mapped by {@code name} if it exists and is a {@code
-   * JSONObject}, or throws otherwise.
-   * @param name The name of the field that we want.
-   * @return a specified field value (if it is a JSONObject)
-   * @throws JSONException if the mapping doesn't exist or is not a {@code JSONObject}.
+   * Get an optional string associated with a key. It returns the defaultValue if there is no such
+   * key.
+   *
+   * @param key A key string.
+   * @param defaultValue The default.
+   * @return A string which is the value.
    */
-  public JSONObject getJSONObject(String name) throws JSONException {
-    Object object = get(name);
-    if (object instanceof JSONObject) {
-      return (JSONObject) object;
-    } else {
-      throw JSON.typeMismatch(name, object, "JSONObject");
+  public String optString(String key, String defaultValue) {
+    Object object = this.opt(key);
+    return NULL.equals(object) ? defaultValue : object.toString();
+  }
+
+
+  private void populateMap(Object bean) {
+    Class klass = bean.getClass();
+
+    // If klass is a System class then set includeSuperClass to false.
+
+    boolean includeSuperClass = klass.getClassLoader() != null;
+
+    Method[] methods = includeSuperClass ? klass.getMethods() : klass.getDeclaredMethods();
+    for (int i = 0; i < methods.length; i += 1) {
+      try {
+        Method method = methods[i];
+        if (Modifier.isPublic(method.getModifiers()) && !Modifier.isStatic(method.getModifiers())) {
+          String name = method.getName();
+          String key = "";
+          if (name.startsWith("get")) {
+            if ("getClass".equals(name) || "getDeclaringClass".equals(name)) {
+              key = "";
+            } else {
+              key = name.substring(3);
+            }
+          } else if (name.startsWith("is")) {
+            key = name.substring(2);
+          }
+          if (key.length() > 0 && Character.isUpperCase(key.charAt(0))
+              && method.getParameterTypes().length == 0) {
+            if (key.length() == 1) {
+              key = key.toLowerCase();
+            } else if (!Character.isUpperCase(key.charAt(1))) {
+              key = key.substring(0, 1).toLowerCase() + key.substring(1);
+            }
+            Object result = method.invoke(bean, (Object[]) null);
+            if (result != null) {
+              this.map.put(key, wrap(result));
+            } else if (!method.getReturnType().isArray()) {
+              this.map.put(key, JSONObject.NULL);
+            }
+          }
+        }
+      } catch (Exception ignore) {
+      }
     }
+    this.map.put("type-class", klass.getCanonicalName());
   }
 
+
   /**
-   * Returns the value mapped by {@code name} if it exists and is a {@code
-   * JSONObject}, or null otherwise.
-   * @param name The name of the value we want.
-   * @return The specified value.
+   * Put a key/boolean pair in the JSONObject.
+   *
+   * @param key A key string.
+   * @param value A boolean which is the value.
+   * @return this.
+   * @throws JSONException If the key is null.
    */
-  public JSONObject optJSONObject(String name) {
-    Object object = opt(name);
-    return object instanceof JSONObject ? (JSONObject) object : null;
+  public JSONObject put(String key, boolean value) throws JSONException {
+    this.put(key, value ? Boolean.TRUE : Boolean.FALSE);
+    return this;
   }
 
+
   /**
-   * Returns an array with the values corresponding to {@code names}. The
-   * array contains null for names that aren't mapped. This method returns
-   * null if {@code names} is either null or empty.
-   * @param names The names of the fields that we want the values for.
-   * @return The selected values.
-   * @throws JSONException On internal errors. Shouldn't happen.
+   * Put a key/value pair in the JSONObject, where the value will be a JSONArray which is produced
+   * from a Collection.
+   * 
+   * @param key A key string.
+   * @param value A Collection value.
+   * @return this.
+   * @throws JSONException
    */
-  public JSONArray toJSONArray(JSONArray names) throws JSONException {
-    JSONArray result = new JSONArray();
-    if (names == null) {
-      return null;
-    }
-    int length = names.length();
-    if (length == 0) {
-      return null;
-    }
-    for (int i = 0; i < length; i++) {
-      String name = JSON.toString(names.opt(i));
-      result.put(opt(name));
-    }
-    return result;
+  public JSONObject put(String key, Collection value) throws JSONException {
+    this.put(key, new JSONArray(value));
+    return this;
   }
 
+
   /**
-   * Returns an iterator of the {@code String} names in this object. The
-   * returned iterator supports {@link Iterator#remove() remove}, which will
-   * remove the corresponding mapping from this object. If this object is
-   * modified after the iterator is returned, the iterator's behavior is
-   * undefined. The order of the keys is undefined.
-   * @return an iterator over the keys.
+   * Put a key/double pair in the JSONObject.
+   *
+   * @param key A key string.
+   * @param value A double which is the value.
+   * @return this.
+   * @throws JSONException If the key is null or if the number is invalid.
    */
-  public Iterator<String> keys() {
-    return nameValuePairs.keySet().iterator();
+  public JSONObject put(String key, double value) throws JSONException {
+    this.put(key, new Double(value));
+    return this;
   }
 
+
   /**
-   * Returns the set of {@code String} names in this object. The returned set
-   * is a view of the keys in this object. {@link Set#remove(Object)} will remove
-   * the corresponding mapping from this object and set iterator behaviour
-   * is undefined if this object is modified after it is returned.
+   * Put a key/int pair in the JSONObject.
    *
-   * See {@link #keys()}.
-   * @return The names in this object.
+   * @param key A key string.
+   * @param value An int which is the value.
+   * @return this.
+   * @throws JSONException If the key is null.
    */
-  public Set<String> keySet() {
-    return nameValuePairs.keySet();
+  public JSONObject put(String key, int value) throws JSONException {
+    this.put(key, new Integer(value));
+    return this;
   }
 
+
   /**
-   * Returns an array containing the string names in this object. This method
-   * returns null if this object contains no mappings.
-   * @return the names.
+   * Put a key/long pair in the JSONObject.
+   *
+   * @param key A key string.
+   * @param value A long which is the value.
+   * @return this.
+   * @throws JSONException If the key is null.
    */
-  public JSONArray names() {
-    return nameValuePairs.isEmpty()
-        ? null
-        : new JSONArray(new ArrayList<String>(nameValuePairs.keySet()));
+  public JSONObject put(String key, long value) throws JSONException {
+    this.put(key, new Long(value));
+    return this;
   }
 
+
   /**
-   * Encodes this object as a compact JSON string, such as:
-   * <pre>{"query":"Pizza","locations":[94043,90210]}</pre>
+   * Put a key/value pair in the JSONObject, where the value will be a JSONObject which is produced
+   * from a Map.
+   * 
+   * @param key A key string.
+   * @param value A Map value.
+   * @return this.
+   * @throws JSONException
    */
-  @Override
-  public String toString() {
-    try {
-      JSONStringer stringer = new JSONStringer();
-      writeTo(stringer);
-      return stringer.toString();
-    } catch (JSONException e) {
-      return null;
+  public JSONObject put(String key, Map value) throws JSONException {
+    this.put(key, new JSONObject(value));
+    return this;
+  }
+
+
+  /**
+   * Put a key/value pair in the JSONObject. If the value is null, then the key will be removed from
+   * the JSONObject if it is present.
+   * 
+   * @param key A key string.
+   * @param value An object which is the value. It should be of one of these types: Boolean, Double,
+   *        Integer, JSONArray, JSONObject, Long, String, or the JSONObject.NULL object.
+   * @return this.
+   * @throws JSONException If the value is non-finite number or if the key is null.
+   */
+  public JSONObject put(String key, Object value) throws JSONException {
+    if (key == null) {
+      throw new JSONException("Null key.");
+    }
+    if (value != null) {
+      testValidity(value);
+      this.map.put(key, value);
+    } else {
+      this.remove(key);
     }
+    return this;
   }
 
+
   /**
-   * Encodes this object as a human readable JSON string for debugging, such
-   * as:
-   * <pre>
-   * {
-   *     "query": "Pizza",
-   *     "locations": [
-   *         94043,
-   *         90210
-   *     ]
-   * }</pre>
-   * @param indentSpaces the number of spaces to indent for each level of nesting.
-   * @return The string containing the pretty form of this.
-   * @throws JSONException On internal errors. Shouldn't happen.
+   * Put a key/value pair in the JSONObject, but only if the key and the value are both non-null,
+   * and only if there is not already a member with that name.
+   * 
+   * @param key
+   * @param value
+   * @return his.
+   * @throws JSONException if the key is a duplicate
    */
-  public String toString(int indentSpaces) throws JSONException {
-    JSONStringer stringer = new JSONStringer(indentSpaces);
-    writeTo(stringer);
-    return stringer.toString();
+  public JSONObject putOnce(String key, Object value) throws JSONException {
+    if (key != null && value != null) {
+      if (this.opt(key) != null) {
+        throw new JSONException("Duplicate key \"" + key + "\"");
+      }
+      this.put(key, value);
+    }
+    return this;
   }
 
-  void writeTo(JSONStringer stringer) throws JSONException {
-    stringer.object();
-    for (Map.Entry<String, Object> entry : nameValuePairs.entrySet()) {
-      stringer.key(entry.getKey()).value(entry.getValue());
+
+  /**
+   * Put a key/value pair in the JSONObject, but only if the key and the value are both non-null.
+   * 
+   * @param key A key string.
+   * @param value An object which is the value. It should be of one of these types: Boolean, Double,
+   *        Integer, JSONArray, JSONObject, Long, String, or the JSONObject.NULL object.
+   * @return this.
+   * @throws JSONException If the value is a non-finite number.
+   */
+  public JSONObject putOpt(String key, Object value) throws JSONException {
+    if (key != null && value != null) {
+      this.put(key, value);
     }
-    stringer.endObject();
+    return this;
   }
 
+
   /**
-   * Encodes the number as a JSON string.
-   * @param number a finite value. May not be {@link Double#isNaN() NaNs} or {@link
-   * Double#isInfinite() infinities}.
-   * @return The encoded number in string form.
-   * @throws JSONException On internal errors. Shouldn't happen.
+   * Produce a string in double quotes with backslash sequences in all the right places. A backslash
+   * will be inserted within </, producing <\/, allowing JSON text to be delivered in HTML. In JSON
+   * text, a string cannot contain a control character or an unescaped quote or backslash.
+   * 
+   * @param string A String
+   * @return A String correctly formatted for insertion in a JSON text.
    */
-  public static String numberToString(Number number) throws JSONException {
-    if (number == null) {
-      throw new JSONException("Number must be non-null");
+  public static String quote(String string) {
+    StringWriter sw = new StringWriter();
+    synchronized (sw.getBuffer()) {
+      try {
+        return quote(string, sw).toString();
+      } catch (IOException ignored) {
+        // will never happen - we are writing to a string writer
+        return "";
+      }
     }
+  }
 
-    double doubleValue = number.doubleValue();
-    JSON.checkDouble(doubleValue);
+  public static Writer quote(String string, Writer w) throws IOException {
+    if (string == null || string.length() == 0) {
+      w.write("\"\"");
+      return w;
+    }
 
-    // the original returns "-0" instead of "-0.0" for negative zero
-    if (number.equals(NEGATIVE_ZERO)) {
-      return "-0";
+    char b;
+    char c = 0;
+    String hhhh;
+    int i;
+    int len = string.length();
+
+    w.write('"');
+    for (i = 0; i < len; i += 1) {
+      b = c;
+      c = string.charAt(i);
+      switch (c) {
+        case '\\':
+        case '"':
+          w.write('\\');
+          w.write(c);
+          break;
+        case '/':
+          if (b == '<') {
+            w.write('\\');
+          }
+          w.write(c);
+          break;
+        case '\b':
+          w.write("\\b");
+          break;
+        case '\t':
+          w.write("\\t");
+          break;
+        case '\n':
+          w.write("\\n");
+          break;
+        case '\f':
+          w.write("\\f");
+          break;
+        case '\r':
+          w.write("\\r");
+          break;
+        default:
+          if (c < ' ' || (c >= '\u0080' && c < '\u00a0') || (c >= '\u2000' && c < '\u2100')) {
+            hhhh = "000" + Integer.toHexString(c);
+            w.write("\\u" + hhhh.substring(hhhh.length() - 4));
+          } else {
+            w.write(c);
+          }
+      }
     }
+    w.write('"');
+    return w;
+  }
 
-    long longValue = number.longValue();
-    if (doubleValue == (double) longValue) {
-      return Long.toString(longValue);
+  /**
+   * Remove a name and its value, if present.
+   * 
+   * @param key The name to be removed.
+   * @return The value that was associated with the name, or null if there was no value.
+   */
+  public Object remove(String key) {
+    return this.map.remove(key);
+  }
+
+  /**
+   * Try to convert a string into a number, boolean, or null. If the string can't be converted,
+   * return the string.
+   * 
+   * @param string A String.
+   * @return A simple JSON value.
+   */
+  public static Object stringToValue(String string) {
+    Double d;
+    if (string.equals("")) {
+      return string;
+    }
+    if (string.equalsIgnoreCase("true")) {
+      return Boolean.TRUE;
+    }
+    if (string.equalsIgnoreCase("false")) {
+      return Boolean.FALSE;
+    }
+    if (string.equalsIgnoreCase("null")) {
+      return JSONObject.NULL;
     }
 
-    return number.toString();
+    /*
+     * If it might be a number, try converting it. If a number cannot be produced, then the value
+     * will just be a string. Note that the plus and implied string conventions are non-standard. A
+     * JSON parser may accept non-JSON forms as long as it accepts all correct JSON forms.
+     */
+
+    char b = string.charAt(0);
+    if ((b >= '0' && b <= '9') || b == '.' || b == '-' || b == '+') {
+      try {
+        if (string.indexOf('.') > -1 || string.indexOf('e') > -1 || string.indexOf('E') > -1) {
+          d = Double.valueOf(string);
+          if (!d.isInfinite() && !d.isNaN()) {
+            return d;
+          }
+        } else {
+          Long myLong = new Long(string);
+          if (myLong.longValue() == myLong.intValue()) {
+            return new Integer(myLong.intValue());
+          } else {
+            return myLong;
+          }
+        }
+      } catch (Exception ignore) {
+      }
+    }
+    return string;
+  }
+
+
+  /**
+   * Throw an exception if the object is a NaN or infinite number.
+   * 
+   * @param o The object to test.
+   * @throws JSONException If o is a non-finite number.
+   */
+  public static void testValidity(Object o) throws JSONException {
+    if (o != null) {
+      if (o instanceof Double) {
+        if (((Double) o).isInfinite() || ((Double) o).isNaN()) {
+          throw new JSONException("JSON does not allow non-finite numbers.");
+        }
+      } else if (o instanceof Float) {
+        if (((Float) o).isInfinite() || ((Float) o).isNaN()) {
+          throw new JSONException("JSON does not allow non-finite numbers.");
+        }
+      }
+    }
   }
 
+
   /**
-   * Encodes {@code data} as a JSON string. This applies quotes and any
-   * necessary character escaping.
-   * @param data the string to encode. Null will be interpreted as an empty string.
-   * @return the quoted string.
+   * Produce a JSONArray containing the values of the members of this JSONObject.
+   * 
+   * @param names A JSONArray containing a list of key strings. This determines the sequence of the
+   *        values in the result.
+   * @return A JSONArray of values.
+   * @throws JSONException If any of the values are non-finite numbers.
    */
-  public static String quote(String data) {
-    if (data == null) {
-      return "\"\"";
+  public JSONArray toJSONArray(JSONArray names) throws JSONException {
+    if (names == null || names.length() == 0) {
+      return null;
     }
+    JSONArray ja = new JSONArray();
+    for (int i = 0; i < names.length(); i += 1) {
+      ja.put(this.opt(names.getString(i)));
+    }
+    return ja;
+  }
+
+  /**
+   * Make a JSON text of this JSONObject. For compactness, no whitespace is added. If this would not
+   * result in a syntactically correct JSON text, then null will be returned instead.
+   * <p>
+   * Warning: This method assumes that the data structure is acyclical.
+   *
+   * @return a printable, displayable, portable, transmittable representation of the object,
+   *         beginning with <code>{</code>&nbsp;<small>(left brace)</small> and ending with
+   *         <code>}</code>&nbsp;<small>(right brace)</small>.
+   */
+  public String toString() {
     try {
-      JSONStringer stringer = new JSONStringer();
-      stringer.open(JSONStringer.Scope.NULL, "");
-      stringer.value(data);
-      stringer.close(JSONStringer.Scope.NULL, JSONStringer.Scope.NULL, "");
-      return stringer.toString();
-    } catch (JSONException e) {
-      throw new AssertionError();
+      return this.toString(0);
+    } catch (Exception e) {
+      return null;
     }
   }
 
+
   /**
-   * Wraps the given object if necessary.
+   * Make a prettyprinted JSON text of this JSONObject.
+   * <p>
+   * 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, portable, transmittable representation of the object,
+   *         beginning with <code>{</code>&nbsp;<small>(left brace)</small> and ending with
+   *         <code>}</code>&nbsp;<small>(right brace)</small>.
+   * @throws JSONException If the object contains an invalid number.
+   */
+  public String toString(int indentFactor) throws JSONException {
+    StringWriter w = new StringWriter();
+    synchronized (w.getBuffer()) {
+      return this.write(w, indentFactor, 0).toString();
+    }
+  }
+
+  /**
+   * Make a JSON text of an Object value. If the object has an value.toJSONString() method, then
+   * that method will be used to produce the JSON text. The method is required to produce a strictly
+   * conforming text. If the object does not contain a toJSONString method (which is the most common
+   * case), then a text will be produced by other means. If the value is an array or Collection,
+   * then a JSONArray will be made from it and its toJSONString method will be called. If the value
+   * is a MAP, then a JSONObject will be made from it and its toJSONString method will be called.
+   * Otherwise, the value's toString method will be called, and the result will be quoted.
    *
-   * <p>If the object is null or , returns {@link #NULL}. If the object is a {@code JSONArray} or
-   * {@code JSONObject}, no wrapping is necessary. If the object is {@code NULL}, no wrapping is
-   * necessary. If the object is an array or {@code Collection}, returns an equivalent {@code
-   * JSONArray}. If the object is a {@code Map}, returns an equivalent {@code JSONObject}. If the
-   * object is a primitive wrapper type or {@code String}, returns the object. If the object is from
-   * a {@code java} package, returns the result of {@code toString}. If the object is some other
-   * kind of object then it is assumed to be a bean and is converted to a JSONObject. If wrapping
-   * fails, returns null.
-   * @param o The object to wrap.
-   * @return The wrapped (if necessary) form of the object {$code o}
+   * <p>
+   * Warning: This method assumes that the data structure is acyclical.
+   * 
+   * @param value The value to be serialized.
+   * @return a printable, displayable, transmittable representation of the object, beginning with
+   *         <code>{</code>&nbsp;<small>(left brace)</small> and ending with
+   *         <code>}</code>&nbsp;<small>(right brace)</small>.
+   * @throws JSONException If the value is or contains an invalid number.
    */
-  public static Object wrap(Object o) {
-    if (o == null) {
-      return NULL;
+  public static String valueToString(Object value) throws JSONException {
+    if (value == null || value.equals(null)) {
+      return "null";
+    }
+    if (value instanceof JSONString) {
+      Object object;
+      try {
+        object = ((JSONString) value).toJSONString();
+      } catch (Exception e) {
+        throw new JSONException(e);
+      }
+      if (object instanceof String) {
+        return (String) object;
+      }
+      throw new JSONException("Bad value from toJSONString: " + object);
+    }
+    if (value instanceof Number) {
+      return numberToString((Number) value);
+    }
+    if (value instanceof Boolean || value instanceof JSONObject || value instanceof JSONArray) {
+      return value.toString();
     }
-    if (o instanceof JSONArray || o instanceof JSONObject) {
-      return o;
+    if (value instanceof Map) {
+      return new JSONObject((Map) value).toString();
     }
-    if (o.equals(NULL)) {
-      return o;
+    if (value instanceof Collection) {
+      return new JSONArray((Collection) value).toString();
     }
+    if (value.getClass().isArray()) {
+      return new JSONArray(value).toString();
+    }
+    return quote(value.toString());
+  }
+
+  /**
+   * Wrap an object, if necessary. If the object is null, return the NULL object. If it is an array
+   * or collection, wrap it in a JSONArray. If it is a map, wrap it in a JSONObject. If it is a
+   * standard property (Double, String, et al) then it is already wrapped. Otherwise, if it comes
+   * from one of the java packages, turn it into a string. And if it doesn't, try to wrap it in a
+   * JSONObject. If the wrapping fails, then null is returned.
+   *
+   * @param object The object to wrap
+   * @return The wrapped value
+   */
+  public static Object wrap(Object object) {
     try {
-      if (o instanceof Collection) {
-        return new JSONArray((Collection) o);
-      } else if (o.getClass().isArray()) {
-        return new JSONArray(o);
+      if (object == null) {
+        return NULL;
       }
-      if (o instanceof Map) {
-        return new JSONObject((Map) o);
+      if (object instanceof JSONObject || object instanceof JSONArray || NULL.equals(object)
+          || object instanceof JSONString || object instanceof Byte || object instanceof Character
+          || object instanceof Short || object instanceof Integer || object instanceof Long
+          || object instanceof Boolean || object instanceof Float || object instanceof Double
+          || object instanceof String) {
+        return object;
       }
-      if (o instanceof Boolean ||
-          o instanceof Byte ||
-          o instanceof Character ||
-          o instanceof Double ||
-          o instanceof Float ||
-          o instanceof Integer ||
-          o instanceof Long ||
-          o instanceof Short ||
-          o instanceof String) {
-        return o;
+
+      if (object instanceof Collection) {
+        return new JSONArray((Collection) object);
+      }
+      if (object.getClass().isArray()) {
+        return new JSONArray(object);
       }
-      // GEODE-2142: Added check to ignore GemFireCacheImpl
-//      if (o.getClass().getPackage().getName().startsWith("java.") || o instanceof Enum<?>) {
-//        return o.toString();
-//      }
-      Package objectPackage = o.getClass().getPackage();
+      if (object instanceof Map) {
+        return new JSONObject((Map) object);
+      }
+      Package objectPackage = object.getClass().getPackage();
       String objectPackageName = objectPackage != null ? objectPackage.getName() : "";
-      if (objectPackageName.startsWith("java.") || objectPackageName.startsWith("javax.") || o instanceof Enum<?>
-          || o.getClass().getClassLoader() == null
-          || o.getClass().getName().contains("GemFireCacheImpl")) {
-        return o.toString();
+      if (objectPackageName.startsWith("java.") || objectPackageName.startsWith("javax.")
+          || object.getClass().getClassLoader() == null
+          || object.getClass().getName().contains("GemFireCacheImpl")) {
+        return object.toString();
       }
-//      if (o.getClass().getPackage().getName().startsWith("java.") || o instanceof Enum<?> ||
-//          || objectPackageName.startsWith("javax.")
-//          || o.getClass().getClassLoader() == null
-//          o.getClass().getName().contains("GemFireCacheImpl")) {
-//        return o.toString();
-//      }
-      // GEODE-2142: Added the cyclicalDepCheck
+
       if (cyclicDepChkEnabled.get() != null && cyclicDependencySet.get() != null) {
-        if (cyclicDepChkEnabled.get() && cyclicDependencySet.get().contains(o)) {
+        if (cyclicDepChkEnabled.get() && cyclicDependencySet.get().contains(object)) {
           // break cyclic reference
-          return o.getClass().getCanonicalName();
+          return object.getClass().getCanonicalName();
         } else {
-          cyclicDependencySet.get().add(o);
-          return new JSONObject(o);
+          cyclicDependencySet.get().add(object);
+          return new JSONObject(object);
+        }
+      } else
+        return new JSONObject(object);
+
+    } catch (Exception exception) {
+      return null;
+    }
+  }
+
+
+  /**
+   * Write the contents of the JSONObject 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);
+  }
+
+
+  static final Writer writeValue(Writer writer, Object value, int indentFactor, int indent)
+      throws JSONException, IOException {
+    if (value == null || value.equals(null)) {
+      writer.write("null");
+    } else if (value instanceof JSONObject) {
+      ((JSONObject) value).write(writer, indentFactor, indent);
+    } else if (value instanceof JSONArray) {
+      ((JSONArray) value).write(writer, indentFactor, indent);
+    } else if (value instanceof Map) {
+      new JSONObject((Map) value).write(writer, indentFactor, indent);
+    } else if (value instanceof Collection) {
+      new JSONArray((Collection) value).write(writer, indentFactor, indent);
+    } else if (value.getClass().isArray()) {
+      new JSONArray(value).write(writer, indentFactor, indent);
+    } else if (value instanceof Number) {
+      writer.write(numberToString((Number) value));
+    } else if (value instanceof Boolean) {
+      writer.write(value.toString());
+    } else if (value instanceof JSONString) {
+      Object o;
+      try {
+        o = ((JSONString) value).toJSONString();
+      } catch (Exception e) {
+        throw new JSONException(e);
+      }
+      writer.write(o != null ? o.toString() : quote(value.toString()));
+    } else {
+      quote(value.toString(), writer);
+    }
+    return writer;
+  }
+
+  static final void indent(Writer writer, int indent) throws IOException {
+    for (int i = 0; i < indent; i += 1) {
+      writer.write(' ');
+    }
+  }
+
+  /**
+   * Write the contents of the JSONObject 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
+   */
+  Writer write(Writer writer, int indentFactor, int indent) throws JSONException {
+    try {
+      boolean commanate = false;
+      final int length = this.length();
+      Iterator keys = this.keys();
+      writer.write('{');
+
+      if (length == 1) {
+        Object key = keys.next();
+        writer.write(quote(key.toString()));
+        writer.write(':');
+        if (indentFactor > 0) {
+          writer.write(' ');
+        }
+        writeValue(writer, this.map.get(key), indentFactor, indent);
+      } else if (length != 0) {
+        final int newindent = indent + indentFactor;
+        while (keys.hasNext()) {
+          Object key = keys.next();
+          if (commanate) {
+            writer.write(',');
+          }
+          if (indentFactor > 0) {
+            writer.write('\n');
+          }
+          indent(writer, newindent);
+          writer.write(quote(key.toString()));
+          writer.write(':');
+          if (indentFactor > 0) {
+            writer.write(' ');
+          }
+          writeValue(writer, this.map.get(key), indentFactor, newindent);
+          commanate = true;
+        }
+        if (indentFactor > 0) {
+          writer.write('\n');
         }
-      } else {
-        return new JSONObject(o);
+        indent(writer, indent);
       }
-    } catch (Exception ignored) {
+      writer.write('}');
+      return writer;
+    } catch (IOException exception) {
+      throw new JSONException(exception);
     }
-    return null;
   }
-}
\ No newline at end of file
+}

http://git-wip-us.apache.org/repos/asf/geode/blob/0805036e/geode-json/src/main/java/org/json/JSONString.java
----------------------------------------------------------------------
diff --git a/geode-json/src/main/java/org/json/JSONString.java b/geode-json/src/main/java/org/json/JSONString.java
index 34815a8..4a09d89 100755
--- a/geode-json/src/main/java/org/json/JSONString.java
+++ b/geode-json/src/main/java/org/json/JSONString.java
@@ -1,18 +1,17 @@
 package org.json;
+
 /**
- * The <code>JSONString</code> interface allows a <code>toJSONString()</code> 
- * method so that a class can change the behavior of 
- * <code>JSONObject.toString()</code>, <code>JSONArray.toString()</code>,
- * and <code>JSONWriter.value(</code>Object<code>)</code>. The 
- * <code>toJSONString</code> method will be used instead of the default behavior 
- * of using the Object's <code>toString()</code> method and quoting the result.
+ * The <code>JSONString</code> interface allows a <code>toJSONString()</code> method so that a class
+ * can change the behavior of <code>JSONObject.toString()</code>, <code>JSONArray.toString()</code>,
+ * and <code>JSONWriter.value(</code>Object<code>)</code>. The <code>toJSONString</code> method will
+ * be used instead of the default behavior of using the Object's <code>toString()</code> method and
+ * quoting the result.
  */
 public interface JSONString {
   /**
-   * The <code>toJSONString</code> method allows a class to produce its own JSON 
-   * serialization. 
+   * The <code>toJSONString</code> method allows a class to produce its own JSON serialization.
    * 
    * @return A strictly syntactically correct JSON text.
    */
   public String toJSONString();
-}
\ No newline at end of file
+}


[8/8] geode git commit: Revert "GEODE-2142: Removal of non-compliant org.json implementation."

Posted by ud...@apache.org.
Revert "GEODE-2142: Removal of non-compliant org.json implementation."

This reverts commit b3ec80bc72fee3a40da297945a85d8df6c2a6460.


Project: http://git-wip-us.apache.org/repos/asf/geode/repo
Commit: http://git-wip-us.apache.org/repos/asf/geode/commit/0805036e
Tree: http://git-wip-us.apache.org/repos/asf/geode/tree/0805036e
Diff: http://git-wip-us.apache.org/repos/asf/geode/diff/0805036e

Branch: refs/heads/develop
Commit: 0805036e81756e3d843f3227e94927a520a07946
Parents: 1253d78
Author: Udo Kohlmeyer <uk...@pivotal.io>
Authored: Fri Feb 17 13:57:54 2017 -0800
Committer: Udo Kohlmeyer <uk...@pivotal.io>
Committed: Fri Feb 17 13:57:54 2017 -0800

----------------------------------------------------------------------
 .../geode/management/internal/cli/CliUtil.java  |   42 +
 .../internal/cli/commands/ConfigCommands.java   |    3 +-
 ...xportImportClusterConfigurationCommands.java |    2 +-
 .../cli/functions/ExportConfigFunction.java     |    4 +-
 .../internal/cli/json/GfJsonObject.java         |   54 +-
 .../internal/cli/result/AbstractResultData.java |   56 +-
 .../cli/result/CompositeResultData.java         |   46 +
 .../internal/cli/result/ResultBuilder.java      |   30 +
 .../cli/commands/CliCommandTestBase.java        |    6 +-
 geode-json/src/main/java/org/json/CDL.java      |  272 +++
 geode-json/src/main/java/org/json/Cookie.java   |  162 ++
 .../src/main/java/org/json/CookieList.java      |   87 +
 geode-json/src/main/java/org/json/HTTP.java     |  185 ++
 .../src/main/java/org/json/HTTPTokener.java     |   77 +
 geode-json/src/main/java/org/json/JSON.java     |  116 --
 .../src/main/java/org/json/JSONArray.java       | 1587 +++++++-------
 .../src/main/java/org/json/JSONException.java   |   71 +-
 geode-json/src/main/java/org/json/JSONML.java   |  454 ++++
 .../src/main/java/org/json/JSONObject.java      | 1952 +++++++++++-------
 .../src/main/java/org/json/JSONString.java      |   17 +-
 .../src/main/java/org/json/JSONStringer.java    |  531 +----
 .../src/main/java/org/json/JSONTokener.java     | 1013 ++++-----
 .../src/main/java/org/json/JSONWriter.java      |  321 +++
 geode-json/src/main/java/org/json/XML.java      |  504 +++++
 .../src/main/java/org/json/XMLTokener.java      |  362 ++++
 25 files changed, 5196 insertions(+), 2758 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/geode/blob/0805036e/geode-core/src/main/java/org/apache/geode/management/internal/cli/CliUtil.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/management/internal/cli/CliUtil.java b/geode-core/src/main/java/org/apache/geode/management/internal/cli/CliUtil.java
index a505001..8525b58 100755
--- a/geode-core/src/main/java/org/apache/geode/management/internal/cli/CliUtil.java
+++ b/geode-core/src/main/java/org/apache/geode/management/internal/cli/CliUtil.java
@@ -440,6 +440,11 @@ public class CliUtil {
 
       compressedDataLength = compresser.deflate(buffer);
       totalCompressedDataLength += compressedDataLength;
+      // System.out.println(compressedDataLength);
+      // System.out.println("uc: b "+buffer.length);
+      // System.out.println("uc: r "+result.length);
+      // System.out.println("uc: nr "+newResult.length);
+      // System.out.println();
       System.arraycopy(buffer, 0, newResult, result.length, buffer.length);
       result = newResult;
     } while (compressedDataLength != 0);
@@ -495,6 +500,43 @@ public class CliUtil {
     }
   }
 
+  public static void main(String[] args) {
+    try {
+      byte[][] filesToBytes =
+          filesToBytes(new String[] {"/export/abhishek1/work/aspenmm/GFTryouts/test.json"});
+
+      System.out.println(filesToBytes[1].length);
+
+      DeflaterInflaterData compressBytes = compressBytes(filesToBytes[1]);
+      System.out.println(compressBytes);
+
+      DeflaterInflaterData uncompressBytes =
+          uncompressBytes(compressBytes.data, compressBytes.dataLength);
+      System.out.println(uncompressBytes);
+
+      System.out.println(new String(uncompressBytes.getData()));
+    } catch (FileNotFoundException e) {
+      e.printStackTrace();
+    } catch (IOException e) {
+      e.printStackTrace();
+    } catch (DataFormatException e) {
+      e.printStackTrace();
+    }
+  }
+
+  public static void main1(String[] args) {
+    try {
+      byte[][] fileToBytes = filesToBytes(new String[] {"../dumped/source/lib"});
+
+      bytesToFiles(fileToBytes, "../dumped/dest/lib/", true);
+
+    } catch (FileNotFoundException e) {
+      e.printStackTrace();
+    } catch (IOException e) {
+      e.printStackTrace();
+    }
+  }
+
   public static boolean contains(Object[] array, Object object) {
     boolean contains = false;
 

http://git-wip-us.apache.org/repos/asf/geode/blob/0805036e/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/ConfigCommands.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/ConfigCommands.java b/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/ConfigCommands.java
index 283f09d..12a0a64 100644
--- a/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/ConfigCommands.java
+++ b/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/ConfigCommands.java
@@ -234,8 +234,7 @@ public class ConfigCommands extends AbstractCommandsSupport {
               false);
         }
       }
-      Result result = ResultBuilder.buildResult(infoData);
-      return result;
+      return ResultBuilder.buildResult(infoData);
     } catch (VirtualMachineError e) {
       SystemFailure.initiateFailure(e);
       throw e;

http://git-wip-us.apache.org/repos/asf/geode/blob/0805036e/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/ExportImportClusterConfigurationCommands.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/ExportImportClusterConfigurationCommands.java b/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/ExportImportClusterConfigurationCommands.java
index 7485d9f..e94af4f 100644
--- a/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/ExportImportClusterConfigurationCommands.java
+++ b/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/ExportImportClusterConfigurationCommands.java
@@ -75,7 +75,6 @@ public class ExportImportClusterConfigurationCommands extends AbstractCommandsSu
   public Result exportSharedConfig(@CliOption(key = {CliStrings.EXPORT_SHARED_CONFIG__FILE},
       mandatory = true, help = CliStrings.EXPORT_SHARED_CONFIG__FILE__HELP) String zipFileName) {
 
-    System.err.println("Out 1");
     InternalLocator locator = InternalLocator.getLocator();
     if (!locator.isSharedConfigurationRunning()) {
       return ResultBuilder.createGemFireErrorResult(CliStrings.SHARED_CONFIGURATION_NOT_STARTED);
@@ -100,6 +99,7 @@ public class ExportImportClusterConfigurationCommands extends AbstractCommandsSu
         sc.writeConfigToFile(config);
       }
       ZipUtils.zipDirectory(sc.getSharedConfigurationDirPath(), zipFile.getCanonicalPath());
+
       InfoResultData infoData = ResultBuilder.createInfoResultData();
       byte[] byteData = FileUtils.readFileToByteArray(zipFile);
       infoData.addAsFile(zipFileName, byteData, InfoResultData.FILE_TYPE_BINARY,

http://git-wip-us.apache.org/repos/asf/geode/blob/0805036e/geode-core/src/main/java/org/apache/geode/management/internal/cli/functions/ExportConfigFunction.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/management/internal/cli/functions/ExportConfigFunction.java b/geode-core/src/main/java/org/apache/geode/management/internal/cli/functions/ExportConfigFunction.java
index 64bc374..49e27b0 100644
--- a/geode-core/src/main/java/org/apache/geode/management/internal/cli/functions/ExportConfigFunction.java
+++ b/geode-core/src/main/java/org/apache/geode/management/internal/cli/functions/ExportConfigFunction.java
@@ -93,10 +93,12 @@ public class ExportConfigFunction implements Function, InternalEntity {
               .append(lineSeparator);
         }
       }
+
       CliFunctionResult result = new CliFunctionResult(memberId,
           new String[] {xmlWriter.toString(), propStringBuf.toString()});
-      System.err.println("ExportConfigFunction.execute CLI function result: "+result);
+
       context.getResultSender().lastResult(result);
+
     } catch (CacheClosedException cce) {
       CliFunctionResult result = new CliFunctionResult(memberId, false, null);
       context.getResultSender().lastResult(result);

http://git-wip-us.apache.org/repos/asf/geode/blob/0805036e/geode-core/src/main/java/org/apache/geode/management/internal/cli/json/GfJsonObject.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/management/internal/cli/json/GfJsonObject.java b/geode-core/src/main/java/org/apache/geode/management/internal/cli/json/GfJsonObject.java
index 9137f72..69666ff 100644
--- a/geode-core/src/main/java/org/apache/geode/management/internal/cli/json/GfJsonObject.java
+++ b/geode-core/src/main/java/org/apache/geode/management/internal/cli/json/GfJsonObject.java
@@ -49,6 +49,22 @@ public class GfJsonObject {
       this.jsonObject = (JSONObject) bean;
     } else {
       this.jsonObject = new JSONObject(bean);
+      // If we want to print out the values of the primitive arrays and report back
+      // Class klass = bean.getClass();
+      // if(klass.isArray() && klass.getComponentType().isPrimitive()){
+      // String str = "";
+      // int length = Array.getLength(bean);
+      // for (int i = 0; i < length; i++) {
+      // if(i==0)
+      // str += (Array.get(bean, i));
+      // else
+      // str +=(","+Array.get(bean, i));
+      // }
+      // try {
+      // this.jsonObject.put("Value", str);
+      // } catch (JSONException ignore) {
+      // }
+      // }
     }
     if (checkCyclicDep) {
       JSONObject.cyclicDepChkEnabled.set(false);
@@ -72,9 +88,9 @@ public class GfJsonObject {
     }
   }
 
-//  public GfJsonObject(Object bean, String[] paramNames) {
-//    this.jsonObject = new JSONObject(bean, paramNames);
-//  }
+  public GfJsonObject(Object bean, String[] paramNames) {
+    this.jsonObject = new JSONObject(bean, paramNames);
+  }
 
   /**
    * 
@@ -237,21 +253,21 @@ public class GfJsonObject {
     return this;
   }
 
-//  /**
-//   *
-//   * @param key
-//   * @param value
-//   * @return this GfJsonObject
-//   * @throws GfJsonException if the key is a duplicate
-//   */
-//  public GfJsonObject putOnce(String key, Object value) throws GfJsonException {
-//    try {
-//      jsonObject.putOnce(key, value);
-//    } catch (JSONException e) {
-//      throw new GfJsonException(e.getMessage());
-//    }
-//    return this;
-//  }
+  /**
+   * 
+   * @param key
+   * @param value
+   * @return this GfJsonObject
+   * @throws GfJsonException if the key is a duplicate
+   */
+  public GfJsonObject putOnce(String key, Object value) throws GfJsonException {
+    try {
+      jsonObject.putOnce(key, value);
+    } catch (JSONException e) {
+      throw new GfJsonException(e.getMessage());
+    }
+    return this;
+  }
 
   /**
    * 
@@ -346,7 +362,7 @@ public class GfJsonObject {
     }
   }
 
-  private Object extractInternalForGfJsonOrReturnSame(Object value) {
+  private static Object extractInternalForGfJsonOrReturnSame(Object value) {
     Object returnedValue = value;
     if (value instanceof GfJsonObject) {
       returnedValue = ((GfJsonObject) value).getInternalJsonObject();

http://git-wip-us.apache.org/repos/asf/geode/blob/0805036e/geode-core/src/main/java/org/apache/geode/management/internal/cli/result/AbstractResultData.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/management/internal/cli/result/AbstractResultData.java b/geode-core/src/main/java/org/apache/geode/management/internal/cli/result/AbstractResultData.java
index 81ab511..e08d9b7 100644
--- a/geode-core/src/main/java/org/apache/geode/management/internal/cli/result/AbstractResultData.java
+++ b/geode-core/src/main/java/org/apache/geode/management/internal/cli/result/AbstractResultData.java
@@ -20,10 +20,7 @@ import java.io.FileNotFoundException;
 import java.io.FileOutputStream;
 import java.io.FileWriter;
 import java.io.IOException;
-import java.io.UnsupportedEncodingException;
-import java.nio.charset.Charset;
 import java.text.MessageFormat;
-import java.util.Base64;
 import java.util.zip.DataFormatException;
 
 import org.apache.geode.management.cli.Result.Status;
@@ -154,10 +151,26 @@ public abstract class AbstractResultData implements ResultData {
     if (addTimeStampToName) {
       fileName = addTimeStampBeforeLastDot(fileName);
     }
-    return addAsFile(fileName, bytes, fileType, message);
+    return addAsFile(fileName.getBytes(), bytes, fileType, message);
   }
 
-  private ResultData addAsFile(String fileName, byte[] data, int fileType, String message) {
+  public ResultData addByteDataFromFileFile(String filePath, int fileType, String message,
+      boolean addTimeStampToName) throws FileNotFoundException, IOException {
+    byte[][] filesToBytes = CliUtil.filesToBytes(new String[] {filePath});
+
+    byte[] bytes = filesToBytes[0];
+    if (addTimeStampToName) {
+      String fileName = new String(filesToBytes[0]);
+      fileName = addTimeStampBeforeLastDot(fileName);
+      bytes = fileName.getBytes();
+    }
+    return addAsFile(bytes, filesToBytes[1], fileType, message);
+  }
+
+  private ResultData addAsFile(byte[] fileName, byte[] data, int fileType, String message) {
+    // System.out.println("fileType :: "+fileType);
+    // System.out.println("FILE_TYPE_BINARY :: "+FILE_TYPE_BINARY);
+    // System.out.println("FILE_TYPE_TEXT :: "+FILE_TYPE_TEXT);
     if (fileType != FILE_TYPE_BINARY && fileType != FILE_TYPE_TEXT) {
       throw new IllegalArgumentException("Unsupported file type is specified.");
     }
@@ -173,12 +186,14 @@ public abstract class AbstractResultData implements ResultData {
 
       sectionData.put(FILE_NAME_FIELD, fileName);
       sectionData.put(FILE_TYPE_FIELD, fileType);
-      sectionData.put(FILE_MESSAGE, message);
-      DeflaterInflaterData deflaterInflaterData = CliUtil.compressBytes(data);
-      sectionData.put(FILE_DATA_FIELD, Base64.getEncoder().encodeToString(deflaterInflaterData.getData()));
-      sectionData.put(DATA_LENGTH_FIELD,deflaterInflaterData.getDataLength());
+      sectionData.put(FILE_MESSAGE, message.getBytes());
+      sectionData.putAsJSONObject(FILE_DATA_FIELD, CliUtil.compressBytes(data));
+      // System.out.println(data);
+      // sectionData.put(FILE_DATA_FIELD, Base64.encodeBytes(data, Base64.GZIP));
     } catch (GfJsonException e) {
       throw new ResultDataException(e.getMessage());
+      // } catch (IOException e) {
+      // e.printStackTrace();
     }
     return this;
   }
@@ -208,30 +223,29 @@ public abstract class AbstractResultData implements ResultData {
 
       // build file name
       byte[] fileNameBytes = null;
-      String fileName = null;
       GfJsonArray fileNameJsonBytes = object.getJSONArray(FILE_NAME_FIELD);
       if (fileNameJsonBytes != null) { // if in gfsh
         fileNameBytes = GfJsonArray.toByteArray(fileNameJsonBytes);
-        fileName = new String(fileNameBytes);
       } else { // if on member
-        fileName = (String) object.get(FILE_NAME_FIELD);
+        fileNameBytes = (byte[]) object.get(FILE_NAME_FIELD);
       }
+      String fileName = new String(fileNameBytes);
 
       // build file message
       byte[] fileMessageBytes = null;
-      String fileMessage = null;
       GfJsonArray fileMessageJsonBytes = object.getJSONArray(FILE_MESSAGE);
       if (fileMessageJsonBytes != null) { // if in gfsh
         fileMessageBytes = GfJsonArray.toByteArray(fileMessageJsonBytes);
-        fileMessage = new String(fileMessageBytes);
       } else { // if on member
-        fileMessage = (String) object.get(FILE_MESSAGE);
+        fileMessageBytes = (byte[]) object.get(FILE_MESSAGE);
       }
+      String fileMessage = new String(fileMessageBytes);
 
-      String fileDataString = (String) object.get(FILE_DATA_FIELD);
-      int fileDataLength = (int) object.get(DATA_LENGTH_FIELD);
-      byte[] byteArray = Base64.getDecoder().decode(fileDataString);
-      byte[] uncompressBytes = CliUtil.uncompressBytes(byteArray,fileDataLength).getData();
+      GfJsonObject fileDataBytes = object.getJSONObject(FILE_DATA_FIELD);
+      byte[] byteArray = GfJsonArray.toByteArray(fileDataBytes.getJSONArray(DATA_FIELD));
+      int dataLength = fileDataBytes.getInt(DATA_LENGTH_FIELD);
+      DeflaterInflaterData uncompressBytes = CliUtil.uncompressBytes(byteArray, dataLength);
+      byte[] uncompressed = uncompressBytes.getData();
 
       boolean isGfshVM = CliUtil.isGfshVM();
       File fileToDumpData = new File(fileName);
@@ -285,13 +299,13 @@ public abstract class AbstractResultData implements ResultData {
       if (fileType == FILE_TYPE_TEXT) {
         FileWriter fw = new FileWriter(fileToDumpData);
         BufferedWriter bw = new BufferedWriter(fw);
-        bw.write(new String(uncompressBytes));
+        bw.write(new String(uncompressed));
         bw.flush();
         fw.flush();
         fw.close();
       } else if (fileType == FILE_TYPE_BINARY) {
         FileOutputStream fos = new FileOutputStream(fileToDumpData);
-        fos.write(uncompressBytes);
+        fos.write(uncompressed);
         fos.flush();
         fos.close();
       }

http://git-wip-us.apache.org/repos/asf/geode/blob/0805036e/geode-core/src/main/java/org/apache/geode/management/internal/cli/result/CompositeResultData.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/management/internal/cli/result/CompositeResultData.java b/geode-core/src/main/java/org/apache/geode/management/internal/cli/result/CompositeResultData.java
index c1db133..7d0d23b 100644
--- a/geode-core/src/main/java/org/apache/geode/management/internal/cli/result/CompositeResultData.java
+++ b/geode-core/src/main/java/org/apache/geode/management/internal/cli/result/CompositeResultData.java
@@ -324,4 +324,50 @@ public class CompositeResultData extends AbstractResultData {
     // }
   }
 
+  public static void main(String[] args) {
+    CompositeResultData crd = new CompositeResultData();
+
+    SectionResultData r1Section = crd.addSection("R1");
+    r1Section.addData("Region", "R1").addData("IsPartitioned", false).addData("IsPersistent", true)
+        .addData("Disk Store", "DiskStore1").addData("Group", "Group1");
+    TabularResultData r1Table = r1Section.addTable("R1Members");
+    r1Table.accumulate("Member Id", "host1(3467):12435:12423")
+        .accumulate("PrimaryEntryCount", 20000).accumulate("BackupEntryCount", 20000)
+        .accumulate("Memory(MB)", "100").accumulate("NumOfCopies", 1);
+    r1Table.accumulate("Member Id", "host3(5756):57665:90923")
+        .accumulate("PrimaryEntryCount", 25000).accumulate("BackupEntryCount", 10000)
+        .accumulate("Memory(MB)", "200").accumulate("NumOfCopies", 1);
+
+    SectionResultData r3Section = crd.addSection("R3");
+    r3Section.addData("Region", "R3").addData("IsPartitioned", true).addData("IsPersistent", true)
+        .addData("Disk Store", "DiskStore2").addData("Group", "Group2")
+        .addData("ColocatedWith", "-");
+    SectionResultData r3SubSection = r3Section.addSection("R3Config");
+    r3SubSection.addData("Configuration", "");
+    r3SubSection.addData("Config1", "abcd");
+    r3SubSection.addData("Config2", "abcde");
+    r3SubSection.addData("Config3", "abcdfg");
+    TabularResultData r3Table = r3Section.addTable("R3Members");
+    r3Table.accumulate("Member Id", "host1(3467):12435:12423")
+        .accumulate("PrimaryEntryCount", 20000).accumulate("BackupEntryCount", 20000)
+        .accumulate("Memory(MB)", "100").accumulate("NumOfCopies", 1)
+        .accumulate("NumOfBuckets", 100);
+    r3Table.accumulate("Member Id", "host2(3353):23545:14723")
+        .accumulate("PrimaryEntryCount", 20000).accumulate("BackupEntryCount", 20000)
+        .accumulate("Memory(MB)", "100").accumulate("NumOfCopies", 1)
+        .accumulate("NumOfBuckets", 100);
+    r3Table.accumulate("Member Id", "host3(5756):57665:90923")
+        .accumulate("PrimaryEntryCount", 25000).accumulate("BackupEntryCount", 10000)
+        .accumulate("Memory(MB)", "200").accumulate("NumOfCopies", 1)
+        .accumulate("NumOfBuckets", 100);
+
+    try {
+      System.out.println(crd.getGfJsonObject().toIndentedString(/* 2 */0));
+
+    } catch (GfJsonException e) {
+      e.printStackTrace();
+    } catch (Exception e) {
+      e.printStackTrace();
+    }
+  }
 }

http://git-wip-us.apache.org/repos/asf/geode/blob/0805036e/geode-core/src/main/java/org/apache/geode/management/internal/cli/result/ResultBuilder.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/management/internal/cli/result/ResultBuilder.java b/geode-core/src/main/java/org/apache/geode/management/internal/cli/result/ResultBuilder.java
index 9bd2bf9..06060a4 100755
--- a/geode-core/src/main/java/org/apache/geode/management/internal/cli/result/ResultBuilder.java
+++ b/geode-core/src/main/java/org/apache/geode/management/internal/cli/result/ResultBuilder.java
@@ -301,6 +301,12 @@ public class ResultBuilder {
         }
 
         @Override
+        public ResultData addByteDataFromFileFile(String filePath, int fileType, String message,
+            boolean addTimeStampToName) throws FileNotFoundException, IOException {
+          throw new UnsupportedOperationException("This is read only result data");
+        }
+
+        @Override
         public TabularResultData accumulate(String accumulateFor, Object value) {
           throw new UnsupportedOperationException("This is read only result data");
         }
@@ -320,6 +326,12 @@ public class ResultBuilder {
         }
 
         @Override
+        public ResultData addByteDataFromFileFile(String filePath, int fileType, String message,
+            boolean addTimeStampToName) throws FileNotFoundException, IOException {
+          throw new UnsupportedOperationException("This is read only result data");
+        }
+
+        @Override
         public ErrorResultData addLine(String line) {
           throw new UnsupportedOperationException("This is read only result data");
         }
@@ -339,6 +351,12 @@ public class ResultBuilder {
         }
 
         @Override
+        public ResultData addByteDataFromFileFile(String filePath, int fileType, String message,
+            boolean addTimeStampToName) throws FileNotFoundException, IOException {
+          throw new UnsupportedOperationException("This is read only result data");
+        }
+
+        @Override
         public ErrorResultData addLine(String line) {
           throw new UnsupportedOperationException("This is read only result data");
         }
@@ -363,6 +381,12 @@ public class ResultBuilder {
         }
 
         @Override
+        public ResultData addByteDataFromFileFile(String filePath, int fileType, String message,
+            boolean addTimeStampToName) throws FileNotFoundException, IOException {
+          throw new UnsupportedOperationException("This is read only result data");
+        }
+
+        @Override
         public SectionResultData addSection() {
           throw new UnsupportedOperationException("This is read only result data");
         }
@@ -392,6 +416,12 @@ public class ResultBuilder {
         }
 
         @Override
+        public ResultData addByteDataFromFileFile(String filePath, int fileType, String message,
+            boolean addTimeStampToName) throws FileNotFoundException, IOException {
+          throw new UnsupportedOperationException("This is read only result data");
+        }
+
+        @Override
         public ObjectResultData<CliJsonSerializable> addCollection(
             Collection<CliJsonSerializable> infoBeans) {
           throw new UnsupportedOperationException("This is read only result data");

http://git-wip-us.apache.org/repos/asf/geode/blob/0805036e/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/CliCommandTestBase.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/CliCommandTestBase.java b/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/CliCommandTestBase.java
index 239810b..21426d6 100644
--- a/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/CliCommandTestBase.java
+++ b/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/CliCommandTestBase.java
@@ -360,11 +360,7 @@ public abstract class CliCommandTestBase extends JUnit4CacheTestCase {
 
     CommandResult result = null;
     try {
-      Object result1 = shell.getResult();
-      if (result1 instanceof String) {
-        System.err.println("result1 = " + result1);
-      }
-      result = (CommandResult) result1; // TODO: this can result in ClassCastException if
+      result = (CommandResult) shell.getResult(); // TODO: this can result in ClassCastException if
                                                   // command resulted in error
     } catch (InterruptedException ex) {
       error("shell received InterruptedException");

http://git-wip-us.apache.org/repos/asf/geode/blob/0805036e/geode-json/src/main/java/org/json/CDL.java
----------------------------------------------------------------------
diff --git a/geode-json/src/main/java/org/json/CDL.java b/geode-json/src/main/java/org/json/CDL.java
new file mode 100755
index 0000000..d78935b
--- /dev/null
+++ b/geode-json/src/main/java/org/json/CDL.java
@@ -0,0 +1,272 @@
+package org.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.
+ */
+
+/**
+ * This provides static methods to convert comma delimited text into a JSONArray, and to covert a
+ * JSONArray into comma delimited text. Comma delimited text is a very popular format for data
+ * interchange. It is understood by most database, spreadsheet, and organizer programs.
+ * <p>
+ * Each row of text represents a row in a table or a data record. Each row ends with a NEWLINE
+ * character. Each row contains one or more values. Values are separated by commas. A value can
+ * contain any character except for comma, unless is is wrapped in single quotes or double quotes.
+ * <p>
+ * The first row usually contains the names of the columns.
+ * <p>
+ * A comma delimited list can be converted into a JSONArray of JSONObjects. The names for the
+ * elements in the JSONObjects can be taken from the names in the first row.
+ * 
+ * @author JSON.org
+ * @version 2010-12-24
+ */
+public class CDL {
+
+  /**
+   * Get the next value. The value can be wrapped in quotes. The value can be empty.
+   * 
+   * @param x A JSONTokener of the source text.
+   * @return The value string, or null if empty.
+   * @throws JSONException if the quoted string is badly formed.
+   */
+  private static String getValue(JSONTokener x) throws JSONException {
+    char c;
+    char q;
+    StringBuffer sb;
+    do {
+      c = x.next();
+    } while (c == ' ' || c == '\t');
+    switch (c) {
+      case 0:
+        return null;
+      case '"':
+      case '\'':
+        q = c;
+        sb = new StringBuffer();
+        for (;;) {
+          c = x.next();
+          if (c == q) {
+            break;
+          }
+          if (c == 0 || c == '\n' || c == '\r') {
+            throw x.syntaxError("Missing close quote '" + q + "'.");
+          }
+          sb.append(c);
+        }
+        return sb.toString();
+      case ',':
+        x.back();
+        return "";
+      default:
+        x.back();
+        return x.nextTo(',');
+    }
+  }
+
+  /**
+   * Produce a JSONArray of strings from a row of comma delimited values.
+   * 
+   * @param x A JSONTokener of the source text.
+   * @return A JSONArray of strings.
+   * @throws JSONException
+   */
+  public static JSONArray rowToJSONArray(JSONTokener x) throws JSONException {
+    JSONArray ja = new JSONArray();
+    for (;;) {
+      String value = getValue(x);
+      char c = x.next();
+      if (value == null || (ja.length() == 0 && value.length() == 0 && c != ',')) {
+        return null;
+      }
+      ja.put(value);
+      for (;;) {
+        if (c == ',') {
+          break;
+        }
+        if (c != ' ') {
+          if (c == '\n' || c == '\r' || c == 0) {
+            return ja;
+          }
+          throw x.syntaxError("Bad character '" + c + "' (" + (int) c + ").");
+        }
+        c = x.next();
+      }
+    }
+  }
+
+  /**
+   * Produce a JSONObject from a row of comma delimited text, using a parallel JSONArray of strings
+   * to provides the names of the elements.
+   * 
+   * @param names A JSONArray of names. This is commonly obtained from the first row of a comma
+   *        delimited text file using the rowToJSONArray method.
+   * @param x A JSONTokener of the source text.
+   * @return A JSONObject combining the names and values.
+   * @throws JSONException
+   */
+  public static JSONObject rowToJSONObject(JSONArray names, JSONTokener x) throws JSONException {
+    JSONArray ja = rowToJSONArray(x);
+    return ja != null ? ja.toJSONObject(names) : null;
+  }
+
+  /**
+   * Produce a comma delimited text row from a JSONArray. Values containing the comma character will
+   * be quoted. Troublesome characters may be removed.
+   * 
+   * @param ja A JSONArray of strings.
+   * @return A string ending in NEWLINE.
+   */
+  public static String rowToString(JSONArray ja) {
+    StringBuffer sb = new StringBuffer();
+    for (int i = 0; i < ja.length(); i += 1) {
+      if (i > 0) {
+        sb.append(',');
+      }
+      Object object = ja.opt(i);
+      if (object != null) {
+        String string = object.toString();
+        if (string.length() > 0 && (string.indexOf(',') >= 0 || string.indexOf('\n') >= 0
+            || string.indexOf('\r') >= 0 || string.indexOf(0) >= 0 || string.charAt(0) == '"')) {
+          sb.append('"');
+          int length = string.length();
+          for (int j = 0; j < length; j += 1) {
+            char c = string.charAt(j);
+            if (c >= ' ' && c != '"') {
+              sb.append(c);
+            }
+          }
+          sb.append('"');
+        } else {
+          sb.append(string);
+        }
+      }
+    }
+    sb.append('\n');
+    return sb.toString();
+  }
+
+  /**
+   * Produce a JSONArray of JSONObjects from a comma delimited text string, using the first row as a
+   * source of names.
+   * 
+   * @param string The comma delimited text.
+   * @return A JSONArray of JSONObjects.
+   * @throws JSONException
+   */
+  public static JSONArray toJSONArray(String string) throws JSONException {
+    return toJSONArray(new JSONTokener(string));
+  }
+
+  /**
+   * Produce a JSONArray of JSONObjects from a comma delimited text string, using the first row as a
+   * source of names.
+   * 
+   * @param x The JSONTokener containing the comma delimited text.
+   * @return A JSONArray of JSONObjects.
+   * @throws JSONException
+   */
+  public static JSONArray toJSONArray(JSONTokener x) throws JSONException {
+    return toJSONArray(rowToJSONArray(x), x);
+  }
+
+  /**
+   * Produce a JSONArray of JSONObjects from a comma delimited text string using a supplied
+   * JSONArray as the source of element names.
+   * 
+   * @param names A JSONArray of strings.
+   * @param string The comma delimited text.
+   * @return A JSONArray of JSONObjects.
+   * @throws JSONException
+   */
+  public static JSONArray toJSONArray(JSONArray names, String string) throws JSONException {
+    return toJSONArray(names, new JSONTokener(string));
+  }
+
+  /**
+   * Produce a JSONArray of JSONObjects from a comma delimited text string using a supplied
+   * JSONArray as the source of element names.
+   * 
+   * @param names A JSONArray of strings.
+   * @param x A JSONTokener of the source text.
+   * @return A JSONArray of JSONObjects.
+   * @throws JSONException
+   */
+  public static JSONArray toJSONArray(JSONArray names, JSONTokener x) throws JSONException {
+    if (names == null || names.length() == 0) {
+      return null;
+    }
+    JSONArray ja = new JSONArray();
+    for (;;) {
+      JSONObject jo = rowToJSONObject(names, x);
+      if (jo == null) {
+        break;
+      }
+      ja.put(jo);
+    }
+    if (ja.length() == 0) {
+      return null;
+    }
+    return ja;
+  }
+
+
+  /**
+   * Produce a comma delimited text from a JSONArray of JSONObjects. The first row will be a list of
+   * names obtained by inspecting the first JSONObject.
+   * 
+   * @param ja A JSONArray of JSONObjects.
+   * @return A comma delimited text.
+   * @throws JSONException
+   */
+  public static String toString(JSONArray ja) throws JSONException {
+    JSONObject jo = ja.optJSONObject(0);
+    if (jo != null) {
+      JSONArray names = jo.names();
+      if (names != null) {
+        return rowToString(names) + toString(names, ja);
+      }
+    }
+    return null;
+  }
+
+  /**
+   * Produce a comma delimited text from a JSONArray of JSONObjects using a provided list of names.
+   * The list of names is not included in the output.
+   * 
+   * @param names A JSONArray of strings.
+   * @param ja A JSONArray of JSONObjects.
+   * @return A comma delimited text.
+   * @throws JSONException
+   */
+  public static String toString(JSONArray names, JSONArray ja) throws JSONException {
+    if (names == null || names.length() == 0) {
+      return null;
+    }
+    StringBuffer sb = new StringBuffer();
+    for (int i = 0; i < ja.length(); i += 1) {
+      JSONObject jo = ja.optJSONObject(i);
+      if (jo != null) {
+        sb.append(rowToString(jo.toJSONArray(names)));
+      }
+    }
+    return sb.toString();
+  }
+}

http://git-wip-us.apache.org/repos/asf/geode/blob/0805036e/geode-json/src/main/java/org/json/Cookie.java
----------------------------------------------------------------------
diff --git a/geode-json/src/main/java/org/json/Cookie.java b/geode-json/src/main/java/org/json/Cookie.java
new file mode 100755
index 0000000..21f88d8
--- /dev/null
+++ b/geode-json/src/main/java/org/json/Cookie.java
@@ -0,0 +1,162 @@
+package org.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.
+ */
+
+/**
+ * Convert a web browser cookie specification to a JSONObject and back. JSON and Cookies are both
+ * notations for name/value pairs.
+ * 
+ * @author JSON.org
+ * @version 2010-12-24
+ */
+public class Cookie {
+
+  /**
+   * Produce a copy of a string in which the characters '+', '%', '=', ';' and control characters
+   * are replaced with "%hh". This is a gentle form of URL encoding, attempting to cause as little
+   * distortion to the string as possible. The characters '=' and ';' are meta characters in
+   * cookies. By convention, they are escaped using the URL-encoding. This is only a convention, not
+   * a standard. Often, cookies are expected to have encoded values. We encode '=' and ';' because
+   * we must. We encode '%' and '+' because they are meta characters in URL encoding.
+   * 
+   * @param string The source string.
+   * @return The escaped result.
+   */
+  public static String escape(String string) {
+    char c;
+    String s = string.trim();
+    StringBuffer sb = new StringBuffer();
+    int length = s.length();
+    for (int i = 0; i < length; i += 1) {
+      c = s.charAt(i);
+      if (c < ' ' || c == '+' || c == '%' || c == '=' || c == ';') {
+        sb.append('%');
+        sb.append(Character.forDigit((char) ((c >>> 4) & 0x0f), 16));
+        sb.append(Character.forDigit((char) (c & 0x0f), 16));
+      } else {
+        sb.append(c);
+      }
+    }
+    return sb.toString();
+  }
+
+
+  /**
+   * Convert a cookie specification string into a JSONObject. The string will contain a name value
+   * pair separated by '='. The name and the value will be unescaped, possibly converting '+' and
+   * '%' sequences. The cookie properties may follow, separated by ';', also represented as
+   * name=value (except the secure property, which does not have a value). The name will be stored
+   * under the key "name", and the value will be stored under the key "value". This method does not
+   * do checking or validation of the parameters. It only converts the cookie string into a
+   * JSONObject.
+   * 
+   * @param string The cookie specification string.
+   * @return A JSONObject containing "name", "value", and possibly other members.
+   * @throws JSONException
+   */
+  public static JSONObject toJSONObject(String string) throws JSONException {
+    String name;
+    JSONObject jo = new JSONObject();
+    Object value;
+    JSONTokener x = new JSONTokener(string);
+    jo.put("name", x.nextTo('='));
+    x.next('=');
+    jo.put("value", x.nextTo(';'));
+    x.next();
+    while (x.more()) {
+      name = unescape(x.nextTo("=;"));
+      if (x.next() != '=') {
+        if (name.equals("secure")) {
+          value = Boolean.TRUE;
+        } else {
+          throw x.syntaxError("Missing '=' in cookie parameter.");
+        }
+      } else {
+        value = unescape(x.nextTo(';'));
+        x.next();
+      }
+      jo.put(name, value);
+    }
+    return jo;
+  }
+
+
+  /**
+   * Convert a JSONObject into a cookie specification string. The JSONObject must contain "name" and
+   * "value" members. If the JSONObject contains "expires", "domain", "path", or "secure" members,
+   * they will be appended to the cookie specification string. All other members are ignored.
+   * 
+   * @param jo A JSONObject
+   * @return A cookie specification string
+   * @throws JSONException
+   */
+  public static String toString(JSONObject jo) throws JSONException {
+    StringBuffer sb = new StringBuffer();
+
+    sb.append(escape(jo.getString("name")));
+    sb.append("=");
+    sb.append(escape(jo.getString("value")));
+    if (jo.has("expires")) {
+      sb.append(";expires=");
+      sb.append(jo.getString("expires"));
+    }
+    if (jo.has("domain")) {
+      sb.append(";domain=");
+      sb.append(escape(jo.getString("domain")));
+    }
+    if (jo.has("path")) {
+      sb.append(";path=");
+      sb.append(escape(jo.getString("path")));
+    }
+    if (jo.optBoolean("secure")) {
+      sb.append(";secure");
+    }
+    return sb.toString();
+  }
+
+  /**
+   * Convert <code>%</code><i>hh</i> sequences to single characters, and convert plus to space.
+   * 
+   * @param string A string that may contain <code>+</code>&nbsp;<small>(plus)</small> and
+   *        <code>%</code><i>hh</i> sequences.
+   * @return The unescaped string.
+   */
+  public static String unescape(String string) {
+    int length = string.length();
+    StringBuffer sb = new StringBuffer();
+    for (int i = 0; i < length; ++i) {
+      char c = string.charAt(i);
+      if (c == '+') {
+        c = ' ';
+      } else if (c == '%' && i + 2 < length) {
+        int d = JSONTokener.dehexchar(string.charAt(i + 1));
+        int e = JSONTokener.dehexchar(string.charAt(i + 2));
+        if (d >= 0 && e >= 0) {
+          c = (char) (d * 16 + e);
+          i += 2;
+        }
+      }
+      sb.append(c);
+    }
+    return sb.toString();
+  }
+}

http://git-wip-us.apache.org/repos/asf/geode/blob/0805036e/geode-json/src/main/java/org/json/CookieList.java
----------------------------------------------------------------------
diff --git a/geode-json/src/main/java/org/json/CookieList.java b/geode-json/src/main/java/org/json/CookieList.java
new file mode 100755
index 0000000..35e1a97
--- /dev/null
+++ b/geode-json/src/main/java/org/json/CookieList.java
@@ -0,0 +1,87 @@
+package org.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.util.Iterator;
+
+/**
+ * Convert a web browser cookie list string to a JSONObject and back.
+ * 
+ * @author JSON.org
+ * @version 2010-12-24
+ */
+public class CookieList {
+
+  /**
+   * Convert a cookie list into a JSONObject. A cookie list is a sequence of name/value pairs. The
+   * names are separated from the values by '='. The pairs are separated by ';'. The names and the
+   * values will be unescaped, possibly converting '+' and '%' sequences.
+   *
+   * To add a cookie to a cooklist, cookielistJSONObject.put(cookieJSONObject.getString("name"),
+   * cookieJSONObject.getString("value"));
+   * 
+   * @param string A cookie list string
+   * @return A JSONObject
+   * @throws JSONException
+   */
+  public static JSONObject toJSONObject(String string) throws JSONException {
+    JSONObject jo = new JSONObject();
+    JSONTokener x = new JSONTokener(string);
+    while (x.more()) {
+      String name = Cookie.unescape(x.nextTo('='));
+      x.next('=');
+      jo.put(name, Cookie.unescape(x.nextTo(';')));
+      x.next();
+    }
+    return jo;
+  }
+
+
+  /**
+   * Convert a JSONObject into a cookie list. A cookie list is a sequence of name/value pairs. The
+   * names are separated from the values by '='. The pairs are separated by ';'. The characters '%',
+   * '+', '=', and ';' in the names and values are replaced by "%hh".
+   * 
+   * @param jo A JSONObject
+   * @return A cookie list string
+   * @throws JSONException
+   */
+  public static String toString(JSONObject jo) throws JSONException {
+    boolean b = false;
+    Iterator keys = jo.keys();
+    String string;
+    StringBuffer sb = new StringBuffer();
+    while (keys.hasNext()) {
+      string = keys.next().toString();
+      if (!jo.isNull(string)) {
+        if (b) {
+          sb.append(';');
+        }
+        sb.append(Cookie.escape(string));
+        sb.append("=");
+        sb.append(Cookie.escape(jo.getString(string)));
+        b = true;
+      }
+    }
+    return sb.toString();
+  }
+}

http://git-wip-us.apache.org/repos/asf/geode/blob/0805036e/geode-json/src/main/java/org/json/HTTP.java
----------------------------------------------------------------------
diff --git a/geode-json/src/main/java/org/json/HTTP.java b/geode-json/src/main/java/org/json/HTTP.java
new file mode 100755
index 0000000..1e815aa
--- /dev/null
+++ b/geode-json/src/main/java/org/json/HTTP.java
@@ -0,0 +1,185 @@
+package org.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.util.Iterator;
+
+/**
+ * Convert an HTTP header to a JSONObject and back.
+ * 
+ * @author JSON.org
+ * @version 2010-12-24
+ */
+public class HTTP {
+
+  /** Carriage return/line feed. */
+  public static final String CRLF = "\r\n";
+
+  /**
+   * Convert an HTTP header string into a JSONObject. It can be a request header or a response
+   * header. A request header will contain
+   * 
+   * <pre>
+   * {
+   *    Method: "POST" (for example),
+   *    "Request-URI": "/" (for example),
+   *    "HTTP-Version": "HTTP/1.1" (for example)
+   * }
+   * </pre>
+   * 
+   * A response header will contain
+   * 
+   * <pre>
+   * {
+   *    "HTTP-Version": "HTTP/1.1" (for example),
+   *    "Status-Code": "200" (for example),
+   *    "Reason-Phrase": "OK" (for example)
+   * }
+   * </pre>
+   * 
+   * In addition, the other parameters in the header will be captured, using the HTTP field names as
+   * JSON names, so that
+   * 
+   * <pre>
+   *    Date: Sun, 26 May 2002 18:06:04 GMT
+   *    Cookie: Q=q2=PPEAsg--; B=677gi6ouf29bn&b=2&f=s
+   *    Cache-Control: no-cache
+   * </pre>
+   * 
+   * become
+   * 
+   * <pre>
+   * {...
+   *    Date: "Sun, 26 May 2002 18:06:04 GMT",
+   *    Cookie: "Q=q2=PPEAsg--; B=677gi6ouf29bn&b=2&f=s",
+   *    "Cache-Control": "no-cache",
+   * ...}
+   * </pre>
+   * 
+   * It does no further checking or conversion. It does not parse dates. It does not do '%'
+   * transforms on URLs.
+   * 
+   * @param string An HTTP header string.
+   * @return A JSONObject containing the elements and attributes of the XML string.
+   * @throws JSONException
+   */
+  public static JSONObject toJSONObject(String string) throws JSONException {
+    JSONObject jo = new JSONObject();
+    HTTPTokener x = new HTTPTokener(string);
+    String token;
+
+    token = x.nextToken();
+    if (token.toUpperCase().startsWith("HTTP")) {
+
+      // Response
+
+      jo.put("HTTP-Version", token);
+      jo.put("Status-Code", x.nextToken());
+      jo.put("Reason-Phrase", x.nextTo('\0'));
+      x.next();
+
+    } else {
+
+      // Request
+
+      jo.put("Method", token);
+      jo.put("Request-URI", x.nextToken());
+      jo.put("HTTP-Version", x.nextToken());
+    }
+
+    // Fields
+
+    while (x.more()) {
+      String name = x.nextTo(':');
+      x.next(':');
+      jo.put(name, x.nextTo('\0'));
+      x.next();
+    }
+    return jo;
+  }
+
+
+  /**
+   * Convert a JSONObject into an HTTP header. A request header must contain
+   * 
+   * <pre>
+   * {
+   *    Method: "POST" (for example),
+   *    "Request-URI": "/" (for example),
+   *    "HTTP-Version": "HTTP/1.1" (for example)
+   * }
+   * </pre>
+   * 
+   * A response header must contain
+   * 
+   * <pre>
+   * {
+   *    "HTTP-Version": "HTTP/1.1" (for example),
+   *    "Status-Code": "200" (for example),
+   *    "Reason-Phrase": "OK" (for example)
+   * }
+   * </pre>
+   * 
+   * Any other members of the JSONObject will be output as HTTP fields. The result will end with two
+   * CRLF pairs.
+   * 
+   * @param jo A JSONObject
+   * @return An HTTP header string.
+   * @throws JSONException if the object does not contain enough information.
+   */
+  public static String toString(JSONObject jo) throws JSONException {
+    Iterator keys = jo.keys();
+    String string;
+    StringBuffer sb = new StringBuffer();
+    if (jo.has("Status-Code") && jo.has("Reason-Phrase")) {
+      sb.append(jo.getString("HTTP-Version"));
+      sb.append(' ');
+      sb.append(jo.getString("Status-Code"));
+      sb.append(' ');
+      sb.append(jo.getString("Reason-Phrase"));
+    } else if (jo.has("Method") && jo.has("Request-URI")) {
+      sb.append(jo.getString("Method"));
+      sb.append(' ');
+      sb.append('"');
+      sb.append(jo.getString("Request-URI"));
+      sb.append('"');
+      sb.append(' ');
+      sb.append(jo.getString("HTTP-Version"));
+    } else {
+      throw new JSONException("Not enough material for an HTTP header.");
+    }
+    sb.append(CRLF);
+    while (keys.hasNext()) {
+      string = keys.next().toString();
+      if (!"HTTP-Version".equals(string) && !"Status-Code".equals(string)
+          && !"Reason-Phrase".equals(string) && !"Method".equals(string)
+          && !"Request-URI".equals(string) && !jo.isNull(string)) {
+        sb.append(string);
+        sb.append(": ");
+        sb.append(jo.getString(string));
+        sb.append(CRLF);
+      }
+    }
+    sb.append(CRLF);
+    return sb.toString();
+  }
+}

http://git-wip-us.apache.org/repos/asf/geode/blob/0805036e/geode-json/src/main/java/org/json/HTTPTokener.java
----------------------------------------------------------------------
diff --git a/geode-json/src/main/java/org/json/HTTPTokener.java b/geode-json/src/main/java/org/json/HTTPTokener.java
new file mode 100755
index 0000000..72c9b88
--- /dev/null
+++ b/geode-json/src/main/java/org/json/HTTPTokener.java
@@ -0,0 +1,77 @@
+package org.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.
+ */
+
+/**
+ * The HTTPTokener extends the JSONTokener to provide additional methods for the parsing of HTTP
+ * headers.
+ * 
+ * @author JSON.org
+ * @version 2010-12-24
+ */
+public class HTTPTokener extends JSONTokener {
+
+  /**
+   * Construct an HTTPTokener from a string.
+   * 
+   * @param string A source string.
+   */
+  public HTTPTokener(String string) {
+    super(string);
+  }
+
+
+  /**
+   * Get the next token or string. This is used in parsing HTTP headers.
+   * 
+   * @throws JSONException
+   * @return A String.
+   */
+  public String nextToken() throws JSONException {
+    char c;
+    char q;
+    StringBuffer sb = new StringBuffer();
+    do {
+      c = next();
+    } while (Character.isWhitespace(c));
+    if (c == '"' || c == '\'') {
+      q = c;
+      for (;;) {
+        c = next();
+        if (c < ' ') {
+          throw syntaxError("Unterminated string.");
+        }
+        if (c == q) {
+          return sb.toString();
+        }
+        sb.append(c);
+      }
+    }
+    for (;;) {
+      if (c == 0 || Character.isWhitespace(c)) {
+        return sb.toString();
+      }
+      sb.append(c);
+      c = next();
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/geode/blob/0805036e/geode-json/src/main/java/org/json/JSON.java
----------------------------------------------------------------------
diff --git a/geode-json/src/main/java/org/json/JSON.java b/geode-json/src/main/java/org/json/JSON.java
deleted file mode 100755
index 1b32e69..0000000
--- a/geode-json/src/main/java/org/json/JSON.java
+++ /dev/null
@@ -1,116 +0,0 @@
-/*
- * 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.json;
-
-class JSON {
-    /**
-     * Returns the input if it is a JSON-permissible value; throws otherwise.
-     */
-    static double checkDouble(double d) throws JSONException {
-        if (Double.isInfinite(d) || Double.isNaN(d)) {
-            throw new JSONException("Forbidden numeric value: " + d);
-        }
-        return d;
-    }
-
-    static Boolean toBoolean(Object value) {
-        if (value instanceof Boolean) {
-            return (Boolean) value;
-        } else if (value instanceof String) {
-            String stringValue = (String) value;
-            if ("true".equalsIgnoreCase(stringValue)) {
-                return true;
-            } else if ("false".equalsIgnoreCase(stringValue)) {
-                return false;
-            }
-        }
-        return null;
-    }
-
-    static Double toDouble(Object value) {
-        if (value instanceof Double) {
-            return (Double) value;
-        } else if (value instanceof Number) {
-            return ((Number) value).doubleValue();
-        } else if (value instanceof String) {
-            try {
-                return Double.valueOf((String) value);
-            } catch (NumberFormatException ignored) {
-            }
-        }
-        return null;
-    }
-
-    static Integer toInteger(Object value) {
-        if (value instanceof Integer) {
-            return (Integer) value;
-        } else if (value instanceof Number) {
-            return ((Number) value).intValue();
-        } else if (value instanceof String) {
-            try {
-                return (int) Double.parseDouble((String) value);
-            } catch (NumberFormatException ignored) {
-            }
-        }
-        return null;
-    }
-
-    static Long toLong(Object value) {
-        if (value instanceof Long) {
-            return (Long) value;
-        } else if (value instanceof Number) {
-            return ((Number) value).longValue();
-        } else if (value instanceof String) {
-            try {
-                return (long) Double.parseDouble((String) value);
-            } catch (NumberFormatException ignored) {
-            }
-        }
-        return null;
-    }
-
-    static String toString(Object value) {
-        if (value instanceof String) {
-            return (String) value;
-        } else if (value != null) {
-            return String.valueOf(value);
-        }
-        return null;
-    }
-
-    public static JSONException typeMismatch(Object indexOrName, Object actual,
-            String requiredType) throws JSONException {
-        if (actual == null) {
-            throw new JSONException("Value at " + indexOrName + " is null.");
-        } else {
-            throw new JSONException("Value " + actual + " at " + indexOrName
-                    + " of type " + actual.getClass().getName()
-                    + " cannot be converted to " + requiredType);
-        }
-    }
-
-    public static JSONException typeMismatch(Object actual, String requiredType)
-            throws JSONException {
-        if (actual == null) {
-            throw new JSONException("Value is null.");
-        } else {
-            throw new JSONException("Value " + actual
-                    + " of type " + actual.getClass().getName()
-                    + " cannot be converted to " + requiredType);
-        }
-    }
-}


[4/8] geode git commit: Revert "GEODE-2142: Removal of non-compliant org.json implementation."

Posted by ud...@apache.org.
http://git-wip-us.apache.org/repos/asf/geode/blob/0805036e/geode-json/src/main/java/org/json/XMLTokener.java
----------------------------------------------------------------------
diff --git a/geode-json/src/main/java/org/json/XMLTokener.java b/geode-json/src/main/java/org/json/XMLTokener.java
new file mode 100755
index 0000000..f56a1f6
--- /dev/null
+++ b/geode-json/src/main/java/org/json/XMLTokener.java
@@ -0,0 +1,362 @@
+package org.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.
+ */
+
+/**
+ * The XMLTokener extends the JSONTokener to provide additional methods for the parsing of XML
+ * texts.
+ * 
+ * @author JSON.org
+ * @version 2010-12-24
+ */
+public class XMLTokener extends JSONTokener {
+
+
+  /**
+   * The table of entity values. It initially contains Character values for amp, apos, gt, lt, quot.
+   */
+  public static final java.util.HashMap entity;
+
+  static {
+    entity = new java.util.HashMap(8);
+    entity.put("amp", XML.AMP);
+    entity.put("apos", XML.APOS);
+    entity.put("gt", XML.GT);
+    entity.put("lt", XML.LT);
+    entity.put("quot", XML.QUOT);
+  }
+
+  /**
+   * Construct an XMLTokener from a string.
+   * 
+   * @param s A source string.
+   */
+  public XMLTokener(String s) {
+    super(s);
+  }
+
+  /**
+   * Get the text in the CDATA block.
+   * 
+   * @return The string up to the <code>]]&gt;</code>.
+   * @throws JSONException If the <code>]]&gt;</code> is not found.
+   */
+  public String nextCDATA() throws JSONException {
+    char c;
+    int i;
+    StringBuffer sb = new StringBuffer();
+    for (;;) {
+      c = next();
+      if (end()) {
+        throw syntaxError("Unclosed CDATA");
+      }
+      sb.append(c);
+      i = sb.length() - 3;
+      if (i >= 0 && sb.charAt(i) == ']' && sb.charAt(i + 1) == ']' && sb.charAt(i + 2) == '>') {
+        sb.setLength(i);
+        return sb.toString();
+      }
+    }
+  }
+
+
+  /**
+   * Get the next XML outer token, trimming whitespace. There are two kinds of tokens: the '<'
+   * character which begins a markup tag, and the content text between markup tags.
+   *
+   * @return A string, or a '<' Character, or null if there is no more source text.
+   * @throws JSONException
+   */
+  public Object nextContent() throws JSONException {
+    char c;
+    StringBuffer sb;
+    do {
+      c = next();
+    } while (Character.isWhitespace(c));
+    if (c == 0) {
+      return null;
+    }
+    if (c == '<') {
+      return XML.LT;
+    }
+    sb = new StringBuffer();
+    for (;;) {
+      if (c == '<' || c == 0) {
+        back();
+        return sb.toString().trim();
+      }
+      if (c == '&') {
+        sb.append(nextEntity(c));
+      } else {
+        sb.append(c);
+      }
+      c = next();
+    }
+  }
+
+
+  /**
+   * Return the next entity. These entities are translated to Characters:
+   * <code>&amp;  &apos;  &gt;  &lt;  &quot;</code>.
+   * 
+   * @param ampersand An ampersand character.
+   * @return A Character or an entity String if the entity is not recognized.
+   * @throws JSONException If missing ';' in XML entity.
+   */
+  public Object nextEntity(char ampersand) throws JSONException {
+    StringBuffer sb = new StringBuffer();
+    for (;;) {
+      char c = next();
+      if (Character.isLetterOrDigit(c) || c == '#') {
+        sb.append(Character.toLowerCase(c));
+      } else if (c == ';') {
+        break;
+      } else {
+        throw syntaxError("Missing ';' in XML entity: &" + sb);
+      }
+    }
+    String string = sb.toString();
+    Object object = entity.get(string);
+    return object != null ? object : ampersand + string + ";";
+  }
+
+
+  /**
+   * Returns the next XML meta token. This is used for skipping over <!...> and <?...?> structures.
+   * 
+   * @return Syntax characters (<code>< > / = ! ?</code>) are returned as Character, and strings and
+   *         names are returned as Boolean. We don't care what the values actually are.
+   * @throws JSONException If a string is not properly closed or if the XML is badly structured.
+   */
+  public Object nextMeta() throws JSONException {
+    char c;
+    char q;
+    do {
+      c = next();
+    } while (Character.isWhitespace(c));
+    switch (c) {
+      case 0:
+        throw syntaxError("Misshaped meta tag");
+      case '<':
+        return XML.LT;
+      case '>':
+        return XML.GT;
+      case '/':
+        return XML.SLASH;
+      case '=':
+        return XML.EQ;
+      case '!':
+        return XML.BANG;
+      case '?':
+        return XML.QUEST;
+      case '"':
+      case '\'':
+        q = c;
+        for (;;) {
+          c = next();
+          if (c == 0) {
+            throw syntaxError("Unterminated string");
+          }
+          if (c == q) {
+            return Boolean.TRUE;
+          }
+        }
+      default:
+        for (;;) {
+          c = next();
+          if (Character.isWhitespace(c)) {
+            return Boolean.TRUE;
+          }
+          switch (c) {
+            case 0:
+            case '<':
+            case '>':
+            case '/':
+            case '=':
+            case '!':
+            case '?':
+            case '"':
+            case '\'':
+              back();
+              return Boolean.TRUE;
+          }
+        }
+    }
+  }
+
+
+  /**
+   * Get the next XML Token. These tokens are found inside of angle brackets. It may be one of these
+   * characters: <code>/ > = ! ?</code> or it may be a string wrapped in single quotes or double
+   * quotes, or it may be a name.
+   * 
+   * @return a String or a Character.
+   * @throws JSONException If the XML is not well formed.
+   */
+  public Object nextToken() throws JSONException {
+    char c;
+    char q;
+    StringBuffer sb;
+    do {
+      c = next();
+    } while (Character.isWhitespace(c));
+    switch (c) {
+      case 0:
+        throw syntaxError("Misshaped element");
+      case '<':
+        throw syntaxError("Misplaced '<'");
+      case '>':
+        return XML.GT;
+      case '/':
+        return XML.SLASH;
+      case '=':
+        return XML.EQ;
+      case '!':
+        return XML.BANG;
+      case '?':
+        return XML.QUEST;
+
+      // Quoted string
+
+      case '"':
+      case '\'':
+        q = c;
+        sb = new StringBuffer();
+        for (;;) {
+          c = next();
+          if (c == 0) {
+            throw syntaxError("Unterminated string");
+          }
+          if (c == q) {
+            return sb.toString();
+          }
+          if (c == '&') {
+            sb.append(nextEntity(c));
+          } else {
+            sb.append(c);
+          }
+        }
+      default:
+
+        // Name
+
+        sb = new StringBuffer();
+        for (;;) {
+          sb.append(c);
+          c = next();
+          if (Character.isWhitespace(c)) {
+            return sb.toString();
+          }
+          switch (c) {
+            case 0:
+              return sb.toString();
+            case '>':
+            case '/':
+            case '=':
+            case '!':
+            case '?':
+            case '[':
+            case ']':
+              back();
+              return sb.toString();
+            case '<':
+            case '"':
+            case '\'':
+              throw syntaxError("Bad character in a name");
+          }
+        }
+    }
+  }
+
+
+  /**
+   * Skip characters until past the requested string. If it is not found, we are left at the end of
+   * the source with a result of false.
+   * 
+   * @param to A string to skip past.
+   * @throws JSONException
+   */
+  public boolean skipPast(String to) throws JSONException {
+    boolean b;
+    char c;
+    int i;
+    int j;
+    int offset = 0;
+    int length = to.length();
+    char[] circle = new char[length];
+
+    /*
+     * First fill the circle buffer with as many characters as are in the to string. If we reach an
+     * early end, bail.
+     */
+
+    for (i = 0; i < length; i += 1) {
+      c = next();
+      if (c == 0) {
+        return false;
+      }
+      circle[i] = c;
+    }
+    /*
+     * We will loop, possibly for all of the remaining characters.
+     */
+    for (;;) {
+      j = offset;
+      b = true;
+      /*
+       * Compare the circle buffer with the to string.
+       */
+      for (i = 0; i < length; i += 1) {
+        if (circle[j] != to.charAt(i)) {
+          b = false;
+          break;
+        }
+        j += 1;
+        if (j >= length) {
+          j -= length;
+        }
+      }
+      /*
+       * If we exit the loop with b intact, then victory is ours.
+       */
+      if (b) {
+        return true;
+      }
+      /*
+       * Get the next character. If there isn't one, then defeat is ours.
+       */
+      c = next();
+      if (c == 0) {
+        return false;
+      }
+      /*
+       * Shove the character in the circle buffer and advance the circle offset. The offset is mod
+       * n.
+       */
+      circle[offset] = c;
+      offset += 1;
+      if (offset >= length) {
+        offset -= length;
+      }
+    }
+  }
+}


[2/8] geode git commit: Revert "GEODE-2142: Spotless"

Posted by ud...@apache.org.
http://git-wip-us.apache.org/repos/asf/geode/blob/1253d780/geode-json/src/main/java/org/json/JSONObject.java
----------------------------------------------------------------------
diff --git a/geode-json/src/main/java/org/json/JSONObject.java b/geode-json/src/main/java/org/json/JSONObject.java
index bddfb56..d5de19f 100755
--- a/geode-json/src/main/java/org/json/JSONObject.java
+++ b/geode-json/src/main/java/org/json/JSONObject.java
@@ -1,15 +1,17 @@
 /*
  * 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
+ * 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
+ *      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.
+ * 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.json;
@@ -31,53 +33,55 @@ import java.util.TreeMap;
 // Note: this class was written without inspecting the non-free org.json sourcecode.
 
 /**
- * A modifiable set of name/value mappings. Names are unique, non-null strings. Values may be any
- * mix of {@link JSONObject JSONObjects}, {@link JSONArray JSONArrays}, Strings, Booleans, Integers,
- * Longs, Doubles or {@link #NULL}. Values may not be {@code null}, {@link Double#isNaN() NaNs},
- * {@link Double#isInfinite() infinities}, or of any type not listed here.
+ * A modifiable set of name/value mappings. Names are unique, non-null strings.
+ * Values may be any mix of {@link JSONObject JSONObjects}, {@link JSONArray
+ * JSONArrays}, Strings, Booleans, Integers, Longs, Doubles or {@link #NULL}.
+ * Values may not be {@code null}, {@link Double#isNaN() NaNs}, {@link
+ * Double#isInfinite() infinities}, or of any type not listed here.
  *
- * <p>
- * This class can coerce values to another type when requested.
+ * <p>This class can coerce values to another type when requested.
  * <ul>
- * <li>When the requested type is a boolean, strings will be coerced using a case-insensitive
- * comparison to "true" and "false".
- * <li>When the requested type is a double, other {@link Number} types will be coerced using
- * {@link Number#doubleValue() doubleValue}. Strings that can be coerced using
- * {@link Double#valueOf(String)} will be.
- * <li>When the requested type is an int, other {@link Number} types will be coerced using
- * {@link Number#intValue() intValue}. Strings that can be coerced using
- * {@link Double#valueOf(String)} will be, and then cast to int.
- * <li><a name="lossy">When the requested type is a long, other {@link Number} types will be coerced
- * using {@link Number#longValue() longValue}. Strings that can be coerced using
- * {@link Double#valueOf(String)} will be, and then cast to long. This two-step conversion is lossy
- * for very large values. For example, the string "9223372036854775806" yields the long
- * 9223372036854775807.</a>
- * <li>When the requested type is a String, other non-null values will be coerced using
- * {@link String#valueOf(Object)}. Although null cannot be coerced, the sentinel value
- * {@link JSONObject#NULL} is coerced to the string "null".
+ * <li>When the requested type is a boolean, strings will be coerced using a
+ * case-insensitive comparison to "true" and "false".
+ * <li>When the requested type is a double, other {@link Number} types will
+ * be coerced using {@link Number#doubleValue() doubleValue}. Strings
+ * that can be coerced using {@link Double#valueOf(String)} will be.
+ * <li>When the requested type is an int, other {@link Number} types will
+ * be coerced using {@link Number#intValue() intValue}. Strings
+ * that can be coerced using {@link Double#valueOf(String)} will be,
+ * and then cast to int.
+ * <li><a name="lossy">When the requested type is a long, other {@link Number} types will
+ * be coerced using {@link Number#longValue() longValue}. Strings
+ * that can be coerced using {@link Double#valueOf(String)} will be,
+ * and then cast to long. This two-step conversion is lossy for very
+ * large values. For example, the string "9223372036854775806" yields the
+ * long 9223372036854775807.</a>
+ * <li>When the requested type is a String, other non-null values will be
+ * coerced using {@link String#valueOf(Object)}. Although null cannot be
+ * coerced, the sentinel value {@link JSONObject#NULL} is coerced to the
+ * string "null".
  * </ul>
  *
- * <p>
- * This class can look up both mandatory and optional values:
+ * <p>This class can look up both mandatory and optional values:
  * <ul>
- * <li>Use <code>get<i>Type</i>()</code> to retrieve a mandatory value. This fails with a
- * {@code JSONException} if the requested name has no value or if the value cannot be coerced to the
- * requested type.
- * <li>Use <code>opt<i>Type</i>()</code> to retrieve an optional value. This returns a system- or
- * user-supplied default if the requested name has no value or if the value cannot be coerced to the
- * requested type.
+ * <li>Use <code>get<i>Type</i>()</code> to retrieve a mandatory value. This
+ * fails with a {@code JSONException} if the requested name has no value
+ * or if the value cannot be coerced to the requested type.
+ * <li>Use <code>opt<i>Type</i>()</code> to retrieve an optional value. This
+ * returns a system- or user-supplied default if the requested name has no
+ * value or if the value cannot be coerced to the requested type.
  * </ul>
  *
- * <p>
- * <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, calling
- * {@code put(name, null)} removes the named entry from the object but
- * {@code put(name, JSONObject.NULL)} stores an entry whose value is {@code JSONObject.NULL}.
+ * <p><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, calling {@code put(name, null)} removes the
+ * named entry from the object but {@code put(name, JSONObject.NULL)} stores an
+ * entry whose value is {@code JSONObject.NULL}.
  *
- * <p>
- * Instances of this class are not thread safe. Although this class is nonfinal, it was not designed
- * for inheritance and should not be subclassed. In particular, self-use by overrideable methods is
- * not specified. See <i>Effective Java</i> Item 17, "Design and Document or inheritance or else
+ * <p>Instances of this class are not thread safe. Although this class is
+ * nonfinal, it was not designed for inheritance and should not be subclassed.
+ * In particular, self-use by overrideable 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 JSONObject {
@@ -88,8 +92,8 @@ public class JSONObject {
   public static ThreadLocal<Boolean> cyclicDepChkEnabled = new ThreadLocal();
 
   /**
-   * A sentinel value used to explicitly define a name with no value. Unlike {@code null}, names
-   * with this value:
+   * A sentinel value used to explicitly define a name with no value. Unlike
+   * {@code null}, names with this value:
    * <ul>
    * <li>show up in the {@link #names} array
    * <li>show up in the {@link #keys} iterator
@@ -98,9 +102,9 @@ public class JSONObject {
    * <li>are included in the encoded JSON string.
    * </ul>
    *
-   * <p>
-   * This value violates the general contract of {@link Object#equals} by returning true when
-   * compared to {@code null}. Its {@link #toString} method returns "null".
+   * <p>This value violates the general contract of {@link Object#equals} by
+   * returning true when compared to {@code null}. Its {@link #toString}
+   * method returns "null".
    */
   public static final Object NULL = new Object() {
     @SuppressWarnings("EqualsWhichDoesntCheckParameterClass")
@@ -131,21 +135,21 @@ public class JSONObject {
   }
 
   /**
-   * Creates a new {@code JSONObject} by copying all name/value mappings from the given map.
-   * 
+   * Creates a new {@code JSONObject} by copying all name/value mappings from
+   * the given map.
    * @param copyFrom a map whose keys are of type {@link String} and whose values are of supported
-   *        types.
+   * types.
    * @throws NullPointerException if any of the map's keys are null.
    */
-  /* (accept a raw type for API compatibility) */
+    /* (accept a raw type for API compatibility) */
   public JSONObject(Map copyFrom) {
     this();
     Map<?, ?> contentsTyped = (Map<?, ?>) copyFrom;
     for (Map.Entry<?, ?> entry : contentsTyped.entrySet()) {
-      /*
-       * Deviate from the original by checking that keys are non-null and of the proper type. (We
-       * still defer validating the values).
-       */
+            /*
+             * Deviate from the original by checking that keys are non-null and
+             * of the proper type. (We still defer validating the values).
+             */
       String key = (String) entry.getKey();
       if (key == null) {
         throw new NullPointerException("key == null");
@@ -155,16 +159,16 @@ public class JSONObject {
   }
 
   /**
-   * Creates a new {@code JSONObject} with name/value mappings from the next object in the tokener.
-   * 
+   * Creates a new {@code JSONObject} with name/value mappings from the next
+   * object in the tokener.
    * @param readFrom a tokener whose nextValue() method will yield a {@code JSONObject}.
    * @throws JSONException if the parse fails or doesn't yield a {@code JSONObject}.
    */
   public JSONObject(JSONTokener readFrom) throws JSONException {
-    /*
-     * Getting the parser to populate this could get tricky. Instead, just parse to temporary
-     * JSONObject and then steal the data from that.
-     */
+        /*
+         * Getting the parser to populate this could get tricky. Instead, just
+         * parse to temporary JSONObject and then steal the data from that.
+         */
     Object object = readFrom.nextValue();
     if (object instanceof JSONObject) {
       this.nameValuePairs = ((JSONObject) object).nameValuePairs;
@@ -174,8 +178,8 @@ public class JSONObject {
   }
 
   /**
-   * Creates a new {@code JSONObject} with name/value mappings from the JSON string.
-   * 
+   * Creates a new {@code JSONObject} with name/value mappings from the JSON
+   * string.
    * @param json a JSON-encoded string containing an object.
    * @throws JSONException if the parse fails or doesn't yield a {@code JSONObject}.
    */
@@ -184,9 +188,9 @@ public class JSONObject {
   }
 
   /**
-   * Creates a new {@code JSONObject} by copying mappings for the listed names from the given
-   * object. Names that aren't present in {@code copyFrom} will be skipped.
-   * 
+   * Creates a new {@code JSONObject} by copying mappings for the listed names
+   * from the given object. Names that aren't present in {@code copyFrom} will
+   * be skipped.
    * @param copyFrom The source object.
    * @param names The names of the fields to copy.
    * @throws JSONException On internal errors. Shouldn't happen.
@@ -203,7 +207,6 @@ public class JSONObject {
 
   /**
    * Creates a json object from a bean
-   * 
    * @param bean the bean to create the json object from
    * @throws JSONException If there is an exception while reading the bean
    */
@@ -211,7 +214,7 @@ public class JSONObject {
     this(propertiesAsMap(bean));
   }
 
-  // This is custom properties mapping specific for GEODE
+  //This is custom properties mapping specific for GEODE
   private static Map<String, Object> propertiesAsMap(Object bean) {
     Map<String, Object> props = new TreeMap();
     Class klass = bean.getClass();
@@ -270,7 +273,6 @@ public class JSONObject {
 
   /**
    * Returns the number of name/value mappings in this object.
-   * 
    * @return the length of this.
    */
   public int length() {
@@ -278,9 +280,8 @@ public class JSONObject {
   }
 
   /**
-   * Maps {@code name} to {@code value}, clobbering any existing name/value mapping with the same
-   * name.
-   * 
+   * Maps {@code name} to {@code value}, clobbering any existing name/value
+   * mapping with the same name.
    * @param name The name of the value to insert.
    * @param value The value to insert.
    * @return this object.
@@ -292,12 +293,11 @@ public class JSONObject {
   }
 
   /**
-   * Maps {@code name} to {@code value}, clobbering any existing name/value mapping with the same
-   * name.
-   * 
+   * Maps {@code name} to {@code value}, clobbering any existing name/value
+   * mapping with the same name.
    * @param name The name for the new value.
-   * @param value a finite value. May not be {@link Double#isNaN() NaNs} or
-   *        {@link Double#isInfinite() infinities}.
+   * @param value a finite value. May not be {@link Double#isNaN() NaNs} or {@link
+   * Double#isInfinite() infinities}.
    * @return this object.
    * @throws JSONException if value is NaN or infinite.
    */
@@ -307,9 +307,8 @@ public class JSONObject {
   }
 
   /**
-   * Maps {@code name} to {@code value}, clobbering any existing name/value mapping with the same
-   * name.
-   * 
+   * Maps {@code name} to {@code value}, clobbering any existing name/value
+   * mapping with the same name.
    * @param name The name for the new value.
    * @param value The new value.
    * @return this object.
@@ -321,9 +320,8 @@ public class JSONObject {
   }
 
   /**
-   * Maps {@code name} to {@code value}, clobbering any existing name/value mapping with the same
-   * name.
-   * 
+   * Maps {@code name} to {@code value}, clobbering any existing name/value
+   * mapping with the same name.
    * @param name The name of the new value.
    * @param value The new value to insert.
    * @return this object.
@@ -335,13 +333,13 @@ public class JSONObject {
   }
 
   /**
-   * Maps {@code name} to {@code value}, clobbering any existing name/value mapping with the same
-   * name. If the value is {@code null}, any existing mapping for {@code name} is removed.
-   * 
+   * Maps {@code name} to {@code value}, clobbering any existing name/value
+   * mapping with the same name. If the value is {@code null}, any existing
+   * mapping for {@code name} is removed.
    * @param name The name of the new value.
    * @param value a {@link JSONObject}, {@link JSONArray}, String, Boolean, Integer, Long, Double,
-   *        {@link #NULL}, or {@code null}. May not be {@link Double#isNaN() NaNs} or
-   *        {@link Double#isInfinite() infinities}.
+   * {@link #NULL}, or {@code null}. May not be {@link Double#isNaN() NaNs} or {@link
+   * Double#isInfinite() infinities}.
    * @return this object.
    * @throws JSONException if the value is an invalid double (infinite or NaN).
    */
@@ -373,9 +371,8 @@ public class JSONObject {
   }
 
   /**
-   * Equivalent to {@code put(name, value)} when both parameters are non-null; does nothing
-   * otherwise.
-   * 
+   * Equivalent to {@code put(name, value)} when both parameters are non-null;
+   * does nothing otherwise.
    * @param name The name of the value to insert.
    * @param value The value to insert.
    * @return this object.
@@ -389,21 +386,22 @@ public class JSONObject {
   }
 
   /**
-   * Appends {@code value} to the array already mapped to {@code name}. If this object has no
-   * mapping for {@code name}, this inserts a new mapping. If the mapping exists but its value is
-   * not an array, the existing and new values are inserted in order into a new array which is
-   * itself mapped to {@code name}. In aggregate, this allows values to be added to a mapping one at
-   * a time.
+   * Appends {@code value} to the array already mapped to {@code name}. If
+   * this object has no mapping for {@code name}, this inserts a new mapping.
+   * If the mapping exists but its value is not an array, the existing
+   * and new values are inserted in order into a new array which is itself
+   * mapped to {@code name}. In aggregate, this allows values to be added to a
+   * mapping one at a time.
    *
-   * Note that {@code append(String, Object)} provides better semantics. In particular, the mapping
-   * for {@code name} will <b>always</b> be a {@link JSONArray}. Using {@code accumulate} will
-   * result in either a {@link JSONArray} or a mapping whose type is the type of {@code value}
+   * Note that {@code append(String, Object)} provides better semantics.
+   * In particular, the mapping for {@code name} will <b>always</b> be a
+   * {@link JSONArray}. Using {@code accumulate} will result in either a
+   * {@link JSONArray} or a mapping whose type is the type of {@code value}
    * depending on the number of calls to it.
-   * 
    * @param name The name of the field to change.
    * @param value a {@link JSONObject}, {@link JSONArray}, String, Boolean, Integer, Long, Double,
-   *        {@link #NULL} or null. May not be {@link Double#isNaN() NaNs} or
-   *        {@link Double#isInfinite() infinities}.
+   * {@link #NULL} or null. May not be {@link Double#isNaN() NaNs} or {@link Double#isInfinite()
+   * infinities}.
    * @return this object after mutation.
    * @throws JSONException If the object being added is an invalid number.
    */
@@ -428,15 +426,15 @@ public class JSONObject {
   }
 
   /**
-   * Appends values to the array mapped to {@code name}. A new {@link JSONArray} mapping for
-   * {@code name} will be inserted if no mapping exists. If the existing mapping for {@code name} is
-   * not a {@link JSONArray}, a {@link JSONException} will be thrown.
-   * 
+   * Appends values to the array mapped to {@code name}. A new {@link JSONArray}
+   * mapping for {@code name} will be inserted if no mapping exists. If the existing
+   * mapping for {@code name} is not a {@link JSONArray}, a {@link JSONException}
+   * will be thrown.
    * @param name The name of the array to which the value should be appended.
    * @param value The value to append.
    * @return this object.
    * @throws JSONException if {@code name} is {@code null} or if the mapping for {@code name} is
-   *         non-null and is not a {@link JSONArray}.
+   * non-null and is not a {@link JSONArray}.
    */
   public JSONObject append(String name, Object value) throws JSONException {
     Object current = nameValuePairs.get(checkName(name));
@@ -466,7 +464,6 @@ public class JSONObject {
 
   /**
    * Removes the named mapping if it exists; does nothing otherwise.
-   * 
    * @param name The name of the mapping to remove.
    * @return the value previously mapped by {@code name}, or null if there was no such mapping.
    */
@@ -475,9 +472,8 @@ public class JSONObject {
   }
 
   /**
-   * Returns true if this object has no mapping for {@code name} or if it has a mapping whose value
-   * is {@link #NULL}.
-   * 
+   * Returns true if this object has no mapping for {@code name} or if it has
+   * a mapping whose value is {@link #NULL}.
    * @param name The name of the value to check on.
    * @return true if the field doesn't exist or is null.
    */
@@ -487,8 +483,8 @@ public class JSONObject {
   }
 
   /**
-   * Returns true if this object has a mapping for {@code name}. The mapping may be {@link #NULL}.
-   * 
+   * Returns true if this object has a mapping for {@code name}. The mapping
+   * may be {@link #NULL}.
    * @param name The name of the value to check on.
    * @return true if this object has a field named {@code name}
    */
@@ -498,7 +494,6 @@ public class JSONObject {
 
   /**
    * Returns the value mapped by {@code name}, or throws if no such mapping exists.
-   * 
    * @param name The name of the value to get.
    * @return The value.
    * @throws JSONException if no such mapping exists.
@@ -512,8 +507,8 @@ public class JSONObject {
   }
 
   /**
-   * Returns the value mapped by {@code name}, or null if no such mapping exists.
-   * 
+   * Returns the value mapped by {@code name}, or null if no such mapping
+   * exists.
    * @param name The name of the value to get.
    * @return The value.
    */
@@ -522,9 +517,8 @@ public class JSONObject {
   }
 
   /**
-   * Returns the value mapped by {@code name} if it exists and is a boolean or can be coerced to a
-   * boolean, or throws otherwise.
-   * 
+   * Returns the value mapped by {@code name} if it exists and is a boolean or
+   * can be coerced to a boolean, or throws otherwise.
    * @param name The name of the field we want.
    * @return The selected value if it exists.
    * @throws JSONException if the mapping doesn't exist or cannot be coerced to a boolean.
@@ -539,9 +533,8 @@ public class JSONObject {
   }
 
   /**
-   * Returns the value mapped by {@code name} if it exists and is a boolean or can be coerced to a
-   * boolean, or false otherwise.
-   * 
+   * Returns the value mapped by {@code name} if it exists and is a boolean or
+   * can be coerced to a boolean, or false otherwise.
    * @param name The name of the field we want.
    * @return The selected value if it exists.
    */
@@ -550,9 +543,8 @@ public class JSONObject {
   }
 
   /**
-   * Returns the value mapped by {@code name} if it exists and is a boolean or can be coerced to a
-   * boolean, or {@code fallback} otherwise.
-   * 
+   * Returns the value mapped by {@code name} if it exists and is a boolean or
+   * can be coerced to a boolean, or {@code fallback} otherwise.
    * @param name The name of the field we want.
    * @param fallback The value to return if the field isn't there.
    * @return The selected value or the fallback.
@@ -564,9 +556,8 @@ public class JSONObject {
   }
 
   /**
-   * Returns the value mapped by {@code name} if it exists and is a double or can be coerced to a
-   * double, or throws otherwise.
-   * 
+   * Returns the value mapped by {@code name} if it exists and is a double or
+   * can be coerced to a double, or throws otherwise.
    * @param name The name of the field we want.
    * @return The selected value if it exists.
    * @throws JSONException if the mapping doesn't exist or cannot be coerced to a double.
@@ -581,9 +572,8 @@ public class JSONObject {
   }
 
   /**
-   * Returns the value mapped by {@code name} if it exists and is a double or can be coerced to a
-   * double, or {@code NaN} otherwise.
-   * 
+   * Returns the value mapped by {@code name} if it exists and is a double or
+   * can be coerced to a double, or {@code NaN} otherwise.
    * @param name The name of the field we want.
    * @return The selected value if it exists.
    */
@@ -592,9 +582,8 @@ public class JSONObject {
   }
 
   /**
-   * Returns the value mapped by {@code name} if it exists and is a double or can be coerced to a
-   * double, or {@code fallback} otherwise.
-   * 
+   * Returns the value mapped by {@code name} if it exists and is a double or
+   * can be coerced to a double, or {@code fallback} otherwise.
    * @param name The name of the field we want.
    * @param fallback The value to return if the field isn't there.
    * @return The selected value or the fallback.
@@ -606,9 +595,8 @@ public class JSONObject {
   }
 
   /**
-   * Returns the value mapped by {@code name} if it exists and is an int or can be coerced to an
-   * int, or throws otherwise.
-   * 
+   * Returns the value mapped by {@code name} if it exists and is an int or
+   * can be coerced to an int, or throws otherwise.
    * @param name The name of the field we want.
    * @return The selected value if it exists.
    * @throws JSONException if the mapping doesn't exist or cannot be coerced to an int.
@@ -623,9 +611,8 @@ public class JSONObject {
   }
 
   /**
-   * Returns the value mapped by {@code name} if it exists and is an int or can be coerced to an
-   * int, or 0 otherwise.
-   * 
+   * Returns the value mapped by {@code name} if it exists and is an int or
+   * can be coerced to an int, or 0 otherwise.
    * @param name The name of the field we want.
    * @return The selected value if it exists.
    */
@@ -634,9 +621,8 @@ public class JSONObject {
   }
 
   /**
-   * Returns the value mapped by {@code name} if it exists and is an int or can be coerced to an
-   * int, or {@code fallback} otherwise.
-   * 
+   * Returns the value mapped by {@code name} if it exists and is an int or
+   * can be coerced to an int, or {@code fallback} otherwise.
    * @param name The name of the field we want.
    * @param fallback The value to return if the field isn't there.
    * @return The selected value or the fallback.
@@ -648,11 +634,12 @@ public class JSONObject {
   }
 
   /**
-   * Returns the value mapped by {@code name} if it exists and is a long or can be coerced to a
-   * long, or throws otherwise. Note that JSON represents numbers as doubles,
+   * Returns the value mapped by {@code name} if it exists and is a long or
+   * can be coerced to a long, or throws otherwise.
+   * Note that JSON represents numbers as doubles,
    *
-   * so this is <a href="#lossy">lossy</a>; use strings to transfer numbers via JSON without loss.
-   * 
+   * so this is <a href="#lossy">lossy</a>; use strings to transfer numbers
+   * via JSON without loss.
    * @param name The name of the field that we want.
    * @return The value of the field.
    * @throws JSONException if the mapping doesn't exist or cannot be coerced to a long.
@@ -667,10 +654,9 @@ public class JSONObject {
   }
 
   /**
-   * Returns the value mapped by {@code name} if it exists and is a long or can be coerced to a
-   * long, or 0 otherwise. Note that JSON represents numbers as doubles, so this is
-   * <a href="#lossy">lossy</a>; use strings to transfer numbers via JSON.
-   * 
+   * Returns the value mapped by {@code name} if it exists and is a long or
+   * can be coerced to a long, or 0 otherwise. Note that JSON represents numbers as doubles,
+   * so this is <a href="#lossy">lossy</a>; use strings to transfer numbers via JSON.
    * @param name The name of the field we want.
    * @return The selected value.
    */
@@ -679,10 +665,10 @@ public class JSONObject {
   }
 
   /**
-   * Returns the value mapped by {@code name} if it exists and is a long or can be coerced to a
-   * long, or {@code fallback} otherwise. Note that JSON represents numbers as doubles, so this is
-   * <a href="#lossy">lossy</a>; use strings to transfer numbers via JSON.
-   * 
+   * Returns the value mapped by {@code name} if it exists and is a long or
+   * can be coerced to a long, or {@code fallback} otherwise. Note that JSON represents
+   * numbers as doubles, so this is <a href="#lossy">lossy</a>; use strings to transfer
+   * numbers via JSON.
    * @param name The name of the field we want.
    * @param fallback The value to return if the field isn't there.
    * @return The selected value or the fallback.
@@ -694,9 +680,8 @@ public class JSONObject {
   }
 
   /**
-   * Returns the value mapped by {@code name} if it exists, coercing it if necessary, or throws if
-   * no such mapping exists.
-   * 
+   * Returns the value mapped by {@code name} if it exists, coercing it if
+   * necessary, or throws if no such mapping exists.
    * @param name The name of the field we want.
    * @return The value of the field.
    * @throws JSONException if no such mapping exists.
@@ -711,9 +696,8 @@ public class JSONObject {
   }
 
   /**
-   * Returns the value mapped by {@code name} if it exists, coercing it if necessary, or the empty
-   * string if no such mapping exists.
-   * 
+   * Returns the value mapped by {@code name} if it exists, coercing it if
+   * necessary, or the empty string if no such mapping exists.
    * @param name The name of the field we want.
    * @return The value of the field.
    */
@@ -722,9 +706,8 @@ public class JSONObject {
   }
 
   /**
-   * Returns the value mapped by {@code name} if it exists, coercing it if necessary, or
-   * {@code fallback} if no such mapping exists.
-   * 
+   * Returns the value mapped by {@code name} if it exists, coercing it if
+   * necessary, or {@code fallback} if no such mapping exists.
    * @param name The name of the field that we want.
    * @param fallback The value to return if the field doesn't exist.
    * @return The value of the field or fallback.
@@ -738,7 +721,6 @@ public class JSONObject {
   /**
    * Returns the value mapped by {@code name} if it exists and is a {@code
    * JSONArray}, or throws otherwise.
-   * 
    * @param name The field we want to get.
    * @return The value of the field (if it is a JSONArray.
    * @throws JSONException if the mapping doesn't exist or is not a {@code JSONArray}.
@@ -755,7 +737,6 @@ public class JSONObject {
   /**
    * Returns the value mapped by {@code name} if it exists and is a {@code
    * JSONArray}, or null otherwise.
-   * 
    * @param name The name of the field we want.
    * @return The value of the specified field (assuming it is a JSNOArray
    */
@@ -767,7 +748,6 @@ public class JSONObject {
   /**
    * Returns the value mapped by {@code name} if it exists and is a {@code
    * JSONObject}, or throws otherwise.
-   * 
    * @param name The name of the field that we want.
    * @return a specified field value (if it is a JSONObject)
    * @throws JSONException if the mapping doesn't exist or is not a {@code JSONObject}.
@@ -784,7 +764,6 @@ public class JSONObject {
   /**
    * Returns the value mapped by {@code name} if it exists and is a {@code
    * JSONObject}, or null otherwise.
-   * 
    * @param name The name of the value we want.
    * @return The specified value.
    */
@@ -794,9 +773,9 @@ public class JSONObject {
   }
 
   /**
-   * Returns an array with the values corresponding to {@code names}. The array contains null for
-   * names that aren't mapped. This method returns null if {@code names} is either null or empty.
-   * 
+   * Returns an array with the values corresponding to {@code names}. The
+   * array contains null for names that aren't mapped. This method returns
+   * null if {@code names} is either null or empty.
    * @param names The names of the fields that we want the values for.
    * @return The selected values.
    * @throws JSONException On internal errors. Shouldn't happen.
@@ -818,11 +797,11 @@ public class JSONObject {
   }
 
   /**
-   * Returns an iterator of the {@code String} names in this object. The returned iterator supports
-   * {@link Iterator#remove() remove}, which will remove the corresponding mapping from this object.
-   * If this object is modified after the iterator is returned, the iterator's behavior is
+   * Returns an iterator of the {@code String} names in this object. The
+   * returned iterator supports {@link Iterator#remove() remove}, which will
+   * remove the corresponding mapping from this object. If this object is
+   * modified after the iterator is returned, the iterator's behavior is
    * undefined. The order of the keys is undefined.
-   * 
    * @return an iterator over the keys.
    */
   public Iterator<String> keys() {
@@ -830,12 +809,12 @@ public class JSONObject {
   }
 
   /**
-   * Returns the set of {@code String} names in this object. The returned set is a view of the keys
-   * in this object. {@link Set#remove(Object)} will remove the corresponding mapping from this
-   * object and set iterator behaviour is undefined if this object is modified after it is returned.
+   * Returns the set of {@code String} names in this object. The returned set
+   * is a view of the keys in this object. {@link Set#remove(Object)} will remove
+   * the corresponding mapping from this object and set iterator behaviour
+   * is undefined if this object is modified after it is returned.
    *
    * See {@link #keys()}.
-   * 
    * @return The names in this object.
    */
   public Set<String> keySet() {
@@ -843,22 +822,19 @@ public class JSONObject {
   }
 
   /**
-   * Returns an array containing the string names in this object. This method returns null if this
-   * object contains no mappings.
-   * 
+   * Returns an array containing the string names in this object. This method
+   * returns null if this object contains no mappings.
    * @return the names.
    */
   public JSONArray names() {
-    return nameValuePairs.isEmpty() ? null
+    return nameValuePairs.isEmpty()
+        ? null
         : new JSONArray(new ArrayList<String>(nameValuePairs.keySet()));
   }
 
   /**
    * Encodes this object as a compact JSON string, such as:
-   * 
-   * <pre>
-   * {"query":"Pizza","locations":[94043,90210]}
-   * </pre>
+   * <pre>{"query":"Pizza","locations":[94043,90210]}</pre>
    */
   @Override
   public String toString() {
@@ -872,8 +848,8 @@ public class JSONObject {
   }
 
   /**
-   * Encodes this object as a human readable JSON string for debugging, such as:
-   * 
+   * Encodes this object as a human readable JSON string for debugging, such
+   * as:
    * <pre>
    * {
    *     "query": "Pizza",
@@ -881,9 +857,7 @@ public class JSONObject {
    *         94043,
    *         90210
    *     ]
-   * }
-   * </pre>
-   * 
+   * }</pre>
    * @param indentSpaces the number of spaces to indent for each level of nesting.
    * @return The string containing the pretty form of this.
    * @throws JSONException On internal errors. Shouldn't happen.
@@ -904,9 +878,8 @@ public class JSONObject {
 
   /**
    * Encodes the number as a JSON string.
-   * 
-   * @param number a finite value. May not be {@link Double#isNaN() NaNs} or
-   *        {@link Double#isInfinite() infinities}.
+   * @param number a finite value. May not be {@link Double#isNaN() NaNs} or {@link
+   * Double#isInfinite() infinities}.
    * @return The encoded number in string form.
    * @throws JSONException On internal errors. Shouldn't happen.
    */
@@ -932,9 +905,8 @@ public class JSONObject {
   }
 
   /**
-   * Encodes {@code data} as a JSON string. This applies quotes and any necessary character
-   * escaping.
-   * 
+   * Encodes {@code data} as a JSON string. This applies quotes and any
+   * necessary character escaping.
    * @param data the string to encode. Null will be interpreted as an empty string.
    * @return the quoted string.
    */
@@ -956,8 +928,7 @@ public class JSONObject {
   /**
    * Wraps the given object if necessary.
    *
-   * <p>
-   * If the object is null or , returns {@link #NULL}. If the object is a {@code JSONArray} or
+   * <p>If the object is null or , returns {@link #NULL}. If the object is a {@code JSONArray} or
    * {@code JSONObject}, no wrapping is necessary. If the object is {@code NULL}, no wrapping is
    * necessary. If the object is an array or {@code Collection}, returns an equivalent {@code
    * JSONArray}. If the object is a {@code Map}, returns an equivalent {@code JSONObject}. If the
@@ -965,7 +936,6 @@ public class JSONObject {
    * a {@code java} package, returns the result of {@code toString}. If the object is some other
    * kind of object then it is assumed to be a bean and is converted to a JSONObject. If wrapping
    * fails, returns null.
-   * 
    * @param o The object to wrap.
    * @return The wrapped (if necessary) form of the object {$code o}
    */
@@ -988,28 +958,34 @@ public class JSONObject {
       if (o instanceof Map) {
         return new JSONObject((Map) o);
       }
-      if (o instanceof Boolean || o instanceof Byte || o instanceof Character || o instanceof Double
-          || o instanceof Float || o instanceof Integer || o instanceof Long || o instanceof Short
-          || o instanceof String) {
+      if (o instanceof Boolean ||
+          o instanceof Byte ||
+          o instanceof Character ||
+          o instanceof Double ||
+          o instanceof Float ||
+          o instanceof Integer ||
+          o instanceof Long ||
+          o instanceof Short ||
+          o instanceof String) {
         return o;
       }
       // GEODE-2142: Added check to ignore GemFireCacheImpl
-      // if (o.getClass().getPackage().getName().startsWith("java.") || o instanceof Enum<?>) {
-      // return o.toString();
-      // }
+//      if (o.getClass().getPackage().getName().startsWith("java.") || o instanceof Enum<?>) {
+//        return o.toString();
+//      }
       Package objectPackage = o.getClass().getPackage();
       String objectPackageName = objectPackage != null ? objectPackage.getName() : "";
-      if (objectPackageName.startsWith("java.") || objectPackageName.startsWith("javax.")
-          || o instanceof Enum<?> || o.getClass().getClassLoader() == null
+      if (objectPackageName.startsWith("java.") || objectPackageName.startsWith("javax.") || o instanceof Enum<?>
+          || o.getClass().getClassLoader() == null
           || o.getClass().getName().contains("GemFireCacheImpl")) {
         return o.toString();
       }
-      // if (o.getClass().getPackage().getName().startsWith("java.") || o instanceof Enum<?> ||
-      // || objectPackageName.startsWith("javax.")
-      // || o.getClass().getClassLoader() == null
-      // o.getClass().getName().contains("GemFireCacheImpl")) {
-      // return o.toString();
-      // }
+//      if (o.getClass().getPackage().getName().startsWith("java.") || o instanceof Enum<?> ||
+//          || objectPackageName.startsWith("javax.")
+//          || o.getClass().getClassLoader() == null
+//          o.getClass().getName().contains("GemFireCacheImpl")) {
+//        return o.toString();
+//      }
       // GEODE-2142: Added the cyclicalDepCheck
       if (cyclicDepChkEnabled.get() != null && cyclicDependencySet.get() != null) {
         if (cyclicDepChkEnabled.get() && cyclicDependencySet.get().contains(o)) {
@@ -1026,4 +1002,4 @@ public class JSONObject {
     }
     return null;
   }
-}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/geode/blob/1253d780/geode-json/src/main/java/org/json/JSONString.java
----------------------------------------------------------------------
diff --git a/geode-json/src/main/java/org/json/JSONString.java b/geode-json/src/main/java/org/json/JSONString.java
index 4a09d89..34815a8 100755
--- a/geode-json/src/main/java/org/json/JSONString.java
+++ b/geode-json/src/main/java/org/json/JSONString.java
@@ -1,17 +1,18 @@
 package org.json;
-
 /**
- * The <code>JSONString</code> interface allows a <code>toJSONString()</code> method so that a class
- * can change the behavior of <code>JSONObject.toString()</code>, <code>JSONArray.toString()</code>,
- * and <code>JSONWriter.value(</code>Object<code>)</code>. The <code>toJSONString</code> method will
- * be used instead of the default behavior of using the Object's <code>toString()</code> method and
- * quoting the result.
+ * The <code>JSONString</code> interface allows a <code>toJSONString()</code> 
+ * method so that a class can change the behavior of 
+ * <code>JSONObject.toString()</code>, <code>JSONArray.toString()</code>,
+ * and <code>JSONWriter.value(</code>Object<code>)</code>. The 
+ * <code>toJSONString</code> method will be used instead of the default behavior 
+ * of using the Object's <code>toString()</code> method and quoting the result.
  */
 public interface JSONString {
   /**
-   * The <code>toJSONString</code> method allows a class to produce its own JSON serialization.
+   * The <code>toJSONString</code> method allows a class to produce its own JSON 
+   * serialization. 
    * 
    * @return A strictly syntactically correct JSON text.
    */
   public String toJSONString();
-}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/geode/blob/1253d780/geode-json/src/main/java/org/json/JSONStringer.java
----------------------------------------------------------------------
diff --git a/geode-json/src/main/java/org/json/JSONStringer.java b/geode-json/src/main/java/org/json/JSONStringer.java
index 43224a5..db1121e 100755
--- a/geode-json/src/main/java/org/json/JSONStringer.java
+++ b/geode-json/src/main/java/org/json/JSONStringer.java
@@ -1,15 +1,17 @@
 /*
  * 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
+ * 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
+ *      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.
+ * 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.json;
@@ -21,439 +23,448 @@ import java.util.List;
 // Note: this class was written without inspecting the non-free org.json sourcecode.
 
 /**
- * Implements {@link JSONObject#toString} and {@link JSONArray#toString}. Most application
- * developers should use those methods directly and disregard this API. For example:
- * 
- * <pre>
+ * Implements {@link JSONObject#toString} and {@link JSONArray#toString}. Most
+ * application developers should use those methods directly and disregard this
+ * API. For example:<pre>
  * JSONObject object = ...
- * String json = object.toString();
- * </pre>
+ * String json = object.toString();</pre>
  *
- * <p>
- * Stringers only encode well-formed JSON strings. In particular:
+ * <p>Stringers only encode well-formed JSON strings. In particular:
  * <ul>
  * <li>The stringer must have exactly one top-level array or object.
- * <li>Lexical scopes must be balanced: every call to {@link #array} must have a matching call to
- * {@link #endArray} and every call to {@link #object} must have a matching call to
- * {@link #endObject}.
+ * <li>Lexical scopes must be balanced: every call to {@link #array} must
+ * have a matching call to {@link #endArray} and every call to {@link
+ * #object} must have a matching call to {@link #endObject}.
  * <li>Arrays may not contain keys (property names).
  * <li>Objects must alternate keys (property names) and values.
- * <li>Values are inserted with either literal {@link #value(Object) value} calls, or by nesting
- * arrays or objects.
+ * <li>Values are inserted with either literal {@link #value(Object) value}
+ * calls, or by nesting arrays or objects.
  * </ul>
- * Calls that would result in a malformed JSON string will fail with a {@link JSONException}.
+ * Calls that would result in a malformed JSON string will fail with a
+ * {@link JSONException}.
  *
- * <p>
- * This class provides no facility for pretty-printing (ie. indenting) output. To encode indented
- * output, use {@link JSONObject#toString(int)} or {@link JSONArray#toString(int)}.
+ * <p>This class provides no facility for pretty-printing (ie. indenting)
+ * output. To encode indented output, use {@link JSONObject#toString(int)} or
+ * {@link JSONArray#toString(int)}.
  *
- * <p>
- * Some implementations of the API support at most 20 levels of nesting. Attempts to create more
- * than 20 levels of nesting may fail with a {@link JSONException}.
+ * <p>Some implementations of the API support at most 20 levels of nesting.
+ * Attempts to create more than 20 levels of nesting may fail with a {@link
+ * JSONException}.
  *
- * <p>
- * Each stringer may be used to encode a single top level value. Instances of this class are not
- * thread safe. Although this class is nonfinal, it was not designed for inheritance and should not
- * be subclassed. In particular, self-use by overrideable methods is not specified. See <i>Effective
- * Java</i> Item 17, "Design and Document or inheritance or else prohibit it" for further
+ * <p>Each stringer may be used to encode a single top level value. Instances of
+ * this class are not thread safe. Although this class is nonfinal, it was not
+ * designed for inheritance and should not be subclassed. In particular,
+ * self-use by overrideable 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 JSONStringer {
 
-  /**
-   * The output data, containing at most one top-level array or object.
-   */
-  final StringBuilder out = new StringBuilder();
-
-  /**
-   * Lexical scoping elements within this stringer, necessary to insert the appropriate separator
-   * characters (ie. commas and colons) and to detect nesting errors.
-   */
-  enum Scope {
-
     /**
-     * An array with no elements requires no separators or newlines before it is closed.
+     * The output data, containing at most one top-level array or object.
      */
-    EMPTY_ARRAY,
+    final StringBuilder out = new StringBuilder();
 
     /**
-     * A array with at least one value requires a comma and newline before the next element.
+     * Lexical scoping elements within this stringer, necessary to insert the
+     * appropriate separator characters (ie. commas and colons) and to detect
+     * nesting errors.
      */
-    NONEMPTY_ARRAY,
+    enum Scope {
+
+        /**
+         * An array with no elements requires no separators or newlines before
+         * it is closed.
+         */
+        EMPTY_ARRAY,
+
+        /**
+         * A array with at least one value requires a comma and newline before
+         * the next element.
+         */
+        NONEMPTY_ARRAY,
+
+        /**
+         * An object with no keys or values requires no separators or newlines
+         * before it is closed.
+         */
+        EMPTY_OBJECT,
+
+        /**
+         * An object whose most recent element is a key. The next element must
+         * be a value.
+         */
+        DANGLING_KEY,
+
+        /**
+         * An object with at least one name/value pair requires a comma and
+         * newline before the next element.
+         */
+        NONEMPTY_OBJECT,
+
+        /**
+         * A special bracketless array needed by JSONStringer.join() and
+         * JSONObject.quote() only. Not used for JSON encoding.
+         */
+        NULL,
+    }
 
     /**
-     * An object with no keys or values requires no separators or newlines before it is closed.
+     * Unlike the original implementation, this stack isn't limited to 20
+     * levels of nesting.
      */
-    EMPTY_OBJECT,
+    private final List<Scope> stack = new ArrayList<Scope>();
 
     /**
-     * An object whose most recent element is a key. The next element must be a value.
+     * A string containing a full set of spaces for a single level of
+     * indentation, or null for no pretty printing.
      */
-    DANGLING_KEY,
+    private final String indent;
+
+    public JSONStringer() {
+        indent = null;
+    }
+
+    JSONStringer(int indentSpaces) {
+        char[] indentChars = new char[indentSpaces];
+        Arrays.fill(indentChars, ' ');
+        indent = new String(indentChars);
+    }
 
     /**
-     * An object with at least one name/value pair requires a comma and newline before the next
-     * element.
+     * Begins encoding a new array. Each call to this method must be paired with
+     * a call to {@link #endArray}.
+     *
+     * @return this stringer.
+     * @throws JSONException On internal errors. Shouldn't happen.
      */
-    NONEMPTY_OBJECT,
+    public JSONStringer array() throws JSONException {
+        return open(Scope.EMPTY_ARRAY, "[");
+    }
 
     /**
-     * A special bracketless array needed by JSONStringer.join() and JSONObject.quote() only. Not
-     * used for JSON encoding.
+     * Ends encoding the current array.
+     *
+     * @return this stringer.
+     * @throws JSONException On internal errors. Shouldn't happen.
      */
-    NULL,
-  }
-
-  /**
-   * Unlike the original implementation, this stack isn't limited to 20 levels of nesting.
-   */
-  private final List<Scope> stack = new ArrayList<Scope>();
-
-  /**
-   * A string containing a full set of spaces for a single level of indentation, or null for no
-   * pretty printing.
-   */
-  private final String indent;
-
-  public JSONStringer() {
-    indent = null;
-  }
-
-  JSONStringer(int indentSpaces) {
-    char[] indentChars = new char[indentSpaces];
-    Arrays.fill(indentChars, ' ');
-    indent = new String(indentChars);
-  }
-
-  /**
-   * Begins encoding a new array. Each call to this method must be paired with a call to
-   * {@link #endArray}.
-   *
-   * @return this stringer.
-   * @throws JSONException On internal errors. Shouldn't happen.
-   */
-  public JSONStringer array() throws JSONException {
-    return open(Scope.EMPTY_ARRAY, "[");
-  }
-
-  /**
-   * Ends encoding the current array.
-   *
-   * @return this stringer.
-   * @throws JSONException On internal errors. Shouldn't happen.
-   */
-  public JSONStringer endArray() throws JSONException {
-    return close(Scope.EMPTY_ARRAY, Scope.NONEMPTY_ARRAY, "]");
-  }
-
-  /**
-   * Begins encoding a new object. Each call to this method must be paired with a call to
-   * {@link #endObject}.
-   *
-   * @return this stringer.
-   * @throws JSONException On internal errors. Shouldn't happen.
-   */
-  public JSONStringer object() throws JSONException {
-    return open(Scope.EMPTY_OBJECT, "{");
-  }
-
-  /**
-   * Ends encoding the current object.
-   *
-   * @return this stringer.
-   * @throws JSONException On internal errors. Shouldn't happen.
-   */
-  public JSONStringer endObject() throws JSONException {
-    return close(Scope.EMPTY_OBJECT, Scope.NONEMPTY_OBJECT, "}");
-  }
-
-  /**
-   * Enters a new scope by appending any necessary whitespace and the given bracket.
-   */
-  JSONStringer open(Scope empty, String openBracket) throws JSONException {
-    if (stack.isEmpty() && out.length() > 0) {
-      throw new JSONException("Nesting problem: multiple top-level roots");
-    }
-    beforeValue();
-    stack.add(empty);
-    out.append(openBracket);
-    return this;
-  }
-
-  /**
-   * Closes the current scope by appending any necessary whitespace and the given bracket.
-   */
-  JSONStringer close(Scope empty, Scope nonempty, String closeBracket) throws JSONException {
-    Scope context = peek();
-    if (context != nonempty && context != empty) {
-      throw new JSONException("Nesting problem");
+    public JSONStringer endArray() throws JSONException {
+        return close(Scope.EMPTY_ARRAY, Scope.NONEMPTY_ARRAY, "]");
     }
 
-    stack.remove(stack.size() - 1);
-    if (context == nonempty) {
-      newline();
-    }
-    out.append(closeBracket);
-    return this;
-  }
-
-  /**
-   * Returns the value on the top of the stack.
-   */
-  private Scope peek() throws JSONException {
-    if (stack.isEmpty()) {
-      throw new JSONException("Nesting problem");
-    }
-    return stack.get(stack.size() - 1);
-  }
-
-  /**
-   * Replace the value on the top of the stack with the given value.
-   */
-  private void replaceTop(Scope topOfStack) {
-    stack.set(stack.size() - 1, topOfStack);
-  }
-
-  /**
-   * Encodes {@code value}.
-   *
-   * @param value a {@link JSONObject}, {@link JSONArray}, String, Boolean, Integer, Long, Double or
-   *        null. May not be {@link Double#isNaN() NaNs} or {@link Double#isInfinite() infinities}.
-   * @return this stringer.
-   * @throws JSONException On internal errors. Shouldn't happen.
-   */
-  public JSONStringer value(Object value) throws JSONException {
-    if (stack.isEmpty()) {
-      throw new JSONException("Nesting problem");
+    /**
+     * Begins encoding a new object. Each call to this method must be paired
+     * with a call to {@link #endObject}.
+     *
+     * @return this stringer.
+     * @throws JSONException On internal errors. Shouldn't happen.
+     */
+    public JSONStringer object() throws JSONException {
+        return open(Scope.EMPTY_OBJECT, "{");
     }
 
-    if (value instanceof JSONArray) {
-      ((JSONArray) value).writeTo(this);
-      return this;
+    /**
+     * Ends encoding the current object.
+     *
+     * @return this stringer.
+     * @throws JSONException On internal errors. Shouldn't happen.
+     */
+    public JSONStringer endObject() throws JSONException {
+        return close(Scope.EMPTY_OBJECT, Scope.NONEMPTY_OBJECT, "}");
+    }
 
-    } else if (value instanceof JSONObject) {
-      ((JSONObject) value).writeTo(this);
-      return this;
+    /**
+     * Enters a new scope by appending any necessary whitespace and the given
+     * bracket.
+     */
+    JSONStringer open(Scope empty, String openBracket) throws JSONException {
+        if (stack.isEmpty() && out.length() > 0) {
+            throw new JSONException("Nesting problem: multiple top-level roots");
+        }
+        beforeValue();
+        stack.add(empty);
+        out.append(openBracket);
+        return this;
     }
 
-    beforeValue();
+    /**
+     * Closes the current scope by appending any necessary whitespace and the
+     * given bracket.
+     */
+    JSONStringer close(Scope empty, Scope nonempty, String closeBracket) throws JSONException {
+        Scope context = peek();
+        if (context != nonempty && context != empty) {
+            throw new JSONException("Nesting problem");
+        }
+
+        stack.remove(stack.size() - 1);
+        if (context == nonempty) {
+            newline();
+        }
+        out.append(closeBracket);
+        return this;
+    }
 
-    if (value instanceof JSONString) {
-      out.append(((JSONString) value).toJSONString());
-      return this;
+    /**
+     * Returns the value on the top of the stack.
+     */
+    private Scope peek() throws JSONException {
+        if (stack.isEmpty()) {
+            throw new JSONException("Nesting problem");
+        }
+        return stack.get(stack.size() - 1);
     }
 
-    if (value == null || value instanceof Boolean || value == JSONObject.NULL) {
-      out.append(value);
+    /**
+     * Replace the value on the top of the stack with the given value.
+     */
+    private void replaceTop(Scope topOfStack) {
+        stack.set(stack.size() - 1, topOfStack);
+    }
 
-    } else if (value instanceof Number) {
-      out.append(JSONObject.numberToString((Number) value));
+    /**
+     * Encodes {@code value}.
+     *
+     * @param value a {@link JSONObject}, {@link JSONArray}, String, Boolean,
+     *              Integer, Long, Double or null. May not be {@link Double#isNaN() NaNs}
+     *              or {@link Double#isInfinite() infinities}.
+     * @return this stringer.
+     * @throws JSONException On internal errors. Shouldn't happen.
+     */
+    public JSONStringer value(Object value) throws JSONException {
+        if (stack.isEmpty()) {
+            throw new JSONException("Nesting problem");
+        }
+
+        if (value instanceof JSONArray) {
+            ((JSONArray) value).writeTo(this);
+            return this;
+
+        } else if (value instanceof JSONObject) {
+            ((JSONObject) value).writeTo(this);
+            return this;
+        }
+
+        beforeValue();
+
+        if (value instanceof JSONString) {
+          out.append(((JSONString) value).toJSONString());
+          return this;
+        }
+
+        if (value == null
+              || value instanceof Boolean
+              || value == JSONObject.NULL) {
+            out.append(value);
+
+        } else if (value instanceof Number) {
+            out.append(JSONObject.numberToString((Number) value));
+
+        } else {
+            // Hack to make it possible that the value is not surrounded by quotes. (Used for JavaScript function calls)
+            // Example: { "name": "testkey", "value": window.myfunction() }
+            if (value.getClass().getSimpleName().contains("JSONFunction")) {
+                // note that no escaping of quotes (or anything else) is done in this case.
+                // that is fine because the only way to get to this point is to
+                // explicitly put a special kind of object into the JSON data structure.
+                out.append(value);
+            } else {
+                string(value.toString());
+            }
+        }
+
+        return this;
+    }
 
-    } else {
-      // Hack to make it possible that the value is not surrounded by quotes. (Used for JavaScript
-      // function calls)
-      // Example: { "name": "testkey", "value": window.myfunction() }
-      if (value.getClass().getSimpleName().contains("JSONFunction")) {
-        // note that no escaping of quotes (or anything else) is done in this case.
-        // that is fine because the only way to get to this point is to
-        // explicitly put a special kind of object into the JSON data structure.
+    /**
+     * Encodes {@code value} to this stringer.
+     *
+     * @param value The value to encode.
+     * @return this stringer.
+     * @throws JSONException On internal errors. Shouldn't happen.
+     */
+    public JSONStringer value(boolean value) throws JSONException {
+        if (stack.isEmpty()) {
+            throw new JSONException("Nesting problem");
+        }
+        beforeValue();
         out.append(value);
-      } else {
-        string(value.toString());
-      }
+        return this;
     }
 
-    return this;
-  }
-
-  /**
-   * Encodes {@code value} to this stringer.
-   *
-   * @param value The value to encode.
-   * @return this stringer.
-   * @throws JSONException On internal errors. Shouldn't happen.
-   */
-  public JSONStringer value(boolean value) throws JSONException {
-    if (stack.isEmpty()) {
-      throw new JSONException("Nesting problem");
-    }
-    beforeValue();
-    out.append(value);
-    return this;
-  }
-
-  /**
-   * Encodes {@code value} to this stringer.
-   *
-   * @param value a finite value. May not be {@link Double#isNaN() NaNs} or
-   *        {@link Double#isInfinite() infinities}.
-   * @return this stringer.
-   * @throws JSONException On internal errors. Shouldn't happen.
-   */
-  public JSONStringer value(double value) throws JSONException {
-    if (stack.isEmpty()) {
-      throw new JSONException("Nesting problem");
-    }
-    beforeValue();
-    out.append(JSONObject.numberToString(value));
-    return this;
-  }
-
-  /**
-   * Encodes {@code value} to this stringer.
-   *
-   * @param value The value to encode.
-   * @return this stringer.
-   * @throws JSONException If we have an internal error. Shouldn't happen.
-   */
-  public JSONStringer value(long value) throws JSONException {
-    if (stack.isEmpty()) {
-      throw new JSONException("Nesting problem");
+    /**
+     * Encodes {@code value} to this stringer.
+     *
+     * @param value a finite value. May not be {@link Double#isNaN() NaNs} or
+     *              {@link Double#isInfinite() infinities}.
+     * @return this stringer.
+     * @throws JSONException On internal errors. Shouldn't happen.
+     */
+    public JSONStringer value(double value) throws JSONException {
+        if (stack.isEmpty()) {
+            throw new JSONException("Nesting problem");
+        }
+        beforeValue();
+        out.append(JSONObject.numberToString(value));
+        return this;
     }
-    beforeValue();
-    out.append(value);
-    return this;
-  }
-
-  private void string(String value) {
-    out.append("\"");
-    char currentChar = 0;
-
-    for (int i = 0, length = value.length(); i < length; i++) {
-      char previousChar = currentChar;
-      currentChar = value.charAt(i);
-
-      /*
-       * From RFC 4627, "All Unicode characters may be placed within the quotation marks except for
-       * the characters that must be escaped: quotation mark, reverse solidus, and the control
-       * characters (U+0000 through U+001F)."
-       */
-      switch (currentChar) {
-        case '"':
-        case '\\':
-          out.append('\\').append(currentChar);
-          break;
-
-        case '/':
-          // it makes life easier for HTML embedding of javascript if we escape </ sequences
-          if (previousChar == '<') {
-            out.append('\\');
-          }
-          out.append(currentChar);
-          break;
-
-        case '\t':
-          out.append("\\t");
-          break;
-
-        case '\b':
-          out.append("\\b");
-          break;
-
-        case '\n':
-          out.append("\\n");
-          break;
-
-        case '\r':
-          out.append("\\r");
-          break;
-
-        case '\f':
-          out.append("\\f");
-          break;
-
-        default:
-          if (currentChar <= 0x1F) {
-            out.append(String.format("\\u%04x", (int) currentChar));
-          } else {
-            out.append(currentChar);
-          }
-          break;
-      }
 
+    /**
+     * Encodes {@code value} to this stringer.
+     *
+     * @param value The value to encode.
+     * @return this stringer.
+     * @throws JSONException If we have an internal error. Shouldn't happen.
+     */
+    public JSONStringer value(long value) throws JSONException {
+        if (stack.isEmpty()) {
+            throw new JSONException("Nesting problem");
+        }
+        beforeValue();
+        out.append(value);
+        return this;
     }
-    out.append("\"");
-  }
 
-  private void newline() {
-    if (indent == null) {
-      return;
+    private void string(String value) {
+        out.append("\"");
+        char currentChar = 0;
+
+        for (int i = 0, length = value.length(); i < length; i++) {
+            char previousChar = currentChar;
+            currentChar = value.charAt(i);
+
+            /*
+             * From RFC 4627, "All Unicode characters may be placed within the
+             * quotation marks except for the characters that must be escaped:
+             * quotation mark, reverse solidus, and the control characters
+             * (U+0000 through U+001F)."
+             */
+            switch (currentChar) {
+                case '"':
+                case '\\':
+                    out.append('\\').append(currentChar);
+                    break;
+
+                case '/':
+                    // it makes life easier for HTML embedding of javascript if we escape </ sequences
+                    if (previousChar == '<') {
+                        out.append('\\');
+                    }
+                    out.append(currentChar);
+                    break;
+
+                case '\t':
+                    out.append("\\t");
+                    break;
+
+                case '\b':
+                    out.append("\\b");
+                    break;
+
+                case '\n':
+                    out.append("\\n");
+                    break;
+
+                case '\r':
+                    out.append("\\r");
+                    break;
+
+                case '\f':
+                    out.append("\\f");
+                    break;
+
+                default:
+                    if (currentChar <= 0x1F) {
+                        out.append(String.format("\\u%04x", (int) currentChar));
+                    } else {
+                        out.append(currentChar);
+                    }
+                    break;
+            }
+
+        }
+        out.append("\"");
     }
 
-    out.append("\n");
-    for (int i = 0; i < stack.size(); i++) {
-      out.append(indent);
+    private void newline() {
+        if (indent == null) {
+            return;
+        }
+
+        out.append("\n");
+        for (int i = 0; i < stack.size(); i++) {
+            out.append(indent);
+        }
     }
-  }
-
-  /**
-   * Encodes the key (property name) to this stringer.
-   *
-   * @param name the name of the forthcoming value. May not be null.
-   * @return this stringer.
-   * @throws JSONException on internal errors, shouldn't happen.
-   */
-  public JSONStringer key(String name) throws JSONException {
-    if (name == null) {
-      throw new JSONException("Names must be non-null");
+
+    /**
+     * Encodes the key (property name) to this stringer.
+     *
+     * @param name the name of the forthcoming value. May not be null.
+     * @return this stringer.
+     * @throws JSONException on internal errors, shouldn't happen.
+     */
+    public JSONStringer key(String name) throws JSONException {
+        if (name == null) {
+            throw new JSONException("Names must be non-null");
+        }
+        beforeKey();
+        string(name);
+        return this;
     }
-    beforeKey();
-    string(name);
-    return this;
-  }
-
-  /**
-   * Inserts any necessary separators and whitespace before a name. Also adjusts the stack to expect
-   * the key's value.
-   */
-  private void beforeKey() throws JSONException {
-    Scope context = peek();
-    if (context == Scope.NONEMPTY_OBJECT) { // first in object
-      out.append(',');
-    } else if (context != Scope.EMPTY_OBJECT) { // not in an object!
-      throw new JSONException("Nesting problem");
+
+    /**
+     * Inserts any necessary separators and whitespace before a name. Also
+     * adjusts the stack to expect the key's value.
+     */
+    private void beforeKey() throws JSONException {
+        Scope context = peek();
+        if (context == Scope.NONEMPTY_OBJECT) { // first in object
+            out.append(',');
+        } else if (context != Scope.EMPTY_OBJECT) { // not in an object!
+            throw new JSONException("Nesting problem");
+        }
+        newline();
+        replaceTop(Scope.DANGLING_KEY);
     }
-    newline();
-    replaceTop(Scope.DANGLING_KEY);
-  }
-
-  /**
-   * Inserts any necessary separators and whitespace before a literal value, inline array, or inline
-   * object. Also adjusts the stack to expect either a closing bracket or another element.
-   */
-  private void beforeValue() throws JSONException {
-    if (stack.isEmpty()) {
-      return;
+
+    /**
+     * Inserts any necessary separators and whitespace before a literal value,
+     * inline array, or inline object. Also adjusts the stack to expect either a
+     * closing bracket or another element.
+     */
+    private void beforeValue() throws JSONException {
+        if (stack.isEmpty()) {
+            return;
+        }
+
+        Scope context = peek();
+        if (context == Scope.EMPTY_ARRAY) { // first in array
+            replaceTop(Scope.NONEMPTY_ARRAY);
+            newline();
+        } else if (context == Scope.NONEMPTY_ARRAY) { // another in array
+            out.append(',');
+            newline();
+        } else if (context == Scope.DANGLING_KEY) { // value for key
+            out.append(indent == null ? ":" : ": ");
+            replaceTop(Scope.NONEMPTY_OBJECT);
+        } else if (context != Scope.NULL) {
+            throw new JSONException("Nesting problem");
+        }
     }
 
-    Scope context = peek();
-    if (context == Scope.EMPTY_ARRAY) { // first in array
-      replaceTop(Scope.NONEMPTY_ARRAY);
-      newline();
-    } else if (context == Scope.NONEMPTY_ARRAY) { // another in array
-      out.append(',');
-      newline();
-    } else if (context == Scope.DANGLING_KEY) { // value for key
-      out.append(indent == null ? ":" : ": ");
-      replaceTop(Scope.NONEMPTY_OBJECT);
-    } else if (context != Scope.NULL) {
-      throw new JSONException("Nesting problem");
+    /**
+     * Returns the encoded JSON string.
+     *
+     * <p>If invoked with unterminated arrays or unclosed objects, this method's
+     * return value is undefined.
+     *
+     * <p><strong>Warning:</strong> although it contradicts the general contract
+     * of {@link Object#toString}, this method returns null if the stringer
+     * contains no data.
+     */
+    @Override
+    public String toString() {
+        return out.length() == 0 ? null : out.toString();
     }
-  }
-
-  /**
-   * Returns the encoded JSON string.
-   *
-   * <p>
-   * If invoked with unterminated arrays or unclosed objects, this method's return value is
-   * undefined.
-   *
-   * <p>
-   * <strong>Warning:</strong> although it contradicts the general contract of
-   * {@link Object#toString}, this method returns null if the stringer contains no data.
-   */
-  @Override
-  public String toString() {
-    return out.length() == 0 ? null : out.toString();
-  }
 }


[3/8] geode git commit: Revert "GEODE-2142: Spotless"

Posted by ud...@apache.org.
Revert "GEODE-2142: Spotless"

This reverts commit 2e3a88f7bc61796042140aa92b44390b9970b53e.


Project: http://git-wip-us.apache.org/repos/asf/geode/repo
Commit: http://git-wip-us.apache.org/repos/asf/geode/commit/1253d780
Tree: http://git-wip-us.apache.org/repos/asf/geode/tree/1253d780
Diff: http://git-wip-us.apache.org/repos/asf/geode/diff/1253d780

Branch: refs/heads/develop
Commit: 1253d7808e3d35d2d6868e98e1ccb5bfa1749e35
Parents: 2e3a88f
Author: Udo Kohlmeyer <uk...@pivotal.io>
Authored: Fri Feb 17 13:56:15 2017 -0800
Committer: Udo Kohlmeyer <uk...@pivotal.io>
Committed: Fri Feb 17 13:56:15 2017 -0800

----------------------------------------------------------------------
 .../cli/functions/ExportConfigFunction.java     |    2 +-
 .../internal/cli/json/GfJsonObject.java         |   36 +-
 .../internal/cli/result/AbstractResultData.java |    7 +-
 .../cli/commands/CliCommandTestBase.java        |    2 +-
 geode-json/src/main/java/org/json/JSON.java     |  176 +--
 .../src/main/java/org/json/JSONArray.java       | 1458 +++++++++---------
 .../src/main/java/org/json/JSONException.java   |   59 +-
 .../src/main/java/org/json/JSONObject.java      |  416 +++--
 .../src/main/java/org/json/JSONString.java      |   17 +-
 .../src/main/java/org/json/JSONStringer.java    |  779 +++++-----
 .../src/main/java/org/json/JSONTokener.java     | 1149 +++++++-------
 11 files changed, 2061 insertions(+), 2040 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/geode/blob/1253d780/geode-core/src/main/java/org/apache/geode/management/internal/cli/functions/ExportConfigFunction.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/management/internal/cli/functions/ExportConfigFunction.java b/geode-core/src/main/java/org/apache/geode/management/internal/cli/functions/ExportConfigFunction.java
index 4e92623..64bc374 100644
--- a/geode-core/src/main/java/org/apache/geode/management/internal/cli/functions/ExportConfigFunction.java
+++ b/geode-core/src/main/java/org/apache/geode/management/internal/cli/functions/ExportConfigFunction.java
@@ -95,7 +95,7 @@ public class ExportConfigFunction implements Function, InternalEntity {
       }
       CliFunctionResult result = new CliFunctionResult(memberId,
           new String[] {xmlWriter.toString(), propStringBuf.toString()});
-      System.err.println("ExportConfigFunction.execute CLI function result: " + result);
+      System.err.println("ExportConfigFunction.execute CLI function result: "+result);
       context.getResultSender().lastResult(result);
     } catch (CacheClosedException cce) {
       CliFunctionResult result = new CliFunctionResult(memberId, false, null);

http://git-wip-us.apache.org/repos/asf/geode/blob/1253d780/geode-core/src/main/java/org/apache/geode/management/internal/cli/json/GfJsonObject.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/management/internal/cli/json/GfJsonObject.java b/geode-core/src/main/java/org/apache/geode/management/internal/cli/json/GfJsonObject.java
index 8b7e004..9137f72 100644
--- a/geode-core/src/main/java/org/apache/geode/management/internal/cli/json/GfJsonObject.java
+++ b/geode-core/src/main/java/org/apache/geode/management/internal/cli/json/GfJsonObject.java
@@ -72,9 +72,9 @@ public class GfJsonObject {
     }
   }
 
-  // public GfJsonObject(Object bean, String[] paramNames) {
-  // this.jsonObject = new JSONObject(bean, paramNames);
-  // }
+//  public GfJsonObject(Object bean, String[] paramNames) {
+//    this.jsonObject = new JSONObject(bean, paramNames);
+//  }
 
   /**
    * 
@@ -237,21 +237,21 @@ public class GfJsonObject {
     return this;
   }
 
-  // /**
-  // *
-  // * @param key
-  // * @param value
-  // * @return this GfJsonObject
-  // * @throws GfJsonException if the key is a duplicate
-  // */
-  // public GfJsonObject putOnce(String key, Object value) throws GfJsonException {
-  // try {
-  // jsonObject.putOnce(key, value);
-  // } catch (JSONException e) {
-  // throw new GfJsonException(e.getMessage());
-  // }
-  // return this;
-  // }
+//  /**
+//   *
+//   * @param key
+//   * @param value
+//   * @return this GfJsonObject
+//   * @throws GfJsonException if the key is a duplicate
+//   */
+//  public GfJsonObject putOnce(String key, Object value) throws GfJsonException {
+//    try {
+//      jsonObject.putOnce(key, value);
+//    } catch (JSONException e) {
+//      throw new GfJsonException(e.getMessage());
+//    }
+//    return this;
+//  }
 
   /**
    * 

http://git-wip-us.apache.org/repos/asf/geode/blob/1253d780/geode-core/src/main/java/org/apache/geode/management/internal/cli/result/AbstractResultData.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/management/internal/cli/result/AbstractResultData.java b/geode-core/src/main/java/org/apache/geode/management/internal/cli/result/AbstractResultData.java
index f453ec6..81ab511 100644
--- a/geode-core/src/main/java/org/apache/geode/management/internal/cli/result/AbstractResultData.java
+++ b/geode-core/src/main/java/org/apache/geode/management/internal/cli/result/AbstractResultData.java
@@ -175,9 +175,8 @@ public abstract class AbstractResultData implements ResultData {
       sectionData.put(FILE_TYPE_FIELD, fileType);
       sectionData.put(FILE_MESSAGE, message);
       DeflaterInflaterData deflaterInflaterData = CliUtil.compressBytes(data);
-      sectionData.put(FILE_DATA_FIELD,
-          Base64.getEncoder().encodeToString(deflaterInflaterData.getData()));
-      sectionData.put(DATA_LENGTH_FIELD, deflaterInflaterData.getDataLength());
+      sectionData.put(FILE_DATA_FIELD, Base64.getEncoder().encodeToString(deflaterInflaterData.getData()));
+      sectionData.put(DATA_LENGTH_FIELD,deflaterInflaterData.getDataLength());
     } catch (GfJsonException e) {
       throw new ResultDataException(e.getMessage());
     }
@@ -232,7 +231,7 @@ public abstract class AbstractResultData implements ResultData {
       String fileDataString = (String) object.get(FILE_DATA_FIELD);
       int fileDataLength = (int) object.get(DATA_LENGTH_FIELD);
       byte[] byteArray = Base64.getDecoder().decode(fileDataString);
-      byte[] uncompressBytes = CliUtil.uncompressBytes(byteArray, fileDataLength).getData();
+      byte[] uncompressBytes = CliUtil.uncompressBytes(byteArray,fileDataLength).getData();
 
       boolean isGfshVM = CliUtil.isGfshVM();
       File fileToDumpData = new File(fileName);

http://git-wip-us.apache.org/repos/asf/geode/blob/1253d780/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/CliCommandTestBase.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/CliCommandTestBase.java b/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/CliCommandTestBase.java
index 662ff4d..239810b 100644
--- a/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/CliCommandTestBase.java
+++ b/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/CliCommandTestBase.java
@@ -365,7 +365,7 @@ public abstract class CliCommandTestBase extends JUnit4CacheTestCase {
         System.err.println("result1 = " + result1);
       }
       result = (CommandResult) result1; // TODO: this can result in ClassCastException if
-                                        // command resulted in error
+                                                  // command resulted in error
     } catch (InterruptedException ex) {
       error("shell received InterruptedException");
     }

http://git-wip-us.apache.org/repos/asf/geode/blob/1253d780/geode-json/src/main/java/org/json/JSON.java
----------------------------------------------------------------------
diff --git a/geode-json/src/main/java/org/json/JSON.java b/geode-json/src/main/java/org/json/JSON.java
index 7105cab..1b32e69 100755
--- a/geode-json/src/main/java/org/json/JSON.java
+++ b/geode-json/src/main/java/org/json/JSON.java
@@ -1,112 +1,116 @@
 /*
  * 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
+ * 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
+ *      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.
+ * 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.json;
 
 class JSON {
-  /**
-   * Returns the input if it is a JSON-permissible value; throws otherwise.
-   */
-  static double checkDouble(double d) throws JSONException {
-    if (Double.isInfinite(d) || Double.isNaN(d)) {
-      throw new JSONException("Forbidden numeric value: " + d);
+    /**
+     * Returns the input if it is a JSON-permissible value; throws otherwise.
+     */
+    static double checkDouble(double d) throws JSONException {
+        if (Double.isInfinite(d) || Double.isNaN(d)) {
+            throw new JSONException("Forbidden numeric value: " + d);
+        }
+        return d;
     }
-    return d;
-  }
 
-  static Boolean toBoolean(Object value) {
-    if (value instanceof Boolean) {
-      return (Boolean) value;
-    } else if (value instanceof String) {
-      String stringValue = (String) value;
-      if ("true".equalsIgnoreCase(stringValue)) {
-        return true;
-      } else if ("false".equalsIgnoreCase(stringValue)) {
-        return false;
-      }
+    static Boolean toBoolean(Object value) {
+        if (value instanceof Boolean) {
+            return (Boolean) value;
+        } else if (value instanceof String) {
+            String stringValue = (String) value;
+            if ("true".equalsIgnoreCase(stringValue)) {
+                return true;
+            } else if ("false".equalsIgnoreCase(stringValue)) {
+                return false;
+            }
+        }
+        return null;
     }
-    return null;
-  }
 
-  static Double toDouble(Object value) {
-    if (value instanceof Double) {
-      return (Double) value;
-    } else if (value instanceof Number) {
-      return ((Number) value).doubleValue();
-    } else if (value instanceof String) {
-      try {
-        return Double.valueOf((String) value);
-      } catch (NumberFormatException ignored) {
-      }
+    static Double toDouble(Object value) {
+        if (value instanceof Double) {
+            return (Double) value;
+        } else if (value instanceof Number) {
+            return ((Number) value).doubleValue();
+        } else if (value instanceof String) {
+            try {
+                return Double.valueOf((String) value);
+            } catch (NumberFormatException ignored) {
+            }
+        }
+        return null;
     }
-    return null;
-  }
 
-  static Integer toInteger(Object value) {
-    if (value instanceof Integer) {
-      return (Integer) value;
-    } else if (value instanceof Number) {
-      return ((Number) value).intValue();
-    } else if (value instanceof String) {
-      try {
-        return (int) Double.parseDouble((String) value);
-      } catch (NumberFormatException ignored) {
-      }
+    static Integer toInteger(Object value) {
+        if (value instanceof Integer) {
+            return (Integer) value;
+        } else if (value instanceof Number) {
+            return ((Number) value).intValue();
+        } else if (value instanceof String) {
+            try {
+                return (int) Double.parseDouble((String) value);
+            } catch (NumberFormatException ignored) {
+            }
+        }
+        return null;
     }
-    return null;
-  }
 
-  static Long toLong(Object value) {
-    if (value instanceof Long) {
-      return (Long) value;
-    } else if (value instanceof Number) {
-      return ((Number) value).longValue();
-    } else if (value instanceof String) {
-      try {
-        return (long) Double.parseDouble((String) value);
-      } catch (NumberFormatException ignored) {
-      }
+    static Long toLong(Object value) {
+        if (value instanceof Long) {
+            return (Long) value;
+        } else if (value instanceof Number) {
+            return ((Number) value).longValue();
+        } else if (value instanceof String) {
+            try {
+                return (long) Double.parseDouble((String) value);
+            } catch (NumberFormatException ignored) {
+            }
+        }
+        return null;
     }
-    return null;
-  }
 
-  static String toString(Object value) {
-    if (value instanceof String) {
-      return (String) value;
-    } else if (value != null) {
-      return String.valueOf(value);
+    static String toString(Object value) {
+        if (value instanceof String) {
+            return (String) value;
+        } else if (value != null) {
+            return String.valueOf(value);
+        }
+        return null;
     }
-    return null;
-  }
 
-  public static JSONException typeMismatch(Object indexOrName, Object actual, String requiredType)
-      throws JSONException {
-    if (actual == null) {
-      throw new JSONException("Value at " + indexOrName + " is null.");
-    } else {
-      throw new JSONException("Value " + actual + " at " + indexOrName + " of type "
-          + actual.getClass().getName() + " cannot be converted to " + requiredType);
+    public static JSONException typeMismatch(Object indexOrName, Object actual,
+            String requiredType) throws JSONException {
+        if (actual == null) {
+            throw new JSONException("Value at " + indexOrName + " is null.");
+        } else {
+            throw new JSONException("Value " + actual + " at " + indexOrName
+                    + " of type " + actual.getClass().getName()
+                    + " cannot be converted to " + requiredType);
+        }
     }
-  }
 
-  public static JSONException typeMismatch(Object actual, String requiredType)
-      throws JSONException {
-    if (actual == null) {
-      throw new JSONException("Value is null.");
-    } else {
-      throw new JSONException("Value " + actual + " of type " + actual.getClass().getName()
-          + " cannot be converted to " + requiredType);
+    public static JSONException typeMismatch(Object actual, String requiredType)
+            throws JSONException {
+        if (actual == null) {
+            throw new JSONException("Value is null.");
+        } else {
+            throw new JSONException("Value " + actual
+                    + " of type " + actual.getClass().getName()
+                    + " cannot be converted to " + requiredType);
+        }
     }
-  }
 }

http://git-wip-us.apache.org/repos/asf/geode/blob/1253d780/geode-json/src/main/java/org/json/JSONArray.java
----------------------------------------------------------------------
diff --git a/geode-json/src/main/java/org/json/JSONArray.java b/geode-json/src/main/java/org/json/JSONArray.java
index c961139..074624d 100755
--- a/geode-json/src/main/java/org/json/JSONArray.java
+++ b/geode-json/src/main/java/org/json/JSONArray.java
@@ -1,15 +1,17 @@
 /*
  * 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
+ * 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
+ *      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.
+ * 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.json;
@@ -22,726 +24,736 @@ import java.util.List;
 // Note: this class was written without inspecting the non-free org.json sourcecode.
 
 /**
- * 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.
+ * 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.
  *
- * {@code JSONArray} has the same type coercion behavior and optional/mandatory accessors as
- * {@link JSONObject}. See that class' documentation for details.
+ * {@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}.
+ * <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.
+ * 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;
-
-  /**
-   * Creates a {@code JSONArray} with no values.
-   */
-  public JSONArray() {
-    values = new ArrayList<Object>();
-  }
-
-  /**
-   * 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.
-   */
-  /* Accept a raw type for API compatibility */
-  public JSONArray(Collection<?> copyFrom) {
-    this();
-    if (copyFrom != null) {
-      for (Object aCopyFrom : copyFrom) {
-        put(JSONObject.wrap(aCopyFrom));
-      }
-    }
-  }
-
-  /**
-   * 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");
-    }
-  }
-
-  /**
-   * 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(String json) throws JSONException {
-    this(new JSONTokener(json));
-  }
-
-  /**
-   * 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 {
-    if (!array.getClass().isArray()) {
-      throw new JSONException("Not a primitive array: " + array.getClass());
-    }
-    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 Returns the number of values in this array.
-   */
-  public int length() {
-    return values.size();
-  }
-
-  /**
-   * Appends {@code value} to the end of this array.
-   *
-   * @param value The value to append.
-   * @return this array.
-   */
-  public JSONArray put(boolean value) {
-    values.add(value);
-    return this;
-  }
-
-  /**
-   * Appends {@code value} to the end of this array.
-   *
-   * @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 JSONArray put(double value) throws JSONException {
-    values.add(JSON.checkDouble(value));
-    return this;
-  }
-
-  /**
-   * Appends {@code value} to the end of this array.
-   *
-   * @param value The value to append.
-   * @return this array.
-   */
-  public JSONArray put(int value) {
-    values.add(value);
-    return this;
-  }
-
-  /**
-   * Appends {@code value} to the end of this array.
-   *
-   * @param value The value to append.
-   * @return this array.
-   */
-  public JSONArray put(long value) {
-    values.add(value);
-    return this;
-  }
-
-  /**
-   * Appends {@code value} wrapped by {@link JSONArray} to the end of this array.
-   *
-   * @param value any collection.
-   * @return this array.
-   */
-  public JSONArray put(Collection<?> value) {
-    if (value == null) {
-      return put((Object) null);
-    }
-    values.add(new JSONArray(value));
-    return this;
-  }
-
-  /**
-   * Appends {@code value} to the end of this array.
-   *
-   * @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 JSONArray put(Object value) {
-    values.add(value);
-    return this;
-  }
-
-  /**
-   * Same as {@link #put}, with added validity checks.
-   *
-   * @param value The value to append.
-   */
-  void checkedPut(Object value) throws JSONException {
-    if (value instanceof Number) {
-      JSON.checkDouble(((Number) value).doubleValue());
-    }
-
-    put(value);
-  }
-
-  /**
-   * 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 JSONArray put(int index, boolean value) throws JSONException {
-    return put(index, (Boolean) value);
-  }
-
-  /**
-   * 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 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 JSONArray put(int index, double value) throws JSONException {
-    return put(index, (Double) value);
-  }
-
-  /**
-   * 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 JSONArray put(int index, int value) throws JSONException {
-    return put(index, (Integer) value);
-  }
-
-  /**
-   * 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 JSONArray put(int index, long value) throws JSONException {
-    return put(index, (Long) value);
-  }
-
-  /**
-   * Sets the value at {@code index} to {@code value} wrapped into {@link JSONArray}, 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 JSONArray put(int index, Collection<?> value) throws JSONException {
-    if (value == null) {
-      return put(index, (Object) null);
-    }
-    return put(index, new JSONArray(value));
-  }
-
-  /**
-   * 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 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 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;
-  }
-
-  /**
-   * 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 Which value to check.
-   * @return true if the value is null.
-   */
-  public boolean isNull(int index) {
-    Object value = opt(index);
-    return value == null || value == JSONObject.NULL;
-  }
-
-  /**
-   * Returns the value at {@code index}.
-   *
-   * @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 Object get(int index) throws JSONException {
-    try {
-      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() + ")");
-    }
-  }
-
-  /**
-   * Returns the value at {@code index}, or null if the array has no value at {@code index}.
-   *
-   * @param index Which value to get.
-   * @return the value at the specified location.
-   */
-  public Object opt(int index) {
-    if (index < 0 || index >= values.size()) {
-      return null;
-    }
-    return values.get(index);
-  }
-
-  /**
-   * 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 Object remove(int index) {
-    if (index < 0 || index >= values.size()) {
-      return null;
-    }
-    return values.remove(index);
-  }
-
-  /**
-   * 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 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;
-  }
-
-  /**
-   * 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 Which value to get.
-   * @return the value at the specified location.
-   */
-  public boolean optBoolean(int index) {
-    return optBoolean(index, false);
-  }
-
-  /**
-   * 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 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 boolean optBoolean(int index, boolean fallback) {
-    Object object = opt(index);
-    Boolean result = JSON.toBoolean(object);
-    return result != null ? result : fallback;
-  }
-
-  /**
-   * 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 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;
-  }
-
-  /**
-   * 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 Which value to get.
-   * @return the value at the specified location.
-   */
-  public double optDouble(int index) {
-    return optDouble(index, Double.NaN);
-  }
-
-  /**
-   * 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 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 double optDouble(int index, double fallback) {
-    Object object = opt(index);
-    Double result = JSON.toDouble(object);
-    return result != null ? result : fallback;
-  }
-
-  /**
-   * Returns the value at {@code index} if it exists and is an int or can be coerced to an int.
-   *
-   * @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 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;
-  }
-
-  /**
-   * Returns the value at {@code index} if it exists and is an int or can be coerced to an int.
-   * Returns 0 otherwise.
-   *
-   * @param index Which value to get.
-   * @return the value at the specified location.
-   */
-  public int optInt(int index) {
-    return optInt(index, 0);
-  }
-
-  /**
-   * 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 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 int optInt(int index, int fallback) {
-    Object object = opt(index);
-    Integer result = JSON.toInteger(object);
-    return result != null ? result : fallback;
-  }
-
-  /**
-   * Returns the value at {@code index} if it exists and is a long or can be coerced to a long.
-   *
-   * @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 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;
-  }
-
-  /**
-   * 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 long optLong(int index) {
-    return optLong(index, 0L);
-  }
-
-  /**
-   * 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 long optLong(int index, long fallback) {
-    Object object = opt(index);
-    Long result = JSON.toLong(object);
-    return result != null ? result : fallback;
-  }
-
-  /**
-   * 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 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;
-  }
-
-  /**
-   * 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 String optString(int index) {
-    return optString(index, "");
-  }
-
-  /**
-   * 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 String optString(int index, String fallback) {
-    Object object = opt(index);
-    String result = JSON.toString(object);
-    return result != null ? result : fallback;
-  }
-
-  /**
-   * 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 getJSONArray(int index) throws JSONException {
-    Object object = get(index);
-    if (object instanceof JSONArray) {
-      return (JSONArray) object;
-    } else {
-      throw JSON.typeMismatch(index, object, "JSONArray");
-    }
-  }
-
-  /**
-   * 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 optJSONArray(int index) {
-    Object object = opt(index);
-    return object instanceof JSONArray ? (JSONArray) object : null;
-  }
-
-  /**
-   * 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 JSONObject getJSONObject(int index) throws JSONException {
-    Object object = get(index);
-    if (object instanceof JSONObject) {
-      return (JSONObject) object;
-    } else {
-      throw JSON.typeMismatch(index, object, "JSONObject");
-    }
-  }
-
-  /**
-   * 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 JSONObject optJSONObject(int index) {
-    Object object = opt(index);
-    return object instanceof JSONObject ? (JSONObject) object : 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 {
-    JSONObject result = new JSONObject();
-    int length = Math.min(names.length(), values.size());
-    if (length == 0) {
-      return null;
-    }
-    for (int i = 0; i < length; i++) {
-      String name = JSON.toString(names.opt(i));
-      result.put(name, opt(i));
-    }
-    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();
-  }
-
-  /**
-   * Encodes this array as a compact JSON string, such as:
-   * 
-   * <pre>
-   * [94043,90210]
-   * </pre>
-   *
-   * @return The string form of this array.
-   */
-  @Override
-  public String toString() {
-    try {
-      JSONStringer stringer = new JSONStringer();
-      writeTo(stringer);
-      return stringer.toString();
-    } catch (JSONException e) {
-      return null;
-    }
-  }
-
-  /**
-   * 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 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();
-  }
-
-  @Override
-  public boolean equals(Object o) {
-    return o instanceof JSONArray && ((JSONArray) o).values.equals(values);
-  }
-
-  @Override
-  public int hashCode() {
-    // diverge from the original, which doesn't implement hashCode
-    return values.hashCode();
-  }
+    private final List<Object> values;
+
+    /**
+     * Creates a {@code JSONArray} with no values.
+     */
+    public JSONArray() {
+        values = new ArrayList<Object>();
+    }
+
+    /**
+     * 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.
+     */
+    /* Accept a raw type for API compatibility */
+    public JSONArray(Collection<?> copyFrom) {
+        this();
+        if (copyFrom != null) {
+            for (Object aCopyFrom : copyFrom) {
+                put(JSONObject.wrap(aCopyFrom));
+            }
+        }
+    }
+
+    /**
+     * 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");
+        }
+    }
+
+    /**
+     * 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(String json) throws JSONException {
+        this(new JSONTokener(json));
+    }
+
+    /**
+     * 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 {
+        if (!array.getClass().isArray()) {
+            throw new JSONException("Not a primitive array: " + array.getClass());
+        }
+        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 Returns the number of values in this array.
+     */
+    public int length() {
+        return values.size();
+    }
+
+    /**
+     * Appends {@code value} to the end of this array.
+     *
+     * @param value The value to append.
+     * @return this array.
+     */
+    public JSONArray put(boolean value) {
+        values.add(value);
+        return this;
+    }
+
+    /**
+     * Appends {@code value} to the end of this array.
+     *
+     * @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 JSONArray put(double value) throws JSONException {
+        values.add(JSON.checkDouble(value));
+        return this;
+    }
+
+    /**
+     * Appends {@code value} to the end of this array.
+     *
+     * @param value The value to append.
+     * @return this array.
+     */
+    public JSONArray put(int value) {
+        values.add(value);
+        return this;
+    }
+
+    /**
+     * Appends {@code value} to the end of this array.
+     *
+     * @param value The value to append.
+     * @return this array.
+     */
+    public JSONArray put(long value) {
+        values.add(value);
+        return this;
+    }
+
+    /**
+     * Appends {@code value} wrapped by {@link JSONArray} to the end of this array.
+     *
+     * @param value any collection.
+     * @return this array.
+     */
+    public JSONArray put(Collection<?> value) {
+        if (value == null) {
+            return put((Object)null);
+        }
+        values.add(new JSONArray(value));
+        return this;
+    }
+
+    /**
+     * Appends {@code value} to the end of this array.
+     *
+     * @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 JSONArray put(Object value) {
+        values.add(value);
+        return this;
+    }
+
+    /**
+     * Same as {@link #put}, with added validity checks.
+     *
+     * @param value The value to append.
+     */
+    void checkedPut(Object value) throws JSONException {
+        if (value instanceof Number) {
+            JSON.checkDouble(((Number) value).doubleValue());
+        }
+
+        put(value);
+    }
+
+    /**
+     * 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 JSONArray put(int index, boolean value) throws JSONException {
+        return put(index, (Boolean) value);
+    }
+
+    /**
+     * 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 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 JSONArray put(int index, double value) throws JSONException {
+        return put(index, (Double) value);
+    }
+
+    /**
+     * 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 JSONArray put(int index, int value) throws JSONException {
+        return put(index, (Integer) value);
+    }
+
+    /**
+     * 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 JSONArray put(int index, long value) throws JSONException {
+        return put(index, (Long) value);
+    }
+
+    /**
+     * Sets the value at {@code index} to {@code value} wrapped into {@link JSONArray},
+     * 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 JSONArray put(int index, Collection<?> value) throws JSONException {
+        if (value == null) {
+            return put(index, (Object)null);
+        }
+        return put(index, new JSONArray(value));
+    }
+
+    /**
+     * 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 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 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;
+    }
+
+    /**
+     * 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 Which value to check.
+     * @return true if the value is null.
+     */
+    public boolean isNull(int index) {
+        Object value = opt(index);
+        return value == null || value == JSONObject.NULL;
+    }
+
+    /**
+     * Returns the value at {@code index}.
+     *
+     * @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 Object get(int index) throws JSONException {
+        try {
+            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() + ")");
+        }
+    }
+
+    /**
+     * Returns the value at {@code index}, or null if the array has no value
+     * at {@code index}.
+     *
+     * @param index Which value to get.
+     * @return the value at the specified location.
+     */
+    public Object opt(int index) {
+        if (index < 0 || index >= values.size()) {
+            return null;
+        }
+        return values.get(index);
+    }
+
+    /**
+     * 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 Object remove(int index) {
+        if (index < 0 || index >= values.size()) {
+            return null;
+        }
+        return values.remove(index);
+    }
+
+    /**
+     * 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 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;
+    }
+
+    /**
+     * 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 Which value to get.
+     * @return the value at the specified location.
+     */
+    public boolean optBoolean(int index) {
+        return optBoolean(index, false);
+    }
+
+    /**
+     * 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    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 boolean optBoolean(int index, boolean fallback) {
+        Object object = opt(index);
+        Boolean result = JSON.toBoolean(object);
+        return result != null ? result : fallback;
+    }
+
+    /**
+     * 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 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;
+    }
+
+    /**
+     * 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 Which value to get.
+     * @return the value at the specified location.
+     */
+    public double optDouble(int index) {
+        return optDouble(index, Double.NaN);
+    }
+
+    /**
+     * 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    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 double optDouble(int index, double fallback) {
+        Object object = opt(index);
+        Double result = JSON.toDouble(object);
+        return result != null ? result : fallback;
+    }
+
+    /**
+     * Returns the value at {@code index} if it exists and is an int or
+     * can be coerced to an int.
+     *
+     * @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 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;
+    }
+
+    /**
+     * Returns the value at {@code index} if it exists and is an int or
+     * can be coerced to an int. Returns 0 otherwise.
+     *
+     * @param index Which value to get.
+     * @return the value at the specified location.
+     */
+    public int optInt(int index) {
+        return optInt(index, 0);
+    }
+
+    /**
+     * 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 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 int optInt(int index, int fallback) {
+        Object object = opt(index);
+        Integer result = JSON.toInteger(object);
+        return result != null ? result : fallback;
+    }
+
+    /**
+     * Returns the value at {@code index} if it exists and is a long or
+     * can be coerced to a long.
+     *
+     * @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 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;
+    }
+
+    /**
+     * 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 long optLong(int index) {
+        return optLong(index, 0L);
+    }
+
+    /**
+     * 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 long optLong(int index, long fallback) {
+        Object object = opt(index);
+        Long result = JSON.toLong(object);
+        return result != null ? result : fallback;
+    }
+
+    /**
+     * 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 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;
+    }
+
+    /**
+     * 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 String optString(int index) {
+        return optString(index, "");
+    }
+
+    /**
+     * 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 String optString(int index, String fallback) {
+        Object object = opt(index);
+        String result = JSON.toString(object);
+        return result != null ? result : fallback;
+    }
+
+    /**
+     * 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 getJSONArray(int index) throws JSONException {
+        Object object = get(index);
+        if (object instanceof JSONArray) {
+            return (JSONArray) object;
+        } else {
+            throw JSON.typeMismatch(index, object, "JSONArray");
+        }
+    }
+
+    /**
+     * 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 optJSONArray(int index) {
+        Object object = opt(index);
+        return object instanceof JSONArray ? (JSONArray) object : null;
+    }
+
+    /**
+     * 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 JSONObject getJSONObject(int index) throws JSONException {
+        Object object = get(index);
+        if (object instanceof JSONObject) {
+            return (JSONObject) object;
+        } else {
+            throw JSON.typeMismatch(index, object, "JSONObject");
+        }
+    }
+
+    /**
+     * 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 JSONObject optJSONObject(int index) {
+        Object object = opt(index);
+        return object instanceof JSONObject ? (JSONObject) object : 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 {
+        JSONObject result = new JSONObject();
+        int length = Math.min(names.length(), values.size());
+        if (length == 0) {
+            return null;
+        }
+        for (int i = 0; i < length; i++) {
+            String name = JSON.toString(names.opt(i));
+            result.put(name, opt(i));
+        }
+        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();
+    }
+
+    /**
+     * Encodes this array as a compact JSON string, such as:
+     * <pre>[94043,90210]</pre>
+     *
+     * @return The string form of this array.
+     */
+    @Override
+    public String toString() {
+        try {
+            JSONStringer stringer = new JSONStringer();
+            writeTo(stringer);
+            return stringer.toString();
+        } catch (JSONException e) {
+            return null;
+        }
+    }
+
+    /**
+     * 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 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();
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        return o instanceof JSONArray && ((JSONArray) o).values.equals(values);
+    }
+
+    @Override
+    public int hashCode() {
+        // diverge from the original, which doesn't implement hashCode
+        return values.hashCode();
+    }
 }

http://git-wip-us.apache.org/repos/asf/geode/blob/1253d780/geode-json/src/main/java/org/json/JSONException.java
----------------------------------------------------------------------
diff --git a/geode-json/src/main/java/org/json/JSONException.java b/geode-json/src/main/java/org/json/JSONException.java
index 83fb4b8..1292e86 100755
--- a/geode-json/src/main/java/org/json/JSONException.java
+++ b/geode-json/src/main/java/org/json/JSONException.java
@@ -1,15 +1,17 @@
 /*
  * 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
+ * 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
+ *      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.
+ * 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.json;
@@ -19,40 +21,37 @@ package org.json;
 /**
  * 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
+ *   <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() {
+ * <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>
+ * }</pre>
  */
 public class JSONException extends RuntimeException {
 
-  public JSONException(String s) {
-    super(s);
-  }
+    public JSONException(String s) {
+        super(s);
+    }
 
-  public JSONException(Throwable cause) {
-    super(cause);
-  }
+    public JSONException(Throwable cause) {
+        super(cause);
+    }
 
-  public JSONException(String message, Throwable cause) {
-    super(message, cause);
-  }
+    public JSONException(String message, Throwable cause) {
+        super(message, cause);
+    }
 }


[5/8] geode git commit: Revert "GEODE-2142: Removal of non-compliant org.json implementation."

Posted by ud...@apache.org.
http://git-wip-us.apache.org/repos/asf/geode/blob/0805036e/geode-json/src/main/java/org/json/JSONStringer.java
----------------------------------------------------------------------
diff --git a/geode-json/src/main/java/org/json/JSONStringer.java b/geode-json/src/main/java/org/json/JSONStringer.java
index db1121e..234e174 100755
--- a/geode-json/src/main/java/org/json/JSONStringer.java
+++ b/geode-json/src/main/java/org/json/JSONStringer.java
@@ -1,470 +1,75 @@
-/*
- * 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.json;
 
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
+/*
+ * Copyright (c) 2006 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.
+ */
 
-// Note: this class was written without inspecting the non-free org.json sourcecode.
+import java.io.StringWriter;
 
 /**
- * Implements {@link JSONObject#toString} and {@link JSONArray#toString}. Most
- * application developers should use those methods directly and disregard this
- * API. For example:<pre>
- * JSONObject object = ...
- * String json = object.toString();</pre>
- *
- * <p>Stringers only encode well-formed JSON strings. In particular:
- * <ul>
- * <li>The stringer must have exactly one top-level array or object.
- * <li>Lexical scopes must be balanced: every call to {@link #array} must
- * have a matching call to {@link #endArray} and every call to {@link
- * #object} must have a matching call to {@link #endObject}.
- * <li>Arrays may not contain keys (property names).
- * <li>Objects must alternate keys (property names) and values.
- * <li>Values are inserted with either literal {@link #value(Object) value}
- * calls, or by nesting arrays or objects.
- * </ul>
- * Calls that would result in a malformed JSON string will fail with a
- * {@link JSONException}.
- *
- * <p>This class provides no facility for pretty-printing (ie. indenting)
- * output. To encode indented output, use {@link JSONObject#toString(int)} or
- * {@link JSONArray#toString(int)}.
- *
- * <p>Some implementations of the API support at most 20 levels of nesting.
- * Attempts to create more than 20 levels of nesting may fail with a {@link
- * JSONException}.
- *
- * <p>Each stringer may be used to encode a single top level value. Instances of
- * this class are not thread safe. Although this class is nonfinal, it was not
- * designed for inheritance and should not be subclassed. In particular,
- * self-use by overrideable methods is not specified. See <i>Effective Java</i>
- * Item 17, "Design and Document or inheritance or else prohibit it" for further
- * information.
+ * JSONStringer provides a quick and convenient way of producing JSON text. The texts produced
+ * strictly conform to JSON syntax rules. No whitespace is added, so the results are ready for
+ * transmission or storage. Each instance of JSONStringer can produce one JSON text.
+ * <p>
+ * A JSONStringer instance provides a <code>value</code> method for appending values to the text,
+ * and a <code>key</code> method for adding keys before values in objects. There are
+ * <code>array</code> and <code>endArray</code> methods that make and bound array values, and
+ * <code>object</code> and <code>endObject</code> methods which make and bound object values. All of
+ * these methods return the JSONWriter instance, permitting cascade style. For example,
+ * 
+ * <pre>
+ * myString = new JSONStringer().object().key("JSON").value("Hello, World!").endObject().toString();
+ * </pre>
+ * 
+ * which produces the string
+ * 
+ * <pre>
+ * {"JSON":"Hello, World!"}
+ * </pre>
+ * <p>
+ * The first method called must be <code>array</code> or <code>object</code>. There are no methods
+ * for adding commas or colons. JSONStringer adds them for you. Objects and arrays can be nested up
+ * to 20 levels deep.
+ * <p>
+ * This can sometimes be easier than using a JSONObject to build a string.
+ * 
+ * @author JSON.org
+ * @version 2008-09-18
  */
-public class JSONStringer {
-
-    /**
-     * The output data, containing at most one top-level array or object.
-     */
-    final StringBuilder out = new StringBuilder();
-
-    /**
-     * Lexical scoping elements within this stringer, necessary to insert the
-     * appropriate separator characters (ie. commas and colons) and to detect
-     * nesting errors.
-     */
-    enum Scope {
-
-        /**
-         * An array with no elements requires no separators or newlines before
-         * it is closed.
-         */
-        EMPTY_ARRAY,
-
-        /**
-         * A array with at least one value requires a comma and newline before
-         * the next element.
-         */
-        NONEMPTY_ARRAY,
-
-        /**
-         * An object with no keys or values requires no separators or newlines
-         * before it is closed.
-         */
-        EMPTY_OBJECT,
-
-        /**
-         * An object whose most recent element is a key. The next element must
-         * be a value.
-         */
-        DANGLING_KEY,
-
-        /**
-         * An object with at least one name/value pair requires a comma and
-         * newline before the next element.
-         */
-        NONEMPTY_OBJECT,
-
-        /**
-         * A special bracketless array needed by JSONStringer.join() and
-         * JSONObject.quote() only. Not used for JSON encoding.
-         */
-        NULL,
-    }
-
-    /**
-     * Unlike the original implementation, this stack isn't limited to 20
-     * levels of nesting.
-     */
-    private final List<Scope> stack = new ArrayList<Scope>();
-
-    /**
-     * A string containing a full set of spaces for a single level of
-     * indentation, or null for no pretty printing.
-     */
-    private final String indent;
-
-    public JSONStringer() {
-        indent = null;
-    }
-
-    JSONStringer(int indentSpaces) {
-        char[] indentChars = new char[indentSpaces];
-        Arrays.fill(indentChars, ' ');
-        indent = new String(indentChars);
-    }
-
-    /**
-     * Begins encoding a new array. Each call to this method must be paired with
-     * a call to {@link #endArray}.
-     *
-     * @return this stringer.
-     * @throws JSONException On internal errors. Shouldn't happen.
-     */
-    public JSONStringer array() throws JSONException {
-        return open(Scope.EMPTY_ARRAY, "[");
-    }
-
-    /**
-     * Ends encoding the current array.
-     *
-     * @return this stringer.
-     * @throws JSONException On internal errors. Shouldn't happen.
-     */
-    public JSONStringer endArray() throws JSONException {
-        return close(Scope.EMPTY_ARRAY, Scope.NONEMPTY_ARRAY, "]");
-    }
-
-    /**
-     * Begins encoding a new object. Each call to this method must be paired
-     * with a call to {@link #endObject}.
-     *
-     * @return this stringer.
-     * @throws JSONException On internal errors. Shouldn't happen.
-     */
-    public JSONStringer object() throws JSONException {
-        return open(Scope.EMPTY_OBJECT, "{");
-    }
-
-    /**
-     * Ends encoding the current object.
-     *
-     * @return this stringer.
-     * @throws JSONException On internal errors. Shouldn't happen.
-     */
-    public JSONStringer endObject() throws JSONException {
-        return close(Scope.EMPTY_OBJECT, Scope.NONEMPTY_OBJECT, "}");
-    }
-
-    /**
-     * Enters a new scope by appending any necessary whitespace and the given
-     * bracket.
-     */
-    JSONStringer open(Scope empty, String openBracket) throws JSONException {
-        if (stack.isEmpty() && out.length() > 0) {
-            throw new JSONException("Nesting problem: multiple top-level roots");
-        }
-        beforeValue();
-        stack.add(empty);
-        out.append(openBracket);
-        return this;
-    }
-
-    /**
-     * Closes the current scope by appending any necessary whitespace and the
-     * given bracket.
-     */
-    JSONStringer close(Scope empty, Scope nonempty, String closeBracket) throws JSONException {
-        Scope context = peek();
-        if (context != nonempty && context != empty) {
-            throw new JSONException("Nesting problem");
-        }
-
-        stack.remove(stack.size() - 1);
-        if (context == nonempty) {
-            newline();
-        }
-        out.append(closeBracket);
-        return this;
-    }
-
-    /**
-     * Returns the value on the top of the stack.
-     */
-    private Scope peek() throws JSONException {
-        if (stack.isEmpty()) {
-            throw new JSONException("Nesting problem");
-        }
-        return stack.get(stack.size() - 1);
-    }
-
-    /**
-     * Replace the value on the top of the stack with the given value.
-     */
-    private void replaceTop(Scope topOfStack) {
-        stack.set(stack.size() - 1, topOfStack);
-    }
-
-    /**
-     * Encodes {@code value}.
-     *
-     * @param value a {@link JSONObject}, {@link JSONArray}, String, Boolean,
-     *              Integer, Long, Double or null. May not be {@link Double#isNaN() NaNs}
-     *              or {@link Double#isInfinite() infinities}.
-     * @return this stringer.
-     * @throws JSONException On internal errors. Shouldn't happen.
-     */
-    public JSONStringer value(Object value) throws JSONException {
-        if (stack.isEmpty()) {
-            throw new JSONException("Nesting problem");
-        }
-
-        if (value instanceof JSONArray) {
-            ((JSONArray) value).writeTo(this);
-            return this;
-
-        } else if (value instanceof JSONObject) {
-            ((JSONObject) value).writeTo(this);
-            return this;
-        }
-
-        beforeValue();
-
-        if (value instanceof JSONString) {
-          out.append(((JSONString) value).toJSONString());
-          return this;
-        }
-
-        if (value == null
-              || value instanceof Boolean
-              || value == JSONObject.NULL) {
-            out.append(value);
-
-        } else if (value instanceof Number) {
-            out.append(JSONObject.numberToString((Number) value));
-
-        } else {
-            // Hack to make it possible that the value is not surrounded by quotes. (Used for JavaScript function calls)
-            // Example: { "name": "testkey", "value": window.myfunction() }
-            if (value.getClass().getSimpleName().contains("JSONFunction")) {
-                // note that no escaping of quotes (or anything else) is done in this case.
-                // that is fine because the only way to get to this point is to
-                // explicitly put a special kind of object into the JSON data structure.
-                out.append(value);
-            } else {
-                string(value.toString());
-            }
-        }
-
-        return this;
-    }
-
-    /**
-     * Encodes {@code value} to this stringer.
-     *
-     * @param value The value to encode.
-     * @return this stringer.
-     * @throws JSONException On internal errors. Shouldn't happen.
-     */
-    public JSONStringer value(boolean value) throws JSONException {
-        if (stack.isEmpty()) {
-            throw new JSONException("Nesting problem");
-        }
-        beforeValue();
-        out.append(value);
-        return this;
-    }
-
-    /**
-     * Encodes {@code value} to this stringer.
-     *
-     * @param value a finite value. May not be {@link Double#isNaN() NaNs} or
-     *              {@link Double#isInfinite() infinities}.
-     * @return this stringer.
-     * @throws JSONException On internal errors. Shouldn't happen.
-     */
-    public JSONStringer value(double value) throws JSONException {
-        if (stack.isEmpty()) {
-            throw new JSONException("Nesting problem");
-        }
-        beforeValue();
-        out.append(JSONObject.numberToString(value));
-        return this;
-    }
-
-    /**
-     * Encodes {@code value} to this stringer.
-     *
-     * @param value The value to encode.
-     * @return this stringer.
-     * @throws JSONException If we have an internal error. Shouldn't happen.
-     */
-    public JSONStringer value(long value) throws JSONException {
-        if (stack.isEmpty()) {
-            throw new JSONException("Nesting problem");
-        }
-        beforeValue();
-        out.append(value);
-        return this;
-    }
-
-    private void string(String value) {
-        out.append("\"");
-        char currentChar = 0;
-
-        for (int i = 0, length = value.length(); i < length; i++) {
-            char previousChar = currentChar;
-            currentChar = value.charAt(i);
-
-            /*
-             * From RFC 4627, "All Unicode characters may be placed within the
-             * quotation marks except for the characters that must be escaped:
-             * quotation mark, reverse solidus, and the control characters
-             * (U+0000 through U+001F)."
-             */
-            switch (currentChar) {
-                case '"':
-                case '\\':
-                    out.append('\\').append(currentChar);
-                    break;
-
-                case '/':
-                    // it makes life easier for HTML embedding of javascript if we escape </ sequences
-                    if (previousChar == '<') {
-                        out.append('\\');
-                    }
-                    out.append(currentChar);
-                    break;
-
-                case '\t':
-                    out.append("\\t");
-                    break;
-
-                case '\b':
-                    out.append("\\b");
-                    break;
-
-                case '\n':
-                    out.append("\\n");
-                    break;
-
-                case '\r':
-                    out.append("\\r");
-                    break;
-
-                case '\f':
-                    out.append("\\f");
-                    break;
-
-                default:
-                    if (currentChar <= 0x1F) {
-                        out.append(String.format("\\u%04x", (int) currentChar));
-                    } else {
-                        out.append(currentChar);
-                    }
-                    break;
-            }
-
-        }
-        out.append("\"");
-    }
-
-    private void newline() {
-        if (indent == null) {
-            return;
-        }
-
-        out.append("\n");
-        for (int i = 0; i < stack.size(); i++) {
-            out.append(indent);
-        }
-    }
-
-    /**
-     * Encodes the key (property name) to this stringer.
-     *
-     * @param name the name of the forthcoming value. May not be null.
-     * @return this stringer.
-     * @throws JSONException on internal errors, shouldn't happen.
-     */
-    public JSONStringer key(String name) throws JSONException {
-        if (name == null) {
-            throw new JSONException("Names must be non-null");
-        }
-        beforeKey();
-        string(name);
-        return this;
-    }
-
-    /**
-     * Inserts any necessary separators and whitespace before a name. Also
-     * adjusts the stack to expect the key's value.
-     */
-    private void beforeKey() throws JSONException {
-        Scope context = peek();
-        if (context == Scope.NONEMPTY_OBJECT) { // first in object
-            out.append(',');
-        } else if (context != Scope.EMPTY_OBJECT) { // not in an object!
-            throw new JSONException("Nesting problem");
-        }
-        newline();
-        replaceTop(Scope.DANGLING_KEY);
-    }
-
-    /**
-     * Inserts any necessary separators and whitespace before a literal value,
-     * inline array, or inline object. Also adjusts the stack to expect either a
-     * closing bracket or another element.
-     */
-    private void beforeValue() throws JSONException {
-        if (stack.isEmpty()) {
-            return;
-        }
-
-        Scope context = peek();
-        if (context == Scope.EMPTY_ARRAY) { // first in array
-            replaceTop(Scope.NONEMPTY_ARRAY);
-            newline();
-        } else if (context == Scope.NONEMPTY_ARRAY) { // another in array
-            out.append(',');
-            newline();
-        } else if (context == Scope.DANGLING_KEY) { // value for key
-            out.append(indent == null ? ":" : ": ");
-            replaceTop(Scope.NONEMPTY_OBJECT);
-        } else if (context != Scope.NULL) {
-            throw new JSONException("Nesting problem");
-        }
-    }
-
-    /**
-     * Returns the encoded JSON string.
-     *
-     * <p>If invoked with unterminated arrays or unclosed objects, this method's
-     * return value is undefined.
-     *
-     * <p><strong>Warning:</strong> although it contradicts the general contract
-     * of {@link Object#toString}, this method returns null if the stringer
-     * contains no data.
-     */
-    @Override
-    public String toString() {
-        return out.length() == 0 ? null : out.toString();
-    }
+public class JSONStringer extends JSONWriter {
+  /**
+   * Make a fresh JSONStringer. It can be used to build one JSON text.
+   */
+  public JSONStringer() {
+    super(new StringWriter());
+  }
+
+  /**
+   * Return the JSON text. This method is used to obtain the product of the JSONStringer instance.
+   * It will return <code>null</code> if there was a problem in the construction of the JSON text
+   * (such as the calls to <code>array</code> were not properly balanced with calls to
+   * <code>endArray</code>).
+   * 
+   * @return The JSON text.
+   */
+  public String toString() {
+    return this.mode == 'd' ? this.writer.toString() : null;
+  }
 }

http://git-wip-us.apache.org/repos/asf/geode/blob/0805036e/geode-json/src/main/java/org/json/JSONTokener.java
----------------------------------------------------------------------
diff --git a/geode-json/src/main/java/org/json/JSONTokener.java b/geode-json/src/main/java/org/json/JSONTokener.java
old mode 100755
new mode 100644
index 59eb4bc..4dd2ba2
--- a/geode-json/src/main/java/org/json/JSONTokener.java
+++ b/geode-json/src/main/java/org/json/JSONTokener.java
@@ -1,658 +1,437 @@
-/*
- * 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.json;
 
-// Note: this class was written without inspecting the non-free org.json sourcecode.
-
+import java.io.BufferedReader;
 import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
 import java.io.Reader;
+import java.io.StringReader;
+
+/*
+ * 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.
+ */
 
 /**
- * Parses a JSON (<a href="http://www.ietf.org/rfc/rfc4627.txt">RFC 4627</a>)
- * encoded string into the corresponding object. Most clients of
- * this class will use only need the {@link #JSONTokener(String) constructor}
- * and {@link #nextValue} method. Example usage: <pre>
- * String json = "{"
- *         + "  \"query\": \"Pizza\", "
- *         + "  \"locations\": [ 94043, 90210 ] "
- *         + "}";
- *
- * JSONObject object = (JSONObject) new JSONTokener(json).nextValue();
- * String query = object.getString("query");
- * JSONArray locations = object.getJSONArray("locations");</pre>
- *
- * <p>For best interoperability and performance use JSON that complies with
- * RFC 4627, such as that generated by {@link JSONStringer}. For legacy reasons
- * this parser is lenient, so a successful parse does not indicate that the
- * input string was valid JSON. All of the following syntax errors will be
- * ignored:
- * <ul>
- * <li>End of line comments starting with {@code //} or {@code #} and ending
- * with a newline character.
- * <li>C-style comments starting with {@code /*} and ending with
- * {@code *}{@code /}. Such comments may not be nested.
- * <li>Strings that are unquoted or {@code 'single quoted'}.
- * <li>Hexadecimal integers prefixed with {@code 0x} or {@code 0X}.
- * <li>Octal integers prefixed with {@code 0}.
- * <li>Array elements separated by {@code ;}.
- * <li>Unnecessary array separators. These are interpreted as if null was the
- * omitted value.
- * <li>Key-value pairs separated by {@code =} or {@code =>}.
- * <li>Key-value pairs separated by {@code ;}.
- * </ul>
- *
- * <p>Each tokener may be used to parse a single JSON string. Instances of this
- * class are not thread safe. Although this class is nonfinal, it was not
- * designed for inheritance and should not be subclassed. In particular,
- * self-use by overrideable methods is not specified. See <i>Effective Java</i>
- * Item 17, "Design and Document or inheritance or else prohibit it" for further
- * information.
+ * A JSONTokener takes a source string and extracts characters and tokens from it. It is used by the
+ * JSONObject and JSONArray constructors to parse JSON source strings.
+ * 
+ * @author JSON.org
+ * @version 2012-02-16
  */
 public class JSONTokener {
 
-    /**
-     * The input JSON.
-     */
-    private final String in;
-
-    /**
-     * The index of the next character to be returned by {@link #next}. When
-     * the input is exhausted, this equals the input's length.
-     */
-    private int pos;
-
-    /**
-     * @param in JSON encoded string. Null is not permitted and will yield a
-     *           tokener that throws {@code NullPointerExceptions} when methods are
-     *           called.
-     */
-    public JSONTokener(String in) {
-        // consume an optional byte order mark (BOM) if it exists
-        if (in != null && in.startsWith("\ufeff")) {
-            in = in.substring(1);
-        }
-        this.in = in;
+  private long character;
+  private boolean eof;
+  private long index;
+  private long line;
+  private char previous;
+  private Reader reader;
+  private boolean usePrevious;
+
+
+  /**
+   * Construct a JSONTokener from a Reader.
+   *
+   * @param reader A reader.
+   */
+  public JSONTokener(Reader reader) {
+    this.reader = reader.markSupported() ? reader : new BufferedReader(reader);
+    this.eof = false;
+    this.usePrevious = false;
+    this.previous = 0;
+    this.index = 0;
+    this.character = 1;
+    this.line = 1;
+  }
+
+
+  /**
+   * Construct a JSONTokener from an InputStream.
+   */
+  public JSONTokener(InputStream inputStream) throws JSONException {
+    this(new InputStreamReader(inputStream));
+  }
+
+
+  /**
+   * Construct a JSONTokener from a string.
+   *
+   * @param s A source string.
+   */
+  public JSONTokener(String s) {
+    this(new StringReader(s));
+  }
+
+
+  /**
+   * Back up one character. This provides a sort of lookahead capability, so that you can test for a
+   * digit or letter before attempting to parse the next number or identifier.
+   */
+  public void back() throws JSONException {
+    if (this.usePrevious || this.index <= 0) {
+      throw new JSONException("Stepping back two steps is not supported");
     }
-
-    public JSONTokener(Reader input) throws IOException {
-        StringBuilder s = new StringBuilder();
-        char[] readBuf = new char[102400];
-        int n = input.read(readBuf);
-        while (n >= 0) {
-            s.append(readBuf, 0, n);
-            n = input.read(readBuf);
-        }
-        in = s.toString();
-        pos = 0;
+    this.index -= 1;
+    this.character -= 1;
+    this.usePrevious = true;
+    this.eof = false;
+  }
+
+
+  /**
+   * Get the hex value of a character (base16).
+   * 
+   * @param c A character between '0' and '9' or between 'A' and 'F' or between 'a' and 'f'.
+   * @return An int between 0 and 15, or -1 if c was not a hex digit.
+   */
+  public static int dehexchar(char c) {
+    if (c >= '0' && c <= '9') {
+      return c - '0';
     }
-
-    /**
-     * Returns the next value from the input.
-     *
-     * @return a {@link JSONObject}, {@link JSONArray}, String, Boolean,
-     * Integer, Long, Double or {@link JSONObject#NULL}.
-     * @throws JSONException if the input is malformed.
-     */
-    public Object nextValue() throws JSONException {
-        int c = nextCleanInternal();
-        switch (c) {
-            case -1:
-                throw syntaxError("End of input");
-
-            case '{':
-                return readObject();
-
-            case '[':
-                return readArray();
-
-            case '\'':
-            case '"':
-                return nextString((char) c);
-
-            default:
-                pos--;
-                return readLiteral();
-        }
+    if (c >= 'A' && c <= 'F') {
+      return c - ('A' - 10);
     }
-
-    private int nextCleanInternal() throws JSONException {
-        while (pos < in.length()) {
-            int c = in.charAt(pos++);
-            switch (c) {
-                case '\t':
-                case ' ':
-                case '\n':
-                case '\r':
-                    continue;
-
-                case '/':
-                    if (pos == in.length()) {
-                        return c;
-                    }
-
-                    char peek = in.charAt(pos);
-                    switch (peek) {
-                        case '*':
-                            // skip a /* c-style comment */
-                            pos++;
-                            int commentEnd = in.indexOf("*/", pos);
-                            if (commentEnd == -1) {
-                                throw syntaxError("Unterminated comment");
-                            }
-                            pos = commentEnd + 2;
-                            continue;
-
-                        case '/':
-                            // skip a // end-of-line comment
-                            pos++;
-                            skipToEndOfLine();
-                            continue;
-
-                        default:
-                            return c;
-                    }
-
-                case '#':
-                    /*
-                     * Skip a # hash end-of-line comment. The JSON RFC doesn't
-                     * specify this behavior, but it's required to parse
-                     * existing documents. See http://b/2571423.
-                     */
-                    skipToEndOfLine();
-                    continue;
-
-                default:
-                    return c;
-            }
-        }
-
-        return -1;
+    if (c >= 'a' && c <= 'f') {
+      return c - ('a' - 10);
     }
-
-    /**
-     * Advances the position until after the next newline character. If the line
-     * is terminated by "\r\n", the '\n' must be consumed as whitespace by the
-     * caller.
-     */
-    private void skipToEndOfLine() {
-        for (; pos < in.length(); pos++) {
-            char c = in.charAt(pos);
-            if (c == '\r' || c == '\n') {
-                pos++;
-                break;
-            }
-        }
+    return -1;
+  }
+
+  public boolean end() {
+    return this.eof && !this.usePrevious;
+  }
+
+
+  /**
+   * Determine if the source string still contains characters that next() can consume.
+   * 
+   * @return true if not yet at the end of the source.
+   */
+  public boolean more() throws JSONException {
+    this.next();
+    if (this.end()) {
+      return false;
     }
-
-    /**
-     * Returns the string up to but not including {@code quote}, unescaping any
-     * character escape sequences encountered along the way. The opening quote
-     * should have already been read. This consumes the closing quote, but does
-     * not include it in the returned string.
-     *
-     * @param quote either ' or ".
-     * @return The unescaped string.
-     * @throws JSONException if the string isn't terminated by a closing quote correctly.
-     */
-    public String nextString(char quote) throws JSONException {
-        /*
-         * For strings that are free of escape sequences, we can just extract
-         * the result as a substring of the input. But if we encounter an escape
-         * sequence, we need to use a StringBuilder to compose the result.
-         */
-        StringBuilder builder = null;
-
-        /* the index of the first character not yet appended to the builder. */
-        int start = pos;
-
-        while (pos < in.length()) {
-            int c = in.charAt(pos++);
-            if (c == quote) {
-                if (builder == null) {
-                    // a new string avoids leaking memory
-                    //noinspection RedundantStringConstructorCall
-                    return new String(in.substring(start, pos - 1));
-                } else {
-                    builder.append(in, start, pos - 1);
-                    return builder.toString();
-                }
-            }
-
-            if (c == '\\') {
-                if (pos == in.length()) {
-                    throw syntaxError("Unterminated escape sequence");
-                }
-                if (builder == null) {
-                    builder = new StringBuilder();
-                }
-                builder.append(in, start, pos - 1);
-                builder.append(readEscapeCharacter());
-                start = pos;
-            }
-        }
-
-        throw syntaxError("Unterminated string");
+    this.back();
+    return true;
+  }
+
+
+  /**
+   * Get the next character in the source string.
+   *
+   * @return The next character, or 0 if past the end of the source string.
+   */
+  public char next() throws JSONException {
+    int c;
+    if (this.usePrevious) {
+      this.usePrevious = false;
+      c = this.previous;
+    } else {
+      try {
+        c = this.reader.read();
+      } catch (IOException exception) {
+        throw new JSONException(exception);
+      }
+
+      if (c <= 0) { // End of stream
+        this.eof = true;
+        c = 0;
+      }
+    }
+    this.index += 1;
+    if (this.previous == '\r') {
+      this.line += 1;
+      this.character = c == '\n' ? 0 : 1;
+    } else if (c == '\n') {
+      this.line += 1;
+      this.character = 0;
+    } else {
+      this.character += 1;
+    }
+    this.previous = (char) c;
+    return this.previous;
+  }
+
+
+  /**
+   * Consume the next character, and check that it matches a specified character.
+   * 
+   * @param c The character to match.
+   * @return The character.
+   * @throws JSONException if the character does not match.
+   */
+  public char next(char c) throws JSONException {
+    char n = this.next();
+    if (n != c) {
+      throw this.syntaxError("Expected '" + c + "' and instead saw '" + n + "'");
+    }
+    return n;
+  }
+
+
+  /**
+   * Get the next n characters.
+   *
+   * @param n The number of characters to take.
+   * @return A string of n characters.
+   * @throws JSONException Substring bounds error if there are not n characters remaining in the
+   *         source string.
+   */
+  public String next(int n) throws JSONException {
+    if (n == 0) {
+      return "";
     }
 
-    /**
-     * Unescapes the character identified by the character or characters that
-     * immediately follow a backslash. The backslash '\' should have already
-     * been read. This supports both unicode escapes "u000A" and two-character
-     * escapes "\n".
-     */
-    private char readEscapeCharacter() throws JSONException {
-        char escaped = in.charAt(pos++);
-        switch (escaped) {
-            case 'u':
-                if (pos + 4 > in.length()) {
-                    throw syntaxError("Unterminated escape sequence");
-                }
-                String hex = in.substring(pos, pos + 4);
-                pos += 4;
-                try {
-                    return (char) Integer.parseInt(hex, 16);
-                } catch (NumberFormatException nfe) {
-                    throw syntaxError("Invalid escape sequence: " + hex);
-                }
-
-            case 't':
-                return '\t';
+    char[] chars = new char[n];
+    int pos = 0;
 
+    while (pos < n) {
+      chars[pos] = this.next();
+      if (this.end()) {
+        throw this.syntaxError("Substring bounds error");
+      }
+      pos += 1;
+    }
+    return new String(chars);
+  }
+
+
+  /**
+   * Get the next char in the string, skipping whitespace.
+   * 
+   * @throws JSONException
+   * @return A character, or 0 if there are no more characters.
+   */
+  public char nextClean() throws JSONException {
+    for (;;) {
+      char c = this.next();
+      if (c == 0 || c > ' ') {
+        return c;
+      }
+    }
+  }
+
+
+  /**
+   * Return the characters up to the next close quote character. Backslash processing is done. The
+   * formal JSON format does not allow strings in single quotes, but an implementation is allowed to
+   * accept them.
+   * 
+   * @param quote The quoting character, either <code>"</code>&nbsp;<small>(double quote)</small> or
+   *        <code>'</code>&nbsp;<small>(single quote)</small>.
+   * @return A String.
+   * @throws JSONException Unterminated string.
+   */
+  public String nextString(char quote) throws JSONException {
+    char c;
+    StringBuffer sb = new StringBuffer();
+    for (;;) {
+      c = this.next();
+      switch (c) {
+        case 0:
+        case '\n':
+        case '\r':
+          throw this.syntaxError("Unterminated string");
+        case '\\':
+          c = this.next();
+          switch (c) {
             case 'b':
-                return '\b';
-
+              sb.append('\b');
+              break;
+            case 't':
+              sb.append('\t');
+              break;
             case 'n':
-                return '\n';
-
-            case 'r':
-                return '\r';
-
+              sb.append('\n');
+              break;
             case 'f':
-                return '\f';
-
-            case '\'':
+              sb.append('\f');
+              break;
+            case 'r':
+              sb.append('\r');
+              break;
+            case 'u':
+              sb.append((char) Integer.parseInt(this.next(4), 16));
+              break;
             case '"':
+            case '\'':
             case '\\':
+            case '/':
+              sb.append(c);
+              break;
             default:
-                return escaped;
-        }
-    }
-
-    /**
-     * Reads a null, boolean, numeric or unquoted string literal value. Numeric
-     * values will be returned as an Integer, Long, or Double, in that order of
-     * preference.
-     */
-    private Object readLiteral() throws JSONException {
-        String literal = nextToInternal("{}[]/\\:,=;# \t\f");
-
-        if (literal.length() == 0) {
-            throw syntaxError("Expected literal value");
-        } else if ("null".equalsIgnoreCase(literal)) {
-            return JSONObject.NULL;
-        } else if ("true".equalsIgnoreCase(literal)) {
-            return Boolean.TRUE;
-        } else if ("false".equalsIgnoreCase(literal)) {
-            return Boolean.FALSE;
-        }
-
-        /* try to parse as an integral type... */
-        if (literal.indexOf('.') == -1) {
-            int base = 10;
-            String number = literal;
-            if (number.startsWith("0x") || number.startsWith("0X")) {
-                number = number.substring(2);
-                base = 16;
-            } else if (number.startsWith("0") && number.length() > 1) {
-                number = number.substring(1);
-                base = 8;
-            }
-            try {
-                long longValue = Long.parseLong(number, base);
-                if (longValue <= Integer.MAX_VALUE && longValue >= Integer.MIN_VALUE) {
-                    return (int) longValue;
-                } else {
-                    return longValue;
-                }
-            } catch (NumberFormatException e) {
-                /*
-                 * This only happens for integral numbers greater than
-                 * Long.MAX_VALUE, numbers in exponential form (5e-10) and
-                 * unquoted strings. Fall through to try floating point.
-                 */
-            }
-        }
-
-        /* ...next try to parse as a floating point... */
-        try {
-            return Double.valueOf(literal);
-        } catch (NumberFormatException ignored) {
-        }
-
-        /* ... finally give up. We have an unquoted string */
-        //noinspection RedundantStringConstructorCall
-        return new String(literal); // a new string avoids leaking memory
-    }
-
-    /**
-     * Returns the string up to but not including any of the given characters or
-     * a newline character. This does not consume the excluded character.
-     */
-    private String nextToInternal(String excluded) {
-        int start = pos;
-        for (; pos < in.length(); pos++) {
-            char c = in.charAt(pos);
-            if (c == '\r' || c == '\n' || excluded.indexOf(c) != -1) {
-                return in.substring(start, pos);
-            }
-        }
-        return in.substring(start);
+              throw this.syntaxError("Illegal escape.");
+          }
+          break;
+        default:
+          if (c == quote) {
+            return sb.toString();
+          }
+          sb.append(c);
+      }
     }
-
-    /**
-     * Reads a sequence of key/value pairs and the trailing closing brace '}' of
-     * an object. The opening brace '{' should have already been read.
-     */
-    private JSONObject readObject() throws JSONException {
-        JSONObject result = new JSONObject();
-
-        /* Peek to see if this is the empty object. */
-        int first = nextCleanInternal();
-        if (first == '}') {
-            return result;
-        } else if (first != -1) {
-            pos--;
-        }
-
-        while (true) {
-            Object name = nextValue();
-            if (!(name instanceof String)) {
-                if (name == null) {
-                    throw syntaxError("Names cannot be null");
-                } else {
-                    throw syntaxError("Names must be strings, but " + name
-                            + " is of type " + name.getClass().getName());
-                }
-            }
-
-            /*
-             * Expect the name/value separator to be either a colon ':', an
-             * equals sign '=', or an arrow "=>". The last two are bogus but we
-             * include them because that's what the original implementation did.
-             */
-            int separator = nextCleanInternal();
-            if (separator != ':' && separator != '=') {
-                throw syntaxError("Expected ':' after " + name);
-            }
-            if (pos < in.length() && in.charAt(pos) == '>') {
-                pos++;
-            }
-
-            result.put((String) name, nextValue());
-
-            switch (nextCleanInternal()) {
-                case '}':
-                    return result;
-                case ';':
-                case ',':
-                    continue;
-                default:
-                    throw syntaxError("Unterminated object");
-            }
+  }
+
+
+  /**
+   * Get the text up but not including the specified character or the end of line, whichever comes
+   * first.
+   * 
+   * @param delimiter A delimiter character.
+   * @return A string.
+   */
+  public String nextTo(char delimiter) throws JSONException {
+    StringBuffer sb = new StringBuffer();
+    for (;;) {
+      char c = this.next();
+      if (c == delimiter || c == 0 || c == '\n' || c == '\r') {
+        if (c != 0) {
+          this.back();
         }
+        return sb.toString().trim();
+      }
+      sb.append(c);
     }
-
-    /**
-     * Reads a sequence of values and the trailing closing brace ']' of an
-     * array. The opening brace '[' should have already been read. Note that
-     * "[]" yields an empty array, but "[,]" returns a two-element array
-     * equivalent to "[null,null]".
-     */
-    private JSONArray readArray() throws JSONException {
-        JSONArray result = new JSONArray();
-
-        /* to cover input that ends with ",]". */
-        boolean hasTrailingSeparator = false;
-
-        while (true) {
-            switch (nextCleanInternal()) {
-                case -1:
-                    throw syntaxError("Unterminated array");
-                case ']':
-                    if (hasTrailingSeparator) {
-                        result.put(null);
-                    }
-                    return result;
-                case ',':
-                case ';':
-                    /* A separator without a value first means "null". */
-                    result.put(null);
-                    hasTrailingSeparator = true;
-                    continue;
-                default:
-                    pos--;
-            }
-
-            result.put(nextValue());
-
-            switch (nextCleanInternal()) {
-                case ']':
-                    return result;
-                case ',':
-                case ';':
-                    hasTrailingSeparator = true;
-                    continue;
-                default:
-                    throw syntaxError("Unterminated array");
-            }
+  }
+
+
+  /**
+   * Get the text up but not including one of the specified delimiter characters or the end of line,
+   * whichever comes first.
+   * 
+   * @param delimiters A set of delimiter characters.
+   * @return A string, trimmed.
+   */
+  public String nextTo(String delimiters) throws JSONException {
+    char c;
+    StringBuffer sb = new StringBuffer();
+    for (;;) {
+      c = this.next();
+      if (delimiters.indexOf(c) >= 0 || c == 0 || c == '\n' || c == '\r') {
+        if (c != 0) {
+          this.back();
         }
+        return sb.toString().trim();
+      }
+      sb.append(c);
     }
-
-    /**
-     * Returns an exception containing the given message plus the current
-     * position and the entire input string.
-     *
-     * @param message The message we want to include.
-     * @return An exception that we can throw.
-     */
-    public JSONException syntaxError(String message) {
-        return new JSONException(message + this);
-    }
-
-    /**
-     * Returns the current position and the entire input string.
-     */
-    @Override
-    public String toString() {
-        // consistent with the original implementation
-        return " at character " + pos + " of " + in;
+  }
+
+
+  /**
+   * Get the next value. The value can be a Boolean, Double, Integer, JSONArray, JSONObject, Long,
+   * or String, or the JSONObject.NULL object.
+   * 
+   * @throws JSONException If syntax error.
+   *
+   * @return An object.
+   */
+  public Object nextValue() throws JSONException {
+    char c = this.nextClean();
+    String string;
+
+    switch (c) {
+      case '"':
+      case '\'':
+        return this.nextString(c);
+      case '{':
+        this.back();
+        return new JSONObject(this);
+      case '[':
+        this.back();
+        return new JSONArray(this);
     }
 
     /*
-     * Legacy APIs.
+     * Handle unquoted text. This could be the values true, false, or null, or it can be a number.
+     * An implementation (such as this one) is allowed to also accept non-standard forms.
      *
-     * None of the methods below are on the critical path of parsing JSON
-     * documents. They exist only because they were exposed by the original
-     * implementation and may be used by some clients.
+     * Accumulate characters until we reach the end of the text or a formatting character.
      */
 
-    /**
-     * Returns true until the input has been exhausted.
-     *
-     * @return true if more input exists.
-     */
-    public boolean more() {
-        return pos < in.length();
+    StringBuffer sb = new StringBuffer();
+    while (c >= ' ' && ",:]}/\\\"[{;=#".indexOf(c) < 0) {
+      sb.append(c);
+      c = this.next();
     }
+    this.back();
 
-    /**
-     * Returns the next available character, or the null character '\0' if all
-     * input has been exhausted. The return value of this method is ambiguous
-     * for JSON strings that contain the character '\0'.
-     *
-     * @return the next character.
-     */
-    public char next() {
-        return pos < in.length() ? in.charAt(pos++) : '\0';
+    string = sb.toString().trim();
+    if ("".equals(string)) {
+      throw this.syntaxError("Missing value");
     }
-
-    /**
-     * Returns the next available character if it equals {@code c}. Otherwise an
-     * exception is thrown.
-     *
-     * @param c The character we are looking for.
-     * @return the next character.
-     * @throws JSONException If the next character isn't {@code c}
-     */
-    public char next(char c) throws JSONException {
-        char result = next();
-        if (result != c) {
-            throw syntaxError("Expected " + c + " but was " + result);
+    return JSONObject.stringToValue(string);
+  }
+
+
+  /**
+   * Skip characters until the next character is the requested character. If the requested character
+   * is not found, no characters are skipped.
+   * 
+   * @param to A character to skip to.
+   * @return The requested character, or zero if the requested character is not found.
+   */
+  public char skipTo(char to) throws JSONException {
+    char c;
+    try {
+      long startIndex = this.index;
+      long startCharacter = this.character;
+      long startLine = this.line;
+      this.reader.mark(1000000);
+      do {
+        c = this.next();
+        if (c == 0) {
+          this.reader.reset();
+          this.index = startIndex;
+          this.character = startCharacter;
+          this.line = startLine;
+          return c;
         }
-        return result;
-    }
-
-    /**
-     * Returns the next character that is not whitespace and does not belong to
-     * a comment. If the input is exhausted before such a character can be
-     * found, the null character '\0' is returned. The return value of this
-     * method is ambiguous for JSON strings that contain the character '\0'.
-     *
-     * @return The next non-whitespace character.
-     * @throws JSONException Should not be possible.
-     */
-    public char nextClean() throws JSONException {
-        int nextCleanInt = nextCleanInternal();
-        return nextCleanInt == -1 ? '\0' : (char) nextCleanInt;
+      } while (c != to);
+    } catch (IOException exc) {
+      throw new JSONException(exc);
     }
 
-    /**
-     * Returns the next {@code length} characters of the input.
-     *
-     * <p>The returned string shares its backing character array with this
-     * tokener's input string. If a reference to the returned string may be held
-     * indefinitely, you should use {@code new String(result)} to copy it first
-     * to avoid memory leaks.
-     *
-     * @param length The desired number of characters to return.
-     * @return The next few characters.
-     * @throws JSONException if the remaining input is not long enough to
-     *                       satisfy this request.
-     */
-    public String next(int length) throws JSONException {
-        if (pos + length > in.length()) {
-            throw syntaxError(length + " is out of bounds");
-        }
-        String result = in.substring(pos, pos + length);
-        pos += length;
-        return result;
-    }
-
-    /**
-     * Returns the {@link String#trim trimmed} string holding the characters up
-     * to but not including the first of:
-     * <ul>
-     * <li>any character in {@code excluded}
-     * <li>a newline character '\n'
-     * <li>a carriage return '\r'
-     * </ul>
-     *
-     * <p>The returned string shares its backing character array with this
-     * tokener's input string. If a reference to the returned string may be held
-     * indefinitely, you should use {@code new String(result)} to copy it first
-     * to avoid memory leaks.
-     *
-     * @param excluded The limiting string where the search should stop.
-     * @return a possibly-empty string
-     */
-    public String nextTo(String excluded) {
-        if (excluded == null) {
-            throw new NullPointerException("excluded == null");
-        }
-        return nextToInternal(excluded).trim();
-    }
-
-    /**
-     * Equivalent to {@code nextTo(String.valueOf(excluded))}.
-     *
-     * @param excluded The limiting character.
-     * @return a possibly-empty string
-     */
-    public String nextTo(char excluded) {
-        return nextToInternal(String.valueOf(excluded)).trim();
-    }
-
-    /**
-     * Advances past all input up to and including the next occurrence of
-     * {@code thru}. If the remaining input doesn't contain {@code thru}, the
-     * input is exhausted.
-     *
-     * @param thru The string to skip over.
-     */
-    public void skipPast(String thru) {
-        int thruStart = in.indexOf(thru, pos);
-        pos = thruStart == -1 ? in.length() : (thruStart + thru.length());
-    }
-
-    /**
-     * Advances past all input up to but not including the next occurrence of
-     * {@code to}. If the remaining input doesn't contain {@code to}, the input
-     * is unchanged.
-     *
-     * @param to The character we want to skip to.
-     * @return The value of {@code to} or null.
-     */
-    public char skipTo(char to) {
-        int index = in.indexOf(to, pos);
-        if (index != -1) {
-            pos = index;
-            return to;
-        } else {
-            return '\0';
-        }
-    }
-
-    /**
-     * Unreads the most recent character of input. If no input characters have
-     * been read, the input is unchanged.
-     */
-    public void back() {
-        if (--pos == -1) {
-            pos = 0;
-        }
-    }
-
-    /**
-     * Returns the integer [0..15] value for the given hex character, or -1
-     * for non-hex input.
-     *
-     * @param hex a character in the ranges [0-9], [A-F] or [a-f]. Any other
-     *            character will yield a -1 result.
-     * @return The decoded integer.
-     */
-    public static int dehexchar(char hex) {
-        if (hex >= '0' && hex <= '9') {
-            return hex - '0';
-        } else if (hex >= 'A' && hex <= 'F') {
-            return hex - 'A' + 10;
-        } else if (hex >= 'a' && hex <= 'f') {
-            return hex - 'a' + 10;
-        } else {
-            return -1;
-        }
-    }
+    this.back();
+    return c;
+  }
+
+
+  /**
+   * Make a JSONException to signal a syntax error.
+   *
+   * @param message The error message.
+   * @return A JSONException object, suitable for throwing
+   */
+  public JSONException syntaxError(String message) {
+    return new JSONException(message + this.toString());
+  }
+
+
+  /**
+   * Make a printable string of this JSONTokener.
+   *
+   * @return " at {index} [character {character} line {line}]"
+   */
+  public String toString() {
+    return " at " + this.index + " [character " + this.character + " line " + this.line + "]";
+  }
 }

http://git-wip-us.apache.org/repos/asf/geode/blob/0805036e/geode-json/src/main/java/org/json/JSONWriter.java
----------------------------------------------------------------------
diff --git a/geode-json/src/main/java/org/json/JSONWriter.java b/geode-json/src/main/java/org/json/JSONWriter.java
new file mode 100755
index 0000000..7d4704b
--- /dev/null
+++ b/geode-json/src/main/java/org/json/JSONWriter.java
@@ -0,0 +1,321 @@
+package org.json;
+
+import java.io.IOException;
+import java.io.Writer;
+
+/*
+ * Copyright (c) 2006 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.
+ */
+
+/**
+ * JSONWriter provides a quick and convenient way of producing JSON text. The texts produced
+ * strictly conform to JSON syntax rules. No whitespace is added, so the results are ready for
+ * transmission or storage. Each instance of JSONWriter can produce one JSON text.
+ * <p>
+ * A JSONWriter instance provides a <code>value</code> method for appending values to the text, and
+ * a <code>key</code> method for adding keys before values in objects. There are <code>array</code>
+ * and <code>endArray</code> methods that make and bound array values, and <code>object</code> and
+ * <code>endObject</code> methods which make and bound object values. All of these methods return
+ * the JSONWriter instance, permitting a cascade style. For example,
+ * 
+ * <pre>
+ * new JSONWriter(myWriter).object().key("JSON").value("Hello, World!").endObject();
+ * </pre>
+ * 
+ * which writes
+ * 
+ * <pre>
+ * {"JSON":"Hello, World!"}
+ * </pre>
+ * <p>
+ * The first method called must be <code>array</code> or <code>object</code>. There are no methods
+ * for adding commas or colons. JSONWriter adds them for you. Objects and arrays can be nested up to
+ * 20 levels deep.
+ * <p>
+ * This can sometimes be easier than using a JSONObject to build a string.
+ * 
+ * @author JSON.org
+ * @version 2011-11-24
+ */
+public class JSONWriter {
+  private static final int maxdepth = 200;
+
+  /**
+   * The comma flag determines if a comma should be output before the next value.
+   */
+  private boolean comma;
+
+  /**
+   * The current mode. Values: 'a' (array), 'd' (done), 'i' (initial), 'k' (key), 'o' (object).
+   */
+  protected char mode;
+
+  /**
+   * The object/array stack.
+   */
+  private final JSONObject stack[];
+
+  /**
+   * The stack top index. A value of 0 indicates that the stack is empty.
+   */
+  private int top;
+
+  /**
+   * The writer that will receive the output.
+   */
+  protected Writer writer;
+
+  /**
+   * Make a fresh JSONWriter. It can be used to build one JSON text.
+   */
+  public JSONWriter(Writer w) {
+    this.comma = false;
+    this.mode = 'i';
+    this.stack = new JSONObject[maxdepth];
+    this.top = 0;
+    this.writer = w;
+  }
+
+  /**
+   * Append a value.
+   * 
+   * @param string A string value.
+   * @return this
+   * @throws JSONException If the value is out of sequence.
+   */
+  private JSONWriter append(String string) throws JSONException {
+    if (string == null) {
+      throw new JSONException("Null pointer");
+    }
+    if (this.mode == 'o' || this.mode == 'a') {
+      try {
+        if (this.comma && this.mode == 'a') {
+          this.writer.write(',');
+        }
+        this.writer.write(string);
+      } catch (IOException e) {
+        throw new JSONException(e);
+      }
+      if (this.mode == 'o') {
+        this.mode = 'k';
+      }
+      this.comma = true;
+      return this;
+    }
+    throw new JSONException("Value out of sequence.");
+  }
+
+  /**
+   * Begin appending a new array. All values until the balancing <code>endArray</code> will be
+   * appended to this array. The <code>endArray</code> method must be called to mark the array's
+   * end.
+   * 
+   * @return this
+   * @throws JSONException If the nesting is too deep, or if the object is started in the wrong
+   *         place (for example as a key or after the end of the outermost array or object).
+   */
+  public JSONWriter array() throws JSONException {
+    if (this.mode == 'i' || this.mode == 'o' || this.mode == 'a') {
+      this.push(null);
+      this.append("[");
+      this.comma = false;
+      return this;
+    }
+    throw new JSONException("Misplaced array.");
+  }
+
+  /**
+   * End something.
+   * 
+   * @param mode Mode
+   * @param c Closing character
+   * @return this
+   * @throws JSONException If unbalanced.
+   */
+  private JSONWriter end(char mode, char c) throws JSONException {
+    if (this.mode != mode) {
+      throw new JSONException(mode == 'a' ? "Misplaced endArray." : "Misplaced endObject.");
+    }
+    this.pop(mode);
+    try {
+      this.writer.write(c);
+    } catch (IOException e) {
+      throw new JSONException(e);
+    }
+    this.comma = true;
+    return this;
+  }
+
+  /**
+   * End an array. This method most be called to balance calls to <code>array</code>.
+   * 
+   * @return this
+   * @throws JSONException If incorrectly nested.
+   */
+  public JSONWriter endArray() throws JSONException {
+    return this.end('a', ']');
+  }
+
+  /**
+   * End an object. This method most be called to balance calls to <code>object</code>.
+   * 
+   * @return this
+   * @throws JSONException If incorrectly nested.
+   */
+  public JSONWriter endObject() throws JSONException {
+    return this.end('k', '}');
+  }
+
+  /**
+   * Append a key. The key will be associated with the next value. In an object, every value must be
+   * preceded by a key.
+   * 
+   * @param string A key string.
+   * @return this
+   * @throws JSONException If the key is out of place. For example, keys do not belong in arrays or
+   *         if the key is null.
+   */
+  public JSONWriter key(String string) throws JSONException {
+    if (string == null) {
+      throw new JSONException("Null key.");
+    }
+    if (this.mode == 'k') {
+      try {
+        this.stack[this.top - 1].putOnce(string, Boolean.TRUE);
+        if (this.comma) {
+          this.writer.write(',');
+        }
+        this.writer.write(JSONObject.quote(string));
+        this.writer.write(':');
+        this.comma = false;
+        this.mode = 'o';
+        return this;
+      } catch (IOException e) {
+        throw new JSONException(e);
+      }
+    }
+    throw new JSONException("Misplaced key.");
+  }
+
+
+  /**
+   * Begin appending a new object. All keys and values until the balancing <code>endObject</code>
+   * will be appended to this object. The <code>endObject</code> method must be called to mark the
+   * object's end.
+   * 
+   * @return this
+   * @throws JSONException If the nesting is too deep, or if the object is started in the wrong
+   *         place (for example as a key or after the end of the outermost array or object).
+   */
+  public JSONWriter object() throws JSONException {
+    if (this.mode == 'i') {
+      this.mode = 'o';
+    }
+    if (this.mode == 'o' || this.mode == 'a') {
+      this.append("{");
+      this.push(new JSONObject());
+      this.comma = false;
+      return this;
+    }
+    throw new JSONException("Misplaced object.");
+
+  }
+
+
+  /**
+   * Pop an array or object scope.
+   * 
+   * @param c The scope to close.
+   * @throws JSONException If nesting is wrong.
+   */
+  private void pop(char c) throws JSONException {
+    if (this.top <= 0) {
+      throw new JSONException("Nesting error.");
+    }
+    char m = this.stack[this.top - 1] == null ? 'a' : 'k';
+    if (m != c) {
+      throw new JSONException("Nesting error.");
+    }
+    this.top -= 1;
+    this.mode = this.top == 0 ? 'd' : this.stack[this.top - 1] == null ? 'a' : 'k';
+  }
+
+  /**
+   * Push an array or object scope.
+   * 
+   * @param jo The scope to open.
+   * @throws JSONException If nesting is too deep.
+   */
+  private void push(JSONObject jo) throws JSONException {
+    if (this.top >= maxdepth) {
+      throw new JSONException("Nesting too deep.");
+    }
+    this.stack[this.top] = jo;
+    this.mode = jo == null ? 'a' : 'k';
+    this.top += 1;
+  }
+
+
+  /**
+   * Append either the value <code>true</code> or the value <code>false</code>.
+   * 
+   * @param b A boolean.
+   * @return this
+   * @throws JSONException
+   */
+  public JSONWriter value(boolean b) throws JSONException {
+    return this.append(b ? "true" : "false");
+  }
+
+  /**
+   * Append a double value.
+   * 
+   * @param d A double.
+   * @return this
+   * @throws JSONException If the number is not finite.
+   */
+  public JSONWriter value(double d) throws JSONException {
+    return this.value(new Double(d));
+  }
+
+  /**
+   * Append a long value.
+   * 
+   * @param l A long.
+   * @return this
+   * @throws JSONException
+   */
+  public JSONWriter value(long l) throws JSONException {
+    return this.append(Long.toString(l));
+  }
+
+
+  /**
+   * Append an object value.
+   * 
+   * @param object The object to append. It can be null, or a Boolean, Number, String, JSONObject,
+   *        or JSONArray, or an object that implements JSONString.
+   * @return this
+   * @throws JSONException If the value is out of sequence.
+   */
+  public JSONWriter value(Object object) throws JSONException {
+    return this.append(JSONObject.valueToString(object));
+  }
+}

http://git-wip-us.apache.org/repos/asf/geode/blob/0805036e/geode-json/src/main/java/org/json/XML.java
----------------------------------------------------------------------
diff --git a/geode-json/src/main/java/org/json/XML.java b/geode-json/src/main/java/org/json/XML.java
new file mode 100755
index 0000000..ae6d61a
--- /dev/null
+++ b/geode-json/src/main/java/org/json/XML.java
@@ -0,0 +1,504 @@
+package org.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.util.Iterator;
+
+
+/**
+ * This provides static methods to convert an XML text into a JSONObject, and to covert a JSONObject
+ * into an XML text.
+ * 
+ * @author JSON.org
+ * @version 2011-02-11
+ */
+public class XML {
+
+  /** The Character '&'. */
+  public static final Character AMP = new Character('&');
+
+  /** The Character '''. */
+  public static final Character APOS = new Character('\'');
+
+  /** The Character '!'. */
+  public static final Character BANG = new Character('!');
+
+  /** The Character '='. */
+  public static final Character EQ = new Character('=');
+
+  /** The Character '>'. */
+  public static final Character GT = new Character('>');
+
+  /** The Character '<'. */
+  public static final Character LT = new Character('<');
+
+  /** The Character '?'. */
+  public static final Character QUEST = new Character('?');
+
+  /** The Character '"'. */
+  public static final Character QUOT = new Character('"');
+
+  /** The Character '/'. */
+  public static final Character SLASH = new Character('/');
+
+  /**
+   * Replace special characters with XML escapes:
+   * 
+   * <pre>
+   * &amp; <small>(ampersand)</small> is replaced by &amp;amp;
+   * &lt; <small>(less than)</small> is replaced by &amp;lt;
+   * &gt; <small>(greater than)</small> is replaced by &amp;gt;
+   * &quot; <small>(double quote)</small> is replaced by &amp;quot;
+   * </pre>
+   * 
+   * @param string The string to be escaped.
+   * @return The escaped string.
+   */
+  public static String escape(String string) {
+    StringBuffer sb = new StringBuffer();
+    for (int i = 0, length = string.length(); i < length; i++) {
+      char c = string.charAt(i);
+      switch (c) {
+        case '&':
+          sb.append("&amp;");
+          break;
+        case '<':
+          sb.append("&lt;");
+          break;
+        case '>':
+          sb.append("&gt;");
+          break;
+        case '"':
+          sb.append("&quot;");
+          break;
+        case '\'':
+          sb.append("&apos;");
+          break;
+        default:
+          sb.append(c);
+      }
+    }
+    return sb.toString();
+  }
+
+  /**
+   * Throw an exception if the string contains whitespace. Whitespace is not allowed in tagNames and
+   * attributes.
+   * 
+   * @param string
+   * @throws JSONException
+   */
+  public static void noSpace(String string) throws JSONException {
+    int i, length = string.length();
+    if (length == 0) {
+      throw new JSONException("Empty string.");
+    }
+    for (i = 0; i < length; i += 1) {
+      if (Character.isWhitespace(string.charAt(i))) {
+        throw new JSONException("'" + string + "' contains a space character.");
+      }
+    }
+  }
+
+  /**
+   * Scan the content following the named tag, attaching it to the context.
+   * 
+   * @param x The XMLTokener containing the source string.
+   * @param context The JSONObject that will include the new material.
+   * @param name The tag name.
+   * @return true if the close tag is processed.
+   * @throws JSONException
+   */
+  private static boolean parse(XMLTokener x, JSONObject context, String name) throws JSONException {
+    char c;
+    int i;
+    JSONObject jsonobject = null;
+    String string;
+    String tagName;
+    Object token;
+
+    // Test for and skip past these forms:
+    // <!-- ... -->
+    // <! ... >
+    // <![ ... ]]>
+    // <? ... ?>
+    // Report errors for these forms:
+    // <>
+    // <=
+    // <<
+
+    token = x.nextToken();
+
+    // <!
+
+    if (token == BANG) {
+      c = x.next();
+      if (c == '-') {
+        if (x.next() == '-') {
+          x.skipPast("-->");
+          return false;
+        }
+        x.back();
+      } else if (c == '[') {
+        token = x.nextToken();
+        if ("CDATA".equals(token)) {
+          if (x.next() == '[') {
+            string = x.nextCDATA();
+            if (string.length() > 0) {
+              context.accumulate("content", string);
+            }
+            return false;
+          }
+        }
+        throw x.syntaxError("Expected 'CDATA['");
+      }
+      i = 1;
+      do {
+        token = x.nextMeta();
+        if (token == null) {
+          throw x.syntaxError("Missing '>' after '<!'.");
+        } else if (token == LT) {
+          i += 1;
+        } else if (token == GT) {
+          i -= 1;
+        }
+      } while (i > 0);
+      return false;
+    } else if (token == QUEST) {
+
+      // <?
+
+      x.skipPast("?>");
+      return false;
+    } else if (token == SLASH) {
+
+      // Close tag </
+
+      token = x.nextToken();
+      if (name == null) {
+        throw x.syntaxError("Mismatched close tag " + token);
+      }
+      if (!token.equals(name)) {
+        throw x.syntaxError("Mismatched " + name + " and " + token);
+      }
+      if (x.nextToken() != GT) {
+        throw x.syntaxError("Misshaped close tag");
+      }
+      return true;
+
+    } else if (token instanceof Character) {
+      throw x.syntaxError("Misshaped tag");
+
+      // Open tag <
+
+    } else {
+      tagName = (String) token;
+      token = null;
+      jsonobject = new JSONObject();
+      for (;;) {
+        if (token == null) {
+          token = x.nextToken();
+        }
+
+        // attribute = value
+
+        if (token instanceof String) {
+          string = (String) token;
+          token = x.nextToken();
+          if (token == EQ) {
+            token = x.nextToken();
+            if (!(token instanceof String)) {
+              throw x.syntaxError("Missing value");
+            }
+            jsonobject.accumulate(string, XML.stringToValue((String) token));
+            token = null;
+          } else {
+            jsonobject.accumulate(string, "");
+          }
+
+          // Empty tag <.../>
+
+        } else if (token == SLASH) {
+          if (x.nextToken() != GT) {
+            throw x.syntaxError("Misshaped tag");
+          }
+          if (jsonobject.length() > 0) {
+            context.accumulate(tagName, jsonobject);
+          } else {
+            context.accumulate(tagName, "");
+          }
+          return false;
+
+          // Content, between <...> and </...>
+
+        } else if (token == GT) {
+          for (;;) {
+            token = x.nextContent();
+            if (token == null) {
+              if (tagName != null) {
+                throw x.syntaxError("Unclosed tag " + tagName);
+              }
+              return false;
+            } else if (token instanceof String) {
+              string = (String) token;
+              if (string.length() > 0) {
+                jsonobject.accumulate("content", XML.stringToValue(string));
+              }
+
+              // Nested element
+
+            } else if (token == LT) {
+              if (parse(x, jsonobject, tagName)) {
+                if (jsonobject.length() == 0) {
+                  context.accumulate(tagName, "");
+                } else if (jsonobject.length() == 1 && jsonobject.opt("content") != null) {
+                  context.accumulate(tagName, jsonobject.opt("content"));
+                } else {
+                  context.accumulate(tagName, jsonobject);
+                }
+                return false;
+              }
+            }
+          }
+        } else {
+          throw x.syntaxError("Misshaped tag");
+        }
+      }
+    }
+  }
+
+
+  /**
+   * Try to convert a string into a number, boolean, or null. If the string can't be converted,
+   * return the string. This is much less ambitious than JSONObject.stringToValue, especially
+   * because it does not attempt to convert plus forms, octal forms, hex forms, or E forms lacking
+   * decimal points.
+   * 
+   * @param string A String.
+   * @return A simple JSON value.
+   */
+  public static Object stringToValue(String string) {
+    if ("".equals(string)) {
+      return string;
+    }
+    if ("true".equalsIgnoreCase(string)) {
+      return Boolean.TRUE;
+    }
+    if ("false".equalsIgnoreCase(string)) {
+      return Boolean.FALSE;
+    }
+    if ("null".equalsIgnoreCase(string)) {
+      return JSONObject.NULL;
+    }
+    if ("0".equals(string)) {
+      return new Integer(0);
+    }
+
+    // If it might be a number, try converting it. If that doesn't work,
+    // return the string.
+
+    try {
+      char initial = string.charAt(0);
+      boolean negative = false;
+      if (initial == '-') {
+        initial = string.charAt(1);
+        negative = true;
+      }
+      if (initial == '0' && string.charAt(negative ? 2 : 1) == '0') {
+        return string;
+      }
+      if ((initial >= '0' && initial <= '9')) {
+        if (string.indexOf('.') >= 0) {
+          return Double.valueOf(string);
+        } else if (string.indexOf('e') < 0 && string.indexOf('E') < 0) {
+          Long myLong = new Long(string);
+          if (myLong.longValue() == myLong.intValue()) {
+            return new Integer(myLong.intValue());
+          } else {
+            return myLong;
+          }
+        }
+      }
+    } catch (Exception ignore) {
+    }
+    return string;
+  }
+
+
+  /**
+   * Convert a well-formed (but not necessarily valid) XML string into a JSONObject. Some
+   * information may be lost in this transformation because JSON is a data format and XML is a
+   * document format. XML uses elements, attributes, and content text, while JSON uses unordered
+   * collections of name/value pairs and arrays of values. JSON does not does not like to
+   * distinguish between elements and attributes. Sequences of similar elements are represented as
+   * JSONArrays. Content text may be placed in a "content" member. Comments, prologs, DTDs, and
+   * <code>&lt;[ [ ]]></code> are ignored.
+   * 
+   * @param string The source string.
+   * @return A JSONObject containing the structured data from the XML string.
+   * @throws JSONException
+   */
+  public static JSONObject toJSONObject(String string) throws JSONException {
+    JSONObject jo = new JSONObject();
+    XMLTokener x = new XMLTokener(string);
+    while (x.more() && x.skipPast("<")) {
+      parse(x, jo, null);
+    }
+    return jo;
+  }
+
+
+  /**
+   * Convert a JSONObject into a well-formed, element-normal XML string.
+   * 
+   * @param object A JSONObject.
+   * @return A string.
+   * @throws JSONException
+   */
+  public static String toString(Object object) throws JSONException {
+    return toString(object, null);
+  }
+
+
+  /**
+   * Convert a JSONObject into a well-formed, element-normal XML string.
+   * 
+   * @param object A JSONObject.
+   * @param tagName The optional name of the enclosing tag.
+   * @return A string.
+   * @throws JSONException
+   */
+  public static String toString(Object object, String tagName) throws JSONException {
+    StringBuffer sb = new StringBuffer();
+    int i;
+    JSONArray ja;
+    JSONObject jo;
+    String key;
+    Iterator keys;
+    int length;
+    String string;
+    Object value;
+    if (object instanceof JSONObject) {
+
+      // Emit <tagName>
+
+      if (tagName != null) {
+        sb.append('<');
+        sb.append(tagName);
+        sb.append('>');
+      }
+
+      // Loop thru the keys.
+
+      jo = (JSONObject) object;
+      keys = jo.keys();
+      while (keys.hasNext()) {
+        key = keys.next().toString();
+        value = jo.opt(key);
+        if (value == null) {
+          value = "";
+        }
+        if (value instanceof String) {
+          string = (String) value;
+        } else {
+          string = null;
+        }
+
+        // Emit content in body
+
+        if ("content".equals(key)) {
+          if (value instanceof JSONArray) {
+            ja = (JSONArray) value;
+            length = ja.length();
+            for (i = 0; i < length; i += 1) {
+              if (i > 0) {
+                sb.append('\n');
+              }
+              sb.append(escape(ja.get(i).toString()));
+            }
+          } else {
+            sb.append(escape(value.toString()));
+          }
+
+          // Emit an array of similar keys
+
+        } else if (value instanceof JSONArray) {
+          ja = (JSONArray) value;
+          length = ja.length();
+          for (i = 0; i < length; i += 1) {
+            value = ja.get(i);
+            if (value instanceof JSONArray) {
+              sb.append('<');
+              sb.append(key);
+              sb.append('>');
+              sb.append(toString(value));
+              sb.append("</");
+              sb.append(key);
+              sb.append('>');
+            } else {
+              sb.append(toString(value, key));
+            }
+          }
+        } else if ("".equals(value)) {
+          sb.append('<');
+          sb.append(key);
+          sb.append("/>");
+
+          // Emit a new tag <k>
+
+        } else {
+          sb.append(toString(value, key));
+        }
+      }
+      if (tagName != null) {
+
+        // Emit the </tagname> close tag
+
+        sb.append("</");
+        sb.append(tagName);
+        sb.append('>');
+      }
+      return sb.toString();
+
+      // XML does not have good support for arrays. If an array appears in a place
+      // where XML is lacking, synthesize an <array> element.
+
+    } else {
+      if (object.getClass().isArray()) {
+        object = new JSONArray(object);
+      }
+      if (object instanceof JSONArray) {
+        ja = (JSONArray) object;
+        length = ja.length();
+        for (i = 0; i < length; i += 1) {
+          sb.append(toString(ja.opt(i), tagName == null ? "array" : tagName));
+        }
+        return sb.toString();
+      } else {
+        string = (object == null) ? "null" : escape(object.toString());
+        return (tagName == null) ? "\"" + string + "\""
+            : (string.length() == 0) ? "<" + tagName + "/>"
+                : "<" + tagName + ">" + string + "</" + tagName + ">";
+      }
+    }
+  }
+}