diff --git a/CDL.java b/CDL.java index 0fc3cf828..8520e862d 100755 --- a/CDL.java +++ b/CDL.java @@ -26,7 +26,7 @@ of this software and associated documentation files (the "Software"), to deal /** * This provides static methods to convert comma delimited text into a - * JSONArray, and to covert a JSONArray into comma delimited text. Comma + * JSONArray, and to convert 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. *

@@ -41,7 +41,7 @@ of this software and associated documentation files (the "Software"), to deal * The names for the elements in the JSONObjects can be taken from the names * in the first row. * @author JSON.org - * @version 2012-11-13 + * @version 2015-05-01 */ public class CDL { @@ -142,7 +142,7 @@ public static JSONObject rowToJSONObject(JSONArray names, JSONTokener x) * @return A string ending in NEWLINE. */ public static String rowToString(JSONArray ja) { - StringBuffer sb = new StringBuffer(); + StringBuilder sb = new StringBuilder(); for (int i = 0; i < ja.length(); i += 1) { if (i > 0) { sb.append(','); diff --git a/Cookie.java b/Cookie.java index 9cf5ce2c5..1867dbd74 100755 --- a/Cookie.java +++ b/Cookie.java @@ -1,169 +1,169 @@ -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 %hh sequences to single characters, and - * convert plus to space. - * @param string A string that may contain - * + (plus) and - * %hh 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(); - } -} +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 2014-05-03 + */ +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(); + int length = s.length(); + StringBuilder sb = new StringBuilder(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 { + StringBuilder sb = new StringBuilder(); + + 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 %hh sequences to single characters, and + * convert plus to space. + * @param string A string that may contain + * + (plus) and + * %hh sequences. + * @return The unescaped string. + */ + public static String unescape(String string) { + int length = string.length(); + StringBuilder sb = new StringBuilder(length); + 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(); + } +} diff --git a/CookieList.java b/CookieList.java index 7f4fe0751..b716fd7e3 100755 --- a/CookieList.java +++ b/CookieList.java @@ -1,90 +1,89 @@ -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(); - } -} +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 2014-05-03 + */ +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; + StringBuilder sb = new StringBuilder(); + while (keys.hasNext()) { + string = keys.next(); + 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(); + } +} diff --git a/HTTP.java b/HTTP.java index 43d04a804..648f4dad7 100755 --- a/HTTP.java +++ b/HTTP.java @@ -29,7 +29,7 @@ of this software and associated documentation files (the "Software"), to deal /** * Convert an HTTP header to a JSONObject and back. * @author JSON.org - * @version 2010-12-24 + * @version 2014-05-03 */ public class HTTP { @@ -125,9 +125,9 @@ public static JSONObject toJSONObject(String string) throws JSONException { * information. */ public static String toString(JSONObject jo) throws JSONException { - Iterator keys = jo.keys(); - String string; - StringBuffer sb = new StringBuffer(); + Iterator keys = jo.keys(); + String string; + StringBuilder sb = new StringBuilder(); if (jo.has("Status-Code") && jo.has("Reason-Phrase")) { sb.append(jo.getString("HTTP-Version")); sb.append(' '); @@ -147,7 +147,7 @@ public static String toString(JSONObject jo) throws JSONException { } sb.append(CRLF); while (keys.hasNext()) { - string = keys.next().toString(); + string = keys.next(); if (!"HTTP-Version".equals(string) && !"Status-Code".equals(string) && !"Reason-Phrase".equals(string) && !"Method".equals(string) && !"Request-URI".equals(string) && !jo.isNull(string)) { diff --git a/HTTPTokener.java b/HTTPTokener.java index ed41744a0..b2489b68d 100755 --- a/HTTPTokener.java +++ b/HTTPTokener.java @@ -28,7 +28,7 @@ of this software and associated documentation files (the "Software"), to deal * The HTTPTokener extends the JSONTokener to provide additional methods * for the parsing of HTTP headers. * @author JSON.org - * @version 2012-11-13 + * @version 2014-05-03 */ public class HTTPTokener extends JSONTokener { @@ -49,7 +49,7 @@ public HTTPTokener(String string) { public String nextToken() throws JSONException { char c; char q; - StringBuffer sb = new StringBuffer(); + StringBuilder sb = new StringBuilder(); do { c = next(); } while (Character.isWhitespace(c)); diff --git a/JSONArray.java b/JSONArray.java index 7c71d8db4..b1334db25 100644 --- a/JSONArray.java +++ b/JSONArray.java @@ -28,6 +28,7 @@ of this software and associated documentation files (the "Software"), to deal import java.io.StringWriter; import java.io.Writer; import java.lang.reflect.Array; +import java.math.*; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; @@ -69,28 +70,26 @@ of this software and associated documentation files (the "Software"), to deal *

  • 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: - * { } [ ] / \ : , = ; # and if they do not look like numbers and + * { } [ ] / \ : , # and if they do not look like numbers and * if they are not the reserved words true, false, or * null.
  • - *
  • Values can be separated by ; (semicolon) as - * well as by , (comma).
  • * * * @author JSON.org - * @version 2012-11-13 + * @version 2015-07-06 */ -public class JSONArray { +public class JSONArray implements Iterable { /** * The arrayList where the JSONArray's properties are kept. */ - private final ArrayList myArrayList; + private final ArrayList myArrayList; /** * Construct an empty JSONArray. */ public JSONArray() { - this.myArrayList = new ArrayList(); + this.myArrayList = new ArrayList(); } /** @@ -117,7 +116,6 @@ public JSONArray(JSONTokener x) throws JSONException { this.myArrayList.add(x.nextValue()); } switch (x.nextClean()) { - case ';': case ',': if (x.nextClean() == ']') { return; @@ -153,10 +151,10 @@ public JSONArray(String source) throws JSONException { * @param collection * A Collection. */ - public JSONArray(Collection collection) { - this.myArrayList = new ArrayList(); + public JSONArray(Collection collection) { + this.myArrayList = new ArrayList(); if (collection != null) { - Iterator iter = collection.iterator(); + Iterator iter = collection.iterator(); while (iter.hasNext()) { this.myArrayList.add(JSONObject.wrap(iter.next())); } @@ -182,6 +180,11 @@ public JSONArray(Object array) throws JSONException { } } + @Override + public Iterator iterator() { + return myArrayList.iterator(); + } + /** * Get the object value associated with an index. * @@ -244,6 +247,46 @@ public double getDouble(int index) throws JSONException { } } + /** + * Get the BigDecimal 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 BigDecimal. + */ + public BigDecimal getBigDecimal (int index) throws JSONException { + Object object = this.get(index); + try { + return new BigDecimal(object.toString()); + } catch (Exception e) { + throw new JSONException("JSONArray[" + index + + "] could not convert to BigDecimal."); + } + } + + /** + * Get the BigInteger 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 BigInteger. + */ + public BigInteger getBigInteger (int index) throws JSONException { + Object object = this.get(index); + try { + return new BigInteger(object.toString()); + } catch (Exception e) { + throw new JSONException("JSONArray[" + index + + "] could not convert to BigInteger."); + } + } + /** * Get the int value associated with an index. * @@ -360,7 +403,7 @@ public boolean isNull(int index) { */ public String join(String separator) throws JSONException { int len = this.length(); - StringBuffer sb = new StringBuffer(); + StringBuilder sb = new StringBuilder(); for (int i = 0; i < len; i += 1) { if (i > 0) { @@ -488,6 +531,44 @@ public int optInt(int index, int defaultValue) { } } + /** + * Get the optional BigInteger 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 BigInteger optBigInteger(int index, BigInteger defaultValue) { + try { + return this.getBigInteger(index); + } catch (Exception e) { + return defaultValue; + } + } + + /** + * Get the optional BigDecimal 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 BigDecimal optBigDecimal(int index, BigDecimal defaultValue) { + try { + return this.getBigDecimal(index); + } catch (Exception e) { + return defaultValue; + } + } + /** * Get the optional JSONArray associated with an index. * @@ -596,7 +677,7 @@ public JSONArray put(boolean value) { * A Collection value. * @return this. */ - public JSONArray put(Collection value) { + public JSONArray put(Collection value) { this.put(new JSONArray(value)); return this; } @@ -649,7 +730,7 @@ public JSONArray put(long value) { * A Map value. * @return this. */ - public JSONArray put(Map value) { + public JSONArray put(Map value) { this.put(new JSONObject(value)); return this; } @@ -698,7 +779,7 @@ public JSONArray put(int index, boolean value) throws JSONException { * @throws JSONException * If the index is negative or if the value is not finite. */ - public JSONArray put(int index, Collection value) throws JSONException { + public JSONArray put(int index, Collection value) throws JSONException { this.put(index, new JSONArray(value)); return this; } @@ -770,7 +851,7 @@ public JSONArray put(int index, long value) 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 { + public JSONArray put(int index, Map value) throws JSONException { this.put(index, new JSONObject(value)); return this; } @@ -816,9 +897,42 @@ public JSONArray put(int index, Object value) throws JSONException { * was no value. */ public Object remove(int index) { - Object o = this.opt(index); - this.myArrayList.remove(index); - return o; + return index >= 0 && index < this.length() + ? this.myArrayList.remove(index) + : null; + } + + /** + * Determine if two JSONArrays are similar. + * They must contain similar sequences. + * + * @param other The other JSONArray + * @return true if they are equal + */ + public boolean similar(Object other) { + if (!(other instanceof JSONArray)) { + return false; + } + int len = this.length(); + if (len != ((JSONArray)other).length()) { + return false; + } + for (int i = 0; i < len; i += 1) { + Object valueThis = this.get(i); + Object valueOther = ((JSONArray)other).get(i); + if (valueThis instanceof JSONObject) { + if (!((JSONObject)valueThis).similar(valueOther)) { + return false; + } + } else if (valueThis instanceof JSONArray) { + if (!((JSONArray)valueThis).similar(valueOther)) { + return false; + } + } else if (!valueThis.equals(valueOther)) { + return false; + } + } + return true; } /** diff --git a/JSONException.java b/JSONException.java index 971547e63..6fef51943 100755 --- a/JSONException.java +++ b/JSONException.java @@ -4,7 +4,7 @@ * The JSONException is thrown by the JSON.org classes when things are amiss. * * @author JSON.org - * @version 2013-02-10 + * @version 2014-05-03 */ public class JSONException extends RuntimeException { private static final long serialVersionUID = 0; @@ -22,6 +22,7 @@ public JSONException(String message) { /** * Constructs a new JSONException with the specified cause. + * @param cause The cause. */ public JSONException(Throwable cause) { super(cause.getMessage()); @@ -32,9 +33,10 @@ public JSONException(Throwable cause) { * Returns the cause of this exception or null if the cause is nonexistent * or unknown. * - * @returns the cause of this exception or null if the cause is nonexistent + * @return the cause of this exception or null if the cause is nonexistent * or unknown. */ + @Override public Throwable getCause() { return this.cause; } diff --git a/JSONML.java b/JSONML.java index 4be686351..42027cb00 100755 --- a/JSONML.java +++ b/JSONML.java @@ -33,7 +33,7 @@ of this software and associated documentation files (the "Software"), to deal * the JsonML transform. * * @author JSON.org - * @version 2012-03-28 + * @version 2014-05-03 */ public class JSONML { @@ -53,12 +53,12 @@ private static Object parse( ) throws JSONException { String attribute; char c; - String closeTag = null; + String closeTag = null; int i; JSONArray newja = null; JSONObject newjo = null; Object token; - String tagName = null; + String tagName = null; // Test for and skip past these forms: // @@ -312,15 +312,15 @@ public static JSONObject toJSONObject(String string) throws JSONException { * @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; + int i; + JSONObject jo; + String key; + Iterator keys; + int length; + Object object; + StringBuilder sb = new StringBuilder(); + String tagName; + String value; // Emit = length) { @@ -373,6 +373,8 @@ public static String toString(JSONArray ja) throws JSONException { sb.append(toString((JSONObject)object)); } else if (object instanceof JSONArray) { sb.append(toString((JSONArray)object)); + } else { + sb.append(object.toString()); } } } while (i < length); @@ -394,15 +396,15 @@ public static String toString(JSONArray ja) throws JSONException { * @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; + StringBuilder sb = new StringBuilder(); + int i; + JSONArray ja; + String key; + Iterator keys; + int length; + Object object; + String tagName; + String value; //Emit get and opt methods for accessing the - * values by name, and put methods for adding or replacing values - * by name. The values can be any of these types: Boolean, + * object having get and opt methods for accessing + * the values by name, and put methods for adding or replacing + * values by name. The values can be any of these types: Boolean, * JSONArray, JSONObject, Number, - * String, or the JSONObject.NULL 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 get and - * opt methods, or to convert values into a JSON text using the - * put and toString methods. A get method - * returns a value if one can be found, and throws an exception if one cannot be - * found. An opt method returns a default value instead of throwing - * an exception, and so is useful for obtaining optional values. + * String, or the JSONObject.NULL 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 + * get and opt methods, or to convert values into a + * JSON text using the put and toString methods. A + * get method returns a value if one can be found, and throws an + * exception if one cannot be found. An opt method returns a + * default value instead of throwing an exception, and so is useful for + * obtaining optional values. *

    * The generic get() and opt() methods return an * object, which you can cast or query for type. There are also typed * get and opt 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. + * 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. *

    - * The put methods add or replace values in an object. For example, + * The put methods add or replace values in an object. For + * example, * *

    - * myString = new JSONObject().put("JSON", "Hello, World!").toString();
    + * myString = new JSONObject()
    + *         .put("JSON", "Hello, World!").toString();
      * 
    * * produces the string {"JSON": "Hello, World"}. @@ -78,63 +83,52 @@ of this software and associated documentation files (the "Software"), to deal * before the closing brace. *
  • Strings may be quoted with ' (single * quote).
  • - *
  • 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: - * { } [ ] / \ : , = ; # and if they do not look like numbers and - * if they are not the reserved words true, false, or - * null.
  • - *
  • Keys can be followed by = or => as well as by - * :.
  • - *
  • Values can be followed by ; (semicolon) as - * well as by , (comma).
  • + *
  • 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: + * { } [ ] / \ : , # and if they do not look like numbers and + * if they are not the reserved words true, false, + * or null.
  • * * * @author JSON.org - * @version 2012-12-01 + * @version 2015-07-06 */ public class JSONObject { - /** - * The maximum number of keys in the key pool. - */ - private static final int keyPoolSize = 100; - - /** - * Key pooling is like string interning, but without permanently tying up - * memory. To help conserve memory, storage of duplicated key strings in - * JSONObjects will be avoided by using a key pool to manage unique key - * string objects. This is used by JSONObject.put(string, object). - */ - private static HashMap keyPool = new HashMap(keyPoolSize); - /** * JSONObject.NULL is equivalent to the value that JavaScript calls null, * whilst Java's null is equivalent to the value that JavaScript calls * undefined. */ - private static final class Null { + 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. + * + * @return NULL. */ + @Override protected final Object clone() { return this; } /** * 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. + * + * @param object + * An object to test for nullness. + * @return true if the object parameter is the JSONObject.NULL object or + * null. */ + @Override public boolean equals(Object object) { return object == null || object == this; } /** * Get the "null" string value. + * * @return The string "null". */ public String toString() { @@ -142,12 +136,10 @@ public String toString() { } } - /** * The map where the JSONObject's properties are kept. */ - private final Map map; - + private final Map map; /** * It is sometimes more convenient and less ambiguous to have a @@ -157,23 +149,26 @@ public String toString() { */ public static final Object NULL = new Null(); - /** * Construct an empty JSONObject. */ public JSONObject() { - this.map = new HashMap(); + this.map = new HashMap(); } - /** - * 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. + * 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. * @throws JSONException - * @exception JSONException If a value is a non-finite number or if a name is duplicated. + * @exception JSONException + * If a value is a non-finite number or if a name is + * duplicated. */ public JSONObject(JSONObject jo, String[] names) { this(); @@ -185,12 +180,14 @@ public JSONObject(JSONObject jo, String[] names) { } } - /** * 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. + * + * @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 x) throws JSONException { this(); @@ -212,19 +209,15 @@ public JSONObject(JSONTokener x) throws JSONException { key = x.nextValue().toString(); } -// The key is followed by ':'. We will also tolerate '=' or '=>'. +// The key is followed by ':'. c = x.nextClean(); - if (c == '=') { - if (x.next() != '>') { - x.back(); - } - } else if (c != ':') { + if (c != ':') { throw x.syntaxError("Expected a ':' after a key"); } this.putOnce(key, x.nextValue()); -// Pairs are separated by ','. We will also tolerate ';'. +// Pairs are separated by ','. switch (x.nextClean()) { case ';': @@ -242,68 +235,71 @@ public JSONObject(JSONTokener x) throws JSONException { } } - /** * Construct a JSONObject from a Map. * - * @param map A map object that can be used to initialize the contents of - * the JSONObject. + * @param map + * A map object that can be used to initialize the contents of + * the JSONObject. * @throws JSONException */ - public JSONObject(Map map) { - this.map = new HashMap(); + public JSONObject(Map map) { + this.map = new HashMap(); if (map != null) { - Iterator i = map.entrySet().iterator(); + Iterator> i = map.entrySet().iterator(); while (i.hasNext()) { - Map.Entry e = (Map.Entry)i.next(); - Object value = e.getValue(); + Entry entry = i.next(); + Object value = entry.getValue(); if (value != null) { - this.map.put(e.getKey(), wrap(value)); + this.map.put(entry.getKey(), wrap(value)); } } } } - /** - * 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 "get" or "is" 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. + * 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 "get" or + * "is" 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 "get" or "is" prefix. - * If the second remaining character is not upper case, then the first - * character is converted to lower case. + * The key is formed by removing the "get" or "is" + * 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 "getName", and - * if the result of calling object.getName() is "Larry Fine", - * then the JSONObject will contain "name": "Larry Fine". + * if the result of calling object.getName() is + * "Larry Fine", then the JSONObject will contain + * "name": "Larry Fine". * - * @param bean An object that has getter methods that should be used - * to make a JSONObject. + * @param bean + * An object that has getter methods that should be used to make + * a JSONObject. */ public JSONObject(Object bean) { this(); this.populateMap(bean); } - /** * 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 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(); + Class c = object.getClass(); for (int i = 0; i < names.length; i += 1) { String name = names[i]; try { @@ -313,26 +309,31 @@ public JSONObject(Object object, String names[]) { } } - /** - * Construct a JSONObject from a source JSON text string. - * This is the most commonly used JSONObject constructor. - * @param source A string beginning - * with { (left brace) and ending - * with } (right brace). - * @exception JSONException If there is a syntax error in the source - * string or a duplicated key. + * Construct a JSONObject from a source JSON text string. This is the most + * commonly used JSONObject constructor. + * + * @param source + * A string beginning with { (left + * brace) and ending with } + *  (right brace). + * @exception JSONException + * If there is a syntax error in the source string or a + * duplicated key. */ public JSONObject(String source) throws JSONException { this(new JSONTokener(source)); } - /** * 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. + * + * @param baseName + * The ResourceBundle base name. + * @param locale + * The Locale to load the ResourceBundle for. + * @throws JSONException + * If any JSONExceptions are detected. */ public JSONObject(String baseName, Locale locale) throws JSONException { this(); @@ -341,16 +342,16 @@ public JSONObject(String baseName, Locale locale) throws JSONException { // Iterate through the keys in the bundle. - Enumeration keys = bundle.getKeys(); + Enumeration keys = bundle.getKeys(); while (keys.hasMoreElements()) { Object key = keys.nextElement(); - if (key instanceof String) { + if (key != null) { // 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("\\."); + String[] path = ((String) key).split("\\."); int last = path.length - 1; JSONObject target = this; for (int i = 0; i < last; i += 1) { @@ -362,57 +363,59 @@ public JSONObject(String baseName, Locale locale) throws JSONException { } target = nextTarget; } - target.put(path[last], bundle.getString((String)key)); + target.put(path[last], bundle.getString((String) key)); } } } - /** * 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. + * 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. + * @throws JSONException + * If the value is an invalid number or if the key is null. */ - public JSONObject accumulate( - String key, - Object value - ) throws JSONException { + 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); + this.put(key, + value instanceof JSONArray ? new JSONArray().put(value) + : value); } else if (object instanceof JSONArray) { - ((JSONArray)object).put(value); + ((JSONArray) object).put(value); } else { this.put(key, new JSONArray().put(object).put(value)); } return this; } - /** * 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. + * + * @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. + * @throws JSONException + * If the key is null or if the current value associated with + * the key is not a JSONArray. */ public JSONObject append(String key, Object value) throws JSONException { testValidity(value); @@ -420,19 +423,20 @@ public JSONObject append(String key, Object value) throws JSONException { if (object == null) { this.put(key, new JSONArray().put(value)); } else if (object instanceof JSONArray) { - this.put(key, ((JSONArray)object).put(value)); + this.put(key, ((JSONArray) object).put(value)); } else { - throw new JSONException("JSONObject[" + key + - "] is not a JSONArray."); + throw new JSONException("JSONObject[" + key + + "] is not a JSONArray."); } return this; } - /** - * Produce a string from a double. The string "null" will be returned if - * the number is not finite. - * @param d A double. + * 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 static String doubleToString(double d) { @@ -443,8 +447,8 @@ public static String doubleToString(double d) { // 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) { + if (string.indexOf('.') > 0 && string.indexOf('e') < 0 + && string.indexOf('E') < 0) { while (string.endsWith("0")) { string = string.substring(0, string.length() - 1); } @@ -455,13 +459,14 @@ public static String doubleToString(double d) { return string; } - /** * 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. + * @param key + * A key string. + * @return The object associated with the key. + * @throws JSONException + * if the key is not found. */ public Object get(String key) throws JSONException { if (key == null) { @@ -469,135 +474,175 @@ public Object get(String key) throws JSONException { } Object object = this.opt(key); if (object == null) { - throw new JSONException("JSONObject[" + quote(key) + - "] not found."); + throw new JSONException("JSONObject[" + quote(key) + "] not found."); } return object; } - /** * Get the boolean value associated with a key. * - * @param key A key string. - * @return The truth. - * @throws JSONException - * if the value is not a Boolean or the String "true" or "false". + * @param key + * A key string. + * @return The truth. + * @throws JSONException + * if the value is not a Boolean or the String "true" or + * "false". */ public boolean getBoolean(String key) throws JSONException { Object object = this.get(key); - if (object.equals(Boolean.FALSE) || - (object instanceof String && - ((String)object).equalsIgnoreCase("false"))) { + 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"))) { + } 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."); + throw new JSONException("JSONObject[" + quote(key) + + "] is not a Boolean."); + } + + /** + * Get the BigInteger 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 cannot + * be converted to BigInteger. + */ + public BigInteger getBigInteger(String key) throws JSONException { + Object object = this.get(key); + try { + return new BigInteger(object.toString()); + } catch (Exception e) { + throw new JSONException("JSONObject[" + quote(key) + + "] could not be converted to BigInteger."); + } } + /** + * Get the BigDecimal 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 + * cannot be converted to BigDecimal. + */ + public BigDecimal getBigDecimal(String key) throws JSONException { + Object object = this.get(key); + try { + return new BigDecimal(object.toString()); + } catch (Exception e) { + throw new JSONException("JSONObject[" + quote(key) + + "] could not be converted to BigDecimal."); + } + } /** * 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. + * + * @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 double getDouble(String key) throws JSONException { Object object = this.get(key); try { - return object instanceof Number - ? ((Number)object).doubleValue() - : Double.parseDouble((String)object); + return object instanceof Number ? ((Number) object).doubleValue() + : Double.parseDouble((String) object); } catch (Exception e) { - throw new JSONException("JSONObject[" + quote(key) + - "] is not a number."); + throw new JSONException("JSONObject[" + quote(key) + + "] is not a number."); } } - /** * Get the int value associated with a key. * - * @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. + * @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. */ public int getInt(String key) throws JSONException { Object object = this.get(key); try { - return object instanceof Number - ? ((Number)object).intValue() - : Integer.parseInt((String)object); + return object instanceof Number ? ((Number) object).intValue() + : Integer.parseInt((String) object); } catch (Exception e) { - throw new JSONException("JSONObject[" + quote(key) + - "] is not an int."); + throw new JSONException("JSONObject[" + quote(key) + + "] is not an int."); } } - /** * 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. + * @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 (JSONArray) object; } - throw new JSONException("JSONObject[" + quote(key) + - "] is not a JSONArray."); + throw new JSONException("JSONObject[" + quote(key) + + "] is not a 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. + * @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 getJSONObject(String key) throws JSONException { Object object = this.get(key); if (object instanceof JSONObject) { - return (JSONObject)object; + return (JSONObject) object; } - throw new JSONException("JSONObject[" + quote(key) + - "] is not a JSONObject."); + throw new JSONException("JSONObject[" + quote(key) + + "] is not a JSONObject."); } - /** * 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. + * @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); + return object instanceof Number ? ((Number) object).longValue() + : Long.parseLong((String) object); } catch (Exception e) { - throw new JSONException("JSONObject[" + quote(key) + - "] is not a long."); + throw new JSONException("JSONObject[" + quote(key) + + "] is not a long."); } } - /** * Get an array of field names from a JSONObject. * @@ -608,17 +653,16 @@ public static String[] getNames(JSONObject jo) { if (length == 0) { return null; } - Iterator iterator = jo.keys(); + Iterator iterator = jo.keys(); String[] names = new String[length]; int i = 0; while (iterator.hasNext()) { - names[i] = (String)iterator.next(); + names[i] = iterator.next(); i += 1; } return names; } - /** * Get an array of field names from an Object. * @@ -628,7 +672,7 @@ public static String[] getNames(Object object) { if (object == null) { return null; } - Class klass = object.getClass(); + Class klass = object.getClass(); Field[] fields = klass.getFields(); int length = fields.length; if (length == 0) { @@ -641,94 +685,99 @@ public static String[] getNames(Object object) { return names; } - /** * 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. + * @param key + * A key string. + * @return A string which is the value. + * @throws JSONException + * if there is no string value for the key. */ public String getString(String key) throws JSONException { Object object = this.get(key); if (object instanceof String) { - return (String)object; + return (String) object; } - throw new JSONException("JSONObject[" + quote(key) + - "] not a string."); + throw new JSONException("JSONObject[" + quote(key) + "] not a string."); } - /** * Determine if the JSONObject contains a specific key. - * @param key A key string. - * @return true if the key exists in the JSONObject. + * + * @param key + * A key string. + * @return true if the key exists in the JSONObject. */ public boolean has(String key) { return this.map.containsKey(key); } - /** * 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. + * 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. + * @throws JSONException + * If there is already a property with this name that is not an + * Integer, Long, Double, or Float. */ public JSONObject increment(String key) throws JSONException { Object value = this.opt(key); if (value == null) { this.put(key, 1); + } else if (value instanceof BigInteger) { + this.put(key, ((BigInteger)value).add(BigInteger.ONE)); + } else if (value instanceof BigDecimal) { + this.put(key, ((BigDecimal)value).add(BigDecimal.ONE)); } else if (value instanceof Integer) { - this.put(key, ((Integer)value).intValue() + 1); + this.put(key, (Integer) value + 1); } else if (value instanceof Long) { - this.put(key, ((Long)value).longValue() + 1); + this.put(key, (Long) value + 1); } else if (value instanceof Double) { - this.put(key, ((Double)value).doubleValue() + 1); + this.put(key, (Double) value + 1); } else if (value instanceof Float) { - this.put(key, ((Float)value).floatValue() + 1); + this.put(key, (Float) value + 1); } else { throw new JSONException("Unable to increment [" + quote(key) + "]."); } return this; } - /** - * 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. + * 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 boolean isNull(String key) { return JSONObject.NULL.equals(this.opt(key)); } - /** * Get an enumeration of the keys of the JSONObject. * * @return An iterator of the keys. */ - public Iterator keys() { + public Iterator keys() { return this.keySet().iterator(); } - /** * Get a set of keys of the JSONObject. * * @return A keySet. */ - public Set keySet() { + public Set keySet() { return this.map.keySet(); } - /** * Get the number of keys stored in the JSONObject. * @@ -738,16 +787,16 @@ public int length() { return this.map.size(); } - /** * 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. + * is empty. */ public JSONArray names() { JSONArray ja = new JSONArray(); - Iterator keys = this.keys(); + Iterator keys = this.keys(); while (keys.hasNext()) { ja.put(keys.next()); } @@ -756,12 +805,14 @@ public JSONArray names() { /** * Produce a string from a Number. - * @param number A Number + * + * @param number + * A Number * @return A String. - * @throws JSONException If n is a non-finite number. + * @throws JSONException + * If n is a non-finite number. */ - public static String numberToString(Number number) - throws JSONException { + public static String numberToString(Number number) throws JSONException { if (number == null) { throw new JSONException("Null pointer"); } @@ -770,8 +821,8 @@ public static String numberToString(Number 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) { + if (string.indexOf('.') > 0 && string.indexOf('e') < 0 + && string.indexOf('E') < 0) { while (string.endsWith("0")) { string = string.substring(0, string.length() - 1); } @@ -782,38 +833,39 @@ public static String numberToString(Number number) return string; } - /** * 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. + * + * @param key + * A key string. + * @return An object which is the value, or null if there is no value. */ public Object opt(String key) { return key == null ? null : this.map.get(key); } - /** - * 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". + * 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. + * @param key + * A key string. + * @return The truth. */ public boolean optBoolean(String key) { return this.optBoolean(key, false); } - /** - * 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). + * 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. + * @param key + * A key string. + * @param defaultValue + * The default. + * @return The truth. */ public boolean optBoolean(String key, boolean defaultValue) { try { @@ -823,30 +875,67 @@ public boolean optBoolean(String key, boolean defaultValue) { } } - /** - * 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. + * 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. + * @param key + * A string which is the key. + * @return An object which is the value. */ public double optDouble(String key) { return this.optDouble(key, Double.NaN); } + /** + * Get an optional BigInteger 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. + * + * @param key + * A key string. + * @param defaultValue + * The default. + * @return An object which is the value. + */ + public BigInteger optBigInteger(String key, BigInteger defaultValue) { + try { + return this.getBigInteger(key); + } catch (Exception e) { + return defaultValue; + } + } + + /** + * Get an optional BigDecimal 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. + * + * @param key + * A key string. + * @param defaultValue + * The default. + * @return An object which is the value. + */ + public BigDecimal optBigDecimal(String key, BigDecimal defaultValue) { + try { + return this.getBigDecimal(key); + } catch (Exception e) { + return defaultValue; + } + } /** - * 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. + * 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. * - * @param key A key string. - * @param defaultValue The default. - * @return An object which is the value. + * @param key + * A key string. + * @param defaultValue + * The default. + * @return An object which is the value. */ public double optDouble(String key, double defaultValue) { try { @@ -856,30 +945,29 @@ public double optDouble(String key, double defaultValue) { } } - /** - * 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. + * 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. + * @param key + * A key string. + * @return An object which is the value. */ public int optInt(String key) { return this.optInt(key, 0); } - /** - * 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. + * 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. + * @param key + * A key string. + * @param defaultValue + * The default. + * @return An object which is the value. */ public int optInt(String key, int defaultValue) { try { @@ -889,58 +977,55 @@ public int optInt(String key, int defaultValue) { } } - /** - * 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. + * 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. + * @param key + * A key string. + * @return A JSONArray which is the value. */ public JSONArray optJSONArray(String key) { Object o = this.opt(key); - return o instanceof JSONArray ? (JSONArray)o : null; + return o instanceof JSONArray ? (JSONArray) o : null; } - /** - * 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. + * 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. + * @param key + * A key string. + * @return A JSONObject which is the value. */ public JSONObject optJSONObject(String key) { Object object = this.opt(key); - return object instanceof JSONObject ? (JSONObject)object : null; + return object instanceof JSONObject ? (JSONObject) object : null; } - /** - * 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. + * 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. + * @param key + * A key string. + * @return An object which is the value. */ public long optLong(String key) { return this.optLong(key, 0); } - /** - * 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. + * 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. + * @param key + * A key string. + * @param defaultValue + * The default. + * @return An object which is the value. */ public long optLong(String key, long defaultValue) { try { @@ -950,44 +1035,43 @@ public long optLong(String key, long defaultValue) { } } - /** - * 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. + * 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. + * @param key + * A key string. + * @return A string which is the value. */ public String optString(String key) { return this.optString(key, ""); } - /** - * Get an optional string associated with a key. - * It returns the defaultValue if there is no such key. + * 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. + * @param key + * A key string. + * @param defaultValue + * The default. + * @return A string which is the value. */ 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(); + 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(); + Method[] methods = includeSuperClass ? klass.getMethods() : klass + .getDeclaredMethods(); for (int i = 0; i < methods.length; i += 1) { try { Method method = methods[i]; @@ -995,8 +1079,8 @@ private void populateMap(Object bean) { String name = method.getName(); String key = ""; if (name.startsWith("get")) { - if ("getClass".equals(name) || - "getDeclaringClass".equals(name)) { + if ("getClass".equals(name) + || "getDeclaringClass".equals(name)) { key = ""; } else { key = name.substring(3); @@ -1004,17 +1088,17 @@ private void populateMap(Object bean) { } 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() > 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); + key = key.substring(0, 1).toLowerCase() + + key.substring(1); } - Object result = method.invoke(bean, (Object[])null); + Object result = method.invoke(bean, (Object[]) null); if (result != null) { this.map.put(key, wrap(result)); } @@ -1025,118 +1109,122 @@ private void populateMap(Object bean) { } } - /** * Put a key/boolean pair in the JSONObject. * - * @param key A key string. - * @param value A boolean which is the value. + * @param key + * A key string. + * @param value + * A boolean which is the value. * @return this. - * @throws JSONException If the key is null. + * @throws JSONException + * If the key is null. */ public JSONObject put(String key, boolean value) throws JSONException { this.put(key, value ? Boolean.TRUE : Boolean.FALSE); return this; } - /** * 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. + * + * @param key + * A key string. + * @param value + * A Collection value. + * @return this. * @throws JSONException */ - public JSONObject put(String key, Collection value) throws JSONException { + public JSONObject put(String key, Collection value) throws JSONException { this.put(key, new JSONArray(value)); return this; } - /** * Put a key/double pair in the JSONObject. * - * @param key A key string. - * @param value A double which is the value. + * @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. + * @throws JSONException + * If the key is null or if the number is invalid. */ public JSONObject put(String key, double value) throws JSONException { this.put(key, new Double(value)); return this; } - /** * Put a key/int pair in the JSONObject. * - * @param key A key string. - * @param value An int which is the value. + * @param key + * A key string. + * @param value + * An int which is the value. * @return this. - * @throws JSONException If the key is null. + * @throws JSONException + * If the key is null. */ public JSONObject put(String key, int value) throws JSONException { this.put(key, new Integer(value)); return this; } - /** * Put a key/long pair in the JSONObject. * - * @param key A key string. - * @param value A long which is the value. + * @param key + * A key string. + * @param value + * A long which is the value. * @return this. - * @throws JSONException If the key is null. + * @throws JSONException + * If the key is null. */ public JSONObject put(String key, long value) throws JSONException { this.put(key, new Long(value)); return this; } - /** * 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. + * + * @param key + * A key string. + * @param value + * A Map value. + * @return this. * @throws JSONException */ - public JSONObject put(String key, Map value) throws JSONException { + 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. + * 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. + * @throws JSONException + * If the value is non-finite number or if the key is null. */ public JSONObject put(String key, Object value) throws JSONException { - String pooled; if (key == null) { - throw new JSONException("Null key."); + throw new NullPointerException("Null key."); } if (value != null) { testValidity(value); - pooled = (String)keyPool.get(key); - if (pooled == null) { - if (keyPool.size() >= keyPoolSize) { - keyPool = new HashMap(keyPoolSize); - } - keyPool.put(key, key); - } else { - key = pooled; - } this.map.put(key, value); } else { this.remove(key); @@ -1144,15 +1232,16 @@ public JSONObject put(String key, Object value) throws JSONException { return this; } - /** - * 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 + * 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 string + * @param value object + * @return this. + * @throws JSONException + * if the key is a duplicate */ public JSONObject putOnce(String key, Object value) throws JSONException { if (key != null && value != null) { @@ -1164,16 +1253,19 @@ public JSONObject putOnce(String key, Object value) throws JSONException { return this; } - /** - * 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. + * 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. + * @throws JSONException + * If the value is a non-finite number. */ public JSONObject putOpt(String key, Object value) throws JSONException { if (key != null && value != null) { @@ -1182,14 +1274,15 @@ public JSONObject putOpt(String key, Object value) throws JSONException { return this; } - /** * Produce a string in double quotes with backslash sequences in all the * right places. A backslash will be inserted within set = this.keySet(); + if (!set.equals(((JSONObject)other).keySet())) { + return false; + } + Iterator iterator = set.iterator(); + while (iterator.hasNext()) { + String name = iterator.next(); + Object valueThis = this.get(name); + Object valueOther = ((JSONObject)other).get(name); + if (valueThis instanceof JSONObject) { + if (!((JSONObject)valueThis).similar(valueOther)) { + return false; + } + } else if (valueThis instanceof JSONArray) { + if (!((JSONArray)valueThis).similar(valueOther)) { + return false; + } + } else if (!valueThis.equals(valueOther)) { + return false; + } + } + return true; + } catch (Throwable exception) { + return false; + } + } + /** * 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. + * + * @param string + * A String. * @return A simple JSON value. */ public static Object stringToValue(String string) { @@ -1294,66 +1431,69 @@ public static Object stringToValue(String string) { } /* - * 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. + * If it might be a number, try converting it. If a number cannot be + * produced, then the value will just be a string. */ char b = string.charAt(0); - if ((b >= '0' && b <= '9') || b == '.' || b == '-' || b == '+') { + if ((b >= '0' && b <= '9') || b == '-') { try { - if (string.indexOf('.') > -1 || - string.indexOf('e') > -1 || string.indexOf('E') > -1) { + 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; + if (string.equals(myLong.toString())) { + if (myLong == myLong.intValue()) { + return myLong.intValue(); + } else { + return myLong; + } } } - } catch (Exception ignore) { + } 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. + * + * @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()) { + if (((Double) o).isInfinite() || ((Double) o).isNaN()) { throw new JSONException( - "JSON does not allow non-finite numbers."); + "JSON does not allow non-finite numbers."); } } else if (o instanceof Float) { - if (((Float)o).isInfinite() || ((Float)o).isNaN()) { + if (((Float) o).isInfinite() || ((Float) o).isNaN()) { throw new JSONException( - "JSON does not allow non-finite numbers."); + "JSON does not allow non-finite numbers."); } } } } - /** * 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. + * + * @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. + * @throws JSONException + * If any of the values are non-finite numbers. */ public JSONArray toJSONArray(JSONArray names) throws JSONException { if (names == null || names.length() == 0) { @@ -1367,16 +1507,16 @@ public JSONArray toJSONArray(JSONArray names) throws JSONException { } /** - * Make a JSON text of this JSONObject. For compactness, no whitespace - * is added. If this would not result in a syntactically correct JSON text, + * 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. *

    * Warning: This method assumes that the data structure is acyclical. * - * @return a printable, displayable, portable, transmittable - * representation of the object, beginning - * with { (left brace) and ending - * with } (right brace). + * @return a printable, displayable, portable, transmittable representation + * of the object, beginning with { (left + * brace) and ending with } (right + * brace). */ public String toString() { try { @@ -1386,18 +1526,19 @@ public String toString() { } } - /** * Make a prettyprinted JSON text of this JSONObject. *

    * 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 { (left brace) and ending - * with } (right brace). - * @throws JSONException If the object contains an invalid number. + * + * @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 { (left + * brace) and ending with } (right + * brace). + * @throws JSONException + * If the object contains an invalid number. */ public String toString(int indentFactor) throws JSONException { StringWriter w = new StringWriter(); @@ -1408,24 +1549,27 @@ public String toString(int indentFactor) throws JSONException { /** * 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. + * 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. * *

    * 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 { (left brace) and ending - * with } (right brace). - * @throws JSONException If the value is or contains an invalid number. + * + * @param value + * The value to be serialized. + * @return a printable, displayable, transmittable representation of the + * object, beginning with { (left + * brace) and ending with } (right + * brace). + * @throws JSONException + * If the value is or contains an invalid number. */ public static String valueToString(Object value) throws JSONException { if (value == null || value.equals(null)) { @@ -1434,27 +1578,31 @@ public static String valueToString(Object value) throws JSONException { if (value instanceof JSONString) { Object object; try { - object = ((JSONString)value).toJSONString(); + object = ((JSONString) value).toJSONString(); } catch (Exception e) { throw new JSONException(e); } if (object instanceof String) { - return (String)object; + 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) { + if (value instanceof Boolean || value instanceof JSONObject + || value instanceof JSONArray) { return value.toString(); } if (value instanceof Map) { - return new JSONObject((Map)value).toString(); + @SuppressWarnings("unchecked") + Map map = (Map) value; + return new JSONObject(map).toString(); } if (value instanceof Collection) { - return new JSONArray((Collection)value).toString(); + @SuppressWarnings("unchecked") + Collection coll = (Collection) value; + return new JSONArray(coll).toString(); } if (value.getClass().isArray()) { return new JSONArray(value).toString(); @@ -1462,73 +1610,73 @@ public static String valueToString(Object value) throws JSONException { 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 (object == null) { - return NULL; - } - 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 (object instanceof Collection) { - return new JSONArray((Collection)object); - } - if (object.getClass().isArray()) { - return new JSONArray(object); - } - 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.") || - object.getClass().getClassLoader() == null - ) { - return object.toString(); - } - 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. - *

    - * 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); + /** + * 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 (object == null) { + return NULL; + } + 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 || object instanceof BigInteger + || object instanceof BigDecimal) { + return object; + } + + if (object instanceof Collection) { + @SuppressWarnings("unchecked") + Collection coll = (Collection) object; + return new JSONArray(coll); + } + if (object.getClass().isArray()) { + return new JSONArray(object); + } + if (object instanceof Map) { + @SuppressWarnings("unchecked") + Map map = (Map) object; + return new JSONObject(map); + } + Package objectPackage = object.getClass().getPackage(); + String objectPackageName = objectPackage != null ? objectPackage + .getName() : ""; + if (objectPackageName.startsWith("java.") + || objectPackageName.startsWith("javax.") + || object.getClass().getClassLoader() == null) { + return object.toString(); + } + 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. + *

    + * 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 { @@ -1539,9 +1687,13 @@ static final Writer writeValue(Writer writer, Object value, } else if (value instanceof JSONArray) { ((JSONArray) value).write(writer, indentFactor, indent); } else if (value instanceof Map) { - new JSONObject((Map) value).write(writer, indentFactor, indent); + @SuppressWarnings("unchecked") + Map map = (Map) value; + new JSONObject(map).write(writer, indentFactor, indent); } else if (value instanceof Collection) { - new JSONArray((Collection) value).write(writer, indentFactor, + @SuppressWarnings("unchecked") + Collection coll = (Collection) value; + new JSONArray(coll).write(writer, indentFactor, indent); } else if (value.getClass().isArray()) { new JSONArray(value).write(writer, indentFactor, indent); @@ -1583,7 +1735,7 @@ Writer write(Writer writer, int indentFactor, int indent) try { boolean commanate = false; final int length = this.length(); - Iterator keys = this.keys(); + Iterator keys = this.keys(); writer.write('{'); if (length == 1) { @@ -1610,8 +1762,7 @@ Writer write(Writer writer, int indentFactor, int indent) if (indentFactor > 0) { writer.write(' '); } - writeValue(writer, this.map.get(key), indentFactor, - newindent); + writeValue(writer, this.map.get(key), indentFactor, newindent); commanate = true; } if (indentFactor > 0) { @@ -1624,5 +1775,5 @@ Writer write(Writer writer, int indentFactor, int indent) } catch (IOException exception) { throw new JSONException(exception); } - } + } } diff --git a/JSONTokener.java b/JSONTokener.java index 13c84f1f5..32548ed9f 100644 --- a/JSONTokener.java +++ b/JSONTokener.java @@ -36,7 +36,7 @@ of this software and associated documentation files (the "Software"), to deal * it. It is used by the JSONObject and JSONArray constructors to parse * JSON source strings. * @author JSON.org - * @version 2012-02-16 + * @version 2014-05-03 */ public class JSONTokener { @@ -69,6 +69,7 @@ public JSONTokener(Reader reader) { /** * Construct a JSONTokener from an InputStream. + * @param inputStream The source. */ public JSONTokener(InputStream inputStream) throws JSONException { this(new InputStreamReader(inputStream)); @@ -250,7 +251,7 @@ public char nextClean() throws JSONException { */ public String nextString(char quote) throws JSONException { char c; - StringBuffer sb = new StringBuffer(); + StringBuilder sb = new StringBuilder(); for (;;) { c = this.next(); switch (c) { @@ -306,7 +307,7 @@ public String nextString(char quote) throws JSONException { * @return A string. */ public String nextTo(char delimiter) throws JSONException { - StringBuffer sb = new StringBuffer(); + StringBuilder sb = new StringBuilder(); for (;;) { char c = this.next(); if (c == delimiter || c == 0 || c == '\n' || c == '\r') { @@ -328,7 +329,7 @@ public String nextTo(char delimiter) throws JSONException { */ public String nextTo(String delimiters) throws JSONException { char c; - StringBuffer sb = new StringBuffer(); + StringBuilder sb = new StringBuilder(); for (;;) { c = this.next(); if (delimiters.indexOf(c) >= 0 || c == 0 || @@ -375,7 +376,7 @@ public Object nextValue() throws JSONException { * formatting character. */ - StringBuffer sb = new StringBuffer(); + StringBuilder sb = new StringBuilder(); while (c >= ' ' && ",:]}/\\\"[{;=#".indexOf(c) < 0) { sb.append(c); c = this.next(); @@ -414,10 +415,9 @@ public char skipTo(char to) throws JSONException { return c; } } while (c != to); - } catch (IOException exc) { - throw new JSONException(exc); + } catch (IOException exception) { + throw new JSONException(exception); } - this.back(); return c; } diff --git a/JSONWriter.java b/JSONWriter.java index 855b2bdb1..07bbc8cfa 100755 --- a/JSONWriter.java +++ b/JSONWriter.java @@ -269,7 +269,7 @@ private void pop(char c) throws JSONException { /** * Push an array or object scope. - * @param c The scope to open. + * @param jo The scope to open. * @throws JSONException If nesting is too deep. */ private void push(JSONObject jo) throws JSONException { diff --git a/None.java b/None.java deleted file mode 100644 index 1dda8bc69..000000000 --- a/None.java +++ /dev/null @@ -1,9 +0,0 @@ -package org.json; - -public interface None { - /** - * Negative One - */ - public static final int none = -1; - -} diff --git a/Property.java b/Property.java new file mode 100644 index 000000000..73ddb1287 --- /dev/null +++ b/Property.java @@ -0,0 +1,72 @@ +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.Enumeration; +import java.util.Iterator; +import java.util.Properties; + +/** + * Converts a Property file data into JSONObject and back. + * @author JSON.org + * @version 2015-05-05 + */ +public class Property { + /** + * Converts a property file object into a JSONObject. The property file object is a table of name value pairs. + * @param properties java.util.Properties + * @return JSONObject + * @throws JSONException + */ + public static JSONObject toJSONObject(java.util.Properties properties) throws JSONException { + JSONObject jo = new JSONObject(); + if (properties != null && !properties.isEmpty()) { + Enumeration enumProperties = properties.propertyNames(); + while(enumProperties.hasMoreElements()) { + String name = (String)enumProperties.nextElement(); + jo.put(name, properties.getProperty(name)); + } + } + return jo; + } + + /** + * Converts the JSONObject into a property file object. + * @param jo JSONObject + * @return java.util.Properties + * @throws JSONException + */ + public static Properties toProperties(JSONObject jo) throws JSONException { + Properties properties = new Properties(); + if (jo != null) { + Iterator keys = jo.keys(); + while (keys.hasNext()) { + String name = keys.next(); + properties.put(name, jo.getString(name)); + } + } + return properties; + } +} diff --git a/README b/README index b77c71a21..925141f9e 100755 --- a/README +++ b/README @@ -1,9 +1,14 @@ JSON in Java [package org.json] +This package needs a new owner. I have not used it in over a decade, and I do +not have time to maintain programs that I do not use. + +If you think you can give this package a good home, please contact me. + Douglas Crockford douglas@crockford.com -2011-02-02 +2015-02-06 JSON is a light-weight, language independent, data interchange format. @@ -21,7 +26,7 @@ The license includes this restriction: "The software shall be used for good, not evil." If your conscience cannot live with that, then choose a different package. -The package compiles on Java 1.2 thru Java 1.4. +The package compiles on Java 1.8. JSONObject.java: The JSONObject can parse text from a String or a JSONTokener @@ -66,3 +71,5 @@ XML.java: XML provides support for converting between JSON and XML. JSONML.java: JSONML provides support for converting between JSONML and XML. XMLTokener.java: XMLTokener extends JSONTokener for parsing XML text. + +Unit tests are maintained in a separate project. Contributing developers can test JSON-java pull requests with the code in this project: https://github.com/stleary/JSON-Java-unit-test diff --git a/README.md b/README.md index c1a24f11e..5acef50d0 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ -# JSON-java +# DEPRECATED fork of JSON-java -This repository is a fork of the original [JSON-java](https://github.com/douglascrockford/JSON-java) repository by Douglas Crockford. This repository only adds two files, build.xml and build.properties, which allow for the ant build system to compile this code into a jar file. The jar file produced by this project is used for JSON parsing in the [GIS Tools for Hadoop](http://github.com/Esri/gis-tools-for-hadoop) and [Spatial Framework for Hadoop](http://github.com/Esri/spatial-framework-for-hadoop) projects. +This repository is a fork of the original [JSON-java](https://github.com/douglascrockford/JSON-java) repository by Douglas Crockford. This repository only adds two files, build.xml and build.properties, which allow for the ant build system to compile this code into a jar file. The jar file produced by this project was used for JSON parsing in the [GIS Tools for Hadoop](http://github.com/Esri/gis-tools-for-hadoop) and [Spatial Framework for Hadoop](http://github.com/Esri/spatial-framework-for-hadoop) projects. Other JSON library implementations may be found at: [JSON.org](http://www.json.org). diff --git a/XML.java b/XML.java index d49784d6d..07090abe3 100755 --- a/XML.java +++ b/XML.java @@ -26,41 +26,40 @@ of this software and associated documentation files (the "Software"), to deal 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 2012-10-26 + * @version 2014-05-03 */ public class XML { /** The Character '&'. */ - public static final Character AMP = new Character('&'); + public static final Character AMP = '&'; /** The Character '''. */ - public static final Character APOS = new Character('\''); + public static final Character APOS = '\''; /** The Character '!'. */ - public static final Character BANG = new Character('!'); + public static final Character BANG = '!'; /** The Character '='. */ - public static final Character EQ = new Character('='); + public static final Character EQ = '='; /** The Character '>'. */ - public static final Character GT = new Character('>'); + public static final Character GT = '>'; /** The Character '<'. */ - public static final Character LT = new Character('<'); + public static final Character LT = '<'; /** The Character '?'. */ - public static final Character QUEST = new Character('?'); + public static final Character QUEST = '?'; /** The Character '"'. */ - public static final Character QUOT = new Character('"'); + public static final Character QUOT = '"'; /** The Character '/'. */ - public static final Character SLASH = new Character('/'); + public static final Character SLASH = '/'; /** * Replace special characters with XML escapes: @@ -74,7 +73,7 @@ public class XML { * @return The escaped string. */ public static String escape(String string) { - StringBuffer sb = new StringBuffer(); + StringBuilder sb = new StringBuilder(string.length()); for (int i = 0, length = string.length(); i < length; i++) { char c = string.charAt(i); switch (c) { @@ -103,7 +102,7 @@ public static String escape(String string) { /** * Throw an exception if the string contains whitespace. * Whitespace is not allowed in tagNames and attributes. - * @param string + * @param string A string. * @throws JSONException */ public static void noSpace(String string) throws JSONException { @@ -301,9 +300,6 @@ private static boolean parse(XMLTokener x, JSONObject context, * @return A simple JSON value. */ public static Object stringToValue(String string) { - if ("".equals(string)) { - return string; - } if ("true".equalsIgnoreCase(string)) { return Boolean.TRUE; } @@ -313,36 +309,26 @@ public static Object stringToValue(String string) { 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. +// If it might be a number, try converting it, first as a Long, and then as a +// Double. 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; - } + if (initial == '-' || (initial >= '0' && initial <= '9')) { + Long value = new Long(string); + if (value.toString().equals(string)) { + return value; } } } catch (Exception ignore) { + try { + Double value = new Double(string); + if (value.toString().equals(string)) { + return value; + } + } catch (Exception ignoreAlso) { + } } return string; } @@ -392,15 +378,15 @@ public static String toString(Object object) 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; + StringBuilder sb = new StringBuilder(); + int i; + JSONArray ja; + JSONObject jo; + String key; + Iterator keys; + int length; + String string; + Object value; if (object instanceof JSONObject) { // Emit @@ -416,16 +402,12 @@ public static String toString(Object object, String tagName) jo = (JSONObject)object; keys = jo.keys(); while (keys.hasNext()) { - key = keys.next().toString(); + key = keys.next(); value = jo.opt(key); if (value == null) { value = ""; } - if (value instanceof String) { - string = (String)value; - } else { - string = null; - } + string = value instanceof String ? (String)value : null; // Emit content in body diff --git a/XMLTokener.java b/XMLTokener.java index be15ebeba..d3197653c 100755 --- a/XMLTokener.java +++ b/XMLTokener.java @@ -28,7 +28,7 @@ of this software and associated documentation files (the "Software"), to deal * The XMLTokener extends the JSONTokener to provide additional methods * for the parsing of XML texts. * @author JSON.org - * @version 2012-11-13 + * @version 2014-05-03 */ public class XMLTokener extends JSONTokener { @@ -36,10 +36,10 @@ 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; + public static final java.util.HashMap entity; static { - entity = new java.util.HashMap(8); + entity = new java.util.HashMap(8); entity.put("amp", XML.AMP); entity.put("apos", XML.APOS); entity.put("gt", XML.GT); @@ -63,7 +63,7 @@ public XMLTokener(String s) { public String nextCDATA() throws JSONException { char c; int i; - StringBuffer sb = new StringBuffer(); + StringBuilder sb = new StringBuilder(); for (;;) { c = next(); if (end()) { @@ -91,7 +91,7 @@ public String nextCDATA() throws JSONException { */ public Object nextContent() throws JSONException { char c; - StringBuffer sb; + StringBuilder sb; do { c = next(); } while (Character.isWhitespace(c)); @@ -101,7 +101,7 @@ public Object nextContent() throws JSONException { if (c == '<') { return XML.LT; } - sb = new StringBuffer(); + sb = new StringBuilder(); for (;;) { if (c == '<' || c == 0) { back(); @@ -125,7 +125,7 @@ public Object nextContent() throws JSONException { * @throws JSONException If missing ';' in XML entity. */ public Object nextEntity(char ampersand) throws JSONException { - StringBuffer sb = new StringBuffer(); + StringBuilder sb = new StringBuilder(); for (;;) { char c = next(); if (Character.isLetterOrDigit(c) || c == '#') { @@ -219,7 +219,7 @@ public Object nextMeta() throws JSONException { public Object nextToken() throws JSONException { char c; char q; - StringBuffer sb; + StringBuilder sb; do { c = next(); } while (Character.isWhitespace(c)); @@ -244,7 +244,7 @@ public Object nextToken() throws JSONException { case '"': case '\'': q = c; - sb = new StringBuffer(); + sb = new StringBuilder(); for (;;) { c = next(); if (c == 0) { @@ -263,7 +263,7 @@ public Object nextToken() throws JSONException { // Name - sb = new StringBuffer(); + sb = new StringBuilder(); for (;;) { sb.append(c); c = next();