diff --git a/build.gradle b/build.gradle index 898f10dc7..703364829 100644 --- a/build.gradle +++ b/build.gradle @@ -44,7 +44,7 @@ subprojects { group = 'org.json' version = 'v20251224-SNAPSHOT' description = 'JSON in Java' -sourceCompatibility = '1.8' +sourceCompatibility = '25' configurations.all { } diff --git a/pom.xml b/pom.xml index 8d0881cbe..64918a5d6 100644 --- a/pom.xml +++ b/pom.xml @@ -12,8 +12,8 @@ See http://www.JSON.org/ The files in this package implement JSON encoders/decoders in Java. - It also includes the capability to convert between JSON and XML, HTTP - headers, Cookies, and CDL. + It provides a comprehensive API for parsing, creating, manipulating, + and serializing JSON structures. This is a reference implementation. There are a large number of JSON packages in Java. Perhaps someday the Java community will standardize on one. Until @@ -79,6 +79,18 @@ 4.2.0 test + + com.pholser + junit-quickcheck-core + 1.0 + test + + + com.pholser + junit-quickcheck-generators + 1.0 + test + @@ -100,10 +112,10 @@ org.apache.maven.plugins maven-compiler-plugin - 3.11.0 + 3.14.0 - 1.8 - 1.8 + 25 + 25 -Xlint:unchecked @@ -169,30 +181,6 @@ false - - org.moditect - moditect-maven-plugin - 1.0.0.Final - - - add-module-infos - package - - add-module-info - - - 9 - - - module org.json { - exports org.json; - } - - - - - - org.apache.maven.plugins maven-jar-plugin diff --git a/src/main/java/module-info.java b/src/main/java/module-info.java new file mode 100644 index 000000000..64780b2d4 --- /dev/null +++ b/src/main/java/module-info.java @@ -0,0 +1,3 @@ +module org.json { + exports org.json; +} diff --git a/src/main/java/org/json/CDL.java b/src/main/java/org/json/CDL.java deleted file mode 100644 index f9afb8338..000000000 --- a/src/main/java/org/json/CDL.java +++ /dev/null @@ -1,399 +0,0 @@ -package org.json; - -/* -Public Domain. - */ - -/** - * This provides static methods to convert comma (or otherwise) delimited text into a - * JSONArray, and to convert a JSONArray into comma (or otherwise) delimited text. Comma - * delimited text is a very popular format for data interchange. It is - * understood by most database, spreadsheet, and organizer programs. - *

- * Each row of text represents a row in a table or a data record. Each row - * ends with a NEWLINE character. Each row contains one or more values. - * Values are separated by commas. A value can contain any character except - * for comma, unless it is wrapped in single quotes or double quotes. - *

- * The first row usually contains the names of the columns. - *

- * A comma delimited list can be converted into a JSONArray of JSONObjects. - * The names for the elements in the JSONObjects can be taken from the names - * in the first row. - * @author JSON.org - * @version 2016-05-01 - */ -public class CDL { - - /** - * Constructs a new CDL object. - * @deprecated (Utility class cannot be instantiated) - */ - @Deprecated - public CDL() { - } - - /** - * Get the next value. The value can be wrapped in quotes. The value can - * be empty. - * @param x A JSONTokener of the source text. - * @param delimiter used in the file - * @return The value string, or null if empty. - * @throws JSONException if the quoted string is badly formed. - */ - private static String getValue(JSONTokener x, char delimiter) throws JSONException { - char c; - char q; - StringBuilder sb; - do { - c = x.next(); - } while (c == ' ' || c == '\t'); - if (c == 0) { - return null; - } else if (c == '"' || c == '\'') { - q = c; - sb = new StringBuilder(); - for (;;) { - c = x.next(); - if (c == q) { - //Handle escaped double-quote - char nextC = x.next(); - if (nextC != '\"') { - // if our quote was the end of the file, don't step - if (nextC > 0) { - x.back(); - } - break; - } - } - if (c == 0 || c == '\n' || c == '\r') { - throw x.syntaxError("Missing close quote '" + q + "'."); - } - sb.append(c); - } - return sb.toString(); - } else if (c == delimiter) { - x.back(); - return ""; - } - x.back(); - return x.nextTo(delimiter); - } - - /** - * Produce a JSONArray of strings from a row of comma delimited values. - * @param x A JSONTokener of the source text. - * @return A JSONArray of strings. - * @throws JSONException if a called function fails - */ - public static JSONArray rowToJSONArray(JSONTokener x) throws JSONException { - return rowToJSONArray(x, ','); - } - - /** - * Produce a JSONArray of strings from a row of comma delimited values. - * @param x A JSONTokener of the source text. - * @param delimiter custom delimiter char - * @return A JSONArray of strings. - * @throws JSONException if a called function fails - */ - public static JSONArray rowToJSONArray(JSONTokener x, char delimiter) throws JSONException { - JSONArray ja = new JSONArray(); - for (;;) { - String value = getValue(x,delimiter); - char c = x.next(); - if (value != null) { - ja.put(value); - } else if (ja.length() == 0 && c != delimiter) { - return null; - } else { - // This line accounts for CSV ending with no newline - ja.put(""); - } - - for (;;) { - if (c == delimiter) { - break; - } - if (c != ' ') { - if (c == '\n' || c == '\r' || c == 0) { - return ja; - } - throw x.syntaxError("Bad character '" + c + "' (" + - (int)c + ")."); - } - c = x.next(); - } - } - } - - /** - * Produce a JSONObject from a row of comma delimited text, using a - * parallel JSONArray of strings to provides the names of the elements. - * @param names A JSONArray of names. This is commonly obtained from the - * first row of a comma delimited text file using the rowToJSONArray - * method. - * @param x A JSONTokener of the source text. - * @return A JSONObject combining the names and values. - * @throws JSONException if a called function fails - */ - public static JSONObject rowToJSONObject(JSONArray names, JSONTokener x) throws JSONException { - return rowToJSONObject(names, x, ','); - } - - /** - * Produce a JSONObject from a row of comma delimited text, using a - * parallel JSONArray of strings to provides the names of the elements. - * @param names A JSONArray of names. This is commonly obtained from the - * first row of a comma delimited text file using the rowToJSONArray - * method. - * @param x A JSONTokener of the source text. - * @param delimiter custom delimiter char - * @return A JSONObject combining the names and values. - * @throws JSONException if a called function fails - */ - public static JSONObject rowToJSONObject(JSONArray names, JSONTokener x, char delimiter) throws JSONException { - JSONArray ja = rowToJSONArray(x, delimiter); - return ja != null ? ja.toJSONObject(names) : null; - } - - /** - * Produce a comma delimited text row from a JSONArray. Values containing - * the comma character will be quoted. Troublesome characters may be - * removed. - * @param ja A JSONArray of strings. - * @return A string ending in NEWLINE. - */ - public static String rowToString(JSONArray ja) { - return rowToString(ja, ','); - } - - /** - * Produce a comma delimited text row from a JSONArray. Values containing - * the comma character will be quoted. Troublesome characters may be - * removed. - * @param ja A JSONArray of strings. - * @param delimiter custom delimiter char - * @return A string ending in NEWLINE. - */ - public static String rowToString(JSONArray ja, char delimiter) { - StringBuilder sb = new StringBuilder(); - for (int i = 0; i < ja.length(); i += 1) { - if (i > 0) { - sb.append(delimiter); - } - Object object = ja.opt(i); - if (object != null) { - String string = object.toString(); - if (!string.isEmpty() && (string.indexOf(delimiter) >= 0 || - string.indexOf('\n') >= 0 || string.indexOf('\r') >= 0 || - string.indexOf(0) >= 0 || string.charAt(0) == '"')) { - sb.append('"'); - int length = string.length(); - for (int j = 0; j < length; j += 1) { - char c = string.charAt(j); - if (c >= ' ' && c != '"') { - sb.append(c); - } - } - sb.append('"'); - } else { - sb.append(string); - } - } - } - sb.append('\n'); - return sb.toString(); - } - - /** - * Produce a JSONArray of JSONObjects from a comma delimited text string, - * using the first row as a source of names. - * @param string The comma delimited text. - * @return A JSONArray of JSONObjects. - * @throws JSONException if a called function fails - */ - public static JSONArray toJSONArray(String string) throws JSONException { - return toJSONArray(string, ','); - } - - /** - * Produce a JSONArray of JSONObjects from a comma delimited text string, - * using the first row as a source of names. - * @param string The comma delimited text. - * @param delimiter custom delimiter char - * @return A JSONArray of JSONObjects. - * @throws JSONException if a called function fails - */ - public static JSONArray toJSONArray(String string, char delimiter) throws JSONException { - return toJSONArray(new JSONTokener(string), delimiter); - } - - /** - * Produce a JSONArray of JSONObjects from a comma delimited text string, - * using the first row as a source of names. - * @param x The JSONTokener containing the comma delimited text. - * @return A JSONArray of JSONObjects. - * @throws JSONException if a called function fails - */ - public static JSONArray toJSONArray(JSONTokener x) throws JSONException { - return toJSONArray(x, ','); - } - - /** - * Produce a JSONArray of JSONObjects from a comma delimited text string, - * using the first row as a source of names. - * @param x The JSONTokener containing the comma delimited text. - * @param delimiter custom delimiter char - * @return A JSONArray of JSONObjects. - * @throws JSONException if a called function fails - */ - public static JSONArray toJSONArray(JSONTokener x, char delimiter) throws JSONException { - return toJSONArray(rowToJSONArray(x, delimiter), x, delimiter); - } - - /** - * Produce a JSONArray of JSONObjects from a comma delimited text string - * using a supplied JSONArray as the source of element names. - * @param names A JSONArray of strings. - * @param string The comma delimited text. - * @return A JSONArray of JSONObjects. - * @throws JSONException if a called function fails - */ - public static JSONArray toJSONArray(JSONArray names, String string) throws JSONException { - return toJSONArray(names, string, ','); - } - - /** - * Produce a JSONArray of JSONObjects from a comma delimited text string - * using a supplied JSONArray as the source of element names. - * @param names A JSONArray of strings. - * @param string The comma delimited text. - * @param delimiter custom delimiter char - * @return A JSONArray of JSONObjects. - * @throws JSONException if a called function fails - */ - public static JSONArray toJSONArray(JSONArray names, String string, char delimiter) throws JSONException { - return toJSONArray(names, new JSONTokener(string), delimiter); - } - - /** - * Produce a JSONArray of JSONObjects from a comma delimited text string - * using a supplied JSONArray as the source of element names. - * @param names A JSONArray of strings. - * @param x A JSONTokener of the source text. - * @return A JSONArray of JSONObjects. - * @throws JSONException if a called function fails - */ - public static JSONArray toJSONArray(JSONArray names, JSONTokener x) throws JSONException { - return toJSONArray(names, x, ','); - } - - /** - * Produce a JSONArray of JSONObjects from a comma delimited text string - * using a supplied JSONArray as the source of element names. - * @param names A JSONArray of strings. - * @param x A JSONTokener of the source text. - * @param delimiter custom delimiter char - * @return A JSONArray of JSONObjects. - * @throws JSONException if a called function fails - */ - public static JSONArray toJSONArray(JSONArray names, JSONTokener x, char delimiter) throws JSONException { - if (names == null || names.length() == 0) { - return null; - } - JSONArray ja = new JSONArray(); - for (;;) { - JSONObject jo = rowToJSONObject(names, x, delimiter); - if (jo == null) { - break; - } - ja.put(jo); - } - if (ja.length() == 0) { - return null; - } - - // The following block accounts for empty datasets (no keys or vals) - if (ja.length() == 1) { - JSONObject j = ja.getJSONObject(0); - if (j.length() == 1) { - String key = j.keys().next(); - if ("".equals(key) && "".equals(j.get(key))) { - return null; - } - } - } - return ja; - } - - - /** - * Produce a comma delimited text from a JSONArray of JSONObjects. The - * first row will be a list of names obtained by inspecting the first - * JSONObject. - * @param ja A JSONArray of JSONObjects. - * @return A comma delimited text. - * @throws JSONException if a called function fails - */ - public static String toString(JSONArray ja) throws JSONException { - return toString(ja, ','); - } - - /** - * Produce a comma delimited text from a JSONArray of JSONObjects. The - * first row will be a list of names obtained by inspecting the first - * JSONObject. - * @param ja A JSONArray of JSONObjects. - * @param delimiter custom delimiter char - * @return A comma delimited text. - * @throws JSONException if a called function fails - */ - public static String toString(JSONArray ja, char delimiter) throws JSONException { - JSONObject jo = ja.optJSONObject(0); - if (jo != null) { - JSONArray names = jo.names(); - if (names != null) { - return rowToString(names, delimiter) + toString(names, ja, delimiter); - } - } - return null; - } - - /** - * Produce a comma delimited text from a JSONArray of JSONObjects using - * a provided list of names. The list of names is not included in the - * output. - * @param names A JSONArray of strings. - * @param ja A JSONArray of JSONObjects. - * @return A comma delimited text. - * @throws JSONException if a called function fails - */ - public static String toString(JSONArray names, JSONArray ja) throws JSONException { - return toString(names, ja, ','); - } - - /** - * Produce a comma delimited text from a JSONArray of JSONObjects using - * a provided list of names. The list of names is not included in the - * output. - * @param names A JSONArray of strings. - * @param ja A JSONArray of JSONObjects. - * @param delimiter custom delimiter char - * @return A comma delimited text. - * @throws JSONException if a called function fails - */ - public static String toString(JSONArray names, JSONArray ja, char delimiter) throws JSONException { - if (names == null || names.length() == 0) { - return null; - } - StringBuilder sb = new StringBuilder(); - for (int i = 0; i < ja.length(); i += 1) { - JSONObject jo = ja.optJSONObject(i); - if (jo != null) { - sb.append(rowToString(jo.toJSONArray(names), delimiter)); - } - } - return sb.toString(); - } -} diff --git a/src/main/java/org/json/Cookie.java b/src/main/java/org/json/Cookie.java deleted file mode 100644 index f7bab236f..000000000 --- a/src/main/java/org/json/Cookie.java +++ /dev/null @@ -1,212 +0,0 @@ -package org.json; - -import java.util.Locale; - -/* -Public Domain. -*/ - -/** - * Convert a web browser cookie specification to a JSONObject and back. - * JSON and Cookies are both notations for name/value pairs. - * See also: https://tools.ietf.org/html/rfc6265 - * @author JSON.org - * @version 2015-12-09 - */ -public class Cookie { - - /** - * Constructs a new Cookie object. - * @deprecated (Utility class cannot be instantiated) - */ - @Deprecated() - public 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 - * must 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 Attribute properties like "Secure" or "HttpOnly", - * which do not have a value. The value {@link Boolean#TRUE} will be used for these). - * 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. All attribute names are converted to lower case keys in the - * JSONObject (HttpOnly => httponly). If an attribute is specified more than - * once, only the value found closer to the end of the cookie-string is kept. - * @param string The cookie specification string. - * @return A JSONObject containing "name", "value", and possibly other - * members. - * @throws JSONException If there is an error parsing the Cookie String. - * Cookie strings must have at least one '=' character and the 'name' - * portion of the cookie must not be blank. - */ - public static JSONObject toJSONObject(String string) { - final JSONObject jo = new JSONObject(); - String name; - Object value; - - - JSONTokener x = new JSONTokener(string); - - name = unescape(x.nextTo('=').trim()); - //per RFC6265, if the name is blank, the cookie should be ignored. - if("".equals(name)) { - throw new JSONException("Cookies must have a 'name'"); - } - jo.put("name", name); - // per RFC6265, if there is no '=', the cookie should be ignored. - // the 'next' call here throws an exception if the '=' is not found. - x.next('='); - jo.put("value", unescape(x.nextTo(';')).trim()); - // discard the ';' - x.next(); - // parse the remaining cookie attributes - while (x.more()) { - name = unescape(x.nextTo("=;")).trim().toLowerCase(Locale.ROOT); - // don't allow a cookies attributes to overwrite its name or value. - if("name".equalsIgnoreCase(name)) { - throw new JSONException("Illegal attribute name: 'name'"); - } - if("value".equalsIgnoreCase(name)) { - throw new JSONException("Illegal attribute name: 'value'"); - } - // check to see if it's a flag property - if (x.next() != '=') { - value = Boolean.TRUE; - } else { - value = unescape(x.nextTo(';')).trim(); - x.next(); - } - // only store non-blank attributes - if(!"".equals(name) && !"".equals(value)) { - jo.put(name, value); - } - } - return jo; - } - - - /** - * Convert a JSONObject into a cookie specification string. The JSONObject - * must contain "name" and "value" members (case insensitive). - * If the JSONObject contains other members, they will be appended to the cookie - * specification string. User-Agents are instructed to ignore unknown attributes, - * so ensure your JSONObject is using only known attributes. - * See also: https://tools.ietf.org/html/rfc6265 - * @param jo A JSONObject - * @return A cookie specification string - * @throws JSONException thrown if the cookie has no name. - */ - public static String toString(JSONObject jo) throws JSONException { - StringBuilder sb = new StringBuilder(); - - String name = null; - Object value = null; - for(String key : jo.keySet()){ - if("name".equalsIgnoreCase(key)) { - name = jo.getString(key).trim(); - } - if("value".equalsIgnoreCase(key)) { - value=jo.getString(key).trim(); - } - if(name != null && value != null) { - break; - } - } - - if(name == null || "".equals(name.trim())) { - throw new JSONException("Cookie does not have a name"); - } - if(value == null) { - value = ""; - } - - sb.append(escape(name)); - sb.append("="); - sb.append(escape((String)value)); - - for(String key : jo.keySet()){ - if("name".equalsIgnoreCase(key) - || "value".equalsIgnoreCase(key)) { - // already processed above - continue; - } - value = jo.opt(key); - if(value instanceof Boolean) { - if(Boolean.TRUE.equals(value)) { - sb.append(';').append(escape(key)); - } - // don't emit false values - } else { - sb.append(';') - .append(escape(key)) - .append('=') - .append(escape(value.toString())); - } - } - - 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/src/main/java/org/json/CookieList.java b/src/main/java/org/json/CookieList.java deleted file mode 100644 index ce47aee02..000000000 --- a/src/main/java/org/json/CookieList.java +++ /dev/null @@ -1,74 +0,0 @@ -package org.json; - -/* -Public Domain. - */ - -/** - * Convert a web browser cookie list string to a JSONObject and back. - * @author JSON.org - * @version 2015-12-09 - */ -public class CookieList { - - /** - * Constructs a new CookieList object. - * @deprecated (Utility class cannot be instantiated) - */ - @Deprecated - public 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 cookie list, - * cookielistJSONObject.put(cookieJSONObject.getString("name"), - * cookieJSONObject.getString("value")); - * @param string A cookie list string - * @return A JSONObject - * @throws JSONException if a called function fails - */ - 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 if a called function fails - */ - public static String toString(JSONObject jo) throws JSONException { - boolean isEndOfPair = false; - final StringBuilder sb = new StringBuilder(); - // Don't use the new entrySet API to maintain Android support - for (final String key : jo.keySet()) { - final Object value = jo.opt(key); - if (!JSONObject.NULL.equals(value)) { - if (isEndOfPair) { - sb.append(';'); - } - sb.append(Cookie.escape(key)); - sb.append("="); - sb.append(Cookie.escape(value.toString())); - isEndOfPair = true; - } - } - return sb.toString(); - } -} diff --git a/src/main/java/org/json/HTTP.java b/src/main/java/org/json/HTTP.java deleted file mode 100644 index 44ab3a6d3..000000000 --- a/src/main/java/org/json/HTTP.java +++ /dev/null @@ -1,148 +0,0 @@ -package org.json; - -/* -Public Domain. -*/ - -import java.util.Locale; - -/** - * Convert an HTTP header to a JSONObject and back. - * @author JSON.org - * @version 2015-12-09 - */ -public class HTTP { - - /** - * Constructs a new HTTP object. - */ - public HTTP() { - } - - /** Carriage return/line feed. */ - public static final String CRLF = "\r\n"; - - /** - * Convert an HTTP header string into a JSONObject. It can be a request - * header or a response header. A request header will contain - *

{
-     *    Method: "POST" (for example),
-     *    "Request-URI": "/" (for example),
-     *    "HTTP-Version": "HTTP/1.1" (for example)
-     * }
- * A response header will contain - *
{
-     *    "HTTP-Version": "HTTP/1.1" (for example),
-     *    "Status-Code": "200" (for example),
-     *    "Reason-Phrase": "OK" (for example)
-     * }
- * In addition, the other parameters in the header will be captured, using - * the HTTP field names as JSON names, so that
{@code
-     *    Date: Sun, 26 May 2002 18:06:04 GMT
-     *    Cookie: Q=q2=PPEAsg--; B=677gi6ouf29bn&b=2&f=s
-     *    Cache-Control: no-cache}
- * become - *
{@code
-     *    Date: "Sun, 26 May 2002 18:06:04 GMT",
-     *    Cookie: "Q=q2=PPEAsg--; B=677gi6ouf29bn&b=2&f=s",
-     *    "Cache-Control": "no-cache",
-     * ...}
- * It does no further checking or conversion. It does not parse dates. - * It does not do '%' transforms on URLs. - * @param string An HTTP header string. - * @return A JSONObject containing the elements and attributes - * of the XML string. - * @throws JSONException if a called function fails - */ - public static JSONObject toJSONObject(String string) throws JSONException { - JSONObject jo = new JSONObject(); - HTTPTokener x = new HTTPTokener(string); - String token; - - token = x.nextToken(); - if (token.toUpperCase(Locale.ROOT).startsWith("HTTP")) { - -// Response - - jo.put("HTTP-Version", token); - jo.put("Status-Code", x.nextToken()); - jo.put("Reason-Phrase", x.nextTo('\0')); - x.next(); - - } else { - -// Request - - jo.put("Method", token); - jo.put("Request-URI", x.nextToken()); - jo.put("HTTP-Version", x.nextToken()); - } - -// Fields - - while (x.more()) { - String name = x.nextTo(':'); - x.next(':'); - jo.put(name, x.nextTo('\0')); - x.next(); - } - return jo; - } - - - /** - * Convert a JSONObject into an HTTP header. A request header must contain - *
{
-     *    Method: "POST" (for example),
-     *    "Request-URI": "/" (for example),
-     *    "HTTP-Version": "HTTP/1.1" (for example)
-     * }
- * A response header must contain - *
{
-     *    "HTTP-Version": "HTTP/1.1" (for example),
-     *    "Status-Code": "200" (for example),
-     *    "Reason-Phrase": "OK" (for example)
-     * }
- * Any other members of the JSONObject will be output as HTTP fields. - * The result will end with two CRLF pairs. - * @param jo A JSONObject - * @return An HTTP header string. - * @throws JSONException if the object does not contain enough - * information. - */ - public static String toString(JSONObject jo) throws JSONException { - StringBuilder sb = new StringBuilder(); - if (jo.has("Status-Code") && jo.has("Reason-Phrase")) { - sb.append(jo.getString("HTTP-Version")); - sb.append(' '); - sb.append(jo.getString("Status-Code")); - sb.append(' '); - sb.append(jo.getString("Reason-Phrase")); - } else if (jo.has("Method") && jo.has("Request-URI")) { - sb.append(jo.getString("Method")); - sb.append(' '); - sb.append('"'); - sb.append(jo.getString("Request-URI")); - sb.append('"'); - sb.append(' '); - sb.append(jo.getString("HTTP-Version")); - } else { - throw new JSONException("Not enough material for an HTTP header."); - } - sb.append(CRLF); - // Don't use the new entrySet API to maintain Android support - for (final String key : jo.keySet()) { - String value = jo.optString(key); - if (!"HTTP-Version".equals(key) && !"Status-Code".equals(key) && - !"Reason-Phrase".equals(key) && !"Method".equals(key) && - !"Request-URI".equals(key) && !JSONObject.NULL.equals(value)) { - sb.append(key); - sb.append(": "); - sb.append(jo.optString(key)); - sb.append(CRLF); - } - } - sb.append(CRLF); - return sb.toString(); - } -} diff --git a/src/main/java/org/json/HTTPTokener.java b/src/main/java/org/json/HTTPTokener.java deleted file mode 100644 index 48cad31a3..000000000 --- a/src/main/java/org/json/HTTPTokener.java +++ /dev/null @@ -1,57 +0,0 @@ -package org.json; - -/* -Public Domain. -*/ - -/** - * The HTTPTokener extends the JSONTokener to provide additional methods - * for the parsing of HTTP headers. - * @author JSON.org - * @version 2015-12-09 - */ -public class HTTPTokener extends JSONTokener { - - /** - * Construct an HTTPTokener from a string. - * @param string A source string. - */ - public HTTPTokener(String string) { - super(string); - } - - - /** - * Get the next token or string. This is used in parsing HTTP headers. - * @return A String. - * @throws JSONException if a syntax error occurs - */ - public String nextToken() throws JSONException { - char c; - char q; - StringBuilder sb = new StringBuilder(); - do { - c = next(); - } while (Character.isWhitespace(c)); - if (c == '"' || c == '\'') { - q = c; - for (;;) { - c = next(); - if (c < ' ') { - throw syntaxError("Unterminated string."); - } - if (c == q) { - return sb.toString(); - } - sb.append(c); - } - } - for (;;) { - if (c == 0 || Character.isWhitespace(c)) { - return sb.toString(); - } - sb.append(c); - c = next(); - } - } -} diff --git a/src/main/java/org/json/JSONArray.java b/src/main/java/org/json/JSONArray.java index 2a3c553a6..b1226b44f 100644 --- a/src/main/java/org/json/JSONArray.java +++ b/src/main/java/org/json/JSONArray.java @@ -5,6 +5,7 @@ */ import java.io.IOException; +import java.io.UncheckedIOException; import java.io.Writer; import java.lang.reflect.Array; import java.math.BigDecimal; @@ -71,7 +72,7 @@ public class JSONArray implements Iterable { * Construct an empty JSONArray. */ public JSONArray() { - this.myArrayList = new ArrayList(); + this.myArrayList = new ArrayList<>(); } /** @@ -79,10 +80,8 @@ public JSONArray() { * * @param x * A JSONTokener - * @throws JSONException - * If there is a syntax error. */ - public JSONArray(JSONTokener x) throws JSONException { + public JSONArray(JSONTokener x) { this(x, x.getJsonParserConfiguration()); } @@ -91,9 +90,8 @@ public JSONArray(JSONTokener x) throws JSONException { * * @param x A JSONTokener instance from which the JSONArray is constructed. * @param jsonParserConfiguration A JSONParserConfiguration instance that controls the behavior of the parser. - * @throws JSONException If a syntax error occurs during the construction of the JSONArray. */ - public JSONArray(JSONTokener x, JSONParserConfiguration jsonParserConfiguration) throws JSONException { + public JSONArray(JSONTokener x, JSONParserConfiguration jsonParserConfiguration) { this(); boolean isInitial = x.getPrevious() == 0; @@ -134,43 +132,43 @@ public JSONArray(JSONTokener x, JSONParserConfiguration jsonParserConfiguration) * @return */ private static boolean checkForSyntaxError(JSONTokener x, JSONParserConfiguration jsonParserConfiguration, boolean isInitial) { - char nextChar; - switch (x.nextClean()) { - case 0: - // array is unclosed. No ']' found, instead EOF - throw x.syntaxError("Expected a ',' or ']'"); - case ',': - nextChar = x.nextClean(); - if (nextChar == 0) { + return switch (x.nextClean()) { + case 0 -> // array is unclosed. No ']' found, instead EOF throw x.syntaxError("Expected a ',' or ']'"); - } - if (nextChar == ']') { - // trailing commas are not allowed in strict mode - if (jsonParserConfiguration.isStrictMode()) { - throw x.syntaxError("Strict mode error: Expected another array element"); + case ',' -> { + char nextChar = x.nextClean(); + if (nextChar == 0) { + // array is unclosed. No ']' found, instead EOF + throw x.syntaxError("Expected a ',' or ']'"); } - return true; - } - if (nextChar == ',') { - // consecutive commas are not allowed in strict mode - if (jsonParserConfiguration.isStrictMode()) { - throw x.syntaxError("Strict mode error: Expected a valid array element"); + if (nextChar == ']') { + // trailing commas are not allowed in strict mode + if (jsonParserConfiguration.isStrictMode()) { + throw x.syntaxError("Strict mode error: Expected another array element"); + } + yield true; } - return true; + if (nextChar == ',') { + // consecutive commas are not allowed in strict mode + if (jsonParserConfiguration.isStrictMode()) { + throw x.syntaxError("Strict mode error: Expected a valid array element"); + } + yield true; + } + x.back(); + yield false; } - x.back(); - break; - case ']': - if (isInitial && jsonParserConfiguration.isStrictMode() && - x.nextClean() != 0) { - throw x.syntaxError("Strict mode error: Unparsed characters found at end of input text"); + case ']' -> { + if (isInitial && jsonParserConfiguration.isStrictMode() && + x.nextClean() != 0) { + throw x.syntaxError("Strict mode error: Unparsed characters found at end of input text"); + } + yield true; } - return true; - default: - throw x.syntaxError("Expected a ',' or ']'"); - } - return false; + default -> + throw x.syntaxError("Expected a ',' or ']'"); + }; } /** @@ -180,10 +178,8 @@ private static boolean checkForSyntaxError(JSONTokener x, JSONParserConfiguratio * A string that begins with [ (left * bracket) and ends with ] *  (right bracket). - * @throws JSONException - * If there is a syntax error. */ - public JSONArray(String source) throws JSONException { + public JSONArray(String source) { this(source, new JSONParserConfiguration()); } @@ -195,10 +191,8 @@ public JSONArray(String source) throws JSONException { * bracket) and ends with ] *  (right bracket). * @param jsonParserConfiguration the parser config object - * @throws JSONException - * If there is a syntax error. */ - public JSONArray(String source, JSONParserConfiguration jsonParserConfiguration) throws JSONException { + public JSONArray(String source, JSONParserConfiguration jsonParserConfiguration) { this(new JSONTokener(source, jsonParserConfiguration), jsonParserConfiguration); } @@ -236,12 +230,12 @@ public JSONArray(Collection collection, JSONParserConfiguration jsonParserCon */ JSONArray(Collection collection, int recursionDepth, JSONParserConfiguration jsonParserConfiguration) { if (recursionDepth > jsonParserConfiguration.getMaxNestingDepth()) { - throw new JSONException("JSONArray has reached recursion depth limit of " + jsonParserConfiguration.getMaxNestingDepth()); + throw new IllegalStateException("JSONArray has reached recursion depth limit of " + jsonParserConfiguration.getMaxNestingDepth()); } if (collection == null) { - this.myArrayList = new ArrayList(); + this.myArrayList = new ArrayList<>(); } else { - this.myArrayList = new ArrayList(collection.size()); + this.myArrayList = new ArrayList<>(collection.size()); this.addAll(collection, true, recursionDepth, jsonParserConfiguration); } } @@ -268,11 +262,11 @@ public JSONArray(Iterable iter) { */ public JSONArray(JSONArray array) { if (array == null) { - this.myArrayList = new ArrayList(); + this.myArrayList = new ArrayList<>(); } else { // shallow copy directly the internal array lists as any wrapping // should have been done already in the original JSONArray - this.myArrayList = new ArrayList(array.myArrayList); + this.myArrayList = new ArrayList<>(array.myArrayList); } } @@ -283,15 +277,15 @@ public JSONArray(JSONArray array) { * Array. If the parameter passed is null, or not an array, an * exception will be thrown. * - * @throws JSONException + * @throws IllegalArgumentException * If not an array or if an array value is non-finite number. * @throws NullPointerException * Thrown if the array parameter is null. */ - public JSONArray(Object array) throws JSONException { + public JSONArray(Object array) { this(); if (!array.getClass().isArray()) { - throw new JSONException( + throw new IllegalArgumentException( "JSONArray initial value should be a string or collection or array."); } this.addAll(array, true, 0); @@ -302,15 +296,15 @@ public JSONArray(Object array) throws JSONException { * * @param initialCapacity * the initial capacity of the JSONArray. - * @throws JSONException + * @throws IllegalArgumentException * If the initial capacity is negative. */ - public JSONArray(int initialCapacity) throws JSONException { + public JSONArray(int initialCapacity) { if (initialCapacity < 0) { - throw new JSONException( + throw new IllegalArgumentException( "JSONArray initial capacity cannot be negative."); } - this.myArrayList = new ArrayList(initialCapacity); + this.myArrayList = new ArrayList<>(initialCapacity); } @Override @@ -324,13 +318,13 @@ public Iterator iterator() { * @param index * The index must be between 0 and length() - 1. * @return An object value. - * @throws JSONException + * @throws IllegalArgumentException * If there is no value for the index. */ - public Object get(int index) throws JSONException { + public Object get(int index) { Object object = this.opt(index); if (object == null) { - throw new JSONException("JSONArray[" + index + "] not found."); + throw new IllegalArgumentException("JSONArray[" + index + "] not found."); } return object; } @@ -342,17 +336,17 @@ public Object get(int index) throws JSONException { * @param index * The index must be between 0 and length() - 1. * @return The truth. - * @throws JSONException + * @throws IllegalArgumentException * If there is no value for the index or if the value is not * convertible to boolean. */ - public boolean getBoolean(int index) throws JSONException { + public boolean getBoolean(int index) { Object object = this.get(index); if (Boolean.FALSE.equals(object) - || (object instanceof String && "false".equalsIgnoreCase((String) object))) { + || (object instanceof String s && "false".equalsIgnoreCase(s))) { return false; } else if (Boolean.TRUE.equals(object) - || (object instanceof String && "true".equalsIgnoreCase((String) object))) { + || (object instanceof String s && "true".equalsIgnoreCase(s))) { return true; } throw wrongValueFormatException(index, "boolean", object, null); @@ -364,14 +358,14 @@ public boolean getBoolean(int index) throws JSONException { * @param index * The index must be between 0 and length() - 1. * @return The value. - * @throws JSONException + * @throws IllegalArgumentException * If the key is not found or if the value cannot be converted * to a number. */ - public double getDouble(int index) throws JSONException { + public double getDouble(int index) { final Object object = this.get(index); - if(object instanceof Number) { - return ((Number)object).doubleValue(); + if(object instanceof Number n) { + return n.doubleValue(); } try { return Double.parseDouble(object.toString()); @@ -386,14 +380,14 @@ public double getDouble(int index) throws JSONException { * @param index * The index must be between 0 and length() - 1. * @return The numeric value. - * @throws JSONException + * @throws IllegalArgumentException * if the key is not found or if the value is not a Number * object and cannot be converted to a number. */ - public float getFloat(int index) throws JSONException { + public float getFloat(int index) { final Object object = this.get(index); - if(object instanceof Number) { - return ((Number)object).floatValue(); + if(object instanceof Number n) { + return n.floatValue(); } try { return Float.parseFloat(object.toString()); @@ -408,15 +402,15 @@ public float getFloat(int index) throws JSONException { * @param index * The index must be between 0 and length() - 1. * @return The numeric value. - * @throws JSONException + * @throws IllegalArgumentException * if the key is not found or if the value is not a Number * object and cannot be converted to a number. */ - public Number getNumber(int index) throws JSONException { + public Number getNumber(int index) { Object object = this.get(index); try { - if (object instanceof Number) { - return (Number)object; + if (object instanceof Number n) { + return n; } return JSONObject.stringToNumber(object.toString()); } catch (Exception e) { @@ -434,16 +428,13 @@ public Number getNumber(int index) throws JSONException { * @param index * The index must be between 0 and length() - 1. * @return The enum value at the index location - * @throws JSONException + * @throws IllegalArgumentException * if the key is not found or if the value cannot be converted * to an enum. */ - public > E getEnum(Class clazz, int index) throws JSONException { + public > E getEnum(Class clazz, int index) { E val = optEnum(clazz, index); if(val==null) { - // JSONException should really take a throwable argument. - // If it did, I would re-implement this with the Enum.valueOf - // method and place any thrown exception in the JSONException throw wrongValueFormatException(index, "enum of type " + JSONObject.quote(clazz.getSimpleName()), opt(index), null); } @@ -459,11 +450,11 @@ public > E getEnum(Class clazz, int index) throws JSONExcep * @param index * The index must be between 0 and length() - 1. * @return The value. - * @throws JSONException + * @throws IllegalArgumentException * If the key is not found or if the value cannot be converted * to a BigDecimal. */ - public BigDecimal getBigDecimal (int index) throws JSONException { + public BigDecimal getBigDecimal (int index) { Object object = this.get(index); BigDecimal val = JSONObject.objectToBigDecimal(object, null); if(val == null) { @@ -478,11 +469,11 @@ public BigDecimal getBigDecimal (int index) throws JSONException { * @param index * The index must be between 0 and length() - 1. * @return The value. - * @throws JSONException + * @throws IllegalArgumentException * If the key is not found or if the value cannot be converted * to a BigInteger. */ - public BigInteger getBigInteger (int index) throws JSONException { + public BigInteger getBigInteger (int index) { Object object = this.get(index); BigInteger val = JSONObject.objectToBigInteger(object, null); if(val == null) { @@ -497,13 +488,13 @@ public BigInteger getBigInteger (int index) throws JSONException { * @param index * The index must be between 0 and length() - 1. * @return The value. - * @throws JSONException + * @throws IllegalArgumentException * If the key is not found or if the value is not a number. */ - public int getInt(int index) throws JSONException { + public int getInt(int index) { final Object object = this.get(index); - if(object instanceof Number) { - return ((Number)object).intValue(); + if(object instanceof Number n) { + return n.intValue(); } try { return Integer.parseInt(object.toString()); @@ -518,14 +509,14 @@ public int getInt(int index) throws JSONException { * @param index * The index must be between 0 and length() - 1. * @return A JSONArray value. - * @throws JSONException + * @throws IllegalArgumentException * If there is no value for the index. or if the value is not a * JSONArray */ - public JSONArray getJSONArray(int index) throws JSONException { + public JSONArray getJSONArray(int index) { Object object = this.get(index); - if (object instanceof JSONArray) { - return (JSONArray) object; + if (object instanceof JSONArray ja) { + return ja; } throw wrongValueFormatException(index, "JSONArray", object, null); } @@ -536,14 +527,14 @@ public JSONArray getJSONArray(int index) throws JSONException { * @param index * subscript * @return A JSONObject value. - * @throws JSONException + * @throws IllegalArgumentException * If there is no value for the index or if the value is not a * JSONObject */ - public JSONObject getJSONObject(int index) throws JSONException { + public JSONObject getJSONObject(int index) { Object object = this.get(index); - if (object instanceof JSONObject) { - return (JSONObject) object; + if (object instanceof JSONObject jo) { + return jo; } throw wrongValueFormatException(index, "JSONObject", object, null); } @@ -554,14 +545,14 @@ public JSONObject getJSONObject(int index) throws JSONException { * @param index * The index must be between 0 and length() - 1. * @return The value. - * @throws JSONException + * @throws IllegalArgumentException * If the key is not found or if the value cannot be converted * to a number. */ - public long getLong(int index) throws JSONException { + public long getLong(int index) { final Object object = this.get(index); - if(object instanceof Number) { - return ((Number)object).longValue(); + if(object instanceof Number n) { + return n.longValue(); } try { return Long.parseLong(object.toString()); @@ -576,13 +567,13 @@ public long getLong(int index) throws JSONException { * @param index * The index must be between 0 and length() - 1. * @return A string value. - * @throws JSONException + * @throws IllegalArgumentException * If there is no string value for the index. */ - public String getString(int index) throws JSONException { + public String getString(int index) { Object object = this.get(index); - if (object instanceof String) { - return (String) object; + if (object instanceof String s) { + return s; } throw wrongValueFormatException(index, "String", object, null); } @@ -606,16 +597,16 @@ public boolean isNull(int index) { * @param separator * A string that will be inserted between the elements. * @return a string. - * @throws JSONException + * @throws IllegalArgumentException * If the array contains an invalid number. */ - public String join(String separator) throws JSONException { + public String join(String separator) { int len = this.length(); if (len == 0) { return ""; } - StringBuilder sb = new StringBuilder( + var sb = new StringBuilder( JSONObject.valueToString(this.myArrayList.get(0))); for (int i = 1; i < len; i++) { @@ -1018,7 +1009,7 @@ public JSONArray optJSONArray(int index) { */ public JSONArray optJSONArray(int index, JSONArray defaultValue) { Object object = this.opt(index); - return object instanceof JSONArray ? (JSONArray) object : defaultValue; + return object instanceof JSONArray ja ? ja : defaultValue; } /** @@ -1045,7 +1036,7 @@ public JSONObject optJSONObject(int index) { */ public JSONObject optJSONObject(int index, JSONObject defaultValue) { Object object = this.opt(index); - return object instanceof JSONObject ? (JSONObject) object : defaultValue; + return object instanceof JSONObject jo ? jo : defaultValue; } /** @@ -1143,13 +1134,13 @@ public Number optNumber(int index, Number defaultValue) { if (JSONObject.NULL.equals(val)) { return defaultValue; } - if (val instanceof Number){ - return (Number) val; + if (val instanceof Number n){ + return n; } - if (val instanceof String) { + if (val instanceof String s) { try { - return JSONObject.stringToNumber((String) val); + return JSONObject.stringToNumber(s); } catch (Exception e) { return defaultValue; } @@ -1204,7 +1195,7 @@ public JSONArray put(boolean value) { * @param value * A Collection value. * @return this. - * @throws JSONException + * @throws IllegalArgumentException * If the value is non-finite number. */ public JSONArray put(Collection value) { @@ -1217,10 +1208,10 @@ public JSONArray put(Collection value) { * @param value * A double value. * @return this. - * @throws JSONException + * @throws IllegalArgumentException * if the value is not finite. */ - public JSONArray put(double value) throws JSONException { + public JSONArray put(double value) { return this.put(Double.valueOf(value)); } @@ -1230,10 +1221,10 @@ public JSONArray put(double value) throws JSONException { * @param value * A float value. * @return this. - * @throws JSONException + * @throws IllegalArgumentException * if the value is not finite. */ - public JSONArray put(float value) throws JSONException { + public JSONArray put(float value) { return this.put(Float.valueOf(value)); } @@ -1266,7 +1257,7 @@ public JSONArray put(long value) { * @param value * A Map value. * @return this. - * @throws JSONException + * @throws IllegalArgumentException * If a value in the map is non-finite number. * @throws NullPointerException * If a key in the map is null @@ -1283,7 +1274,7 @@ public JSONArray put(Map value) { * Integer, JSONArray, JSONObject, Long, or String, or the * JSONObject.NULL object. * @return this. - * @throws JSONException + * @throws IllegalArgumentException * If the value is non-finite number. */ public JSONArray put(Object value) { @@ -1302,10 +1293,10 @@ public JSONArray put(Object value) { * @param value * A boolean value. * @return this. - * @throws JSONException + * @throws IllegalArgumentException * If the index is negative. */ - public JSONArray put(int index, boolean value) throws JSONException { + public JSONArray put(int index, boolean value) { return this.put(index, value ? Boolean.TRUE : Boolean.FALSE); } @@ -1318,10 +1309,10 @@ public JSONArray put(int index, boolean value) throws JSONException { * @param value * A Collection value. * @return this. - * @throws JSONException + * @throws IllegalArgumentException * If the index is negative or if the value is non-finite. */ - public JSONArray put(int index, Collection value) throws JSONException { + public JSONArray put(int index, Collection value) { return this.put(index, new JSONArray(value)); } @@ -1335,10 +1326,10 @@ public JSONArray put(int index, Collection value) throws JSONException { * @param value * A double value. * @return this. - * @throws JSONException + * @throws IllegalArgumentException * If the index is negative or if the value is non-finite. */ - public JSONArray put(int index, double value) throws JSONException { + public JSONArray put(int index, double value) { return this.put(index, Double.valueOf(value)); } @@ -1352,10 +1343,10 @@ public JSONArray put(int index, double value) throws JSONException { * @param value * A float value. * @return this. - * @throws JSONException + * @throws IllegalArgumentException * If the index is negative or if the value is non-finite. */ - public JSONArray put(int index, float value) throws JSONException { + public JSONArray put(int index, float value) { return this.put(index, Float.valueOf(value)); } @@ -1369,10 +1360,10 @@ public JSONArray put(int index, float value) throws JSONException { * @param value * An int value. * @return this. - * @throws JSONException + * @throws IllegalArgumentException * If the index is negative. */ - public JSONArray put(int index, int value) throws JSONException { + public JSONArray put(int index, int value) { return this.put(index, Integer.valueOf(value)); } @@ -1386,10 +1377,10 @@ public JSONArray put(int index, int value) throws JSONException { * @param value * A long value. * @return this. - * @throws JSONException + * @throws IllegalArgumentException * If the index is negative. */ - public JSONArray put(int index, long value) throws JSONException { + public JSONArray put(int index, long value) { return this.put(index, Long.valueOf(value)); } @@ -1403,13 +1394,13 @@ public JSONArray put(int index, long value) throws JSONException { * The Map value. * @return * reference to self - * @throws JSONException + * @throws IllegalArgumentException * If the index is negative or if the value is an invalid * number. * @throws NullPointerException * If a key in the map is null */ - public JSONArray put(int index, Map value) throws JSONException { + public JSONArray put(int index, Map value) { this.put(index, new JSONObject(value, new JSONParserConfiguration())); return this; } @@ -1425,11 +1416,11 @@ public JSONArray put(int index, Map value) throws JSONException { * @param jsonParserConfiguration * Configuration object for the JSON parser * @return reference to self - * @throws JSONException + * @throws IllegalArgumentException * If the index is negative or if the value is an invalid * number. */ - public JSONArray put(int index, Map value, JSONParserConfiguration jsonParserConfiguration) throws JSONException { + public JSONArray put(int index, Map value, JSONParserConfiguration jsonParserConfiguration) { this.put(index, new JSONObject(value, jsonParserConfiguration)); return this; } @@ -1446,13 +1437,13 @@ public JSONArray put(int index, Map value, JSONParserConfiguration jsonPar * Boolean, Double, Integer, JSONArray, JSONObject, Long, or * String, or the JSONObject.NULL object. * @return this. - * @throws JSONException + * @throws IllegalArgumentException * If the index is negative or if the value is an invalid * number. */ - public JSONArray put(int index, Object value) throws JSONException { + public JSONArray put(int index, Object value) { if (index < 0) { - throw new JSONException("JSONArray[" + index + "] not found."); + throw new IllegalArgumentException("JSONArray[" + index + "] not found."); } if (index < this.length()) { JSONObject.testValidity(value); @@ -1519,90 +1510,16 @@ public JSONArray putAll(JSONArray array) { * exception will be thrown. * @return this. * - * @throws JSONException + * @throws IllegalArgumentException * If not an array, JSONArray, Iterable or if an value is non-finite number. * @throws NullPointerException * Thrown if the array parameter is null. */ - public JSONArray putAll(Object array) throws JSONException { + public JSONArray putAll(Object array) { this.addAll(array, false); return this; } - /** - * Creates a JSONPointer using an initialization string and tries to - * match it to an item within this JSONArray. For example, given a - * JSONArray initialized with this document: - *
-     * [
-     *     {"b":"c"}
-     * ]
-     * 
- * and this JSONPointer string: - *
-     * "/0/b"
-     * 
- * Then this method will return the String "c" - * A JSONPointerException may be thrown from code called by this method. - * - * @param jsonPointer string that can be used to create a JSONPointer - * @return the item matched by the JSONPointer, otherwise null - */ - public Object query(String jsonPointer) { - return query(new JSONPointer(jsonPointer)); - } - - /** - * Uses a user initialized JSONPointer and tries to - * match it to an item within this JSONArray. For example, given a - * JSONArray initialized with this document: - *
-     * [
-     *     {"b":"c"}
-     * ]
-     * 
- * and this JSONPointer: - *
-     * "/0/b"
-     * 
- * Then this method will return the String "c" - * A JSONPointerException may be thrown from code called by this method. - * - * @param jsonPointer string that can be used to create a JSONPointer - * @return the item matched by the JSONPointer, otherwise null - */ - public Object query(JSONPointer jsonPointer) { - return jsonPointer.queryFrom(this); - } - - /** - * Queries and returns a value from this object using {@code jsonPointer}, or - * returns null if the query fails due to a missing key. - * - * @param jsonPointer the string representation of the JSON pointer - * @return the queried value or {@code null} - * @throws IllegalArgumentException if {@code jsonPointer} has invalid syntax - */ - public Object optQuery(String jsonPointer) { - return optQuery(new JSONPointer(jsonPointer)); - } - - /** - * Queries and returns a value from this object using {@code jsonPointer}, or - * returns null if the query fails due to a missing key. - * - * @param jsonPointer The JSON pointer - * @return the queried value or {@code null} - * @throws IllegalArgumentException if {@code jsonPointer} has invalid syntax - */ - public Object optQuery(JSONPointer jsonPointer) { - try { - return jsonPointer.queryFrom(this); - } catch (JSONPointerException e) { - return null; - } - } - /** * Remove an index and close the hole. * @@ -1625,16 +1542,16 @@ public Object remove(int index) { * @return true if they are equal */ public boolean similar(Object other) { - if (!(other instanceof JSONArray)) { + if (!(other instanceof JSONArray ja)) { return false; } int len = this.length(); - if (len != ((JSONArray)other).length()) { + if (len != ja.length()) { return false; } for (int i = 0; i < len; i += 1) { Object valueThis = this.myArrayList.get(i); - Object valueOther = ((JSONArray)other).myArrayList.get(i); + Object valueOther = ja.myArrayList.get(i); if(valueThis == valueOther) { continue; } @@ -1657,20 +1574,20 @@ public boolean similar(Object other) { * @return boolean */ private boolean isSimilar(Object valueThis, Object valueOther) { - if (valueThis instanceof JSONObject) { - if (!((JSONObject)valueThis).similar(valueOther)) { + if (valueThis instanceof JSONObject jo) { + if (!jo.similar(valueOther)) { return false; } - } else if (valueThis instanceof JSONArray) { - if (!((JSONArray)valueThis).similar(valueOther)) { + } else if (valueThis instanceof JSONArray ja) { + if (!ja.similar(valueOther)) { return false; } - } else if (valueThis instanceof Number && valueOther instanceof Number) { - if (!JSONObject.isNumberSimilar((Number)valueThis, (Number)valueOther)) { + } else if (valueThis instanceof Number nThis && valueOther instanceof Number nOther) { + if (!JSONObject.isNumberSimilar(nThis, nOther)) { return false; } - } else if (valueThis instanceof JSONString && valueOther instanceof JSONString) { - if (!((JSONString) valueThis).toJSONString().equals(((JSONString) valueOther).toJSONString())) { + } else if (valueThis instanceof JSONString jsThis && valueOther instanceof JSONString jsOther) { + if (!jsThis.toJSONString().equals(jsOther.toJSONString())) { return false; } } else if (!valueThis.equals(valueOther)) { @@ -1688,14 +1605,14 @@ private boolean isSimilar(Object valueThis, Object valueOther) { * paired with the values. * @return A JSONObject, or null if there are no names or if this JSONArray * has no values. - * @throws JSONException + * @throws IllegalArgumentException * If any of the names are null. */ - public JSONObject toJSONObject(JSONArray names) throws JSONException { + public JSONObject toJSONObject(JSONArray names) { if (names == null || names.isEmpty() || this.isEmpty()) { return null; } - JSONObject jo = new JSONObject(names.length()); + var jo = new JSONObject(names.length()); for (int i = 0; i < names.length(); i += 1) { jo.put(names.getString(i), this.opt(i)); } @@ -1748,10 +1665,9 @@ public String toString() { * object, beginning with [ (left * bracket) and ending with ] *  (right bracket). - * @throws JSONException if a called function fails */ @SuppressWarnings("resource") - public String toString(int indentFactor) throws JSONException { + public String toString(int indentFactor) { // each value requires a comma, so multiply the count by 2 // We don't want to oversize the initial capacity int initialSize = myArrayList.size() * 2; @@ -1767,9 +1683,8 @@ public String toString(int indentFactor) throws JSONException { * * @param writer the writer object * @return The writer. - * @throws JSONException if a called function fails */ - public Writer write(Writer writer) throws JSONException { + public Writer write(Writer writer) { return this.write(writer, 0, 0); } @@ -1799,11 +1714,9 @@ public Writer write(Writer writer) throws JSONException { * @param indent * The indentation of the top level. * @return The writer. - * @throws JSONException if a called function fails or unable to write */ @SuppressWarnings("resource") - public Writer write(Writer writer, int indentFactor, int indent) - throws JSONException { + public Writer write(Writer writer, int indentFactor, int indent) { try { boolean needsComma = false; int length = this.length(); @@ -1833,7 +1746,7 @@ public Writer write(Writer writer, int indentFactor, int indent) writer.write(']'); return writer; } catch (IOException e) { - throw new JSONException(e); + throw new UncheckedIOException(e); } } @@ -1853,7 +1766,7 @@ private void writeArrayAttempt(Writer writer, int indentFactor, int indent, int JSONObject.writeValue(writer, this.myArrayList.get(i), indentFactor, indent); } catch (Exception e) { - throw new JSONException("Unable to write JSONArray value at index: " + i, e); + throw new IllegalStateException("Unable to write JSONArray value at index: " + i, e); } } @@ -1867,14 +1780,14 @@ private void writeArrayAttempt(Writer writer, int indentFactor, int indent, int * @return a java.util.List containing the elements of this array */ public List toList() { - List results = new ArrayList(this.myArrayList.size()); + List results = new ArrayList<>(this.myArrayList.size()); for (Object element : this.myArrayList) { if (element == null || JSONObject.NULL.equals(element)) { results.add(null); - } else if (element instanceof JSONArray) { - results.add(((JSONArray) element).toList()); - } else if (element instanceof JSONObject) { - results.add(((JSONObject) element).toMap()); + } else if (element instanceof JSONArray ja) { + results.add(ja.toList()); + } else if (element instanceof JSONObject jo) { + results.add(jo.toMap()); } else { results.add(element); } @@ -1946,10 +1859,10 @@ private void addAll(Iterable iter, boolean wrap) { * @param wrap * {@code true} to call {@link JSONObject#wrap(Object)} for each item, * {@code false} to add the items directly - * @throws JSONException + * @throws IllegalArgumentException * If not an array or if an array value is non-finite number. */ - private void addAll(Object array, boolean wrap) throws JSONException { + private void addAll(Object array, boolean wrap) { this.addAll(array, wrap, 0); } @@ -1983,12 +1896,12 @@ private void addAll(Object array, boolean wrap, int recursionDepth) { * Variable for tracking the count of nested object creations. * @param jsonParserConfiguration * Variable to pass parser custom configuration for json parsing. - * @throws JSONException + * @throws IllegalArgumentException * If not an array or if an array value is non-finite number. * @throws NullPointerException * Thrown if the array parameter is null. */ - private void addAll(Object array, boolean wrap, int recursionDepth, JSONParserConfiguration jsonParserConfiguration) throws JSONException { + private void addAll(Object array, boolean wrap, int recursionDepth, JSONParserConfiguration jsonParserConfiguration) { if (array.getClass().isArray()) { int length = Array.getLength(array); this.myArrayList.ensureCapacity(this.myArrayList.size() + length); @@ -2001,45 +1914,45 @@ private void addAll(Object array, boolean wrap, int recursionDepth, JSONParserCo this.put(Array.get(array, i)); } } - } else if (array instanceof JSONArray) { + } else if (array instanceof JSONArray ja) { // use the built in array list `addAll` as all object // wrapping should have been completed in the original // JSONArray - this.myArrayList.addAll(((JSONArray)array).myArrayList); - } else if (array instanceof Collection) { - this.addAll((Collection)array, wrap, recursionDepth, jsonParserConfiguration); - } else if (array instanceof Iterable) { - this.addAll((Iterable)array, wrap); + this.myArrayList.addAll(ja.myArrayList); + } else if (array instanceof Collection coll) { + this.addAll(coll, wrap, recursionDepth, jsonParserConfiguration); + } else if (array instanceof Iterable iter) { + this.addAll(iter, wrap); } else { - throw new JSONException( + throw new IllegalArgumentException( "JSONArray initial value should be a string or collection or array."); } } /** - * Create a new JSONException in a common format for incorrect conversions. + * Create a new IllegalArgumentException in a common format for incorrect conversions. * @param idx index of the item * @param valueType the type of value being coerced to * @param cause optional cause of the coercion failure - * @return JSONException that can be thrown. + * @return IllegalArgumentException that can be thrown. */ - private static JSONException wrongValueFormatException( + private static IllegalArgumentException wrongValueFormatException( int idx, String valueType, Object value, Throwable cause) { if(value == null) { - return new JSONException( + return new IllegalArgumentException( "JSONArray[" + idx + "] is not a " + valueType + " (null)." , cause); } // don't try to toString collections or known object types that could be large. if(value instanceof Map || value instanceof Iterable || value instanceof JSONObject) { - return new JSONException( + return new IllegalArgumentException( "JSONArray[" + idx + "] is not a " + valueType + " (" + value.getClass() + ")." , cause); } - return new JSONException( + return new IllegalArgumentException( "JSONArray[" + idx + "] is not a " + valueType + " (" + value.getClass() + " : " + value + ")." , cause); } diff --git a/src/main/java/org/json/JSONException.java b/src/main/java/org/json/JSONException.java deleted file mode 100644 index 02c29f3fc..000000000 --- a/src/main/java/org/json/JSONException.java +++ /dev/null @@ -1,49 +0,0 @@ -package org.json; - -/* -Public Domain. - */ - -/** - * The JSONException is thrown by the JSON.org classes when things are amiss. - * - * @author JSON.org - * @version 2015-12-09 - */ -public class JSONException extends RuntimeException { - /** Serialization ID */ - private static final long serialVersionUID = 0; - - /** - * Constructs a JSONException with an explanatory message. - * - * @param message - * Detail about the reason for the exception. - */ - public JSONException(final String message) { - super(message); - } - - /** - * Constructs a JSONException with an explanatory message and cause. - * - * @param message - * Detail about the reason for the exception. - * @param cause - * The cause. - */ - public JSONException(final String message, final Throwable cause) { - super(message, cause); - } - - /** - * Constructs a new JSONException with the specified cause. - * - * @param cause - * The cause. - */ - public JSONException(final Throwable cause) { - super(cause.getMessage(), cause); - } - -} diff --git a/src/main/java/org/json/JSONML.java b/src/main/java/org/json/JSONML.java deleted file mode 100644 index 6ec997061..000000000 --- a/src/main/java/org/json/JSONML.java +++ /dev/null @@ -1,695 +0,0 @@ -package org.json; - -/* -Public Domain. -*/ - -/** - * This provides static methods to convert an XML text into a JSONArray or - * JSONObject, and to covert a JSONArray or JSONObject into an XML text using - * the JsonML transform. - * - * @author JSON.org - * @version 2016-01-30 - */ -public class JSONML { - - /** - * Constructs a new JSONML object. - * @deprecated (Utility class cannot be instantiated) - */ - @Deprecated - public JSONML() { - } - - /** - * Safely cast parse result to JSONArray with proper type checking. - * @param result The result from parse() method - * @return JSONArray if result is a JSONArray - * @throws JSONException if result is not a JSONArray - */ - private static JSONArray toJSONArraySafe(Object result) throws JSONException { - if (result instanceof JSONArray) { - return (JSONArray) result; - } - throw new JSONException("Expected JSONArray but got " + - (result == null ? "null" : result.getClass().getSimpleName())); - } - - /** - * Safely cast parse result to JSONObject with proper type checking. - * @param result The result from parse() method - * @return JSONObject if result is a JSONObject - * @throws JSONException if result is not a JSONObject - */ - private static JSONObject toJSONObjectSafe(Object result) throws JSONException { - if (result instanceof JSONObject) { - return (JSONObject) result; - } - throw new JSONException("Expected JSONObject but got " + - (result == null ? "null" : result.getClass().getSimpleName())); - } - - /** - * Parse XML values and store them in a JSONArray. - * @param x The XMLTokener containing the source string. - * @param arrayForm true if array form, false if object form. - * @param ja The JSONArray that is containing the current tag or null - * if we are at the outermost level. - * @param keepStrings Don't type-convert text nodes and attribute values - * @return A JSONArray if the value is the outermost tag, otherwise null. - * @throws JSONException if a parsing error occurs - */ - private static Object parse( - XMLTokener x, - boolean arrayForm, - JSONArray ja, - boolean keepStrings, - int currentNestingDepth - ) throws JSONException { - return parse(x,arrayForm, ja, - keepStrings ? JSONMLParserConfiguration.KEEP_STRINGS : JSONMLParserConfiguration.ORIGINAL, - currentNestingDepth); - } - - /** - * Parse XML values and store them in a JSONArray. - * @param x The XMLTokener containing the source string. - * @param arrayForm true if array form, false if object form. - * @param ja The JSONArray that is containing the current tag or null - * if we are at the outermost level. - * @param config The parser configuration: - * JSONMLParserConfiguration.ORIGINAL is the default behaviour; - * JSONMLParserConfiguration.KEEP_STRINGS means Don't type-convert text nodes and attribute values. - * @return A JSONArray if the value is the outermost tag, otherwise null. - * @throws JSONException if a parsing error occurs - */ - private static Object parse( - XMLTokener x, - boolean arrayForm, - JSONArray ja, - JSONMLParserConfiguration config, - int currentNestingDepth - ) throws JSONException { - String attribute; - char c; - String closeTag = null; - int i; - JSONArray newja = null; - JSONObject newjo = null; - Object token; - String tagName = null; - -// Test for and skip past these forms: -// -// -// -// - - while (true) { - if (!x.more()) { - throw x.syntaxError("Bad XML"); - } - token = x.nextContent(); - if (token == XML.LT) { - token = x.nextToken(); - if (token instanceof Character) { - if (token == XML.SLASH) { - -// Close tag "); - } else { - x.back(); - } - } else if (c == '[') { - token = x.nextToken(); - if ("CDATA".equals(token) && x.next() == '[') { - if (ja != null) { - ja.put(x.nextCDATA()); - } - } else { - throw x.syntaxError("Expected 'CDATA['"); - } - } else { - i = 1; - do { - token = x.nextMeta(); - if (token == null) { - throw x.syntaxError("Missing '>' after ' 0); - } - } else if (token == XML.QUEST) { - -// "); - } else { - throw x.syntaxError("Misshaped tag"); - } - -// Open tag < - - } else { - if (!(token instanceof String)) { - throw x.syntaxError("Bad tagName '" + token + "'."); - } - tagName = (String)token; - newja = new JSONArray(); - newjo = new JSONObject(); - if (arrayForm) { - newja.put(tagName); - if (ja != null) { - ja.put(newja); - } - } else { - newjo.put("tagName", tagName); - if (ja != null) { - ja.put(newjo); - } - } - token = null; - for (;;) { - if (token == null) { - token = x.nextToken(); - } - if (token == null) { - throw x.syntaxError("Misshaped tag"); - } - if (!(token instanceof String)) { - break; - } - -// attribute = value - - attribute = (String)token; - if (!arrayForm && ("tagName".equals(attribute) || "childNode".equals(attribute))) { - throw x.syntaxError("Reserved attribute."); - } - token = x.nextToken(); - if (token == XML.EQ) { - token = x.nextToken(); - if (!(token instanceof String)) { - throw x.syntaxError("Missing value"); - } - newjo.accumulate(attribute, config.isKeepStrings() ? ((String)token) :XML.stringToValue((String)token)); - token = null; - } else { - newjo.accumulate(attribute, ""); - } - } - if (arrayForm && newjo.length() > 0) { - newja.put(newjo); - } - -// Empty tag <.../> - - if (token == XML.SLASH) { - if (x.nextToken() != XML.GT) { - throw x.syntaxError("Misshaped tag"); - } - if (ja == null) { - if (arrayForm) { - return newja; - } - return newjo; - } - -// Content, between <...> and - - } else { - if (token != XML.GT) { - throw x.syntaxError("Misshaped tag"); - } - - if (currentNestingDepth == config.getMaxNestingDepth()) { - throw x.syntaxError("Maximum nesting depth of " + config.getMaxNestingDepth() + " reached"); - } - - closeTag = (String)parse(x, arrayForm, newja, config, currentNestingDepth + 1); - if (closeTag != null) { - if (!closeTag.equals(tagName)) { - throw x.syntaxError("Mismatched '" + tagName + - "' and '" + closeTag + "'"); - } - tagName = null; - if (!arrayForm && newja.length() > 0) { - newjo.put("childNodes", newja); - } - if (ja == null) { - if (arrayForm) { - return newja; - } - return newjo; - } - } - } - } - } else { - if (ja != null) { - Object value; - - if (token instanceof String) { - String strToken = (String) token; - if (config.isKeepStrings()) { - value = XML.unescape(strToken); - } else { - value = XML.stringToValue(strToken); - } - } else { - value = token; - } - - ja.put(value); - - } - } - } - } - - - /** - * Convert a well-formed (but not necessarily valid) XML string into a - * JSONArray using the JsonML transform. Each XML tag is represented as - * a JSONArray in which the first element is the tag name. If the tag has - * attributes, then the second element will be JSONObject containing the - * name/value pairs. If the tag contains children, then strings and - * JSONArrays will represent the child tags. - * Comments, prologs, DTDs, and
{@code <[ [ ]]>}
are ignored. - * @param string The source string. - * @return A JSONArray containing the structured data from the XML string. - * @throws JSONException Thrown on error converting to a JSONArray - */ - public static JSONArray toJSONArray(String string) throws JSONException { - return toJSONArraySafe(parse(new XMLTokener(string), true, null, JSONMLParserConfiguration.ORIGINAL, 0)); - } - - - /** - * Convert a well-formed (but not necessarily valid) XML string into a - * JSONArray using the JsonML transform. Each XML tag is represented as - * a JSONArray in which the first element is the tag name. If the tag has - * attributes, then the second element will be JSONObject containing the - * name/value pairs. If the tag contains children, then strings and - * JSONArrays will represent the child tags. - * As opposed to toJSONArray this method does not attempt to convert - * any text node or attribute value to any type - * but just leaves it as a string. - * Comments, prologs, DTDs, and
{@code <[ [ ]]>}
are ignored. - * @param string The source string. - * @param keepStrings If true, then values will not be coerced into boolean - * or numeric values and will instead be left as strings - * @return A JSONArray containing the structured data from the XML string. - * @throws JSONException Thrown on error converting to a JSONArray - */ - public static JSONArray toJSONArray(String string, boolean keepStrings) throws JSONException { - return toJSONArraySafe(parse(new XMLTokener(string), true, null, keepStrings, 0)); - } - - - - /** - * Convert a well-formed (but not necessarily valid) XML string into a - * JSONArray using the JsonML transform. Each XML tag is represented as - * a JSONArray in which the first element is the tag name. If the tag has - * attributes, then the second element will be JSONObject containing the - * name/value pairs. If the tag contains children, then strings and - * JSONArrays will represent the child tags. - * As opposed to toJSONArray this method does not attempt to convert - * any text node or attribute value to any type - * but just leaves it as a string. - * Comments, prologs, DTDs, and
{@code <[ [ ]]>}
are ignored. - * @param string The source string. - * @param config The parser configuration: - * JSONMLParserConfiguration.ORIGINAL is the default behaviour; - * JSONMLParserConfiguration.KEEP_STRINGS means values will not be coerced into boolean - * or numeric values and will instead be left as strings - * @return A JSONArray containing the structured data from the XML string. - * @throws JSONException Thrown on error converting to a JSONArray - */ - public static JSONArray toJSONArray(String string, JSONMLParserConfiguration config) throws JSONException { - return toJSONArraySafe(parse(new XMLTokener(string), true, null, config, 0)); - } - - - /** - * Convert a well-formed (but not necessarily valid) XML string into a - * JSONArray using the JsonML transform. Each XML tag is represented as - * a JSONArray in which the first element is the tag name. If the tag has - * attributes, then the second element will be JSONObject containing the - * name/value pairs. If the tag contains children, then strings and - * JSONArrays will represent the child content and tags. - * As opposed to toJSONArray this method does not attempt to convert - * any text node or attribute value to any type - * but just leaves it as a string. - * Comments, prologs, DTDs, and
{@code <[ [ ]]>}
are ignored. - * @param x An XMLTokener. - * @param config The parser configuration: - * JSONMLParserConfiguration.ORIGINAL is the default behaviour; - * JSONMLParserConfiguration.KEEP_STRINGS means values will not be coerced into boolean - * or numeric values and will instead be left as strings - * @return A JSONArray containing the structured data from the XML string. - * @throws JSONException Thrown on error converting to a JSONArray - */ - public static JSONArray toJSONArray(XMLTokener x, JSONMLParserConfiguration config) throws JSONException { - return toJSONArraySafe(parse(x, true, null, config, 0)); - } - - - /** - * Convert a well-formed (but not necessarily valid) XML string into a - * JSONArray using the JsonML transform. Each XML tag is represented as - * a JSONArray in which the first element is the tag name. If the tag has - * attributes, then the second element will be JSONObject containing the - * name/value pairs. If the tag contains children, then strings and - * JSONArrays will represent the child content and tags. - * As opposed to toJSONArray this method does not attempt to convert - * any text node or attribute value to any type - * but just leaves it as a string. - * Comments, prologs, DTDs, and
{@code <[ [ ]]>}
are ignored. - * @param x An XMLTokener. - * @param keepStrings If true, then values will not be coerced into boolean - * or numeric values and will instead be left as strings - * @return A JSONArray containing the structured data from the XML string. - * @throws JSONException Thrown on error converting to a JSONArray - */ - public static JSONArray toJSONArray(XMLTokener x, boolean keepStrings) throws JSONException { - return toJSONArraySafe(parse(x, true, null, keepStrings, 0)); - } - - - /** - * Convert a well-formed (but not necessarily valid) XML string into a - * JSONArray using the JsonML transform. Each XML tag is represented as - * a JSONArray in which the first element is the tag name. If the tag has - * attributes, then the second element will be JSONObject containing the - * name/value pairs. If the tag contains children, then strings and - * JSONArrays will represent the child content and tags. - * Comments, prologs, DTDs, and
{@code <[ [ ]]>}
are ignored. - * @param x An XMLTokener. - * @return A JSONArray containing the structured data from the XML string. - * @throws JSONException Thrown on error converting to a JSONArray - */ - public static JSONArray toJSONArray(XMLTokener x) throws JSONException { - return toJSONArraySafe(parse(x, true, null, false, 0)); - } - - - /** - * Convert a well-formed (but not necessarily valid) XML string into a - * JSONObject using the JsonML transform. Each XML tag is represented as - * a JSONObject with a "tagName" property. If the tag has attributes, then - * the attributes will be in the JSONObject as properties. If the tag - * contains children, the object will have a "childNodes" property which - * will be an array of strings and JsonML JSONObjects. - - * Comments, prologs, DTDs, and
{@code <[ [ ]]>}
are ignored. - * @param string The XML source text. - * @return A JSONObject containing the structured data from the XML string. - * @throws JSONException Thrown on error converting to a JSONObject - */ - public static JSONObject toJSONObject(String string) throws JSONException { - return toJSONObjectSafe(parse(new XMLTokener(string), false, null, false, 0)); - } - - - /** - * Convert a well-formed (but not necessarily valid) XML string into a - * JSONObject using the JsonML transform. Each XML tag is represented as - * a JSONObject with a "tagName" property. If the tag has attributes, then - * the attributes will be in the JSONObject as properties. If the tag - * contains children, the object will have a "childNodes" property which - * will be an array of strings and JsonML JSONObjects. - - * Comments, prologs, DTDs, and
{@code <[ [ ]]>}
are ignored. - * @param string The XML source text. - * @param keepStrings If true, then values will not be coerced into boolean - * or numeric values and will instead be left as strings - * @return A JSONObject containing the structured data from the XML string. - * @throws JSONException Thrown on error converting to a JSONObject - */ - public static JSONObject toJSONObject(String string, boolean keepStrings) throws JSONException { - return toJSONObjectSafe(parse(new XMLTokener(string), false, null, keepStrings, 0)); - } - - - /** - * Convert a well-formed (but not necessarily valid) XML string into a - * JSONObject using the JsonML transform. Each XML tag is represented as - * a JSONObject with a "tagName" property. If the tag has attributes, then - * the attributes will be in the JSONObject as properties. If the tag - * contains children, the object will have a "childNodes" property which - * will be an array of strings and JsonML JSONObjects. - - * Comments, prologs, DTDs, and
{@code <[ [ ]]>}
are ignored. - * @param string The XML source text. - * @param config The parser configuration: - * JSONMLParserConfiguration.ORIGINAL is the default behaviour; - * JSONMLParserConfiguration.KEEP_STRINGS means values will not be coerced into boolean - * or numeric values and will instead be left as strings - * @return A JSONObject containing the structured data from the XML string. - * @throws JSONException Thrown on error converting to a JSONObject - */ - public static JSONObject toJSONObject(String string, JSONMLParserConfiguration config) throws JSONException { - return toJSONObjectSafe(parse(new XMLTokener(string), false, null, config, 0)); - } - - - /** - * Convert a well-formed (but not necessarily valid) XML string into a - * JSONObject using the JsonML transform. Each XML tag is represented as - * a JSONObject with a "tagName" property. If the tag has attributes, then - * the attributes will be in the JSONObject as properties. If the tag - * contains children, the object will have a "childNodes" property which - * will be an array of strings and JsonML JSONObjects. - - * Comments, prologs, DTDs, and
{@code <[ [ ]]>}
are ignored. - * @param x An XMLTokener of the XML source text. - * @return A JSONObject containing the structured data from the XML string. - * @throws JSONException Thrown on error converting to a JSONObject - */ - public static JSONObject toJSONObject(XMLTokener x) throws JSONException { - return toJSONObjectSafe(parse(x, false, null, false, 0)); - } - - - /** - * Convert a well-formed (but not necessarily valid) XML string into a - * JSONObject using the JsonML transform. Each XML tag is represented as - * a JSONObject with a "tagName" property. If the tag has attributes, then - * the attributes will be in the JSONObject as properties. If the tag - * contains children, the object will have a "childNodes" property which - * will be an array of strings and JsonML JSONObjects. - - * Comments, prologs, DTDs, and
{@code <[ [ ]]>}
are ignored. - * @param x An XMLTokener of the XML source text. - * @param keepStrings If true, then values will not be coerced into boolean - * or numeric values and will instead be left as strings - * @return A JSONObject containing the structured data from the XML string. - * @throws JSONException Thrown on error converting to a JSONObject - */ - public static JSONObject toJSONObject(XMLTokener x, boolean keepStrings) throws JSONException { - return toJSONObjectSafe(parse(x, false, null, keepStrings, 0)); - } - - - /** - * Convert a well-formed (but not necessarily valid) XML string into a - * JSONObject using the JsonML transform. Each XML tag is represented as - * a JSONObject with a "tagName" property. If the tag has attributes, then - * the attributes will be in the JSONObject as properties. If the tag - * contains children, the object will have a "childNodes" property which - * will be an array of strings and JsonML JSONObjects. - - * Comments, prologs, DTDs, and
{@code <[ [ ]]>}
are ignored. - * @param x An XMLTokener of the XML source text. - * @param config The parser configuration: - * JSONMLParserConfiguration.ORIGINAL is the default behaviour; - * JSONMLParserConfiguration.KEEP_STRINGS means values will not be coerced into boolean - * or numeric values and will instead be left as strings - * @return A JSONObject containing the structured data from the XML string. - * @throws JSONException Thrown on error converting to a JSONObject - */ - public static JSONObject toJSONObject(XMLTokener x, JSONMLParserConfiguration config) throws JSONException { - return toJSONObjectSafe(parse(x, false, null, config, 0)); - } - - - /** - * Reverse the JSONML transformation, making an XML text from a JSONArray. - * @param ja A JSONArray. - * @return An XML string. - * @throws JSONException Thrown on error converting to a string - */ - public static String toString(JSONArray ja) throws JSONException { - int i; - JSONObject jo; - int length; - Object object; - StringBuilder sb = new StringBuilder(); - String tagName; - -// Emit = length) { - sb.append('/'); - sb.append('>'); - } else { - sb.append('>'); - do { - object = ja.get(i); - i += 1; - if (object != null) { - if (object instanceof String) { - sb.append(XML.escape(object.toString())); - } else if (object instanceof JSONObject) { - sb.append(toString((JSONObject)object)); - } else if (object instanceof JSONArray) { - sb.append(toString((JSONArray)object)); - } else { - sb.append(object.toString()); - } - } - } while (i < length); - sb.append('<'); - sb.append('/'); - sb.append(tagName); - sb.append('>'); - } - return sb.toString(); - } - - - /** - * Reverse the JSONML transformation, making an XML text from a JSONObject. - * The JSONObject must contain a "tagName" property. If it has children, - * then it must have a "childNodes" property containing an array of objects. - * The other properties are attributes with string values. - * @param jo A JSONObject. - * @return An XML string. - * @throws JSONException Thrown on error converting to a string - */ - public static String toString(JSONObject jo) throws JSONException { - StringBuilder sb = new StringBuilder(); - int i; - JSONArray ja; - int length; - Object object; - String tagName; - Object value; - -//Emit '); - } else { - sb.append('>'); - length = ja.length(); - for (i = 0; i < length; i += 1) { - object = ja.get(i); - if (object != null) { - if (object instanceof String) { - sb.append(XML.escape(object.toString())); - } else if (object instanceof JSONObject) { - sb.append(toString((JSONObject)object)); - } else if (object instanceof JSONArray) { - sb.append(toString((JSONArray)object)); - } else { - sb.append(object.toString()); - } - } - } - sb.append('<'); - sb.append('/'); - sb.append(tagName); - sb.append('>'); - } - return sb.toString(); - } -} diff --git a/src/main/java/org/json/JSONMLParserConfiguration.java b/src/main/java/org/json/JSONMLParserConfiguration.java deleted file mode 100644 index 43ba0db62..000000000 --- a/src/main/java/org/json/JSONMLParserConfiguration.java +++ /dev/null @@ -1,69 +0,0 @@ -package org.json; -/* -Public Domain. -*/ - -/** - * Configuration object for the XML to JSONML parser. The configuration is immutable. - */ -@SuppressWarnings({""}) -public class JSONMLParserConfiguration extends ParserConfiguration { - - /** - * We can override the default maximum nesting depth if needed. - */ - public static final int DEFAULT_MAXIMUM_NESTING_DEPTH = ParserConfiguration.DEFAULT_MAXIMUM_NESTING_DEPTH; - - /** Original Configuration of the XML to JSONML Parser. */ - public static final JSONMLParserConfiguration ORIGINAL - = new JSONMLParserConfiguration(); - /** Original configuration of the XML to JSONML Parser except that values are kept as strings. */ - public static final JSONMLParserConfiguration KEEP_STRINGS - = new JSONMLParserConfiguration().withKeepStrings(true); - - /** - * Default parser configuration. Does not keep strings (tries to implicitly convert values). - */ - public JSONMLParserConfiguration() { - super(); - this.maxNestingDepth = DEFAULT_MAXIMUM_NESTING_DEPTH; - } - - /** - * Configure the parser string processing and use the default CDATA Tag Name as "content". - * @param keepStrings true to parse all values as string. - * false to try and convert XML string values into a JSON value. - * @param maxNestingDepth int to limit the nesting depth - */ - protected JSONMLParserConfiguration(final boolean keepStrings, final int maxNestingDepth) { - super(keepStrings, maxNestingDepth); - } - - /** - * Provides a new instance of the same configuration. - */ - @Override - protected JSONMLParserConfiguration clone() { - // future modifications to this method should always ensure a "deep" - // clone in the case of collections. i.e. if a Map is added as a configuration - // item, a new map instance should be created and if possible each value in the - // map should be cloned as well. If the values of the map are known to also - // be immutable, then a shallow clone of the map is acceptable. - return new JSONMLParserConfiguration( - this.keepStrings, - this.maxNestingDepth - ); - } - - @SuppressWarnings("unchecked") - @Override - public JSONMLParserConfiguration withKeepStrings(final boolean newVal) { - return super.withKeepStrings(newVal); - } - - @SuppressWarnings("unchecked") - @Override - public JSONMLParserConfiguration withMaxNestingDepth(int maxNestingDepth) { - return super.withMaxNestingDepth(maxNestingDepth); - } -} diff --git a/src/main/java/org/json/JSONObject.java b/src/main/java/org/json/JSONObject.java index db2c2aac7..d68fbc5a2 100644 --- a/src/main/java/org/json/JSONObject.java +++ b/src/main/java/org/json/JSONObject.java @@ -6,8 +6,8 @@ import java.io.Closeable; import java.io.IOException; +import java.io.UncheckedIOException; import java.io.Writer; -import java.lang.annotation.Annotation; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; @@ -148,12 +148,10 @@ public Class getMapType() { * Set of method names that should be excluded when identifying record-style accessors. * These are common bean/Object method names that are not property accessors. */ - private static final Set EXCLUDED_RECORD_METHOD_NAMES = Collections.unmodifiableSet( - new HashSet(Arrays.asList( - "get", "is", "set", - "toString", "hashCode", "equals", "clone", - "notify", "notifyAll", "wait" - )) + private static final Set EXCLUDED_RECORD_METHOD_NAMES = Set.of( + "get", "is", "set", + "toString", "hashCode", "equals", "clone", + "notify", "notifyAll", "wait" ); /** @@ -166,7 +164,7 @@ public JSONObject() { // implementations to rearrange their items for a faster element // retrieval based on associative access. // Therefore, an implementation mustn't rely on the order of the item. - this.map = new HashMap(); + this.map = new HashMap<>(); } /** @@ -194,11 +192,11 @@ public JSONObject(JSONObject jo, String ... names) { * * @param x * A JSONTokener object containing the source string. - * @throws JSONException + * @throws IllegalArgumentException * If there is a syntax error in the source string or a * duplicated key. */ - public JSONObject(JSONTokener x) throws JSONException { + public JSONObject(JSONTokener x) { this(x, x.getJsonParserConfiguration()); } @@ -209,11 +207,11 @@ public JSONObject(JSONTokener x) throws JSONException { * A JSONTokener object containing the source string. * @param jsonParserConfiguration * Variable to pass parser custom configuration for json parsing. - * @throws JSONException + * @throws IllegalArgumentException * If there is a syntax error in the source string or a * duplicated key. */ - public JSONObject(JSONTokener x, JSONParserConfiguration jsonParserConfiguration) throws JSONException { + public JSONObject(JSONTokener x, JSONParserConfiguration jsonParserConfiguration) { this(); boolean isInitial = x.getPrevious() == 0; @@ -242,16 +240,17 @@ private boolean parseJSONObject(JSONTokener jsonTokener, JSONParserConfiguration char c = jsonTokener.nextClean(); switch (c) { - case 0: - throw jsonTokener.syntaxError("A JSONObject text must end with '}'"); - case '}': + case 0 -> throw jsonTokener.syntaxError("A JSONObject text must end with '}'"); + case '}' -> { if (isInitial && jsonParserConfiguration.isStrictMode() && jsonTokener.nextClean() != 0) { throw jsonTokener.syntaxError("Strict mode error: Unparsed characters found at end of input text"); } return true; - default: + } + default -> { obj = jsonTokener.nextSimpleValue(c); key = obj.toString(); + } } checkKeyForStrictMode(jsonTokener, jsonParserConfiguration, obj); @@ -293,38 +292,38 @@ private boolean parseJSONObject(JSONTokener jsonTokener, JSONParserConfiguration * @return */ private static boolean parseEndOfKeyValuePair(JSONTokener jsonTokener, JSONParserConfiguration jsonParserConfiguration, boolean isInitial) { - switch (jsonTokener.nextClean()) { - case ';': + return switch (jsonTokener.nextClean()) { + case ';' -> { // In strict mode semicolon is not a valid separator if (jsonParserConfiguration.isStrictMode()) { throw jsonTokener.syntaxError("Strict mode error: Invalid character ';' found"); } - break; - case ',': + yield false; + } + case ',' -> { if (jsonTokener.nextClean() == '}') { // trailing commas are not allowed in strict mode if (jsonParserConfiguration.isStrictMode()) { throw jsonTokener.syntaxError("Strict mode error: Expected another object element"); } // End of JSON object - return true; + yield true; } if (jsonTokener.end()) { throw jsonTokener.syntaxError("A JSONObject text must end with '}'"); } jsonTokener.back(); - break; - case '}': + yield false; + } + case '}' -> { if (isInitial && jsonParserConfiguration.isStrictMode() && jsonTokener.nextClean() != 0) { throw jsonTokener.syntaxError("Strict mode error: Unparsed characters found at end of input text"); } // End of JSON object - return true; - default: - throw jsonTokener.syntaxError("Expected a ',' or '}'"); - } - // Not at end of JSON object - return false; + yield true; + } + default -> throw jsonTokener.syntaxError("Expected a ',' or '}'"); + }; } /** @@ -353,7 +352,7 @@ private static void checkKeyForStrictMode(JSONTokener jsonTokener, JSONParserCon * @param m * A map object that can be used to initialize the contents of * the JSONObject. - * @throws JSONException + * @throws IllegalArgumentException * If a value in the map is non-finite number. * @throws NullPointerException * If a key in the map is null @@ -380,12 +379,12 @@ public JSONObject(Map m, JSONParserConfiguration jsonParserConfiguration) */ private JSONObject(Map m, int recursionDepth, JSONParserConfiguration jsonParserConfiguration) { if (recursionDepth > jsonParserConfiguration.getMaxNestingDepth()) { - throw new JSONException("JSONObject has reached recursion depth limit of " + jsonParserConfiguration.getMaxNestingDepth()); + throw new IllegalStateException("JSONObject has reached recursion depth limit of " + jsonParserConfiguration.getMaxNestingDepth()); } if (m == null) { - this.map = new HashMap(); + this.map = new HashMap<>(); } else { - this.map = new HashMap(m.size()); + this.map = new HashMap<>(m.size()); for (final Entry e : m.entrySet()) { if(e.getKey() == null) { throw new NullPointerException("Null key."); @@ -418,44 +417,11 @@ private JSONObject(Map m, int recursionDepth, JSONParserConfiguration json * if the result of calling object.getName() is * "Larry Fine", then the JSONObject will contain * "name": "Larry Fine". - *

- * The {@link JSONPropertyName} annotation can be used on a bean getter to - * override key name used in the JSONObject. For example, using the object - * above with the getName method, if we annotated it with: - *

-     * @JSONPropertyName("FullName")
-     * public String getName() { return this.name; }
-     * 
- * The resulting JSON object would contain "FullName": "Larry Fine" - *

- * Similarly, the {@link JSONPropertyName} annotation can be used on non- - * get and is methods. We can also override key - * name used in the JSONObject as seen below even though the field would normally - * be ignored: - *

-     * @JSONPropertyName("FullName")
-     * public String fullName() { return this.name; }
-     * 
- * The resulting JSON object would contain "FullName": "Larry Fine" - *

- * The {@link JSONPropertyIgnore} annotation can be used to force the bean property - * to not be serialized into JSON. If both {@link JSONPropertyIgnore} and - * {@link JSONPropertyName} are defined on the same method, a depth comparison is - * performed and the one closest to the concrete class being serialized is used. - * If both annotations are at the same level, then the {@link JSONPropertyIgnore} - * annotation takes precedent and the field is not serialized. - * For example, the following declaration would prevent the getName - * method from being serialized: - *

-     * @JSONPropertyName("FullName")
-     * @JSONPropertyIgnore
-     * public String getName() { return this.name; }
-     * 
* * @param bean * An object that has getter methods that should be used to make * a JSONObject. - * @throws JSONException + * @throws IllegalArgumentException * If a getter returned a non-finite number. */ public JSONObject(Object bean) { @@ -508,11 +474,11 @@ public JSONObject(Object object, String ... names) { * A string beginning with { (left * brace) and ending with } *  (right brace). - * @exception JSONException + * @exception IllegalArgumentException * If there is a syntax error in the source string or a * duplicated key. */ - public JSONObject(String source) throws JSONException { + public JSONObject(String source) { this(source, new JSONParserConfiguration()); } @@ -526,11 +492,11 @@ public JSONObject(String source) throws JSONException { *  (right brace). * @param jsonParserConfiguration * Variable to pass parser custom configuration for json parsing. - * @exception JSONException + * @exception IllegalArgumentException * If there is a syntax error in the source string or a * duplicated key. */ - public JSONObject(String source, JSONParserConfiguration jsonParserConfiguration) throws JSONException { + public JSONObject(String source, JSONParserConfiguration jsonParserConfiguration) { this(new JSONTokener(source, jsonParserConfiguration), jsonParserConfiguration); } @@ -541,10 +507,10 @@ public JSONObject(String source, JSONParserConfiguration jsonParserConfiguration * The ResourceBundle base name. * @param locale * The Locale to load the ResourceBundle for. - * @throws JSONException - * If any JSONExceptions are detected. + * @throws IllegalArgumentException + * If any exceptions are detected. */ - public JSONObject(String baseName, Locale locale) throws JSONException { + public JSONObject(String baseName, Locale locale) { this(); ResourceBundle bundle = ResourceBundle.getBundle(baseName, locale, Thread.currentThread().getContextClassLoader()); @@ -585,7 +551,7 @@ public JSONObject(String baseName, Locale locale) throws JSONException { * @param initialCapacity initial capacity of the internal map. */ protected JSONObject(int initialCapacity){ - this.map = new HashMap(initialCapacity); + this.map = new HashMap<>(initialCapacity); } /** @@ -604,20 +570,20 @@ protected JSONObject(int initialCapacity){ * @param value * An object to be accumulated under the key. * @return this. - * @throws JSONException + * @throws IllegalArgumentException * If the value is non-finite number. * @throws NullPointerException * If the key is null. */ - public JSONObject accumulate(String key, Object value) throws JSONException { + public JSONObject accumulate(String key, Object value) { testValidity(value); Object object = this.opt(key); if (object == null) { this.put(key, value instanceof JSONArray ? new JSONArray().put(value) : value); - } else if (object instanceof JSONArray) { - ((JSONArray) object).put(value); + } else if (object instanceof JSONArray ja) { + ja.put(value); } else { this.put(key, new JSONArray().put(object).put(value)); } @@ -635,19 +601,19 @@ public JSONObject accumulate(String key, Object value) throws JSONException { * @param value * An object to be accumulated under the key. * @return this. - * @throws JSONException + * @throws IllegalArgumentException * If the value is non-finite number or if the current value associated with * the key is not a JSONArray. * @throws NullPointerException * If the key is null. */ - public JSONObject append(String key, Object value) throws JSONException { + public JSONObject append(String key, Object value) { testValidity(value); Object object = this.opt(key); if (object == null) { this.put(key, new JSONArray().put(value)); - } else if (object instanceof JSONArray) { - this.put(key, ((JSONArray) object).put(value)); + } else if (object instanceof JSONArray ja) { + this.put(key, ja.put(value)); } else { throw wrongValueFormatException(key, "JSONArray", null, null); } @@ -688,16 +654,16 @@ public static String doubleToString(double d) { * @param key * A key string. * @return The object associated with the key. - * @throws JSONException + * @throws IllegalArgumentException * if the key is not found. */ - public Object get(String key) throws JSONException { + public Object get(String key) { if (key == null) { - throw new JSONException("Null key."); + throw new IllegalArgumentException("Null key."); } Object object = this.opt(key); if (object == null) { - throw new JSONException("JSONObject[" + quote(key) + "] not found."); + throw new IllegalArgumentException("JSONObject[" + quote(key) + "] not found."); } return object; } @@ -712,16 +678,16 @@ public Object get(String key) throws JSONException { * @param key * A key string. * @return The enum value associated with the key - * @throws JSONException + * @throws IllegalArgumentException * if the key is not found or if the value cannot be converted * to an enum. */ - public > E getEnum(Class clazz, String key) throws JSONException { + public > E getEnum(Class clazz, String key) { E val = optEnum(clazz, key); if(val==null) { - // JSONException should really take a throwable argument. + // IllegalArgumentException should really take a throwable argument. // If it did, I would re-implement this with the Enum.valueOf - // method and place any thrown exception in the JSONException + // method and place any thrown exception in the IllegalArgumentException throw wrongValueFormatException(key, "enum of type " + quote(clazz.getSimpleName()), opt(key), null); } return val; @@ -733,17 +699,17 @@ public > E getEnum(Class clazz, String key) throws JSONExce * @param key * A key string. * @return The truth. - * @throws JSONException + * @throws IllegalArgumentException * if the value is not a Boolean or the String "true" or * "false". */ - public boolean getBoolean(String key) throws JSONException { + public boolean getBoolean(String key) { Object object = this.get(key); if (Boolean.FALSE.equals(object) - || (object instanceof String && "false".equalsIgnoreCase((String) object))) { + || (object instanceof String s && "false".equalsIgnoreCase(s))) { return false; } else if (Boolean.TRUE.equals(object) - || (object instanceof String && "true".equalsIgnoreCase((String) object))) { + || (object instanceof String s && "true".equalsIgnoreCase(s))) { return true; } throw wrongValueFormatException(key, "Boolean", object, null); @@ -755,11 +721,11 @@ public boolean getBoolean(String key) throws JSONException { * @param key * A key string. * @return The numeric value. - * @throws JSONException + * @throws IllegalArgumentException * if the key is not found or if the value cannot * be converted to BigInteger. */ - public BigInteger getBigInteger(String key) throws JSONException { + public BigInteger getBigInteger(String key) { Object object = this.get(key); BigInteger ret = objectToBigInteger(object, null); if (ret != null) { @@ -777,11 +743,11 @@ public BigInteger getBigInteger(String key) throws JSONException { * @param key * A key string. * @return The numeric value. - * @throws JSONException + * @throws IllegalArgumentException * if the key is not found or if the value * cannot be converted to BigDecimal. */ - public BigDecimal getBigDecimal(String key) throws JSONException { + public BigDecimal getBigDecimal(String key) { Object object = this.get(key); BigDecimal ret = objectToBigDecimal(object, null); if (ret != null) { @@ -796,14 +762,14 @@ public BigDecimal getBigDecimal(String key) throws JSONException { * @param key * A key string. * @return The numeric value. - * @throws JSONException + * @throws IllegalArgumentException * 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 { + public double getDouble(String key) { final Object object = this.get(key); - if(object instanceof Number) { - return ((Number)object).doubleValue(); + if(object instanceof Number n) { + return n.doubleValue(); } try { return Double.parseDouble(object.toString()); @@ -818,14 +784,14 @@ public double getDouble(String key) throws JSONException { * @param key * A key string. * @return The numeric value. - * @throws JSONException + * @throws IllegalArgumentException * if the key is not found or if the value is not a Number * object and cannot be converted to a number. */ - public float getFloat(String key) throws JSONException { + public float getFloat(String key) { final Object object = this.get(key); - if(object instanceof Number) { - return ((Number)object).floatValue(); + if(object instanceof Number n) { + return n.floatValue(); } try { return Float.parseFloat(object.toString()); @@ -840,15 +806,15 @@ public float getFloat(String key) throws JSONException { * @param key * A key string. * @return The numeric value. - * @throws JSONException + * @throws IllegalArgumentException * if the key is not found or if the value is not a Number * object and cannot be converted to a number. */ - public Number getNumber(String key) throws JSONException { + public Number getNumber(String key) { Object object = this.get(key); try { - if (object instanceof Number) { - return (Number)object; + if (object instanceof Number n) { + return n; } return stringToNumber(object.toString()); } catch (Exception e) { @@ -862,14 +828,14 @@ public Number getNumber(String key) throws JSONException { * @param key * A key string. * @return The integer value. - * @throws JSONException + * @throws IllegalArgumentException * if the key is not found or if the value cannot be converted * to an integer. */ - public int getInt(String key) throws JSONException { + public int getInt(String key) { final Object object = this.get(key); - if(object instanceof Number) { - return ((Number)object).intValue(); + if(object instanceof Number n) { + return n.intValue(); } try { return Integer.parseInt(object.toString()); @@ -884,13 +850,13 @@ public int getInt(String key) throws JSONException { * @param key * A key string. * @return A JSONArray which is the value. - * @throws JSONException + * @throws IllegalArgumentException * if the key is not found or if the value is not a JSONArray. */ - public JSONArray getJSONArray(String key) throws JSONException { + public JSONArray getJSONArray(String key) { Object object = this.get(key); - if (object instanceof JSONArray) { - return (JSONArray) object; + if (object instanceof JSONArray ja) { + return ja; } throw wrongValueFormatException(key, "JSONArray", object, null); } @@ -901,13 +867,13 @@ public JSONArray getJSONArray(String key) throws JSONException { * @param key * A key string. * @return A JSONObject which is the value. - * @throws JSONException + * @throws IllegalArgumentException * if the key is not found or if the value is not a JSONObject. */ - public JSONObject getJSONObject(String key) throws JSONException { + public JSONObject getJSONObject(String key) { Object object = this.get(key); - if (object instanceof JSONObject) { - return (JSONObject) object; + if (object instanceof JSONObject jo) { + return jo; } throw wrongValueFormatException(key, "JSONObject", object, null); } @@ -918,14 +884,14 @@ public JSONObject getJSONObject(String key) throws JSONException { * @param key * A key string. * @return The long value. - * @throws JSONException + * @throws IllegalArgumentException * if the key is not found or if the value cannot be converted * to a long. */ - public long getLong(String key) throws JSONException { + public long getLong(String key) { final Object object = this.get(key); - if(object instanceof Number) { - return ((Number)object).longValue(); + if(object instanceof Number n) { + return n.longValue(); } try { return Long.parseLong(object.toString()); @@ -965,7 +931,7 @@ public static String[] getNames(Object object) { if (length == 0) { return null; } - String[] names = new String[length]; + var names = new String[length]; for (int i = 0; i < length; i += 1) { names[i] = fields[i].getName(); } @@ -978,13 +944,13 @@ public static String[] getNames(Object object) { * @param key * A key string. * @return A string which is the value. - * @throws JSONException + * @throws IllegalArgumentException * if there is no string value for the key. */ - public String getString(String key) throws JSONException { + public String getString(String key) { Object object = this.get(key); - if (object instanceof String) { - return (String) object; + if (object instanceof String s) { + return s; } throw wrongValueFormatException(key, "string", object, null); } @@ -1011,28 +977,28 @@ public boolean has(String key) { * @param key * A key string. * @return this. - * @throws JSONException + * @throws IllegalStateException * 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 { + public JSONObject increment(String key) { Object value = this.opt(key); if (value == null) { this.put(key, 1); - } else if (value instanceof Integer) { - this.put(key, ((Integer) value).intValue() + 1); - } else if (value instanceof Long) { - this.put(key, ((Long) value).longValue() + 1L); - } else if (value instanceof BigInteger) { - this.put(key, ((BigInteger)value).add(BigInteger.ONE)); - } else if (value instanceof Float) { - this.put(key, ((Float) value).floatValue() + 1.0f); - } else if (value instanceof Double) { - this.put(key, ((Double) value).doubleValue() + 1.0d); - } else if (value instanceof BigDecimal) { - this.put(key, ((BigDecimal)value).add(BigDecimal.ONE)); + } else if (value instanceof Integer i) { + this.put(key, i.intValue() + 1); + } else if (value instanceof Long l) { + this.put(key, l.longValue() + 1L); + } else if (value instanceof BigInteger bi) { + this.put(key, bi.add(BigInteger.ONE)); + } else if (value instanceof Float f) { + this.put(key, f.floatValue() + 1.0f); + } else if (value instanceof Double d) { + this.put(key, d.doubleValue() + 1.0d); + } else if (value instanceof BigDecimal bd) { + this.put(key, bd.add(BigDecimal.ONE)); } else { - throw new JSONException("Unable to increment [" + quote(key) + "]."); + throw new IllegalStateException("Unable to increment [" + quote(key) + "]."); } return this; } @@ -1136,12 +1102,12 @@ public JSONArray names() { * @param number * A Number * @return A String. - * @throws JSONException + * @throws IllegalArgumentException * If n is a non-finite number. */ - public static String numberToString(Number number) throws JSONException { + public static String numberToString(Number number) { if (number == null) { - throw new JSONException("Null pointer"); + throw new IllegalArgumentException("Null pointer"); } testValidity(number); @@ -1248,8 +1214,8 @@ public boolean optBoolean(String key, boolean defaultValue) { if (NULL.equals(val)) { return defaultValue; } - if (val instanceof Boolean){ - return ((Boolean) val).booleanValue(); + if (val instanceof Boolean b){ + return b.booleanValue(); } try { // we'll use the get anyway because it does string conversion. @@ -1287,8 +1253,8 @@ public Boolean optBooleanObject(String key, Boolean defaultValue) { if (NULL.equals(val)) { return defaultValue; } - if (val instanceof Boolean){ - return ((Boolean) val).booleanValue(); + if (val instanceof Boolean b){ + return b.booleanValue(); } try { // we'll use the get anyway because it does string conversion. @@ -1339,11 +1305,11 @@ static BigDecimal objectToBigDecimal(Object val, BigDecimal defaultValue, boolea if (NULL.equals(val)) { return defaultValue; } - if (val instanceof BigDecimal){ - return (BigDecimal) val; + if (val instanceof BigDecimal bd){ + return bd; } - if (val instanceof BigInteger){ - return new BigDecimal((BigInteger) val); + if (val instanceof BigInteger bi){ + return new BigDecimal(bi); } if (val instanceof Double || val instanceof Float){ if (!numberIsFinite((Number)val)) { @@ -1395,11 +1361,11 @@ static BigInteger objectToBigInteger(Object val, BigInteger defaultValue) { if (NULL.equals(val)) { return defaultValue; } - if (val instanceof BigInteger){ - return (BigInteger) val; + if (val instanceof BigInteger bi){ + return bi; } - if (val instanceof BigDecimal){ - return ((BigDecimal) val).toBigInteger(); + if (val instanceof BigDecimal bd){ + return bd.toBigInteger(); } if (val instanceof Double || val instanceof Float){ if (!numberIsFinite((Number)val)) { @@ -1646,7 +1612,7 @@ public JSONArray optJSONArray(String key) { */ public JSONArray optJSONArray(String key, JSONArray defaultValue) { Object object = this.opt(key); - return object instanceof JSONArray ? (JSONArray) object : defaultValue; + return object instanceof JSONArray ja ? ja : defaultValue; } /** @@ -1671,7 +1637,7 @@ public JSONArray optJSONArray(String key, JSONArray defaultValue) { */ public JSONObject optJSONObject(String key, JSONObject defaultValue) { Object object = this.opt(key); - return object instanceof JSONObject ? (JSONObject) object : defaultValue; + return object instanceof JSONObject jo ? jo : defaultValue; } /** @@ -1771,8 +1737,8 @@ public Number optNumber(String key, Number defaultValue) { if (NULL.equals(val)) { return defaultValue; } - if (val instanceof Number){ - return (Number) val; + if (val instanceof Number n){ + return n; } try { @@ -1818,7 +1784,7 @@ public String optString(String key, String defaultValue) { * * @param bean * the bean - * @throws JSONException + * @throws IllegalArgumentException * If a getter returned a non-finite number. */ private void populateMap(Object bean, JSONParserConfiguration jsonParserConfiguration) { @@ -1881,8 +1847,6 @@ private void processMethod(Object bean, Set objectsRecord, JSONParserCon } } catch (IllegalAccessException ignore) { // ignore exception - } catch (IllegalArgumentException ignore) { - // ignore exception } catch (InvocationTargetException ignore) { // ignore exception } @@ -1928,36 +1892,18 @@ private static boolean isValidMethodName(String name) { } private static String getKeyNameFromMethod(Method method, boolean isRecordType) { - final int ignoreDepth = getAnnotationDepth(method, JSONPropertyIgnore.class); - if (ignoreDepth > 0) { - final int forcedNameDepth = getAnnotationDepth(method, JSONPropertyName.class); - if (forcedNameDepth < 0 || ignoreDepth <= forcedNameDepth) { - // the hierarchy asked to ignore, and the nearest name override - // was higher or non-existent - return null; - } - } - JSONPropertyName annotation = getAnnotation(method, JSONPropertyName.class); - if (annotationValueNotEmpty(annotation)) { - return annotation.value(); - } String key; - final String name = method.getName(); + var name = method.getName(); if (name.startsWith("get") && name.length() > 3) { key = name.substring(3); } else if (name.startsWith("is") && name.length() > 2) { key = name.substring(2); } else { - // Only check for record-style accessors if this is actually a record type - // This maintains backward compatibility - classes with lowercase methods won't be affected if (isRecordType && isRecordStyleAccessor(name, method)) { return name; } return null; } - // if the first letter in the key is not uppercase, then skip. - // This is to maintain backwards compatibility before PR406 - // (https://github.com/stleary/JSON-java/pull/406/) if (key.isEmpty() || Character.isLowerCase(key.charAt(0))) { return null; } @@ -2000,15 +1946,6 @@ private static boolean isRecordStyleAccessor(String methodName, Method method) { return !className.startsWith("java.") && !className.startsWith("javax."); } - /** - * checks if the annotation is not null and the {@link JSONPropertyName#value()} is not null and is not empty. - * @param annotation the annotation to check - * @return true if the annotation and the value is not null and not empty, false otherwise. - */ - private static boolean annotationValueNotEmpty(JSONPropertyName annotation) { - return annotation != null && annotation.value() != null && !annotation.value().isEmpty(); - } - /** * Checks if the method is valid for the {@link #populateMap(Object, Set, JSONParserConfiguration)} use case * @param method the Method to check @@ -2032,135 +1969,15 @@ private static void closeClosable(Object input) { // we don't use the result anywhere outside of wrap // if it's a resource we should be sure to close it // after calling toString - if (input instanceof Closeable) { + if (input instanceof Closeable c) { try { - ((Closeable) input).close(); + c.close(); } catch (IOException ignore) { // close has failed; best effort has been made } } } - /** - * Searches the class hierarchy to see if the method or it's super - * implementations and interfaces has the annotation. - * - * @param - * type of the annotation - * - * @param m - * method to check - * @param annotationClass - * annotation to look for - * @return the {@link Annotation} if the annotation exists on the current method - * or one of its super class definitions - */ - private static A getAnnotation(final Method m, final Class annotationClass) { - // If we have invalid data the result is null - if (m == null || annotationClass == null) { - return null; - } - - if (m.isAnnotationPresent(annotationClass)) { - return m.getAnnotation(annotationClass); - } - - // If we've already reached the Object class, return null; - Class c = m.getDeclaringClass(); - if (c.getSuperclass() == null) { - return null; - } - - // check directly implemented interfaces for the method being checked - for (Class i : c.getInterfaces()) { - try { - Method im = i.getMethod(m.getName(), m.getParameterTypes()); - return getAnnotation(im, annotationClass); - } catch (final SecurityException ex) { - // ignore this exception - } catch (final NoSuchMethodException ex) { - // ignore this excpetion - } - } - - // If the superclass is Object, no annotations will be found any more - if (Object.class.equals(c.getSuperclass())) - return null; - - try { - return getAnnotation( - c.getSuperclass().getMethod(m.getName(), m.getParameterTypes()), - annotationClass); - } catch (final SecurityException ex) { - return null; - } catch (final NoSuchMethodException ex) { - return null; - } - } - - /** - * Searches the class hierarchy to see if the method or it's super - * implementations and interfaces has the annotation. Returns the depth of the - * annotation in the hierarchy. - * - * @param m - * method to check - * @param annotationClass - * annotation to look for - * @return Depth of the annotation or -1 if the annotation is not on the method. - */ - private static int getAnnotationDepth(final Method m, final Class annotationClass) { - // if we have invalid data the result is -1 - if (m == null || annotationClass == null) { - return -1; - } - - if (m.isAnnotationPresent(annotationClass)) { - return 1; - } - - // we've already reached the Object class - Class c = m.getDeclaringClass(); - if (c.getSuperclass() == null) { - return -1; - } - - // check directly implemented interfaces for the method being checked - for (Class i : c.getInterfaces()) { - try { - Method im = i.getMethod(m.getName(), m.getParameterTypes()); - int d = getAnnotationDepth(im, annotationClass); - if (d > 0) { - // since the annotation was on the interface, add 1 - return d + 1; - } - } catch (final SecurityException ex) { - // Nothing to do here - } catch (final NoSuchMethodException ex) { - // Nothing to do here - } - } - - //If the superclass is Object, no annotations will be found any more - if (Object.class.equals(c.getSuperclass())) - return -1; - - try { - int d = getAnnotationDepth( - c.getSuperclass().getMethod(m.getName(), m.getParameterTypes()), - annotationClass); - if (d > 0) { - // since the annotation was on the superclass, add 1 - return d + 1; - } - return -1; - } catch (final SecurityException ex) { - return -1; - } catch (final NoSuchMethodException ex) { - return -1; - } - } - /** * Put a key/boolean pair in the JSONObject. * @@ -2169,12 +1986,12 @@ private static int getAnnotationDepth(final Method m, final Classnull. */ - public JSONObject put(String key, boolean value) throws JSONException { + public JSONObject put(String key, boolean value) { return this.put(key, value ? Boolean.TRUE : Boolean.FALSE); } @@ -2187,12 +2004,12 @@ public JSONObject put(String key, boolean value) throws JSONException { * @param value * A Collection value. * @return this. - * @throws JSONException + * @throws IllegalArgumentException * If the value is non-finite number. * @throws NullPointerException * If the key is null. */ - public JSONObject put(String key, Collection value) throws JSONException { + public JSONObject put(String key, Collection value) { return this.put(key, new JSONArray(value)); } @@ -2204,12 +2021,12 @@ public JSONObject put(String key, Collection value) throws JSONException { * @param value * A double which is the value. * @return this. - * @throws JSONException + * @throws IllegalArgumentException * If the value is non-finite number. * @throws NullPointerException * If the key is null. */ - public JSONObject put(String key, double value) throws JSONException { + public JSONObject put(String key, double value) { return this.put(key, Double.valueOf(value)); } @@ -2221,12 +2038,12 @@ public JSONObject put(String key, double value) throws JSONException { * @param value * A float which is the value. * @return this. - * @throws JSONException + * @throws IllegalArgumentException * If the value is non-finite number. * @throws NullPointerException * If the key is null. */ - public JSONObject put(String key, float value) throws JSONException { + public JSONObject put(String key, float value) { return this.put(key, Float.valueOf(value)); } @@ -2238,12 +2055,12 @@ public JSONObject put(String key, float value) throws JSONException { * @param value * An int which is the value. * @return this. - * @throws JSONException + * @throws IllegalArgumentException * If the value is non-finite number. * @throws NullPointerException * If the key is null. */ - public JSONObject put(String key, int value) throws JSONException { + public JSONObject put(String key, int value) { return this.put(key, Integer.valueOf(value)); } @@ -2255,12 +2072,12 @@ public JSONObject put(String key, int value) throws JSONException { * @param value * A long which is the value. * @return this. - * @throws JSONException + * @throws IllegalArgumentException * If the value is non-finite number. * @throws NullPointerException * If the key is null. */ - public JSONObject put(String key, long value) throws JSONException { + public JSONObject put(String key, long value) { return this.put(key, Long.valueOf(value)); } @@ -2273,12 +2090,12 @@ public JSONObject put(String key, long value) throws JSONException { * @param value * A Map value. * @return this. - * @throws JSONException + * @throws IllegalArgumentException * If the value is non-finite number. * @throws NullPointerException * If the key is null. */ - public JSONObject put(String key, Map value) throws JSONException { + public JSONObject put(String key, Map value) { return this.put(key, new JSONObject(value)); } @@ -2293,12 +2110,12 @@ public JSONObject put(String key, Map value) throws JSONException { * types: Boolean, Double, Integer, JSONArray, JSONObject, Long, * String, or the JSONObject.NULL object. * @return this. - * @throws JSONException + * @throws IllegalArgumentException * If the value is non-finite number. * @throws NullPointerException * If the key is null. */ - public JSONObject put(String key, Object value) throws JSONException { + public JSONObject put(String key, Object value) { if (key == null) { throw new NullPointerException("Null key."); } @@ -2321,13 +2138,13 @@ public JSONObject put(String key, Object value) throws JSONException { * @param value * value to insert * @return this. - * @throws JSONException + * @throws IllegalArgumentException * if the key is a duplicate */ - public JSONObject putOnce(String key, Object value) throws JSONException { + public JSONObject putOnce(String key, Object value) { if (key != null && value != null) { if (this.opt(key) != null) { - throw new JSONException("Duplicate key \"" + key + "\""); + throw new IllegalArgumentException("Duplicate key \"" + key + "\""); } return this.put(key, value); } @@ -2345,89 +2162,16 @@ public JSONObject putOnce(String key, Object value) throws JSONException { * types: Boolean, Double, Integer, JSONArray, JSONObject, Long, * String, or the JSONObject.NULL object. * @return this. - * @throws JSONException + * @throws IllegalArgumentException * If the value is a non-finite number. */ - public JSONObject putOpt(String key, Object value) throws JSONException { + public JSONObject putOpt(String key, Object value) { if (key != null && value != null) { return this.put(key, value); } return this; } - /** - * Creates a JSONPointer using an initialization string and tries to - * match it to an item within this JSONObject. For example, given a - * JSONObject initialized with this document: - *
-     * {
-     *     "a":{"b":"c"}
-     * }
-     * 
- * and this JSONPointer string: - *
-     * "/a/b"
-     * 
- * Then this method will return the String "c". - * A JSONPointerException may be thrown from code called by this method. - * - * @param jsonPointer string that can be used to create a JSONPointer - * @return the item matched by the JSONPointer, otherwise null - */ - public Object query(String jsonPointer) { - return query(new JSONPointer(jsonPointer)); - } - /** - * Uses a user initialized JSONPointer and tries to - * match it to an item within this JSONObject. For example, given a - * JSONObject initialized with this document: - *
-     * {
-     *     "a":{"b":"c"}
-     * }
-     * 
- * and this JSONPointer: - *
-     * "/a/b"
-     * 
- * Then this method will return the String "c". - * A JSONPointerException may be thrown from code called by this method. - * - * @param jsonPointer string that can be used to create a JSONPointer - * @return the item matched by the JSONPointer, otherwise null - */ - public Object query(JSONPointer jsonPointer) { - return jsonPointer.queryFrom(this); - } - - /** - * Queries and returns a value from this object using {@code jsonPointer}, or - * returns null if the query fails due to a missing key. - * - * @param jsonPointer the string representation of the JSON pointer - * @return the queried value or {@code null} - * @throws IllegalArgumentException if {@code jsonPointer} has invalid syntax - */ - public Object optQuery(String jsonPointer) { - return optQuery(new JSONPointer(jsonPointer)); - } - - /** - * Queries and returns a value from this object using {@code jsonPointer}, or - * returns null if the query fails due to a missing key. - * - * @param jsonPointer The JSON pointer - * @return the queried value or {@code null} - * @throws IllegalArgumentException if {@code jsonPointer} has invalid syntax - */ - public Object optQuery(JSONPointer jsonPointer) { - try { - return jsonPointer.queryFrom(this); - } catch (JSONPointerException e) { - return null; - } - } - /** * Produce a string in double quotes with backslash sequences in all the * right places. A backslash will be inserted within </, producing @@ -2444,7 +2188,7 @@ public static String quote(String string) { if (string == null || string.isEmpty()) { return "\"\""; } - Writer sw = new StringBuilderWriter(string.length() + 2); + var sw = new StringBuilderWriter(string.length() + 2); try { return quote(string, sw).toString(); } catch (IOException ignored) { @@ -2477,34 +2221,22 @@ public static Writer quote(String string, Writer w) throws IOException { b = c; c = string.charAt(i); switch (c) { - case '\\': - case '"': + case '\\', '"' -> { w.write('\\'); w.write(c); - break; - case '/': + } + case '/' -> { if (b == '<') { w.write('\\'); } w.write(c); - break; - case '\b': - w.write("\\b"); - break; - case '\t': - w.write("\\t"); - break; - case '\n': - w.write("\\n"); - break; - case '\f': - w.write("\\f"); - break; - case '\r': - w.write("\\r"); - break; - default: - writeAsHex(w, c); + } + case '\b' -> w.write("\\b"); + case '\t' -> w.write("\\t"); + case '\n' -> w.write("\\n"); + case '\f' -> w.write("\\f"); + case '\r' -> w.write("\\r"); + default -> writeAsHex(w, c); } } w.write('"'); @@ -2552,23 +2284,23 @@ public Object remove(String key) { */ public boolean similar(Object other) { try { - if (!(other instanceof JSONObject)) { + if (!(other instanceof JSONObject jo)) { return false; } - if (!this.keySet().equals(((JSONObject)other).keySet())) { + if (!this.keySet().equals(jo.keySet())) { return false; } - return checkSimilarEntries(other); + return checkSimilarEntries(jo); } catch (Exception e) { return false; } } - private boolean checkSimilarEntries(Object other) { + private boolean checkSimilarEntries(JSONObject other) { for (final Entry entry : this.entrySet()) { String name = entry.getKey(); Object valueThis = entry.getValue(); - Object valueOther = ((JSONObject)other).get(name); + Object valueOther = other.get(name); if(valueThis == valueOther) { continue; } @@ -2590,14 +2322,14 @@ private boolean checkSimilarEntries(Object other) { * @return true if match, else false */ private boolean checkObjectType(Object valueThis, Object valueOther) { - if (valueThis instanceof JSONObject) { - return ((JSONObject)valueThis).similar(valueOther); - } else if (valueThis instanceof JSONArray) { - return ((JSONArray)valueThis).similar(valueOther); - } else if (valueThis instanceof Number && valueOther instanceof Number) { - return isNumberSimilar((Number)valueThis, (Number)valueOther); - } else if (valueThis instanceof JSONString && valueOther instanceof JSONString) { - return ((JSONString) valueThis).toJSONString().equals(((JSONString) valueOther).toJSONString()); + if (valueThis instanceof JSONObject jo) { + return jo.similar(valueOther); + } else if (valueThis instanceof JSONArray ja) { + return ja.similar(valueOther); + } else if (valueThis instanceof Number nThis && valueOther instanceof Number nOther) { + return isNumberSimilar(nThis, nOther); + } else if (valueThis instanceof JSONString jsThis && valueOther instanceof JSONString jsOther) { + return jsThis.toJSONString().equals(jsOther.toJSONString()); } else if (!valueThis.equals(valueOther)) { return false; } @@ -2627,9 +2359,9 @@ static boolean isNumberSimilar(Number l, Number r) { // if the classes are the same and implement Comparable // then use the built in compare first. - if(l.getClass().equals(r.getClass()) && l instanceof Comparable) { + if(l.getClass().equals(r.getClass()) && l instanceof Comparable c) { @SuppressWarnings({ "rawtypes", "unchecked" }) - int compareTo = ((Comparable)l).compareTo(r); + int compareTo = c.compareTo(r); return compareTo==0; } @@ -2645,9 +2377,9 @@ static boolean isNumberSimilar(Number l, Number r) { } private static boolean numberIsFinite(Number n) { - if (n instanceof Double && (((Double) n).isInfinite() || ((Double) n).isNaN())) { + if (n instanceof Double d && (d.isInfinite() || d.isNaN())) { return false; - } else if (n instanceof Float && (((Float) n).isInfinite() || ((Float) n).isNaN())) { + } else if (n instanceof Float f && (f.isInfinite() || f.isNaN())) { return false; } return true; @@ -2716,7 +2448,7 @@ public static Object stringToValue(String string) { * @param val value to convert * @return Number representation of the value. * @throws NumberFormatException thrown if the value is not a valid number. A public - * caller should catch this and wrap it in a {@link JSONException} if applicable. + * caller should catch this and wrap it in a {@link IllegalArgumentException} if applicable. */ protected static Number stringToNumber(final String val) throws NumberFormatException { char initial = val.charAt(0); @@ -2735,7 +2467,7 @@ protected static Number stringToNumber(final String val) throws NumberFormatExce // BigInteger#intValueExact uses. Increases GC, but objects hold // only what they need. i.e. Less runtime overhead if the value is // long lived. - BigInteger bi = new BigInteger(val); + var bi = new BigInteger(val); if(bi.bitLength() <= 31){ return Integer.valueOf(bi.intValue()); } @@ -2779,7 +2511,7 @@ private static Number getNumber(String val, char initial) { // representation. BigDecimal doesn't support -0.0, ensure we // keep that by forcing a decimal. try { - BigDecimal bd = new BigDecimal(val); + var bd = new BigDecimal(val); if(initial == '-' && BigDecimal.ZERO.compareTo(bd)==0) { return Double.valueOf(-0.0); } @@ -2803,12 +2535,12 @@ private static Number getNumber(String val, char initial) { * * @param o * The object to test. - * @throws JSONException + * @throws IllegalArgumentException * If o is a non-finite number. */ - public static void testValidity(Object o) throws JSONException { - if (o instanceof Number && !numberIsFinite((Number) o)) { - throw new JSONException("JSON does not allow non-finite numbers."); + public static void testValidity(Object o) { + if (o instanceof Number n && !numberIsFinite(n)) { + throw new IllegalArgumentException("JSON does not allow non-finite numbers."); } } @@ -2820,14 +2552,14 @@ public static void testValidity(Object o) throws JSONException { * 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 + * @throws IllegalArgumentException * If any of the values are non-finite numbers. */ - public JSONArray toJSONArray(JSONArray names) throws JSONException { + public JSONArray toJSONArray(JSONArray names) { if (names == null || names.isEmpty()) { return null; } - JSONArray ja = new JSONArray(); + var ja = new JSONArray(); for (int i = 0; i < names.length(); i += 1) { ja.put(this.opt(names.getString(i))); } @@ -2879,15 +2611,15 @@ public String toString() { * of the object, beginning with { (left * brace) and ending with } (right * brace). - * @throws JSONException + * @throws IllegalArgumentException * If the object contains an invalid number. */ @SuppressWarnings("resource") - public String toString(int indentFactor) throws JSONException { + public String toString(int indentFactor) { // 6 characters are the minimum to serialise a key value pair e.g.: "k":1, // and we don't want to oversize the initial capacity int initialSize = map.size() * 6; - Writer w = new StringBuilderWriter(Math.max(initialSize, 16)); + var w = new StringBuilderWriter(Math.max(initialSize, 16)); return this.write(w, indentFactor, 0).toString(); } @@ -2912,10 +2644,10 @@ public String toString(int indentFactor) throws JSONException { * object, beginning with { (left * brace) and ending with } (right * brace). - * @throws JSONException + * @throws IllegalArgumentException * If the value is or contains an invalid number. */ - public static String valueToString(Object value) throws JSONException { + public static String valueToString(Object value) { // moves the implementation to JSONWriter as: // 1. It makes more sense to be part of the writer class // 2. For Android support this method is not available. By implementing it in the Writer @@ -2979,15 +2711,13 @@ private static Object wrap(Object object, Set objectsRecord, int recursi return object; } - if (object instanceof Collection) { - Collection coll = (Collection) object; + if (object instanceof Collection coll) { return new JSONArray(coll, recursionDepth, jsonParserConfiguration); } if (object.getClass().isArray()) { return new JSONArray(object); } - if (object instanceof Map) { - Map map = (Map) object; + if (object instanceof Map map) { return new JSONObject(map, recursionDepth, jsonParserConfiguration); } Package objectPackage = object.getClass().getPackage(); @@ -3003,7 +2733,7 @@ private static Object wrap(Object object, Set objectsRecord, int recursi } return new JSONObject(object); } - catch (JSONException exception) { + catch (RuntimeException exception) { throw exception; } catch (Exception exception) { return null; @@ -3018,15 +2748,15 @@ private static Object wrap(Object object, Set objectsRecord, int recursi * * @param writer the writer object * @return The writer. - * @throws JSONException if a called function has an error + * @throws IllegalStateException if a called function has an error */ - public Writer write(Writer writer) throws JSONException { + public Writer write(Writer writer) { return this.write(writer, 0, 0); } @SuppressWarnings("resource") static final Writer writeValue(Writer writer, Object value, - int indentFactor, int indent) throws JSONException, IOException { + int indentFactor, int indent) throws IOException { if (value == null || value.equals(null)) { writer.write("null"); } else if (value instanceof JSONString) { @@ -3036,22 +2766,20 @@ static final Writer writeValue(Writer writer, Object value, // assuming most values are Strings, so testing it early quote(value.toString(), writer); return writer; - } else if (value instanceof Number) { + } else if (value instanceof Number n) { // may throw an exception - processNumberToWriteValue(writer, (Number) value); + processNumberToWriteValue(writer, n); } else if (value instanceof Boolean) { writer.write(value.toString()); - } else if (value instanceof Enum) { - writer.write(quote(((Enum)value).name())); - } else if (value instanceof JSONObject) { - ((JSONObject) value).write(writer, indentFactor, indent); - } else if (value instanceof JSONArray) { - ((JSONArray) value).write(writer, indentFactor, indent); - } else if (value instanceof Map) { - Map map = (Map) value; + } else if (value instanceof Enum e) { + writer.write(quote(e.name())); + } else if (value instanceof JSONObject jo) { + jo.write(writer, indentFactor, indent); + } else if (value instanceof JSONArray ja) { + ja.write(writer, indentFactor, indent); + } else if (value instanceof Map map) { new JSONObject(map).write(writer, indentFactor, indent); - } else if (value instanceof Collection) { - Collection coll = (Collection) value; + } else if (value instanceof Collection coll) { new JSONArray(coll).write(writer, indentFactor, indent); } else if (value.getClass().isArray()) { new JSONArray(value).write(writer, indentFactor, indent); @@ -3073,7 +2801,7 @@ private static void processJsonStringToWriteValue(Writer writer, Object value) t try { o = ((JSONString) value).toJSONString(); } catch (Exception e) { - throw new JSONException(e); + throw new IllegalStateException(e); } writer.write(o != null ? o.toString() : quote(value.toString())); } @@ -3126,12 +2854,11 @@ static final void indent(Writer writer, int indent) throws IOException { * @param indent * The indentation of the top level. * @return The writer. - * @throws JSONException if a called function has an error or a write error + * @throws UncheckedIOException if a called function has an error or a write error * occurs */ @SuppressWarnings("resource") - public Writer write(Writer writer, int indentFactor, int indent) - throws JSONException { + public Writer write(Writer writer, int indentFactor, int indent) { try { boolean needsComma = false; final int length = this.length(); @@ -3153,7 +2880,7 @@ public Writer write(Writer writer, int indentFactor, int indent) writer.write('}'); return writer; } catch (IOException exception) { - throw new JSONException(exception); + throw new UncheckedIOException(exception); } } @@ -3207,7 +2934,7 @@ private void writeContent(Writer writer, int indentFactor, int indent, boolean n * Contains the value being written * @param key * Identifies the value - * @throws JSONException if a called function has an error or a write error + * @throws IllegalStateException if a called function has an error or a write error * occurs */ @@ -3215,7 +2942,7 @@ private static void attemptWriteValue(Writer writer, int indentFactor, int inden try{ writeValue(writer, entry.getValue(), indentFactor, indent); } catch (Exception e) { - throw new JSONException("Unable to write JSONObject value for key: " + key, e); + throw new IllegalStateException("Unable to write JSONObject value for key: " + key, e); } } @@ -3229,15 +2956,15 @@ private static void attemptWriteValue(Writer writer, int indentFactor, int inden * @return a java.util.Map containing the entries of this object */ public Map toMap() { - Map results = new HashMap(); + Map results = new HashMap<>(); for (Entry entry : this.entrySet()) { Object value; if (entry.getValue() == null || NULL.equals(entry.getValue())) { value = null; - } else if (entry.getValue() instanceof JSONObject) { - value = ((JSONObject) entry.getValue()).toMap(); - } else if (entry.getValue() instanceof JSONArray) { - value = ((JSONArray) entry.getValue()).toList(); + } else if (entry.getValue() instanceof JSONObject jo) { + value = jo.toMap(); + } else if (entry.getValue() instanceof JSONArray ja) { + value = ja.toList(); } else { value = entry.getValue(); } @@ -3247,41 +2974,41 @@ public Map toMap() { } /** - * Create a new JSONException in a common format for incorrect conversions. + * Create a new IllegalArgumentException in a common format for incorrect conversions. * @param key name of the key * @param valueType the type of value being coerced to * @param cause optional cause of the coercion failure - * @return JSONException that can be thrown. + * @return IllegalArgumentException that can be thrown. */ - private static JSONException wrongValueFormatException( + private static IllegalArgumentException wrongValueFormatException( String key, String valueType, Object value, Throwable cause) { if(value == null) { - return new JSONException( + return new IllegalArgumentException( "JSONObject[" + quote(key) + "] is not a " + valueType + " (null)." , cause); } // don't try to toString collections or known object types that could be large. if(value instanceof Map || value instanceof Iterable || value instanceof JSONObject) { - return new JSONException( + return new IllegalArgumentException( "JSONObject[" + quote(key) + "] is not a " + valueType + " (" + value.getClass() + ")." , cause); } - return new JSONException( + return new IllegalArgumentException( "JSONObject[" + quote(key) + "] is not a " + valueType + " (" + value.getClass() + " : " + value + ")." , cause); } /** - * Create a new JSONException in a common format for recursive object definition. + * Create a new IllegalStateException in a common format for recursive object definition. * @param key name of the key - * @return JSONException that can be thrown. + * @return IllegalStateException that can be thrown. */ - private static JSONException recursivelyDefinedObjectException(String key) { - return new JSONException( + private static IllegalStateException recursivelyDefinedObjectException(String key) { + return new IllegalStateException( "JavaBean object contains recursively defined member variable of key " + quote(key) ); } @@ -3290,10 +3017,10 @@ private static JSONException recursivelyDefinedObjectException(String key) { * Helper method to extract the raw Class from Type. */ private Class getRawType(Type type) { - if (type instanceof Class) { - return (Class) type; - } else if (type instanceof ParameterizedType) { - return (Class) ((ParameterizedType) type).getRawType(); + if (type instanceof Class c) { + return c; + } else if (type instanceof ParameterizedType pt) { + return (Class) pt.getRawType(); } else if (type instanceof GenericArrayType) { return Object[].class; // Simplified handling for arrays } @@ -3304,8 +3031,8 @@ private Class getRawType(Type type) { * Extracts the element Type for a Collection Type. */ private Type getElementType(Type type) { - if (type instanceof ParameterizedType) { - Type[] args = ((ParameterizedType) type).getActualTypeArguments(); + if (type instanceof ParameterizedType pt) { + Type[] args = pt.getActualTypeArguments(); return args.length > 0 ? args[0] : Object.class; } return Object.class; @@ -3315,8 +3042,8 @@ private Type getElementType(Type type) { * Extracts the key and value Types for a Map Type. */ private Type[] getMapTypes(Type type) { - if (type instanceof ParameterizedType) { - Type[] args = ((ParameterizedType) type).getActualTypeArguments(); + if (type instanceof ParameterizedType pt) { + Type[] args = pt.getActualTypeArguments(); if (args.length == 2) { return args; } @@ -3338,7 +3065,7 @@ private Type[] getMapTypes(Type type) { * @return an instance of Object T with fields populated from the JSON string */ public static T fromJson(String jsonString, Class clazz) { - JSONObject jsonObject = new JSONObject(jsonString); + var jsonObject = new JSONObject(jsonString); return jsonObject.fromJson(clazz); } @@ -3377,16 +3104,16 @@ public T fromJson(Class clazz) { } return obj; } catch (NoSuchMethodException e) { - throw new JSONException("No no-arg constructor for class: " + clazz.getName(), e); + throw new IllegalStateException("No no-arg constructor for class: " + clazz.getName(), e); } catch (Exception e) { - throw new JSONException("Failed to instantiate or set field for class: " + clazz.getName(), e); + throw new IllegalStateException("Failed to instantiate or set field for class: " + clazz.getName(), e); } } /** * Recursively converts a value to the target Type, handling nested generics for Collections and Maps. */ - private Object convertValue(Object value, Type targetType) throws JSONException { + private Object convertValue(Object value, Type targetType) { if (value == null) { return null; } @@ -3449,7 +3176,7 @@ else if (!rawType.isPrimitive() && !rawType.isEnum() && value instanceof JSONObj * Converts a JSONObject to a Map with the specified generic key and value Types. * Supports nested types via recursive convertValue. */ - private Map convertToMap(JSONObject jsonMap, Type keyType, Type valueType, Class mapType) throws JSONException { + private Map convertToMap(JSONObject jsonMap, Type keyType, Type valueType, Class mapType) { try { @SuppressWarnings("unchecked") Map createdMap = new HashMap(); @@ -3465,21 +3192,21 @@ else if (!rawType.isPrimitive() && !rawType.isEnum() && value instanceof JSONObj } return createdMap; } catch (Exception e) { - throw new JSONException("Failed to convert JSONObject to Map: " + mapType.getName(), e); + throw new IllegalStateException("Failed to convert JSONObject to Map: " + mapType.getName(), e); } } /** * Converts a String to an Enum value. */ - private E stringToEnum(Class enumClass, String value) throws JSONException { + private E stringToEnum(Class enumClass, String value) { try { @SuppressWarnings("unchecked") Class enumType = (Class) enumClass; Method valueOfMethod = enumType.getMethod("valueOf", String.class); return (E) valueOfMethod.invoke(null, value); } catch (Exception e) { - throw new JSONException("Failed to convert string to enum: " + value + " for " + enumClass.getName(), e); + throw new IllegalStateException("Failed to convert string to enum: " + value + " for " + enumClass.getName(), e); } } @@ -3488,7 +3215,7 @@ private E stringToEnum(Class enumClass, String value) throws JSONExceptio * Uses recursive convertValue for elements. */ @SuppressWarnings("unchecked") - private Collection fromJsonArray(JSONArray jsonArray, Class collectionType, Type elementType) throws JSONException { + private Collection fromJsonArray(JSONArray jsonArray, Class collectionType, Type elementType) { try { Collection collection = getCollection(collectionType); @@ -3500,7 +3227,7 @@ private Collection fromJsonArray(JSONArray jsonArray, Class collection } return collection; } catch (Exception e) { - throw new JSONException("Failed to convert JSONArray to Collection: " + collectionType.getName(), e); + throw new IllegalStateException("Failed to convert JSONArray to Collection: " + collectionType.getName(), e); } } @@ -3515,20 +3242,20 @@ private Collection fromJsonArray(JSONArray jsonArray, Class collection *
  • {@code Set.class}
  • *
  • {@code HashSet.class}
  • * - * If the provided type does not match any of the supported types, a {@link JSONException} + * If the provided type does not match any of the supported types, a {@link IllegalArgumentException} * is thrown. * * @param collectionType the {@link Class} object representing the desired collection type * @return a new empty instance of the specified collection type - * @throws JSONException if the specified type is not a supported collection type + * @throws IllegalArgumentException if the specified type is not a supported collection type */ - private Collection getCollection(Class collectionType) throws JSONException { + private Collection getCollection(Class collectionType) { if (collectionType == List.class || collectionType == ArrayList.class) { return new ArrayList(); } else if (collectionType == Set.class || collectionType == HashSet.class) { return new HashSet(); } else { - throw new JSONException("Unsupported Collection type: " + collectionType.getName()); + throw new IllegalArgumentException("Unsupported Collection type: " + collectionType.getName()); } } } diff --git a/src/main/java/org/json/JSONParserConfiguration.java b/src/main/java/org/json/JSONParserConfiguration.java index 0cfa2eaef..7d797b65c 100644 --- a/src/main/java/org/json/JSONParserConfiguration.java +++ b/src/main/java/org/json/JSONParserConfiguration.java @@ -32,7 +32,7 @@ public JSONParserConfiguration() { @Override protected JSONParserConfiguration clone() { - JSONParserConfiguration clone = new JSONParserConfiguration(); + var clone = new JSONParserConfiguration(); clone.overwriteDuplicateKey = overwriteDuplicateKey; clone.strictMode = strictMode; clone.maxNestingDepth = maxNestingDepth; @@ -53,7 +53,7 @@ protected JSONParserConfiguration clone() { @SuppressWarnings("unchecked") @Override public JSONParserConfiguration withMaxNestingDepth(final int maxNestingDepth) { - JSONParserConfiguration clone = this.clone(); + var clone = this.clone(); clone.maxNestingDepth = maxNestingDepth; return clone; @@ -68,7 +68,7 @@ public JSONParserConfiguration withMaxNestingDepth(final int maxNestingDepth) { * @return The existing configuration will not be modified. A new configuration is returned. */ public JSONParserConfiguration withOverwriteDuplicateKey(final boolean overwriteDuplicateKey) { - JSONParserConfiguration clone = this.clone(); + var clone = this.clone(); clone.overwriteDuplicateKey = overwriteDuplicateKey; return clone; @@ -83,7 +83,7 @@ public JSONParserConfiguration withOverwriteDuplicateKey(final boolean overwrite * @return The existing configuration will not be modified. A new configuration is returned. */ public JSONParserConfiguration withUseNativeNulls(final boolean useNativeNulls) { - JSONParserConfiguration clone = this.clone(); + var clone = this.clone(); clone.useNativeNulls = useNativeNulls; return clone; @@ -112,7 +112,7 @@ public JSONParserConfiguration withStrictMode() { * @return a new JSONParserConfiguration instance with the updated strict mode setting */ public JSONParserConfiguration withStrictMode(final boolean mode) { - JSONParserConfiguration clone = this.clone(); + var clone = this.clone(); clone.strictMode = mode; return clone; diff --git a/src/main/java/org/json/JSONPointer.java b/src/main/java/org/json/JSONPointer.java deleted file mode 100644 index 34066c1aa..000000000 --- a/src/main/java/org/json/JSONPointer.java +++ /dev/null @@ -1,287 +0,0 @@ -package org.json; - -import static java.lang.String.format; - -import java.io.UnsupportedEncodingException; -import java.net.URLDecoder; -import java.net.URLEncoder; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -/* -Public Domain. -*/ - -/** - * A JSON Pointer is a simple query language defined for JSON documents by - * RFC 6901. - * - * In a nutshell, JSONPointer allows the user to navigate into a JSON document - * using strings, and retrieve targeted objects, like a simple form of XPATH. - * Path segments are separated by the '/' char, which signifies the root of - * the document when it appears as the first char of the string. Array - * elements are navigated using ordinals, counting from 0. JSONPointer strings - * may be extended to any arbitrary number of segments. If the navigation - * is successful, the matched item is returned. A matched item may be a - * JSONObject, a JSONArray, or a JSON value. If the JSONPointer string building - * fails, an appropriate exception is thrown. If the navigation fails to find - * a match, a JSONPointerException is thrown. - * - * @author JSON.org - * @version 2016-05-14 - */ -public class JSONPointer { - - // used for URL encoding and decoding - private static final String ENCODING = "utf-8"; - - /** - * This class allows the user to build a JSONPointer in steps, using - * exactly one segment in each step. - */ - public static class Builder { - - /** - * Constructs a new Builder object. - */ - public Builder() { - } - - // Segments for the eventual JSONPointer string - private final List refTokens = new ArrayList(); - - /** - * Creates a {@code JSONPointer} instance using the tokens previously set using the - * {@link #append(String)} method calls. - * @return a JSONPointer object - */ - public JSONPointer build() { - return new JSONPointer(this.refTokens); - } - - /** - * Adds an arbitrary token to the list of reference tokens. It can be any non-null value. - * - * Unlike in the case of JSON string or URI fragment representation of JSON pointers, the - * argument of this method MUST NOT be escaped. If you want to query the property called - * {@code "a~b"} then you should simply pass the {@code "a~b"} string as-is, there is no - * need to escape it as {@code "a~0b"}. - * - * @param token the new token to be appended to the list - * @return {@code this} - * @throws NullPointerException if {@code token} is null - */ - public Builder append(String token) { - if (token == null) { - throw new NullPointerException("token cannot be null"); - } - this.refTokens.add(token); - return this; - } - - /** - * Adds an integer to the reference token list. Although not necessarily, mostly this token will - * denote an array index. - * - * @param arrayIndex the array index to be added to the token list - * @return {@code this} - */ - public Builder append(int arrayIndex) { - this.refTokens.add(String.valueOf(arrayIndex)); - return this; - } - } - - /** - * Static factory method for {@link Builder}. Example usage: - * - *
    
    -     * JSONPointer pointer = JSONPointer.builder()
    -     *       .append("obj")
    -     *       .append("other~key").append("another/key")
    -     *       .append("\"")
    -     *       .append(0)
    -     *       .build();
    -     * 
    - * - * @return a builder instance which can be used to construct a {@code JSONPointer} instance by chained - * {@link Builder#append(String)} calls. - */ - public static Builder builder() { - return new Builder(); - } - - // Segments for the JSONPointer string - private final List refTokens; - - /** - * Pre-parses and initializes a new {@code JSONPointer} instance. If you want to - * evaluate the same JSON Pointer on different JSON documents then it is recommended - * to keep the {@code JSONPointer} instances due to performance considerations. - * - * @param pointer the JSON String or URI Fragment representation of the JSON pointer. - * @throws IllegalArgumentException if {@code pointer} is not a valid JSON pointer - */ - public JSONPointer(final String pointer) { - if (pointer == null) { - throw new NullPointerException("pointer cannot be null"); - } - if (pointer.isEmpty() || "#".equals(pointer)) { - this.refTokens = Collections.emptyList(); - return; - } - String refs; - if (pointer.startsWith("#/")) { - refs = pointer.substring(2); - try { - refs = URLDecoder.decode(refs, ENCODING); - } catch (UnsupportedEncodingException e) { - throw new RuntimeException(e); - } - } else if (pointer.startsWith("/")) { - refs = pointer.substring(1); - } else { - throw new IllegalArgumentException("a JSON pointer should start with '/' or '#/'"); - } - this.refTokens = new ArrayList(); - int slashIdx = -1; - int prevSlashIdx = 0; - do { - prevSlashIdx = slashIdx + 1; - slashIdx = refs.indexOf('/', prevSlashIdx); - if(prevSlashIdx == slashIdx || prevSlashIdx == refs.length()) { - // found 2 slashes in a row ( obj//next ) - // or single slash at the end of a string ( obj/test/ ) - this.refTokens.add(""); - } else if (slashIdx >= 0) { - final String token = refs.substring(prevSlashIdx, slashIdx); - this.refTokens.add(unescape(token)); - } else { - // last item after separator, or no separator at all. - final String token = refs.substring(prevSlashIdx); - this.refTokens.add(unescape(token)); - } - } while (slashIdx >= 0); - // using split does not take into account consecutive separators or "ending nulls" - //for (String token : refs.split("/")) { - // this.refTokens.add(unescape(token)); - //} - } - - /** - * Constructs a new JSONPointer instance with the provided list of reference tokens. - * - * @param refTokens A list of strings representing the reference tokens for the JSON Pointer. - * Each token identifies a step in the path to the targeted value. - */ - public JSONPointer(List refTokens) { - this.refTokens = new ArrayList(refTokens); - } - - /** - * @see rfc6901 section 3 - */ - private static String unescape(String token) { - return token.replace("~1", "/").replace("~0", "~"); - } - - /** - * Evaluates this JSON Pointer on the given {@code document}. The {@code document} - * is usually a {@link JSONObject} or a {@link JSONArray} instance, but the empty - * JSON Pointer ({@code ""}) can be evaluated on any JSON values and in such case the - * returned value will be {@code document} itself. - * - * @param document the JSON document which should be the subject of querying. - * @return the result of the evaluation - * @throws JSONPointerException if an error occurs during evaluation - */ - public Object queryFrom(Object document) throws JSONPointerException { - if (this.refTokens.isEmpty()) { - return document; - } - Object current = document; - for (String token : this.refTokens) { - if (current instanceof JSONObject) { - current = ((JSONObject) current).opt(unescape(token)); - } else if (current instanceof JSONArray) { - current = readByIndexToken(current, token); - } else { - throw new JSONPointerException(format( - "value [%s] is not an array or object therefore its key %s cannot be resolved", current, - token)); - } - } - return current; - } - - /** - * Matches a JSONArray element by ordinal position - * @param current the JSONArray to be evaluated - * @param indexToken the array index in string form - * @return the matched object. If no matching item is found a - * @throws JSONPointerException is thrown if the index is out of bounds - */ - private static Object readByIndexToken(Object current, String indexToken) throws JSONPointerException { - try { - int index = Integer.parseInt(indexToken); - JSONArray currentArr = (JSONArray) current; - if (index >= currentArr.length()) { - throw new JSONPointerException(format("index %s is out of bounds - the array has %d elements", indexToken, - Integer.valueOf(currentArr.length()))); - } - try { - return currentArr.get(index); - } catch (JSONException e) { - throw new JSONPointerException("Error reading value at index position " + index, e); - } - } catch (NumberFormatException e) { - throw new JSONPointerException(format("%s is not an array index", indexToken), e); - } - } - - /** - * Returns a string representing the JSONPointer path value using string - * representation - */ - @Override - public String toString() { - StringBuilder rval = new StringBuilder(); - for (String token: this.refTokens) { - rval.append('/').append(escape(token)); - } - return rval.toString(); - } - - /** - * Escapes path segment values to an unambiguous form. - * The escape char to be inserted is '~'. The chars to be escaped - * are ~, which maps to ~0, and /, which maps to ~1. - * @param token the JSONPointer segment value to be escaped - * @return the escaped value for the token - * - * @see rfc6901 section 3 - */ - private static String escape(String token) { - return token.replace("~", "~0") - .replace("/", "~1"); - } - - /** - * Returns a string representing the JSONPointer path value using URI - * fragment identifier representation - * @return a uri fragment string - */ - public String toURIFragment() { - try { - StringBuilder rval = new StringBuilder("#"); - for (String token : this.refTokens) { - rval.append('/').append(URLEncoder.encode(token, ENCODING)); - } - return rval.toString(); - } catch (UnsupportedEncodingException e) { - throw new RuntimeException(e); - } - } - -} diff --git a/src/main/java/org/json/JSONPointerException.java b/src/main/java/org/json/JSONPointerException.java deleted file mode 100644 index dc5a25ad6..000000000 --- a/src/main/java/org/json/JSONPointerException.java +++ /dev/null @@ -1,36 +0,0 @@ -package org.json; - -/* -Public Domain. -*/ - -/** - * The JSONPointerException is thrown by {@link JSONPointer} if an error occurs - * during evaluating a pointer. - * - * @author JSON.org - * @version 2016-05-13 - */ -public class JSONPointerException extends JSONException { - private static final long serialVersionUID = 8872944667561856751L; - - /** - * Constructs a new JSONPointerException with the specified error message. - * - * @param message The detail message describing the reason for the exception. - */ - public JSONPointerException(String message) { - super(message); - } - - /** - * Constructs a new JSONPointerException with the specified error message and cause. - * - * @param message The detail message describing the reason for the exception. - * @param cause The cause of the exception. - */ - public JSONPointerException(String message, Throwable cause) { - super(message, cause); - } - -} diff --git a/src/main/java/org/json/JSONPropertyIgnore.java b/src/main/java/org/json/JSONPropertyIgnore.java deleted file mode 100644 index d3a5bc5a1..000000000 --- a/src/main/java/org/json/JSONPropertyIgnore.java +++ /dev/null @@ -1,23 +0,0 @@ -package org.json; - -/* -Public Domain. -*/ - -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.RetentionPolicy.RUNTIME; - -import java.lang.annotation.Documented; -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -/** - * Use this annotation on a getter method to override the Bean name - * parser for Bean -> JSONObject mapping. If this annotation is - * present at any level in the class hierarchy, then the method will - * not be serialized from the bean into the JSONObject. - */ -@Documented -@Retention(RUNTIME) -@Target({METHOD}) -public @interface JSONPropertyIgnore { } diff --git a/src/main/java/org/json/JSONPropertyName.java b/src/main/java/org/json/JSONPropertyName.java deleted file mode 100644 index 0e4123f37..000000000 --- a/src/main/java/org/json/JSONPropertyName.java +++ /dev/null @@ -1,28 +0,0 @@ -package org.json; - -/* -Public Domain. -*/ - -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.RetentionPolicy.RUNTIME; - -import java.lang.annotation.Documented; -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -/** - * Use this annotation on a getter method to override the Bean name - * parser for Bean -> JSONObject mapping. A value set to empty string "" - * will have the Bean parser fall back to the default field name processing. - */ -@Documented -@Retention(RUNTIME) -@Target({METHOD}) -public @interface JSONPropertyName { - /** - * The value of the JSON property. - * @return The name of the property as to be used in the JSON Object. - */ - String value(); -} diff --git a/src/main/java/org/json/JSONTokener.java b/src/main/java/org/json/JSONTokener.java index 07ff18c99..cb9af4626 100644 --- a/src/main/java/org/json/JSONTokener.java +++ b/src/main/java/org/json/JSONTokener.java @@ -1,7 +1,7 @@ package org.json; import java.io.*; -import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; /* Public Domain. @@ -79,7 +79,7 @@ public JSONTokener(InputStream inputStream) { * @param jsonParserConfiguration A JSONParserConfiguration instance that controls the behavior of the parser. */ public JSONTokener(InputStream inputStream, JSONParserConfiguration jsonParserConfiguration) { - this(new InputStreamReader(inputStream, Charset.forName("UTF-8")), jsonParserConfiguration); + this(new InputStreamReader(inputStream, StandardCharsets.UTF_8), jsonParserConfiguration); } @@ -124,12 +124,10 @@ public void setJsonParserConfiguration(JSONParserConfiguration jsonParserConfigu * Back up one character. This provides a sort of lookahead capability, * so that you can test for a digit or letter before attempting to parse * the next number or identifier. - * @throws JSONException Thrown if trying to step back more than 1 step - * or if already at the start of the string */ - public void back() throws JSONException { + public void back() { if (this.usePrevious || this.index <= 0) { - throw new JSONException("Stepping back two steps is not supported"); + throw new IllegalStateException("Stepping back two steps is not supported"); } this.decrementIndexes(); this.usePrevious = true; @@ -182,17 +180,15 @@ public boolean end() { * Determine if the source string still contains characters that next() * can consume. * @return true if not yet at the end of the source. - * @throws JSONException thrown if there is an error stepping forward - * or backward while checking for more data. */ - public boolean more() throws JSONException { + public boolean more() { if(this.usePrevious) { return true; } try { this.reader.mark(1); } catch (IOException e) { - throw new JSONException("Unable to preserve stream position", e); + throw new UncheckedIOException("Unable to preserve stream position", e); } try { // -1 is EOF, but next() can not consume the null character '\0' @@ -202,7 +198,7 @@ public boolean more() throws JSONException { } this.reader.reset(); } catch (IOException e) { - throw new JSONException("Unable to read the next character from the stream", e); + throw new UncheckedIOException("Unable to read the next character from the stream", e); } return true; } @@ -212,9 +208,8 @@ public boolean more() throws JSONException { * Get the next character in the source string. * * @return The next character, or 0 if past the end of the source string. - * @throws JSONException Thrown if there is an error reading the source string. */ - public char next() throws JSONException { + public char next() { int c; if (this.usePrevious) { this.usePrevious = false; @@ -223,7 +218,7 @@ public char next() throws JSONException { try { c = this.reader.read(); } catch (IOException exception) { - throw new JSONException(exception); + throw new UncheckedIOException(exception); } } if (c <= 0) { // End of stream @@ -270,9 +265,8 @@ private void incrementIndexes(int c) { * character. * @param c The character to match. * @return The character. - * @throws JSONException if the character does not match. */ - public char next(char c) throws JSONException { + public char next(char c) { char n = this.next(); if (n != c) { if(n > 0) { @@ -290,11 +284,8 @@ public char next(char c) throws JSONException { * * @param n The number of characters to take. * @return A string of n characters. - * @throws JSONException - * Substring bounds error if there are not - * n characters remaining in the source string. */ - public String next(int n) throws JSONException { + public String next(int n) { if (n == 0) { return ""; } @@ -315,10 +306,9 @@ public String next(int n) throws JSONException { /** * Get the next char in the string, skipping whitespace. - * @throws JSONException Thrown if there is an error reading the source string. * @return A character, or 0 if there are no more characters. */ - public char nextClean() throws JSONException { + public char nextClean() { for (;;) { char c = this.next(); if (c == 0 || c > ' ') { @@ -337,61 +327,42 @@ public char nextClean() throws JSONException { * " (double quote) or * ' (single quote). * @return A String. - * @throws JSONException Unterminated string. */ - public String nextString(char quote) throws JSONException { + public String nextString(char quote) { char c; - StringBuilder sb = new StringBuilder(); + var sb = new StringBuilder(); for (;;) { c = this.next(); switch (c) { - case 0: - case '\n': - case '\r': - throw this.syntaxError("Unterminated string. " + + case 0, '\n', '\r' -> throw this.syntaxError("Unterminated string. " + "Character with int code " + (int) c + " is not allowed within a quoted string."); - case '\\': - c = this.next(); - switch (c) { - case 'b': - sb.append('\b'); - break; - case 't': - sb.append('\t'); - break; - case 'n': - sb.append('\n'); - break; - case 'f': - sb.append('\f'); - break; - case 'r': - sb.append('\r'); - break; - case 'u': - String next = this.next(4); - try { - sb.append((char)Integer.parseInt(next, 16)); - } catch (NumberFormatException e) { - throw this.syntaxError("Illegal escape. " + - "\\u must be followed by a 4 digit hexadecimal number. \\" + next + " is not valid.", e); + case '\\' -> { + c = this.next(); + switch (c) { + case 'b' -> sb.append('\b'); + case 't' -> sb.append('\t'); + case 'n' -> sb.append('\n'); + case 'f' -> sb.append('\f'); + case 'r' -> sb.append('\r'); + case 'u' -> { + String next = this.next(4); + try { + sb.append((char) Integer.parseInt(next, 16)); + } catch (NumberFormatException e) { + throw this.syntaxError("Illegal escape. " + + "\\u must be followed by a 4 digit hexadecimal number. \\" + next + " is not valid.", e); + } + } + case '"', '\'', '\\', '/' -> sb.append(c); + default -> throw this.syntaxError("Illegal escape. Escape sequence \\" + c + " is not valid."); } - break; - case '"': - case '\'': - case '\\': - case '/': - sb.append(c); - break; - default: - throw this.syntaxError("Illegal escape. Escape sequence \\" + c + " is not valid."); } - break; - default: - if (c == quote) { - return sb.toString(); + default -> { + if (c == quote) { + return sb.toString(); + } + sb.append(c); } - sb.append(c); } } } @@ -402,11 +373,9 @@ public String nextString(char quote) throws JSONException { * end of line, whichever comes first. * @param delimiter A delimiter character. * @return A string. - * @throws JSONException Thrown if there is an error while searching - * for the delimiter */ - public String nextTo(char delimiter) throws JSONException { - StringBuilder sb = new StringBuilder(); + public String nextTo(char delimiter) { + var sb = new StringBuilder(); for (;;) { char c = this.next(); if (c == delimiter || c == 0 || c == '\n' || c == '\r') { @@ -425,12 +394,10 @@ public String nextTo(char delimiter) throws JSONException { * characters or the end of line, whichever comes first. * @param delimiters A set of delimiter characters. * @return A string, trimmed. - * @throws JSONException Thrown if there is an error while searching - * for the delimiter */ - public String nextTo(String delimiters) throws JSONException { + public String nextTo(String delimiters) { char c; - StringBuilder sb = new StringBuilder(); + var sb = new StringBuilder(); for (;;) { c = this.next(); if (delimiters.indexOf(c) >= 0 || c == 0 || @@ -448,26 +415,30 @@ public String nextTo(String delimiters) throws JSONException { /** * Get the next value. The value can be a Boolean, Double, Integer, * JSONArray, JSONObject, Long, or String, or the JSONObject.NULL object. - * @throws JSONException If syntax error. * * @return An object. */ - public Object nextValue() throws JSONException { + public Object nextValue() { char c = this.nextClean(); switch (c) { - case '{': - this.back(); - try { - return new JSONObject(this, jsonParserConfiguration); - } catch (StackOverflowError e) { - throw new JSONException("JSON Array or Object depth too large to process.", e); + case '{' -> { + this.back(); + try { + return new JSONObject(this, jsonParserConfiguration); + } catch (StackOverflowError e) { + throw new IllegalStateException("JSON Array or Object depth too large to process.", e); + } } - case '[': - this.back(); - try { - return new JSONArray(this, jsonParserConfiguration); - } catch (StackOverflowError e) { - throw new JSONException("JSON Array or Object depth too large to process.", e); + case '[' -> { + this.back(); + try { + return new JSONArray(this, jsonParserConfiguration); + } catch (StackOverflowError e) { + throw new IllegalStateException("JSON Array or Object depth too large to process.", e); + } + } + default -> { + // fall through to nextSimpleValue } } return nextSimpleValue(c); @@ -483,9 +454,12 @@ Object nextSimpleValue(char c) { throw this.syntaxError("Strict mode error: Single quoted strings are not allowed"); } switch (c) { - case '"': - case '\'': - return this.nextString(c); + case '"', '\'' -> { + return this.nextString(c); + } + default -> { + // fall through to unquoted text handling + } } /* @@ -497,7 +471,7 @@ Object nextSimpleValue(char c) { * formatting character. */ - StringBuilder sb = new StringBuilder(); + var sb = new StringBuilder(); while (c >= ' ' && ",:]}/\\\"[{;=#".indexOf(c) < 0) { sb.append(c); c = this.next(); @@ -517,17 +491,17 @@ Object nextSimpleValue(char c) { // if obj is a boolean, look at string if (jsonParserConfiguration != null && jsonParserConfiguration.isStrictMode()) { - if (obj instanceof Boolean && !"true".equals(string) && !"false".equals(string)) { + if (obj instanceof Boolean b && !"true".equals(string) && !"false".equals(string)) { // Strict mode only allows lowercase true or false - throw this.syntaxError(String.format("Strict mode error: Value '%s' is not lowercase boolean", obj)); + throw this.syntaxError(String.format("Strict mode error: Value '%s' is not lowercase boolean", b)); } else if (obj == JSONObject.NULL && !"null".equals(string)) { // Strint mode only allows lowercase null throw this.syntaxError(String.format("Strict mode error: Value '%s' is not lowercase null", obj)); } - else if (obj instanceof String) { + else if (obj instanceof String s) { // Strict mode only allows strings with explicit double quotes - throw this.syntaxError(String.format("Strict mode error: Value '%s' is not surrounded by quotes", obj)); + throw this.syntaxError(String.format("Strict mode error: Value '%s' is not surrounded by quotes", s)); } } return obj; @@ -540,10 +514,8 @@ else if (obj instanceof String) { * @param to A character to skip to. * @return The requested character, or zero if the requested character * is not found. - * @throws JSONException Thrown if there is an error while searching - * for the to character */ - public char skipTo(char to) throws JSONException { + public char skipTo(char to) { char c; try { long startIndex = this.index; @@ -565,31 +537,31 @@ public char skipTo(char to) throws JSONException { } while (c != to); this.reader.mark(1); } catch (IOException exception) { - throw new JSONException(exception); + throw new UncheckedIOException(exception); } this.back(); return c; } /** - * Make a JSONException to signal a syntax error. + * Make an IllegalArgumentException to signal a syntax error. * * @param message The error message. - * @return A JSONException object, suitable for throwing + * @return An IllegalArgumentException object, suitable for throwing */ - public JSONException syntaxError(String message) { - return new JSONException(message + this.toString()); + public IllegalArgumentException syntaxError(String message) { + return new IllegalArgumentException(message + this.toString()); } /** - * Make a JSONException to signal a syntax error. + * Make an IllegalArgumentException to signal a syntax error. * * @param message The error message. * @param causedBy The throwable that caused the error. - * @return A JSONException object, suitable for throwing + * @return An IllegalArgumentException object, suitable for throwing */ - public JSONException syntaxError(String message, Throwable causedBy) { - return new JSONException(message + this.toString(), causedBy); + public IllegalArgumentException syntaxError(String message, Throwable causedBy) { + return new IllegalArgumentException(message + this.toString(), causedBy); } /** diff --git a/src/main/java/org/json/JSONWriter.java b/src/main/java/org/json/JSONWriter.java index 11f4a5c7e..c2553505e 100644 --- a/src/main/java/org/json/JSONWriter.java +++ b/src/main/java/org/json/JSONWriter.java @@ -1,6 +1,7 @@ package org.json; import java.io.IOException; +import java.io.UncheckedIOException; import java.util.Collection; import java.util.Map; @@ -59,7 +60,7 @@ public class JSONWriter { /** * The object/array stack. */ - private final JSONObject stack[]; + private final JSONObject[] stack; /** * The stack top index. A value of 0 indicates that the stack is empty. @@ -89,9 +90,9 @@ public JSONWriter(Appendable w) { * @return this * @throws JSONException If the value is out of sequence. */ - private JSONWriter append(String string) throws JSONException { + private JSONWriter append(String string) { if (string == null) { - throw new JSONException("Null pointer"); + throw new IllegalArgumentException("Null pointer"); } if (this.mode == 'o' || this.mode == 'a') { try { @@ -100,10 +101,7 @@ private JSONWriter append(String string) throws JSONException { } this.writer.append(string); } catch (IOException e) { - // Android as of API 25 does not support this exception constructor - // however we won't worry about it. If an exception is happening here - // it will just throw a "Method not found" exception instead. - throw new JSONException(e); + throw new UncheckedIOException(e); } if (this.mode == 'o') { this.mode = 'k'; @@ -111,7 +109,7 @@ private JSONWriter append(String string) throws JSONException { this.comma = true; return this; } - throw new JSONException("Value out of sequence."); + throw new IllegalStateException("Value out of sequence."); } /** @@ -123,14 +121,14 @@ private JSONWriter append(String string) throws JSONException { * started in the wrong place (for example as a key or after the end of the * outermost array or object). */ - public JSONWriter array() throws JSONException { + public JSONWriter array() { if (this.mode == 'i' || this.mode == 'o' || this.mode == 'a') { this.push(null); this.append("["); this.comma = false; return this; } - throw new JSONException("Misplaced array."); + throw new IllegalStateException("Misplaced array."); } /** @@ -140,9 +138,9 @@ public JSONWriter array() throws JSONException { * @return this * @throws JSONException If unbalanced. */ - private JSONWriter end(char m, char c) throws JSONException { + private JSONWriter end(char m, char c) { if (this.mode != m) { - throw new JSONException(m == 'a' + throw new IllegalStateException(m == 'a' ? "Misplaced endArray." : "Misplaced endObject."); } @@ -150,10 +148,7 @@ private JSONWriter end(char m, char c) throws JSONException { try { this.writer.append(c); } catch (IOException e) { - // Android as of API 25 does not support this exception constructor - // however we won't worry about it. If an exception is happening here - // it will just throw a "Method not found" exception instead. - throw new JSONException(e); + throw new UncheckedIOException(e); } this.comma = true; return this; @@ -165,7 +160,7 @@ private JSONWriter end(char m, char c) throws JSONException { * @return this * @throws JSONException If incorrectly nested. */ - public JSONWriter endArray() throws JSONException { + public JSONWriter endArray() { return this.end('a', ']'); } @@ -175,7 +170,7 @@ public JSONWriter endArray() throws JSONException { * @return this * @throws JSONException If incorrectly nested. */ - public JSONWriter endObject() throws JSONException { + public JSONWriter endObject() { return this.end('k', '}'); } @@ -187,16 +182,16 @@ public JSONWriter endObject() throws JSONException { * @throws JSONException If the key is out of place. For example, keys * do not belong in arrays or if the key is null. */ - public JSONWriter key(String string) throws JSONException { + public JSONWriter key(String string) { if (string == null) { - throw new JSONException("Null key."); + throw new IllegalArgumentException("Null key."); } if (this.mode == 'k') { try { - JSONObject topObject = this.stack[this.top - 1]; + var topObject = this.stack[this.top - 1]; // don't use the built in putOnce method to maintain Android support if(topObject.has(string)) { - throw new JSONException("Duplicate key \"" + string + "\""); + throw new IllegalStateException("Duplicate key \"" + string + "\""); } topObject.put(string, true); if (this.comma) { @@ -208,13 +203,10 @@ public JSONWriter key(String string) throws JSONException { this.mode = 'o'; return this; } catch (IOException e) { - // Android as of API 25 does not support this exception constructor - // however we won't worry about it. If an exception is happening here - // it will just throw a "Method not found" exception instead. - throw new JSONException(e); + throw new UncheckedIOException(e); } } - throw new JSONException("Misplaced key."); + throw new IllegalStateException("Misplaced key."); } @@ -227,7 +219,7 @@ public JSONWriter key(String string) throws JSONException { * started in the wrong place (for example as a key or after the end of the * outermost array or object). */ - public JSONWriter object() throws JSONException { + public JSONWriter object() { if (this.mode == 'i') { this.mode = 'o'; } @@ -237,7 +229,7 @@ public JSONWriter object() throws JSONException { this.comma = false; return this; } - throw new JSONException("Misplaced object."); + throw new IllegalStateException("Misplaced object."); } @@ -247,13 +239,13 @@ public JSONWriter object() throws JSONException { * @param c The scope to close. * @throws JSONException If nesting is wrong. */ - private void pop(char c) throws JSONException { + private void pop(char c) { if (this.top <= 0) { - throw new JSONException("Nesting error."); + throw new IllegalStateException("Nesting error."); } char m = this.stack[this.top - 1] == null ? 'a' : 'k'; if (m != c) { - throw new JSONException("Nesting error."); + throw new IllegalStateException("Nesting error."); } this.top -= 1; this.mode = this.top == 0 @@ -268,9 +260,9 @@ private void pop(char c) throws JSONException { * @param jo The scope to open. * @throws JSONException If nesting is too deep. */ - private void push(JSONObject jo) throws JSONException { + private void push(JSONObject jo) { if (this.top >= maxdepth) { - throw new JSONException("Nesting too deep."); + throw new IllegalStateException("Nesting too deep."); } this.stack[this.top] = jo; this.mode = jo == null ? 'a' : 'k'; @@ -301,25 +293,25 @@ private void push(JSONObject jo) throws JSONException { * @throws JSONException * If the value is or contains an invalid number. */ - public static String valueToString(Object value) throws JSONException { + public static String valueToString(Object value) { if (value == null || value.equals(null)) { return "null"; } - if (value instanceof JSONString) { + if (value instanceof JSONString js) { String object; try { - object = ((JSONString) value).toJSONString(); + object = js.toJSONString(); } catch (Exception e) { - throw new JSONException(e); + throw new IllegalStateException(e); } if (object != null) { return object; } - throw new JSONException("Bad value from toJSONString: " + object); + throw new IllegalStateException("Bad value from toJSONString: " + object); } - if (value instanceof Number) { + if (value instanceof Number number) { // not all Numbers may match actual JSON Numbers. i.e. Fractions or Complex - final String numberAsString = JSONObject.numberToString((Number) value); + var numberAsString = JSONObject.numberToString(number); if(JSONObject.NUMBER_PATTERN.matcher(numberAsString).matches()) { // Close enough to a JSON number that we will return it unquoted return numberAsString; @@ -332,19 +324,17 @@ public static String valueToString(Object value) throws JSONException { || value instanceof JSONArray) { return value.toString(); } - if (value instanceof Map) { - Map map = (Map) value; + if (value instanceof Map map) { return new JSONObject(map).toString(); } - if (value instanceof Collection) { - Collection coll = (Collection) value; + if (value instanceof Collection coll) { return new JSONArray(coll).toString(); } if (value.getClass().isArray()) { return new JSONArray(value).toString(); } - if(value instanceof Enum){ - return JSONObject.quote(((Enum)value).name()); + if(value instanceof Enum e){ + return JSONObject.quote(e.name()); } return JSONObject.quote(value.toString()); } @@ -356,7 +346,7 @@ public static String valueToString(Object value) throws JSONException { * @return this * @throws JSONException if a called function has an error */ - public JSONWriter value(boolean b) throws JSONException { + public JSONWriter value(boolean b) { return this.append(b ? "true" : "false"); } @@ -366,7 +356,7 @@ public JSONWriter value(boolean b) throws JSONException { * @return this * @throws JSONException If the number is not finite. */ - public JSONWriter value(double d) throws JSONException { + public JSONWriter value(double d) { return this.value(Double.valueOf(d)); } @@ -376,7 +366,7 @@ public JSONWriter value(double d) throws JSONException { * @return this * @throws JSONException if a called function has an error */ - public JSONWriter value(long l) throws JSONException { + public JSONWriter value(long l) { return this.append(Long.toString(l)); } @@ -388,7 +378,7 @@ public JSONWriter value(long l) throws JSONException { * @return this * @throws JSONException If the value is out of sequence. */ - public JSONWriter value(Object object) throws JSONException { + public JSONWriter value(Object object) { return this.append(valueToString(object)); } } diff --git a/src/main/java/org/json/ParserConfiguration.java b/src/main/java/org/json/ParserConfiguration.java index 06cc44366..9d8bffa48 100644 --- a/src/main/java/org/json/ParserConfiguration.java +++ b/src/main/java/org/json/ParserConfiguration.java @@ -84,7 +84,7 @@ public boolean isKeepStrings() { */ @SuppressWarnings("unchecked") public T withKeepStrings(final boolean newVal) { - T newConfig = (T) this.clone(); + var newConfig = (T) this.clone(); newConfig.keepStrings = newVal; return newConfig; } @@ -113,7 +113,7 @@ public int getMaxNestingDepth() { */ @SuppressWarnings("unchecked") public T withMaxNestingDepth(int maxNestingDepth) { - T newConfig = (T) this.clone(); + var newConfig = (T) this.clone(); if (maxNestingDepth > UNDEFINED_MAXIMUM_NESTING_DEPTH) { newConfig.maxNestingDepth = maxNestingDepth; diff --git a/src/main/java/org/json/Property.java b/src/main/java/org/json/Property.java deleted file mode 100644 index ba6c56967..000000000 --- a/src/main/java/org/json/Property.java +++ /dev/null @@ -1,62 +0,0 @@ -package org.json; - -/* -Public Domain. -*/ - -import java.util.Enumeration; -import java.util.Properties; - -/** - * Converts a Property file data into JSONObject and back. - * @author JSON.org - * @version 2015-05-05 - */ -public class Property { - - /** - * Constructs a new Property object. - */ - public 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 if a called function has an error - */ - public static JSONObject toJSONObject(java.util.Properties properties) throws JSONException { - // can't use the new constructor for Android support - // JSONObject jo = new JSONObject(properties == null ? 0 : properties.size()); - 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 if a called function has an error - */ - public static Properties toProperties(JSONObject jo) throws JSONException { - Properties properties = new Properties(); - if (jo != null) { - // Don't use the new entrySet API to maintain Android support - for (final String key : jo.keySet()) { - Object value = jo.opt(key); - if (!JSONObject.NULL.equals(value)) { - properties.put(key, value.toString()); - } - } - } - return properties; - } -} diff --git a/src/main/java/org/json/StringBuilderWriter.java b/src/main/java/org/json/StringBuilderWriter.java index 4aaa4903f..918f02e7b 100644 --- a/src/main/java/org/json/StringBuilderWriter.java +++ b/src/main/java/org/json/StringBuilderWriter.java @@ -15,7 +15,6 @@ public class StringBuilderWriter extends Writer { */ public StringBuilderWriter() { builder = new StringBuilder(); - lock = builder; } /** @@ -28,7 +27,6 @@ public StringBuilderWriter() { */ public StringBuilderWriter(int initialSize) { builder = new StringBuilder(initialSize); - lock = builder; } @Override diff --git a/src/main/java/org/json/XML.java b/src/main/java/org/json/XML.java deleted file mode 100644 index 7e4b0bb0c..000000000 --- a/src/main/java/org/json/XML.java +++ /dev/null @@ -1,1148 +0,0 @@ -package org.json; - -/* -Public Domain. -*/ - -import java.io.Reader; -import java.io.StringReader; -import java.math.BigDecimal; -import java.math.BigInteger; -import java.util.Iterator; -import java.util.NoSuchElementException; - -/** - * 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 2016-08-10 - */ -@SuppressWarnings("boxing") -public class XML { - - /** - * Constructs a new XML object. - */ - public XML() { - } - - /** The Character '&'. */ - public static final Character AMP = '&'; - - /** The Character '''. */ - public static final Character APOS = '\''; - - /** The Character '!'. */ - public static final Character BANG = '!'; - - /** The Character '='. */ - public static final Character EQ = '='; - - /** The Character
    {@code '>'. }
    */ - public static final Character GT = '>'; - - /** The Character '<'. */ - public static final Character LT = '<'; - - /** The Character '?'. */ - public static final Character QUEST = '?'; - - /** The Character '"'. */ - public static final Character QUOT = '"'; - - /** The Character '/'. */ - public static final Character SLASH = '/'; - - /** - * Null attribute name - */ - public static final String NULL_ATTR = "xsi:nil"; - - /** - * Represents the XML attribute name for specifying type information. - */ - public static final String TYPE_ATTR = "xsi:type"; - - /** - * Creates an iterator for navigating Code Points in a string instead of - * characters. Once Java7 support is dropped, this can be replaced with - * - * string.codePoints() - * - * which is available in Java8 and above. - * - * @see http://stackoverflow.com/a/21791059/6030888 - */ - private static Iterable codePointIterator(final String string) { - return new Iterable() { - @Override - public Iterator iterator() { - return new Iterator() { - private int nextIndex = 0; - private final int length = string.length(); - - @Override - public boolean hasNext() { - return this.nextIndex < this.length; - } - - @Override - public Integer next() { - if (!hasNext()) { - throw new NoSuchElementException(); - } - int result = string.codePointAt(this.nextIndex); - this.nextIndex += Character.charCount(result); - return result; - } - - @Override - public void remove() { - throw new UnsupportedOperationException(); - } - }; - } - }; - } - - /** - * Replace special characters with XML escapes: - * - *
    {@code
    -     * & (ampersand) is replaced by &amp;
    -     * < (less than) is replaced by &lt;
    -     * > (greater than) is replaced by &gt;
    -     * " (double quote) is replaced by &quot;
    -     * ' (single quote / apostrophe) is replaced by &apos;
    -     * }
    - * - * @param string - * The string to be escaped. - * @return The escaped string. - */ - public static String escape(String string) { - StringBuilder sb = new StringBuilder(string.length()); - for (final int cp : codePointIterator(string)) { - switch (cp) { - case '&': - sb.append("&"); - break; - case '<': - sb.append("<"); - break; - case '>': - sb.append(">"); - break; - case '"': - sb.append("""); - break; - case '\'': - sb.append("'"); - break; - default: - if (mustEscape(cp)) { - sb.append("&#x"); - sb.append(Integer.toHexString(cp)); - sb.append(';'); - } else { - sb.appendCodePoint(cp); - } - } - } - return sb.toString(); - } - - /** - * @param cp code point to test - * @return true if the code point is not valid for an XML - */ - private static boolean mustEscape(int cp) { - /* Valid range from https://www.w3.org/TR/REC-xml/#charsets - * - * #x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD] | [#x10000-#x10FFFF] - * - * any Unicode character, excluding the surrogate blocks, FFFE, and FFFF. - */ - // isISOControl is true when (cp >= 0 && cp <= 0x1F) || (cp >= 0x7F && cp <= 0x9F) - // all ISO control characters are out of range except tabs and new lines - return (Character.isISOControl(cp) - && cp != 0x9 - && cp != 0xA - && cp != 0xD - ) || !( - // valid the range of acceptable characters that aren't control - (cp >= 0x20 && cp <= 0xD7FF) - || (cp >= 0xE000 && cp <= 0xFFFD) - || (cp >= 0x10000 && cp <= 0x10FFFF) - ) - ; - } - - /** - * Removes XML escapes from the string. - * - * @param string - * string to remove escapes from - * @return string with converted entities - */ - public static String unescape(String string) { - StringBuilder sb = new StringBuilder(string.length()); - for (int i = 0, length = string.length(); i < length; i++) { - char c = string.charAt(i); - if (c == '&') { - final int semic = string.indexOf(';', i); - if (semic > i) { - final String entity = string.substring(i + 1, semic); - sb.append(XMLTokener.unescapeEntity(entity)); - // skip past the entity we just parsed. - i += entity.length() + 1; - } else { - // this shouldn't happen in most cases since the parser - // errors on unclosed entries. - sb.append(c); - } - } else { - // not part of an entity - sb.append(c); - } - } - return sb.toString(); - } - - /** - * Throw an exception if the string contains whitespace. Whitespace is not - * allowed in tagNames and attributes. - * - * @param string - * A string. - * @throws JSONException Thrown if the string contains whitespace or is empty. - */ - public static void noSpace(String string) throws JSONException { - int i, length = string.length(); - if (length == 0) { - throw new JSONException("Empty string."); - } - for (i = 0; i < length; i += 1) { - if (Character.isWhitespace(string.charAt(i))) { - throw new JSONException("'" + string - + "' contains a space character."); - } - } - } - - /** - * Scan the content following the named tag, attaching it to the context. - * - * @param x - * The XMLTokener containing the source string. - * @param context - * The JSONObject that will include the new material. - * @param name - * The tag name. - * @param config - * The XML parser configuration. - * @param currentNestingDepth - * The current nesting depth. - * @return true if the close tag is processed. - * @throws JSONException Thrown if any parsing error occurs. - */ - private static boolean parse(XMLTokener x, JSONObject context, String name, XMLParserConfiguration config, int currentNestingDepth) - throws JSONException { - char c; - int i; - JSONObject jsonObject = null; - String string; - String tagName; - Object token; - XMLXsiTypeConverter xmlXsiTypeConverter; - - // Test for and skip past these forms: - // - // - // - // - // Report errors for these forms: - // <> - // <= - // << - - token = x.nextToken(); - - // "); - return false; - } - x.back(); - } else if (c == '[') { - token = x.nextToken(); - if ("CDATA".equals(token)) { - if (x.next() == '[') { - string = x.nextCDATA(); - if (string.length() > 0) { - context.accumulate(config.getcDataTagName(), string); - } - return false; - } - } - throw x.syntaxError("Expected 'CDATA['"); - } - i = 1; - do { - token = x.nextMeta(); - if (token == null) { - throw x.syntaxError("Missing '>' after ' 0); - return false; - } else if (token == QUEST) { - - // "); - return false; - } else if (token == SLASH) { - - // Close tag - if (x.nextToken() != GT) { - throw x.syntaxError("Misshaped tag"); - } - if (config.getForceList().contains(tagName)) { - // Force the value to be an array - if (nilAttributeFound) { - context.append(tagName, JSONObject.NULL); - } else if (jsonObject.length() > 0) { - context.append(tagName, jsonObject); - } else if(context.isEmpty()) { //avoids resetting the array in case of an empty tag in the middle or end - context.put(tagName, new JSONArray()); - if (jsonObject.isEmpty()){ - context.append(tagName, ""); - } - } else { - context.append(tagName, ""); - } - } else { - if (nilAttributeFound) { - context.accumulate(tagName, JSONObject.NULL); - } else if (jsonObject.length() > 0) { - context.accumulate(tagName, jsonObject); - } else { - context.accumulate(tagName, ""); - } - } - return false; - - } else if (token == GT) { - // Content, between <...> and - for (;;) { - token = x.nextContent(); - if (token == null) { - if (tagName != null) { - throw x.syntaxError("Unclosed tag " + tagName); - } - return false; - } else if (token instanceof String) { - string = (String) token; - if (string.length() > 0) { - if(xmlXsiTypeConverter != null) { - jsonObject.accumulate(config.getcDataTagName(), - stringToValue(string, xmlXsiTypeConverter)); - } else { - Object obj = stringToValue((String) token); - if (obj instanceof Boolean) { - jsonObject.accumulate(config.getcDataTagName(), - config.isKeepBooleanAsString() - ? ((String) token) - : obj); - } else if (obj instanceof Number) { - jsonObject.accumulate(config.getcDataTagName(), - config.isKeepNumberAsString() - ? ((String) token) - : obj); - } else if (obj == JSONObject.NULL) { - jsonObject.accumulate(config.getcDataTagName(), - config.isKeepStrings() ? ((String) token) : obj); - } else { - jsonObject.accumulate(config.getcDataTagName(), stringToValue((String) token)); - } - } - } - - } else if (token == LT) { - // Nested element - if (currentNestingDepth == config.getMaxNestingDepth()) { - throw x.syntaxError("Maximum nesting depth of " + config.getMaxNestingDepth() + " reached"); - } - - if (parse(x, jsonObject, tagName, config, currentNestingDepth + 1)) { - if (config.getForceList().contains(tagName)) { - // Force the value to be an array - if (jsonObject.length() == 0) { - //avoids resetting the array in case of an empty element in the middle or end - if(context.isEmpty()) { - context.put(tagName, new JSONArray()); - } - context.append(tagName, ""); - } else if (jsonObject.length() == 1 - && jsonObject.opt(config.getcDataTagName()) != null) { - context.append(tagName, jsonObject.opt(config.getcDataTagName())); - } else { - context.append(tagName, jsonObject); - } - } else { - if (jsonObject.length() == 0) { - context.accumulate(tagName, ""); - } else if (jsonObject.length() == 1 - && jsonObject.opt(config.getcDataTagName()) != null) { - context.accumulate(tagName, jsonObject.opt(config.getcDataTagName())); - } else { - if (!config.shouldTrimWhiteSpace()) { - removeEmpty(jsonObject, config); - } - context.accumulate(tagName, jsonObject); - } - } - - return false; - } - } - } - } else { - throw x.syntaxError("Misshaped tag"); - } - } - } - } - /** - * This method removes any JSON entry which has the key set by XMLParserConfiguration.cDataTagName - * and contains whitespace as this is caused by whitespace between tags. See test XMLTest.testNestedWithWhitespaceTrimmingDisabled. - * @param jsonObject JSONObject which may require deletion - * @param config The XMLParserConfiguration which includes the cDataTagName - */ - private static void removeEmpty(final JSONObject jsonObject, final XMLParserConfiguration config) { - if (jsonObject.has(config.getcDataTagName())) { - final Object s = jsonObject.get(config.getcDataTagName()); - if (s instanceof String) { - if (isStringAllWhiteSpace(s.toString())) { - jsonObject.remove(config.getcDataTagName()); - } - } - else if (s instanceof JSONArray) { - final JSONArray sArray = (JSONArray) s; - for (int k = sArray.length()-1; k >= 0; k--){ - final Object eachString = sArray.get(k); - if (eachString instanceof String) { - String s1 = (String) eachString; - if (isStringAllWhiteSpace(s1)) { - sArray.remove(k); - } - } - } - if (sArray.isEmpty()) { - jsonObject.remove(config.getcDataTagName()); - } - } - } - } - - private static boolean isStringAllWhiteSpace(final String s) { - for (int k = 0; k= '0' && initial <= '9') || initial == '-') { - // decimal representation - if (isDecimalNotation(val)) { - // Use a BigDecimal all the time so we keep the original - // representation. BigDecimal doesn't support -0.0, ensure we - // keep that by forcing a decimal. - try { - BigDecimal bd = new BigDecimal(val); - if(initial == '-' && BigDecimal.ZERO.compareTo(bd)==0) { - return Double.valueOf(-0.0); - } - return bd; - } catch (NumberFormatException retryAsDouble) { - // this is to support "Hex Floats" like this: 0x1.0P-1074 - try { - Double d = Double.valueOf(val); - if(d.isNaN() || d.isInfinite()) { - throw new NumberFormatException("val ["+val+"] is not a valid number."); - } - return d; - } catch (NumberFormatException ignore) { - throw new NumberFormatException("val ["+val+"] is not a valid number."); - } - } - } - // block items like 00 01 etc. Java number parsers treat these as Octal. - if(initial == '0' && val.length() > 1) { - char at1 = val.charAt(1); - if(at1 >= '0' && at1 <= '9') { - throw new NumberFormatException("val ["+val+"] is not a valid number."); - } - } else if (initial == '-' && val.length() > 2) { - char at1 = val.charAt(1); - char at2 = val.charAt(2); - if(at1 == '0' && at2 >= '0' && at2 <= '9') { - throw new NumberFormatException("val ["+val+"] is not a valid number."); - } - } - // integer representation. - // This will narrow any values to the smallest reasonable Object representation - // (Integer, Long, or BigInteger) - - // BigInteger down conversion: We use a similar bitLength compare as - // BigInteger#intValueExact uses. Increases GC, but objects hold - // only what they need. i.e. Less runtime overhead if the value is - // long lived. - BigInteger bi = new BigInteger(val); - if(bi.bitLength() <= 31){ - return Integer.valueOf(bi.intValue()); - } - if(bi.bitLength() <= 63){ - return Long.valueOf(bi.longValue()); - } - return bi; - } - throw new NumberFormatException("val ["+val+"] is not a valid number."); - } - - /** - * direct copy of {@link JSONObject#isDecimalNotation(String)} to maintain Android support. - */ - private static boolean isDecimalNotation(final String val) { - return val.indexOf('.') > -1 || val.indexOf('e') > -1 - || val.indexOf('E') > -1 || "-0".equals(val); - } - - /** - * This method tries to convert the given string value to the target object - * @param string String to convert - * @param typeConverter value converter to convert string to integer, boolean e.t.c - * @return JSON value of this string or the string - */ - public static Object stringToValue(String string, XMLXsiTypeConverter typeConverter) { - if(typeConverter != null) { - return typeConverter.convert(string); - } - return stringToValue(string); - } - - /** - * This method is the same as {@link JSONObject#stringToValue(String)}. - * - * @param string String to convert - * @return JSON value of this string or the string - */ - // To maintain compatibility with the Android API, this method is a direct copy of - // the one in JSONObject. Changes made here should be reflected there. - // This method should not make calls out of the XML object. - public static Object stringToValue(String string) { - if ("".equals(string)) { - return string; - } - - // check JSON key words true/false/null - if ("true".equalsIgnoreCase(string)) { - return Boolean.TRUE; - } - if ("false".equalsIgnoreCase(string)) { - return Boolean.FALSE; - } - if ("null".equalsIgnoreCase(string)) { - return JSONObject.NULL; - } - - /* - * If it might be a number, try converting it. If a number cannot be - * produced, then the value will just be a string. - */ - - char initial = string.charAt(0); - if ((initial >= '0' && initial <= '9') || initial == '-') { - try { - return stringToNumber(string); - } catch (Exception ignore) { - } - } - return string; - } - - /** - * Convert a well-formed (but not necessarily valid) XML string into a - * JSONObject. Some information may be lost in this transformation because - * JSON is a data format and XML is a document format. XML uses elements, - * attributes, and content text, while JSON uses unordered collections of - * name/value pairs and arrays of values. JSON does not does not like to - * distinguish between elements and attributes. Sequences of similar - * elements are represented as JSONArrays. Content text may be placed in a - * "content" member. Comments, prologs, DTDs, and
    {@code
    -     * <[ [ ]]>}
    - * are ignored. - * - * @param string - * The source string. - * @return A JSONObject containing the structured data from the XML string. - * @throws JSONException Thrown if there is an errors while parsing the string - */ - public static JSONObject toJSONObject(String string) throws JSONException { - return toJSONObject(string, XMLParserConfiguration.ORIGINAL); - } - - /** - * Convert a well-formed (but not necessarily valid) XML into a - * JSONObject. Some information may be lost in this transformation because - * JSON is a data format and XML is a document format. XML uses elements, - * attributes, and content text, while JSON uses unordered collections of - * name/value pairs and arrays of values. JSON does not does not like to - * distinguish between elements and attributes. Sequences of similar - * elements are represented as JSONArrays. Content text may be placed in a - * "content" member. Comments, prologs, DTDs, and
    {@code
    -     * <[ [ ]]>}
    - * are ignored. - * - * @param reader The XML source reader. - * @return A JSONObject containing the structured data from the XML string. - * @throws JSONException Thrown if there is an errors while parsing the string - */ - public static JSONObject toJSONObject(Reader reader) throws JSONException { - return toJSONObject(reader, XMLParserConfiguration.ORIGINAL); - } - - /** - * Convert a well-formed (but not necessarily valid) XML into a - * JSONObject. Some information may be lost in this transformation because - * JSON is a data format and XML is a document format. XML uses elements, - * attributes, and content text, while JSON uses unordered collections of - * name/value pairs and arrays of values. JSON does not does not like to - * distinguish between elements and attributes. Sequences of similar - * elements are represented as JSONArrays. Content text may be placed in a - * "content" member. Comments, prologs, DTDs, and
    {@code
    -     * <[ [ ]]>}
    - * are ignored. - * - * All values are converted as strings, for 1, 01, 29.0 will not be coerced to - * numbers but will instead be the exact value as seen in the XML document. - * - * @param reader The XML source reader. - * @param keepStrings If true, then values will not be coerced into boolean - * or numeric values and will instead be left as strings - * @return A JSONObject containing the structured data from the XML string. - * @throws JSONException Thrown if there is an errors while parsing the string - */ - public static JSONObject toJSONObject(Reader reader, boolean keepStrings) throws JSONException { - if(keepStrings) { - return toJSONObject(reader, XMLParserConfiguration.KEEP_STRINGS); - } - return toJSONObject(reader, XMLParserConfiguration.ORIGINAL); - } - - /** - * Convert a well-formed (but not necessarily valid) XML into a - * JSONObject. Some information may be lost in this transformation because - * JSON is a data format and XML is a document format. XML uses elements, - * attributes, and content text, while JSON uses unordered collections of - * name/value pairs and arrays of values. JSON does not does not like to - * distinguish between elements and attributes. Sequences of similar - * elements are represented as JSONArrays. Content text may be placed in a - * "content" member. Comments, prologs, DTDs, and
    {@code
    -     * <[ [ ]]>}
    - * are ignored. - * - * All numbers are converted as strings, for 1, 01, 29.0 will not be coerced to - * numbers but will instead be the exact value as seen in the XML document depending - * on how flag is set. - * All booleans are converted as strings, for true, false will not be coerced to - * booleans but will instead be the exact value as seen in the XML document depending - * on how flag is set. - * - * @param reader The XML source reader. - * @param keepNumberAsString If true, then numeric values will not be coerced into - * numeric values and will instead be left as strings - * @param keepBooleanAsString If true, then boolean values will not be coerced into - * * numeric values and will instead be left as strings - * @return A JSONObject containing the structured data from the XML string. - * @throws JSONException Thrown if there is an errors while parsing the string - */ - public static JSONObject toJSONObject(Reader reader, boolean keepNumberAsString, boolean keepBooleanAsString) throws JSONException { - XMLParserConfiguration xmlParserConfiguration = new XMLParserConfiguration(); - if(keepNumberAsString) { - xmlParserConfiguration = xmlParserConfiguration.withKeepNumberAsString(keepNumberAsString); - } - if(keepBooleanAsString) { - xmlParserConfiguration = xmlParserConfiguration.withKeepBooleanAsString(keepBooleanAsString); - } - return toJSONObject(reader, xmlParserConfiguration); - } - - /** - * Convert a well-formed (but not necessarily valid) XML into a - * JSONObject. Some information may be lost in this transformation because - * JSON is a data format and XML is a document format. XML uses elements, - * attributes, and content text, while JSON uses unordered collections of - * name/value pairs and arrays of values. JSON does not does not like to - * distinguish between elements and attributes. Sequences of similar - * elements are represented as JSONArrays. Content text may be placed in a - * "content" member. Comments, prologs, DTDs, and
    {@code
    -     * <[ [ ]]>}
    - * are ignored. - * - * All values are converted as strings, for 1, 01, 29.0 will not be coerced to - * numbers but will instead be the exact value as seen in the XML document. - * - * @param reader The XML source reader. - * @param config Configuration options for the parser - * @return A JSONObject containing the structured data from the XML string. - * @throws JSONException Thrown if there is an errors while parsing the string - */ - public static JSONObject toJSONObject(Reader reader, XMLParserConfiguration config) throws JSONException { - JSONObject jo = new JSONObject(); - XMLTokener x = new XMLTokener(reader, config); - while (x.more()) { - x.skipPast("<"); - if(x.more()) { - parse(x, jo, null, config, 0); - } - } - return jo; - } - - /** - * Convert a well-formed (but not necessarily valid) XML string into a - * JSONObject. Some information may be lost in this transformation because - * JSON is a data format and XML is a document format. XML uses elements, - * attributes, and content text, while JSON uses unordered collections of - * name/value pairs and arrays of values. JSON does not does not like to - * distinguish between elements and attributes. Sequences of similar - * elements are represented as JSONArrays. Content text may be placed in a - * "content" member. Comments, prologs, DTDs, and
    {@code
    -     * <[ [ ]]>}
    - * are ignored. - * - * All values are converted as strings, for 1, 01, 29.0 will not be coerced to - * numbers but will instead be the exact value as seen in the XML document. - * - * @param string - * The source string. - * @param keepStrings If true, then values will not be coerced into boolean - * or numeric values and will instead be left as strings - * @return A JSONObject containing the structured data from the XML string. - * @throws JSONException Thrown if there is an errors while parsing the string - */ - public static JSONObject toJSONObject(String string, boolean keepStrings) throws JSONException { - return toJSONObject(new StringReader(string), keepStrings); - } - - /** - * Convert a well-formed (but not necessarily valid) XML string into a - * JSONObject. Some information may be lost in this transformation because - * JSON is a data format and XML is a document format. XML uses elements, - * attributes, and content text, while JSON uses unordered collections of - * name/value pairs and arrays of values. JSON does not does not like to - * distinguish between elements and attributes. Sequences of similar - * elements are represented as JSONArrays. Content text may be placed in a - * "content" member. Comments, prologs, DTDs, and
    {@code
    -     * <[ [ ]]>}
    - * are ignored. - * - * All numbers are converted as strings, for 1, 01, 29.0 will not be coerced to - * numbers but will instead be the exact value as seen in the XML document depending - * on how flag is set. - * All booleans are converted as strings, for true, false will not be coerced to - * booleans but will instead be the exact value as seen in the XML document depending - * on how flag is set. - * - * @param string - * The source string. - * @param keepNumberAsString If true, then numeric values will not be coerced into - * numeric values and will instead be left as strings - * @param keepBooleanAsString If true, then boolean values will not be coerced into - * numeric values and will instead be left as strings - * @return A JSONObject containing the structured data from the XML string. - * @throws JSONException Thrown if there is an errors while parsing the string - */ - public static JSONObject toJSONObject(String string, boolean keepNumberAsString, boolean keepBooleanAsString) throws JSONException { - return toJSONObject(new StringReader(string), keepNumberAsString, keepBooleanAsString); - } - - /** - * Convert a well-formed (but not necessarily valid) XML string into a - * JSONObject. Some information may be lost in this transformation because - * JSON is a data format and XML is a document format. XML uses elements, - * attributes, and content text, while JSON uses unordered collections of - * name/value pairs and arrays of values. JSON does not does not like to - * distinguish between elements and attributes. Sequences of similar - * elements are represented as JSONArrays. Content text may be placed in a - * "content" member. Comments, prologs, DTDs, and
    {@code
    -     * <[ [ ]]>}
    - * are ignored. - * - * All values are converted as strings, for 1, 01, 29.0 will not be coerced to - * numbers but will instead be the exact value as seen in the XML document. - * - * @param string - * The source string. - * @param config Configuration options for the parser. - * @return A JSONObject containing the structured data from the XML string. - * @throws JSONException Thrown if there is an errors while parsing the string - */ - public static JSONObject toJSONObject(String string, XMLParserConfiguration config) throws JSONException { - return toJSONObject(new StringReader(string), config); - } - - /** - * Convert a JSONObject into a well-formed, element-normal XML string. - * - * @param object - * A JSONObject. - * @return A string. - * @throws JSONException Thrown if there is an error parsing the string - */ - public static String toString(Object object) throws JSONException { - return toString(object, null, XMLParserConfiguration.ORIGINAL); - } - - /** - * Convert a JSONObject into a well-formed, element-normal XML string. - * - * @param object - * A JSONObject. - * @param tagName - * The optional name of the enclosing tag. - * @return A string. - * @throws JSONException Thrown if there is an error parsing the string - */ - public static String toString(final Object object, final String tagName) { - return toString(object, tagName, XMLParserConfiguration.ORIGINAL); - } - - /** - * Convert a JSONObject into a well-formed, element-normal XML string. - * - * @param object - * A JSONObject. - * @param tagName - * The optional name of the enclosing tag. - * @param config - * Configuration that can control output to XML. - * @return A string. - * @throws JSONException Thrown if there is an error parsing the string - */ - public static String toString(final Object object, final String tagName, final XMLParserConfiguration config) - throws JSONException { - return toString(object, tagName, config, 0, 0); - } - - /** - * Convert a JSONObject into a well-formed, element-normal XML string, - * either pretty print or single-lined depending on indent factor. - * - * @param object - * A JSONObject. - * @param tagName - * The optional name of the enclosing tag. - * @param config - * Configuration that can control output to XML. - * @param indentFactor - * The number of spaces to add to each level of indentation. - * @param indent - * The current ident level in spaces. - * @return - * @throws JSONException - */ - private static String toString(final Object object, final String tagName, final XMLParserConfiguration config, int indentFactor, int indent) - throws JSONException { - StringBuilder sb = new StringBuilder(); - JSONArray ja; - JSONObject jo; - String string; - - if (object instanceof JSONObject) { - - // Emit - if (tagName != null) { - sb.append(indent(indent)); - sb.append('<'); - sb.append(tagName); - sb.append('>'); - if(indentFactor > 0){ - sb.append("\n"); - indent += indentFactor; - } - } - - // Loop thru the keys. - // don't use the new entrySet accessor to maintain Android Support - jo = (JSONObject) object; - for (final String key : jo.keySet()) { - Object value = jo.opt(key); - if (value == null) { - value = ""; - } else if (value.getClass().isArray()) { - value = new JSONArray(value); - } - - // Emit content in body - if (key.equals(config.getcDataTagName())) { - if (value instanceof JSONArray) { - ja = (JSONArray) value; - int jaLength = ja.length(); - // don't use the new iterator API to maintain support for Android - for (int i = 0; i < jaLength; i++) { - if (i > 0) { - sb.append('\n'); - } - Object val = ja.opt(i); - sb.append(escape(val.toString())); - } - } else { - sb.append(escape(value.toString())); - } - - // Emit an array of similar keys - - } else if (value instanceof JSONArray) { - ja = (JSONArray) value; - int jaLength = ja.length(); - // don't use the new iterator API to maintain support for Android - for (int i = 0; i < jaLength; i++) { - Object val = ja.opt(i); - if (val instanceof JSONArray) { - sb.append('<'); - sb.append(key); - sb.append('>'); - sb.append(toString(val, null, config, indentFactor, indent)); - sb.append("'); - } else { - sb.append(toString(val, key, config, indentFactor, indent)); - } - } - } else if ("".equals(value)) { - if (config.isCloseEmptyTag()){ - sb.append(indent(indent)); - sb.append('<'); - sb.append(key); - sb.append(">"); - sb.append(""); - if (indentFactor > 0) { - sb.append("\n"); - } - }else { - sb.append(indent(indent)); - sb.append('<'); - sb.append(key); - sb.append("/>"); - if (indentFactor > 0) { - sb.append("\n"); - } - } - - // Emit a new tag - - } else { - sb.append(toString(value, key, config, indentFactor, indent)); - } - } - if (tagName != null) { - - // Emit the close tag - sb.append(indent(indent - indentFactor)); - sb.append("'); - if(indentFactor > 0){ - sb.append("\n"); - } - } - return sb.toString(); - - } - - if (object != null && (object instanceof JSONArray || object.getClass().isArray())) { - if(object.getClass().isArray()) { - ja = new JSONArray(object); - } else { - ja = (JSONArray) object; - } - int jaLength = ja.length(); - // don't use the new iterator API to maintain support for Android - for (int i = 0; i < jaLength; i++) { - Object val = ja.opt(i); - // XML does not have good support for arrays. If an array - // appears in a place where XML is lacking, synthesize an - // element. - sb.append(toString(val, tagName == null ? "array" : tagName, config, indentFactor, indent)); - } - return sb.toString(); - } - - - string = (object == null) ? "null" : escape(object.toString()); - String indentationSuffix = (indentFactor > 0) ? "\n" : ""; - if(tagName == null){ - return indent(indent) + "\"" + string + "\"" + indentationSuffix; - } else if(string.length() == 0){ - return indent(indent) + "<" + tagName + "/>" + indentationSuffix; - } else { - return indent(indent) + "<" + tagName - + ">" + string + "" + indentationSuffix; - } - } - - /** - * Convert a JSONObject into a well-formed, pretty printed element-normal XML string. - * - * @param object - * A JSONObject. - * @param indentFactor - * The number of spaces to add to each level of indentation. - * @return A string. - * @throws JSONException Thrown if there is an error parsing the string - */ - public static String toString(Object object, int indentFactor){ - return toString(object, null, XMLParserConfiguration.ORIGINAL, indentFactor); - } - - /** - * Convert a JSONObject into a well-formed, pretty printed element-normal XML string. - * - * @param object - * A JSONObject. - * @param tagName - * The optional name of the enclosing tag. - * @param indentFactor - * The number of spaces to add to each level of indentation. - * @return A string. - * @throws JSONException Thrown if there is an error parsing the string - */ - public static String toString(final Object object, final String tagName, int indentFactor) { - return toString(object, tagName, XMLParserConfiguration.ORIGINAL, indentFactor); - } - - /** - * Convert a JSONObject into a well-formed, pretty printed element-normal XML string. - * - * @param object - * A JSONObject. - * @param tagName - * The optional name of the enclosing tag. - * @param config - * Configuration that can control output to XML. - * @param indentFactor - * The number of spaces to add to each level of indentation. - * @return A string. - * @throws JSONException Thrown if there is an error parsing the string - */ - public static String toString(final Object object, final String tagName, final XMLParserConfiguration config, int indentFactor) - throws JSONException { - return toString(object, tagName, config, indentFactor, 0); - } - - /** - * Return a String consisting of a number of space characters specified by indent - * - * @param indent - * The number of spaces to be appended to the String. - * @return - */ - private static final String indent(int indent) { - StringBuilder sb = new StringBuilder(); - for (int i = 0; i < indent; i++) { - sb.append(' '); - } - return sb.toString(); - } -} diff --git a/src/main/java/org/json/XMLParserConfiguration.java b/src/main/java/org/json/XMLParserConfiguration.java deleted file mode 100644 index de84b90cb..000000000 --- a/src/main/java/org/json/XMLParserConfiguration.java +++ /dev/null @@ -1,444 +0,0 @@ -package org.json; -/* -Public Domain. -*/ - -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; - - -/** - * Configuration object for the XML parser. The configuration is immutable. - * @author AylwardJ - */ -@SuppressWarnings({""}) -public class XMLParserConfiguration extends ParserConfiguration { - - /** - * The default maximum nesting depth when parsing a XML document to JSON. - */ -// public static final int DEFAULT_MAXIMUM_NESTING_DEPTH = 512; // We could override - - /** - * Allow user to control how numbers are parsed - */ - private boolean keepNumberAsString; - - /** - * Allow user to control how booleans are parsed - */ - private boolean keepBooleanAsString; - - /** Original Configuration of the XML Parser. */ - public static final XMLParserConfiguration ORIGINAL - = new XMLParserConfiguration(); - /** Original configuration of the XML Parser except that values are kept as strings. */ - public static final XMLParserConfiguration KEEP_STRINGS - = new XMLParserConfiguration().withKeepStrings(true); - - /** - * The name of the key in a JSON Object that indicates a CDATA section. Historically this has - * been the value "content" but can be changed. Use null to indicate no CDATA - * processing. - */ - private String cDataTagName; - - /** - * When parsing the XML into JSON, specifies if values with attribute xsi:nil="true" - * should be kept as attribute(false), or they should be converted to - * null(true) - */ - private boolean convertNilAttributeToNull; - - /** - * When creating an XML from JSON Object, an empty tag by default will self-close. - * If it has to be closed explicitly, with empty content between start and end tag, - * this flag is to be turned on. - */ - private boolean closeEmptyTag; - - /** - * This will allow type conversion for values in XML if xsi:type attribute is defined - */ - private Map> xsiTypeMap; - - /** - * When parsing the XML into JSON, specifies the tags whose values should be converted - * to arrays - */ - private Set forceList; - - - /** - * Flag to indicate whether white space should be trimmed when parsing XML. - * The default behaviour is to trim white space. When this is set to false, inputting XML - * with tags that are the same as the value of cDataTagName is unsupported. It is recommended to set cDataTagName - * to a distinct value in this case. - */ - private boolean shouldTrimWhiteSpace; - - /** - * Default parser configuration. Does not keep strings (tries to implicitly convert - * values), and the CDATA Tag Name is "content". Trims whitespace. - */ - public XMLParserConfiguration () { - super(); - this.cDataTagName = "content"; - this.convertNilAttributeToNull = false; - this.xsiTypeMap = Collections.emptyMap(); - this.forceList = Collections.emptySet(); - this.shouldTrimWhiteSpace = true; - } - - /** - * Configure the parser string processing and use the default CDATA Tag Name as "content". - * @param keepStrings true to parse all values as string. - * false to try and convert XML string values into a JSON value. - * @deprecated This constructor has been deprecated in favor of using the new builder - * pattern for the configuration. - * This constructor may be removed in a future release. - */ - @Deprecated - public XMLParserConfiguration (final boolean keepStrings) { - this(keepStrings, "content", false); - } - - /** - * Configure the parser string processing to try and convert XML values to JSON values and - * use the passed CDATA Tag Name the processing value. Pass null to - * disable CDATA processing - * @param cDataTagName null to disable CDATA processing. Any other value - * to use that value as the JSONObject key name to process as CDATA. - * @deprecated This constructor has been deprecated in favor of using the new builder - * pattern for the configuration. - * This constructor may be removed in a future release. - */ - @Deprecated - public XMLParserConfiguration (final String cDataTagName) { - this(false, cDataTagName, false); - } - - /** - * Configure the parser to use custom settings. - * @param keepStrings true to parse all values as string. - * false to try and convert XML string values into a JSON value. - * @param cDataTagName null to disable CDATA processing. Any other value - * to use that value as the JSONObject key name to process as CDATA. - * @deprecated This constructor has been deprecated in favor of using the new builder - * pattern for the configuration. - * This constructor may be removed in a future release. - */ - @Deprecated - public XMLParserConfiguration (final boolean keepStrings, final String cDataTagName) { - super(keepStrings, DEFAULT_MAXIMUM_NESTING_DEPTH); - this.cDataTagName = cDataTagName; - this.convertNilAttributeToNull = false; - } - - /** - * Configure the parser to use custom settings. - * @param keepStrings true to parse all values as string. - * false to try and convert XML string values into a JSON value. - * @param cDataTagName null to disable CDATA processing. Any other value - * to use that value as the JSONObject key name to process as CDATA. - * @param convertNilAttributeToNull true to parse values with attribute xsi:nil="true" as null. - * false to parse values with attribute xsi:nil="true" as {"xsi:nil":true}. - * @deprecated This constructor has been deprecated in favor of using the new builder - * pattern for the configuration. - * This constructor may be removed or marked private in a future release. - */ - @Deprecated - public XMLParserConfiguration (final boolean keepStrings, final String cDataTagName, final boolean convertNilAttributeToNull) { - super(false, DEFAULT_MAXIMUM_NESTING_DEPTH); - this.keepNumberAsString = keepStrings; - this.keepBooleanAsString = keepStrings; - this.cDataTagName = cDataTagName; - this.convertNilAttributeToNull = convertNilAttributeToNull; - } - - /** - * Configure the parser to use custom settings. - * @param keepStrings true to parse all values as string. - * false to try and convert XML string values into a JSON value. - * @param cDataTagName null to disable CDATA processing. Any other value - * to use that value as the JSONObject key name to process as CDATA. - * @param convertNilAttributeToNull true to parse values with attribute xsi:nil="true" as null. - * false to parse values with attribute xsi:nil="true" as {"xsi:nil":true}. - * @param xsiTypeMap new HashMap>() to parse values with attribute - * xsi:type="integer" as integer, xsi:type="string" as string - * @param forceList new HashSet() to parse the provided tags' values as arrays - * @param maxNestingDepth int to limit the nesting depth - * @param closeEmptyTag boolean to turn on explicit end tag for tag with empty value - */ - private XMLParserConfiguration (final boolean keepStrings, final String cDataTagName, - final boolean convertNilAttributeToNull, final Map> xsiTypeMap, final Set forceList, - final int maxNestingDepth, final boolean closeEmptyTag, final boolean keepNumberAsString, final boolean keepBooleanAsString) { - super(false, maxNestingDepth); - this.keepNumberAsString = keepNumberAsString; - this.keepBooleanAsString = keepBooleanAsString; - this.cDataTagName = cDataTagName; - this.convertNilAttributeToNull = convertNilAttributeToNull; - this.xsiTypeMap = Collections.unmodifiableMap(xsiTypeMap); - this.forceList = Collections.unmodifiableSet(forceList); - this.closeEmptyTag = closeEmptyTag; - } - - /** - * Provides a new instance of the same configuration. - */ - @Override - protected XMLParserConfiguration clone() { - // future modifications to this method should always ensure a "deep" - // clone in the case of collections. i.e. if a Map is added as a configuration - // item, a new map instance should be created and if possible each value in the - // map should be cloned as well. If the values of the map are known to also - // be immutable, then a shallow clone of the map is acceptable. - final XMLParserConfiguration config = new XMLParserConfiguration( - this.keepStrings, - this.cDataTagName, - this.convertNilAttributeToNull, - this.xsiTypeMap, - this.forceList, - this.maxNestingDepth, - this.closeEmptyTag, - this.keepNumberAsString, - this.keepBooleanAsString - ); - config.shouldTrimWhiteSpace = this.shouldTrimWhiteSpace; - return config; - } - - /** - * When parsing the XML into JSON, specifies if values should be kept as strings (true), or if - * they should try to be guessed into JSON values (numeric, boolean, string) - * - * @param newVal - * new value to use for the keepStrings configuration option. - * - * @return The existing configuration will not be modified. A new configuration is returned. - */ - @SuppressWarnings("unchecked") - @Override - public XMLParserConfiguration withKeepStrings(final boolean newVal) { - XMLParserConfiguration newConfig = this.clone(); - newConfig.keepStrings = newVal; - newConfig.keepNumberAsString = newVal; - newConfig.keepBooleanAsString = newVal; - return newConfig; - } - - /** - * When parsing the XML into JSON, specifies if numbers should be kept as strings (1), or if - * they should try to be guessed into JSON values (numeric, boolean, string) - * - * @param newVal - * new value to use for the keepNumberAsString configuration option. - * - * @return The existing configuration will not be modified. A new configuration is returned. - */ - public XMLParserConfiguration withKeepNumberAsString(final boolean newVal) { - XMLParserConfiguration newConfig = this.clone(); - newConfig.keepNumberAsString = newVal; - newConfig.keepStrings = newConfig.keepBooleanAsString && newConfig.keepNumberAsString; - return newConfig; - } - - /** - * When parsing the XML into JSON, specifies if booleans should be kept as strings (true), or if - * they should try to be guessed into JSON values (numeric, boolean, string) - * - * @param newVal - * new value to use for the withKeepBooleanAsString configuration option. - * - * @return The existing configuration will not be modified. A new configuration is returned. - */ - public XMLParserConfiguration withKeepBooleanAsString(final boolean newVal) { - XMLParserConfiguration newConfig = this.clone(); - newConfig.keepBooleanAsString = newVal; - newConfig.keepStrings = newConfig.keepBooleanAsString && newConfig.keepNumberAsString; - return newConfig; - } - - /** - * The name of the key in a JSON Object that indicates a CDATA section. Historically this has - * been the value "content" but can be changed. Use null to indicate no CDATA - * processing. - * - * @return The cDataTagName configuration value. - */ - public String getcDataTagName() { - return this.cDataTagName; - } - - /** - * When parsing the XML into JSONML, specifies if numbers should be kept as strings (true), or if - * they should try to be guessed into JSON values (numeric, boolean, string). - * - * @return The keepStrings configuration value. - */ - public boolean isKeepNumberAsString() { - return this.keepNumberAsString; - } - - /** - * When parsing the XML into JSONML, specifies if booleans should be kept as strings (true), or if - * they should try to be guessed into JSON values (numeric, boolean, string). - * - * @return The keepStrings configuration value. - */ - public boolean isKeepBooleanAsString() { - return this.keepBooleanAsString; - } - - /** - * The name of the key in a JSON Object that indicates a CDATA section. Historically this has - * been the value "content" but can be changed. Use null to indicate no CDATA - * processing. - * - * @param newVal - * new value to use for the cDataTagName configuration option. - * - * @return The existing configuration will not be modified. A new configuration is returned. - */ - public XMLParserConfiguration withcDataTagName(final String newVal) { - XMLParserConfiguration newConfig = this.clone(); - newConfig.cDataTagName = newVal; - return newConfig; - } - - /** - * When parsing the XML into JSON, specifies if values with attribute xsi:nil="true" - * should be kept as attribute(false), or they should be converted to - * null(true) - * - * @return The convertNilAttributeToNull configuration value. - */ - public boolean isConvertNilAttributeToNull() { - return this.convertNilAttributeToNull; - } - - /** - * When parsing the XML into JSON, specifies if values with attribute xsi:nil="true" - * should be kept as attribute(false), or they should be converted to - * null(true) - * - * @param newVal - * new value to use for the convertNilAttributeToNull configuration option. - * - * @return The existing configuration will not be modified. A new configuration is returned. - */ - public XMLParserConfiguration withConvertNilAttributeToNull(final boolean newVal) { - XMLParserConfiguration newConfig = this.clone(); - newConfig.convertNilAttributeToNull = newVal; - return newConfig; - } - - /** - * When parsing the XML into JSON, specifies that the values with attribute xsi:type - * will be converted to target type defined to client in this configuration - * {@code Map>} to parse values with attribute - * xsi:type="integer" as integer, xsi:type="string" as string - * @return xsiTypeMap unmodifiable configuration map. - */ - public Map> getXsiTypeMap() { - return this.xsiTypeMap; - } - - /** - * When parsing the XML into JSON, specifies that the values with attribute xsi:type - * will be converted to target type defined to client in this configuration - * {@code Map>} to parse values with attribute - * xsi:type="integer" as integer, xsi:type="string" as string - * @param xsiTypeMap {@code new HashMap>()} to parse values with attribute - * xsi:type="integer" as integer, xsi:type="string" as string - * @return The existing configuration will not be modified. A new configuration is returned. - */ - public XMLParserConfiguration withXsiTypeMap(final Map> xsiTypeMap) { - XMLParserConfiguration newConfig = this.clone(); - Map> cloneXsiTypeMap = new HashMap>(xsiTypeMap); - newConfig.xsiTypeMap = Collections.unmodifiableMap(cloneXsiTypeMap); - return newConfig; - } - - /** - * When parsing the XML into JSON, specifies that tags that will be converted to arrays - * in this configuration {@code Set} to parse the provided tags' values as arrays - * @return forceList unmodifiable configuration set. - */ - public Set getForceList() { - return this.forceList; - } - - /** - * When parsing the XML into JSON, specifies that tags that will be converted to arrays - * in this configuration {@code Set} to parse the provided tags' values as arrays - * @param forceList {@code new HashSet()} to parse the provided tags' values as arrays - * @return The existing configuration will not be modified. A new configuration is returned. - */ - public XMLParserConfiguration withForceList(final Set forceList) { - XMLParserConfiguration newConfig = this.clone(); - Set cloneForceList = new HashSet(forceList); - newConfig.forceList = Collections.unmodifiableSet(cloneForceList); - return newConfig; - } - - /** - * Defines the maximum nesting depth that the parser will descend before throwing an exception - * when parsing the XML into JSON. The default max nesting depth is 512, which means the parser - * will throw a JsonException if the maximum depth is reached. - * Using any negative value as a parameter is equivalent to setting no limit to the nesting depth, - * which means the parses will go as deep as the maximum call stack size allows. - * @param maxNestingDepth the maximum nesting depth allowed to the XML parser - * @return The existing configuration will not be modified. A new configuration is returned. - */ - @SuppressWarnings("unchecked") - @Override - public XMLParserConfiguration withMaxNestingDepth(int maxNestingDepth) { - return super.withMaxNestingDepth(maxNestingDepth); - } - - /** - * To enable explicit end tag with empty value. - * @param closeEmptyTag new value for the closeEmptyTag property - * @return same instance of configuration with empty tag config updated - */ - public XMLParserConfiguration withCloseEmptyTag(boolean closeEmptyTag){ - XMLParserConfiguration clonedConfiguration = this.clone(); - clonedConfiguration.closeEmptyTag = closeEmptyTag; - return clonedConfiguration; - } - - /** - * Sets whether whitespace should be trimmed inside of tags. *NOTE* Do not use this if - * you expect your XML tags to have names that are the same as cDataTagName as this is unsupported. - * cDataTagName should be set to a distinct value in these cases. - * @param shouldTrimWhiteSpace boolean to set trimming on or off. Off is default. - * @return same instance of configuration with empty tag config updated - */ - public XMLParserConfiguration withShouldTrimWhitespace(boolean shouldTrimWhiteSpace){ - XMLParserConfiguration clonedConfiguration = this.clone(); - clonedConfiguration.shouldTrimWhiteSpace = shouldTrimWhiteSpace; - return clonedConfiguration; - } - - /** - * Checks if the parser should automatically close empty XML tags. - * - * @return {@code true} if empty XML tags should be automatically closed, {@code false} otherwise. - */ - public boolean isCloseEmptyTag() { - return this.closeEmptyTag; - } - - /** - * Checks if the parser should trim white spaces from XML content. - * - * @return {@code true} if white spaces should be trimmed, {@code false} otherwise. - */ - public boolean shouldTrimWhiteSpace() { - return this.shouldTrimWhiteSpace; - } -} diff --git a/src/main/java/org/json/XMLTokener.java b/src/main/java/org/json/XMLTokener.java deleted file mode 100644 index dad2e2897..000000000 --- a/src/main/java/org/json/XMLTokener.java +++ /dev/null @@ -1,485 +0,0 @@ -package org.json; - -/* -Public Domain. -*/ - -import java.io.Reader; - -/** - * The XMLTokener extends the JSONTokener to provide additional methods - * for the parsing of XML texts. - * @author JSON.org - * @version 2015-12-09 - */ -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; - - private XMLParserConfiguration configuration = XMLParserConfiguration.ORIGINAL; - - static { - entity = new java.util.HashMap(8); - entity.put("amp", XML.AMP); - entity.put("apos", XML.APOS); - entity.put("gt", XML.GT); - entity.put("lt", XML.LT); - entity.put("quot", XML.QUOT); - } - - /** - * Construct an XMLTokener from a Reader. - * @param r A source reader. - */ - public XMLTokener(Reader r) { - super(r); - } - - /** - * Construct an XMLTokener from a string. - * @param s A source string. - */ - public XMLTokener(String s) { - super(s); - } - - /** - * Construct an XMLTokener from a Reader and an XMLParserConfiguration. - * @param r A source reader. - * @param configuration the configuration that can be used to set certain flags - */ - public XMLTokener(Reader r, XMLParserConfiguration configuration) { - super(r); - this.configuration = configuration; - } - - /** - * Get the text in the CDATA block. - * @return The string up to the ]]>. - * @throws JSONException If the ]]> is not found. - */ - public String nextCDATA() throws JSONException { - char c; - int i; - StringBuilder sb = new StringBuilder(); - while (more()) { - c = next(); - sb.append(c); - i = sb.length() - 3; - if (i >= 0 && sb.charAt(i) == ']' && - sb.charAt(i + 1) == ']' && sb.charAt(i + 2) == '>') { - sb.setLength(i); - return sb.toString(); - } - } - throw syntaxError("Unclosed CDATA"); - } - - - /** - * Get the next XML outer token, trimming whitespace. There are two kinds - * of tokens: the
    {@code '<' }
    character which begins a markup - * tag, and the content - * text between markup tags. - * - * @return A string, or a
    {@code '<' }
    Character, or null if - * there is no more source text. - * @throws JSONException if a called function has an error - */ - public Object nextContent() throws JSONException { - char c; - StringBuilder sb; - do { - c = next(); - } while (Character.isWhitespace(c) && configuration.shouldTrimWhiteSpace()); - if (c == 0) { - return null; - } - if (c == '<') { - return XML.LT; - } - sb = new StringBuilder(); - for (;;) { - if (c == 0) { - return sb.toString().trim(); - } - if (c == '<') { - back(); - if (configuration.shouldTrimWhiteSpace()) { - return sb.toString().trim(); - } else return sb.toString(); - } - if (c == '&') { - sb.append(nextEntity(c)); - } else { - sb.append(c); - } - c = next(); - } - } - - - /** - *
    {@code
    -     * Return the next entity. These entities are translated to Characters:
    -     *     &  '  >  <  ".
    -     * }
    - * @param ampersand An ampersand character. - * @return A Character or an entity String if the entity is not recognized. - * @throws JSONException If missing ';' in XML entity. - */ - public Object nextEntity(@SuppressWarnings("unused") char ampersand) throws JSONException { - StringBuilder sb = new StringBuilder(); - for (;;) { - char c = next(); - if (Character.isLetterOrDigit(c) || c == '#') { - sb.append(Character.toLowerCase(c)); - } else if (c == ';') { - break; - } else { - throw syntaxError("Missing ';' in XML entity: &" + sb); - } - } - String string = sb.toString(); - return unescapeEntity(string); - } - - /** - * Unescape an XML entity encoding; - * @param e entity (only the actual entity value, not the preceding & or ending ; - * @return the unescaped entity string - * @throws JSONException if the entity is malformed - */ - static String unescapeEntity(String e) throws JSONException { - // validate - if (e == null || e.isEmpty()) { - return ""; - } - // if our entity is an encoded unicode point, parse it. - if (e.charAt(0) == '#') { - if (e.length() < 2) { - throw new JSONException("Invalid numeric character reference: &#;"); - } - int cp = (e.charAt(1) == 'x' || e.charAt(1) == 'X') - ? parseHexEntity(e) - : parseDecimalEntity(e); - return new String(new int[] {cp}, 0, 1); - } - Character knownEntity = entity.get(e); - if (knownEntity == null) { - // we don't know the entity so keep it encoded - return '&' + e + ';'; - } - return knownEntity.toString(); - } - - /** - * Parse a hexadecimal numeric character reference (e.g., "઼"). - * @param e entity string starting with '#' (e.g., "#x1F4A9") - * @return the Unicode code point - * @throws JSONException if the format is invalid - */ - private static int parseHexEntity(String e) throws JSONException { - // hex encoded unicode - need at least one hex digit after #x - if (e.length() < 3) { - throw new JSONException("Invalid hex character reference: missing hex digits in &#" + e.substring(1) + ";"); - } - String hex = e.substring(2); - if (!isValidHex(hex)) { - throw new JSONException("Invalid hex character reference: &#" + e.substring(1) + ";"); - } - try { - return Integer.parseInt(hex, 16); - } catch (NumberFormatException nfe) { - throw new JSONException("Invalid hex character reference: &#" + e.substring(1) + ";", nfe); - } - } - - /** - * Parse a decimal numeric character reference (e.g., "{"). - * @param e entity string starting with '#' (e.g., "#123") - * @return the Unicode code point - * @throws JSONException if the format is invalid - */ - private static int parseDecimalEntity(String e) throws JSONException { - String decimal = e.substring(1); - if (!isValidDecimal(decimal)) { - throw new JSONException("Invalid decimal character reference: &#" + decimal + ";"); - } - try { - return Integer.parseInt(decimal); - } catch (NumberFormatException nfe) { - throw new JSONException("Invalid decimal character reference: &#" + decimal + ";", nfe); - } - } - - /** - * Check if a string contains only valid hexadecimal digits. - * @param s the string to check - * @return true if s is non-empty and contains only hex digits (0-9, a-f, A-F) - */ - private static boolean isValidHex(String s) { - if (s == null || s.isEmpty()) { - return false; - } - for (int i = 0; i < s.length(); i++) { - char c = s.charAt(i); - if (!((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'))) { - return false; - } - } - return true; - } - - /** - * Check if a string contains only valid decimal digits. - * @param s the string to check - * @return true if s is non-empty and contains only digits (0-9) - */ - private static boolean isValidDecimal(String s) { - if (s == null || s.isEmpty()) { - return false; - } - for (int i = 0; i < s.length(); i++) { - char c = s.charAt(i); - if (c < '0' || c > '9') { - return false; - } - } - return true; - } - - - /** - *
    {@code 
    -     * Returns the next XML meta token. This is used for skipping over 
    -     * and  structures.
    -     *  }
    - * @return
    {@code Syntax characters (< > / = ! ?) are returned as
    -     *  Character, and strings and names are returned as Boolean. We don't care
    -     *  what the values actually are.
    -     *  }
    - * @throws JSONException If a string is not properly closed or if the XML - * is badly structured. - */ - public Object nextMeta() throws JSONException { - char c; - char q; - do { - c = next(); - } while (Character.isWhitespace(c)); - switch (c) { - case 0: - throw syntaxError("Misshaped meta tag"); - case '<': - return XML.LT; - case '>': - return XML.GT; - case '/': - return XML.SLASH; - case '=': - return XML.EQ; - case '!': - return XML.BANG; - case '?': - return XML.QUEST; - case '"': - case '\'': - q = c; - for (;;) { - c = next(); - if (c == 0) { - throw syntaxError("Unterminated string"); - } - if (c == q) { - return Boolean.TRUE; - } - } - default: - for (;;) { - c = next(); - if (Character.isWhitespace(c)) { - return Boolean.TRUE; - } - switch (c) { - case 0: - throw syntaxError("Unterminated string"); - case '<': - case '>': - case '/': - case '=': - case '!': - case '?': - case '"': - case '\'': - back(); - return Boolean.TRUE; - } - } - } - } - - - /** - *
    {@code
    -     * Get the next XML Token. These tokens are found inside of angle
    -     * brackets. It may be one of these characters: / > = ! ? or it
    -     * may be a string wrapped in single quotes or double quotes, or it may be a
    -     * name.
    -     * }
    - * @return a String or a Character. - * @throws JSONException If the XML is not well formed. - */ - public Object nextToken() throws JSONException { - char c; - char q; - StringBuilder sb; - do { - c = next(); - } while (Character.isWhitespace(c)); - switch (c) { - case 0: - throw syntaxError("Misshaped element"); - case '<': - throw syntaxError("Misplaced '<'"); - case '>': - return XML.GT; - case '/': - return XML.SLASH; - case '=': - return XML.EQ; - case '!': - return XML.BANG; - case '?': - return XML.QUEST; - -// Quoted string - - case '"': - case '\'': - q = c; - sb = new StringBuilder(); - for (;;) { - c = next(); - if (c == 0) { - throw syntaxError("Unterminated string"); - } - if (c == q) { - return sb.toString(); - } - if (c == '&') { - sb.append(nextEntity(c)); - } else { - sb.append(c); - } - } - default: - -// Name - - sb = new StringBuilder(); - for (;;) { - sb.append(c); - c = next(); - if (Character.isWhitespace(c)) { - return sb.toString(); - } - switch (c) { - case 0: - return sb.toString(); - case '>': - case '/': - case '=': - case '!': - case '?': - case '[': - case ']': - back(); - return sb.toString(); - case '<': - case '"': - case '\'': - throw syntaxError("Bad character in a name"); - } - } - } - } - - - /** - * Skip characters until past the requested string. - * If it is not found, we are left at the end of the source with a result of false. - * @param to A string to skip past. - */ - // The Android implementation of JSONTokener has a public method of public void skipPast(String to) - // even though ours does not have that method, to have API compatibility, our method in the subclass - // should match. - public void skipPast(String to) { - boolean b; - char c; - int i; - int j; - int offset = 0; - int length = to.length(); - char[] circle = new char[length]; - - /* - * First fill the circle buffer with as many characters as are in the - * to string. If we reach an early end, bail. - */ - - for (i = 0; i < length; i += 1) { - c = next(); - if (c == 0) { - return; - } - circle[i] = c; - } - - /* We will loop, possibly for all of the remaining characters. */ - - for (;;) { - j = offset; - b = true; - - /* Compare the circle buffer with the to string. */ - - for (i = 0; i < length; i += 1) { - if (circle[j] != to.charAt(i)) { - b = false; - break; - } - j += 1; - if (j >= length) { - j -= length; - } - } - - /* If we exit the loop with b intact, then victory is ours. */ - - if (b) { - return; - } - - /* Get the next character. If there isn't one, then defeat is ours. */ - - c = next(); - if (c == 0) { - return; - } - /* - * Shove the character in the circle buffer and advance the - * circle offset. The offset is mod n. - */ - circle[offset] = c; - offset += 1; - if (offset >= length) { - offset -= length; - } - } - } -} diff --git a/src/main/java/org/json/XMLXsiTypeConverter.java b/src/main/java/org/json/XMLXsiTypeConverter.java deleted file mode 100644 index ea6739d34..000000000 --- a/src/main/java/org/json/XMLXsiTypeConverter.java +++ /dev/null @@ -1,53 +0,0 @@ -package org.json; -/* -Public Domain. -*/ - -/** - * Type conversion configuration interface to be used with xsi:type attributes. - *
    - * XML Sample
    - * {@code
    - *      
    - *          12345
    - *          54321
    - *      
    - * }
    - * JSON Output
    - * {@code
    - *     {
    - *         "root" : {
    - *             "asString" : "12345",
    - *             "asInt": 54321
    - *         }
    - *     }
    - * }
    - *
    - * Usage
    - * {@code
    - *      Map> xsiTypeMap = new HashMap>();
    - *      xsiTypeMap.put("string", new XMLXsiTypeConverter() {
    - *          @Override public String convert(final String value) {
    - *              return value;
    - *          }
    - *      });
    - *      xsiTypeMap.put("integer", new XMLXsiTypeConverter() {
    - *          @Override public Integer convert(final String value) {
    - *              return Integer.valueOf(value);
    - *          }
    - *      });
    - * }
    - * 
    - * @author kumar529 - * @param return type of convert method - */ -public interface XMLXsiTypeConverter { - - /** - * Converts an XML xsi:type attribute value to the specified type {@code T}. - * - * @param value The string representation of the XML xsi:type attribute value to be converted. - * @return An object of type {@code T} representing the converted value. - */ - T convert(String value); -} diff --git a/src/test/java/org/json/junit/CDLTest.java b/src/test/java/org/json/junit/CDLTest.java deleted file mode 100644 index e5eb9eda8..000000000 --- a/src/test/java/org/json/junit/CDLTest.java +++ /dev/null @@ -1,392 +0,0 @@ -package org.json.junit; - -/* -Public Domain. -*/ - -import static org.junit.Assert.*; -import org.junit.Test; - -import org.json.JSONException; -import org.json.JSONObject; -import org.json.JSONArray; -import org.json.CDL; - -/** - * Tests for CDL.java. - * CDL provides an application level API, but it is not used by the - * reference app. To test it, strings will be converted to JSON-Java classes - * and then converted back. - */ -public class CDLTest { - - /** - * String of lines where the column names are in the first row, - * and all subsequent rows are values. All keys and values should be legal. - */ - private static final String LINES = "Col 1, Col 2, \tCol 3, Col 4, Col 5, Col 6, Col 7\n" + - "val1, val2, val3, val4, val5, val6, val7\n" + - "1, 2, 3, 4\t, 5, 6, 7\n" + - "true, false, true, true, false, false, false\n" + - "0.23, 57.42, 5e27, -234.879, 2.34e5, 0.0, 9e-3\n" + - "\"va\tl1\", \"v\bal2\", \"val3\", \"val\f4\", \"val5\", \"va'l6\", val7\n"; - - - /** - * CDL.toJSONArray() adds all values as strings, with no filtering or - * conversions. For testing, this means that the expected JSONObject - * values all must be quoted in the cases where the JSONObject parsing - * might normally convert the value into a non-string. - */ - private static final String EXPECTED_LINES = - "[ " + - "{" + - "\"Col 1\":\"val1\", " + - "\"Col 2\":\"val2\", " + - "\"Col 3\":\"val3\", " + - "\"Col 4\":\"val4\", " + - "\"Col 5\":\"val5\", " + - "\"Col 6\":\"val6\", " + - "\"Col 7\":\"val7\"" + - "}, " + - " {" + - "\"Col 1\":\"1\", " + - "\"Col 2\":\"2\", " + - "\"Col 3\":\"3\", " + - "\"Col 4\":\"4\", " + - "\"Col 5\":\"5\", " + - "\"Col 6\":\"6\", " + - "\"Col 7\":\"7\"" + - "}, " + - " {" + - "\"Col 1\":\"true\", " + - "\"Col 2\":\"false\", " + - "\"Col 3\":\"true\", " + - "\"Col 4\":\"true\", " + - "\"Col 5\":\"false\", " + - "\"Col 6\":\"false\", " + - "\"Col 7\":\"false\"" + - "}, " + - "{" + - "\"Col 1\":\"0.23\", " + - "\"Col 2\":\"57.42\", " + - "\"Col 3\":\"5e27\", " + - "\"Col 4\":\"-234.879\", " + - "\"Col 5\":\"2.34e5\", " + - "\"Col 6\":\"0.0\", " + - "\"Col 7\":\"9e-3\"" + - "}, " + - "{" + - "\"Col 1\":\"va\tl1\", " + - "\"Col 2\":\"v\bal2\", " + - "\"Col 3\":\"val3\", " + - "\"Col 4\":\"val\f4\", " + - "\"Col 5\":\"val5\", " + - "\"Col 6\":\"va'l6\", " + - "\"Col 7\":\"val7\"" + - "}" + - "]"; - - /** - * Attempts to create a JSONArray from a null string. - * Expect a NullPointerException. - */ - @Test(expected=NullPointerException.class) - public void exceptionOnNullString() { - String nullStr = null; - CDL.toJSONArray(nullStr); - } - - /** - * Attempts to create a JSONArray from a string with unbalanced quotes - * in column title line. Expects a JSONException. - */ - @Test - public void unbalancedQuoteInName() { - String badLine = "Col1, \"Col2\nVal1, Val2"; - try { - CDL.toJSONArray(badLine); - fail("Expecting an exception"); - } catch (JSONException e) { - assertEquals("Expecting an exception message", - "Missing close quote '\"'. at 12 [character 0 line 2]", - e.getMessage()); - } - } - - /** - * Attempts to create a JSONArray from a string with unbalanced quotes - * in value line. Expects a JSONException. - */ - @Test - public void unbalancedQuoteInValue() { - String badLine = "Col1, Col2\n\"Val1, Val2"; - try { - CDL.toJSONArray(badLine); - fail("Expecting an exception"); - } catch (JSONException e) { - assertEquals("Expecting an exception message", - "Missing close quote '\"'. at 22 [character 11 line 2]", - e.getMessage()); - - } - } - - /** - * Attempts to create a JSONArray from a string with null char - * in column title line. Expects a JSONException. - */ - @Test - public void nullInName() { - String badLine = "C\0ol1, Col2\nVal1, Val2"; - try { - CDL.toJSONArray(badLine); - fail("Expecting an exception"); - } catch (JSONException e) { - assertEquals("Expecting an exception message", - "Bad character 'o' (111). at 2 [character 3 line 1]", - e.getMessage()); - - } - } - - /** - * Attempt to create a JSONArray with unbalanced quotes and a properly escaped doubled quote. - * Expects a JSONException. - */ - @Test - public void unbalancedEscapedQuote(){ - String badLine = "Col1, Col2\n\"Val1, \"\"Val2\"\""; - try { - CDL.toJSONArray(badLine); - fail("Expecting an exception"); - } catch (JSONException e) { - assertEquals("Expecting an exception message", - "Missing close quote '\"'. at 26 [character 15 line 2]", - e.getMessage()); - - } - } - - /** - * Csv parsing skip last row if last field of this row is empty #943 - */ - @Test - public void csvParsingCatchesLastRow(){ - String data = "Field 1,Field 2,Field 3\n" + - "value11,value12,\n" + - "value21,value22,"; - - JSONArray jsonArray = CDL.toJSONArray(data); - - JSONArray expectedJsonArray = new JSONArray(); - JSONObject jsonObject = new JSONObject(); - jsonObject.put("Field 1", "value11"); - jsonObject.put("Field 2", "value12"); - jsonObject.put("Field 3", ""); - expectedJsonArray.put(jsonObject); - - jsonObject = new JSONObject(); - jsonObject.put("Field 1", "value21"); - jsonObject.put("Field 2", "value22"); - jsonObject.put("Field 3", ""); - expectedJsonArray.put(jsonObject); - - Util.compareActualVsExpectedJsonArrays(jsonArray, expectedJsonArray); - } - - /** - * Assert that there is no error for a single escaped quote within a properly embedded quote. - */ - @Test - public void singleEscapedQuote(){ - String singleEscape = "Col1, Col2\nVal1, \"\"\"Val2\""; - JSONArray jsonArray = CDL.toJSONArray(singleEscape); - - String cdlStr = CDL.toString(jsonArray); - assertTrue(cdlStr.contains("Col1")); - assertTrue(cdlStr.contains("Col2")); - assertTrue(cdlStr.contains("Val1")); - assertTrue(cdlStr.contains("\"Val2")); - } - - /** - * Assert that there is no error for a single escaped quote within a properly - * embedded quote when not the last value. - */ - @Test - public void singleEscapedQuoteMiddleString(){ - String singleEscape = "Col1, Col2\nVal1, \"\"\"Val2\"\nVal 3,Val 4"; - JSONArray jsonArray = CDL.toJSONArray(singleEscape); - - String cdlStr = CDL.toString(jsonArray); - assertTrue(cdlStr.contains("Col1")); - assertTrue(cdlStr.contains("Col2")); - assertTrue(cdlStr.contains("Val1")); - assertTrue(cdlStr.contains("\"Val2")); - } - - /** - * Attempt to create a JSONArray with an escape quote and no enclosing quotes. - * Expects a JSONException. - */ - @Test - public void badEscapedQuote(){ - String badLine = "Col1, Col2\nVal1, \"\"Val2"; - - try { - CDL.toJSONArray(badLine); - fail("Expecting an exception"); - } catch (JSONException e) { - //System.out.println("Message" + e.getMessage()); - assertEquals("Expecting an exception message", - "Bad character 'V' (86). at 20 [character 9 line 2]", - e.getMessage()); - - } - - } - - /** - * call toString with a null array - */ - @Test(expected=NullPointerException.class) - public void nullJSONArrayToString() { - CDL.toString((JSONArray)null); - } - - /** - * Create a JSONArray from an empty string - */ - @Test - public void emptyString() { - String emptyStr = ""; - JSONArray jsonArray = CDL.toJSONArray(emptyStr); - assertNull("CDL should return null when the input string is empty", jsonArray); - } - - /** - * Create a JSONArray with only 1 row - */ - @Test - public void onlyColumnNames() { - String columnNameStr = "col1, col2, col3"; - JSONArray jsonArray = CDL.toJSONArray(columnNameStr); - assertNull("CDL should return null when only 1 row is given", - jsonArray); - } - - /** - * Create a JSONArray from string containing only whitespace and commas - */ - @Test - public void emptyLinesToJSONArray() { - String str = " , , , \n , , , "; - JSONArray jsonArray = CDL.toJSONArray(str); - assertNull("JSONArray should be null for no content", - jsonArray); - } - - /** - * call toString with a null array - */ - @Test - public void emptyJSONArrayToString() { - JSONArray jsonArray = new JSONArray(); - String str = CDL.toString(jsonArray); - assertNull("CDL should return null for toString(null)", - str); - } - - /** - * call toString with a null arrays for names and values - */ - @Test - public void nullJSONArraysToString() { - String str = CDL.toString(null, null); - assertNull("CDL should return null for toString(null)", - str); - } - - /** - * Given a JSONArray that was not built by CDL, some chars may be - * found that would otherwise be filtered out by CDL. - */ - @Test - public void checkSpecialChars() { - JSONArray jsonArray = new JSONArray(); - JSONObject jsonObject = new JSONObject(); - jsonArray.put(jsonObject); - // \r will be filtered from name - jsonObject.put("Col \r1", "V1"); - // \r will be filtered from value - jsonObject.put("Col 2", "V2\r"); - assertEquals("expected length should be 1", 1, jsonArray.length()); - String cdlStr = CDL.toString(jsonArray); - jsonObject = jsonArray.getJSONObject(0); - assertTrue(cdlStr.contains("\"Col 1\"")); - assertTrue(cdlStr.contains("Col 2")); - assertTrue(cdlStr.contains("V1")); - assertTrue(cdlStr.contains("\"V2\"")); - } - - /** - * Create a JSONArray from a string of lines - */ - @Test - public void textToJSONArray() { - JSONArray jsonArray = CDL.toJSONArray(LINES); - JSONArray expectedJsonArray = new JSONArray(EXPECTED_LINES); - Util.compareActualVsExpectedJsonArrays(jsonArray, expectedJsonArray); - } - @Test - public void textToJSONArrayPipeDelimited() { - char delimiter = '|'; - JSONArray jsonArray = CDL.toJSONArray(LINES.replaceAll(",", String.valueOf(delimiter)), delimiter); - JSONArray expectedJsonArray = new JSONArray(EXPECTED_LINES); - Util.compareActualVsExpectedJsonArrays(jsonArray, expectedJsonArray); - } - - /** - * Create a JSONArray from a JSONArray of titles and a - * string of value lines - */ - @Test - public void jsonArrayToJSONArray() { - String nameArrayStr = "[\"Col1\", \"Col2\"]"; - String values = "V1, V2"; - JSONArray nameJSONArray = new JSONArray(nameArrayStr); - JSONArray jsonArray = CDL.toJSONArray(nameJSONArray, values); - JSONArray expectedJsonArray = new JSONArray("[{\"Col1\":\"V1\",\"Col2\":\"V2\"}]"); - Util.compareActualVsExpectedJsonArrays(jsonArray, expectedJsonArray); - } - - /** - * Create a JSONArray from a string of lines, - * then convert to string and then back to JSONArray - */ - @Test - public void textToJSONArrayAndBackToString() { - JSONArray jsonArray = CDL.toJSONArray(LINES); - String jsonStr = CDL.toString(jsonArray); - JSONArray finalJsonArray = CDL.toJSONArray(jsonStr); - JSONArray expectedJsonArray = new JSONArray(EXPECTED_LINES); - Util.compareActualVsExpectedJsonArrays(finalJsonArray, expectedJsonArray); - } - - /** - * Create a JSONArray from a string of lines, - * then convert to string and then back to JSONArray - * with a custom delimiter - */ - @Test - public void textToJSONArrayAndBackToStringCustomDelimiter() { - JSONArray jsonArray = CDL.toJSONArray(LINES, ','); - String jsonStr = CDL.toString(jsonArray, ';'); - JSONArray finalJsonArray = CDL.toJSONArray(jsonStr, ';'); - JSONArray expectedJsonArray = new JSONArray(EXPECTED_LINES); - Util.compareActualVsExpectedJsonArrays(finalJsonArray, expectedJsonArray); - } - - -} \ No newline at end of file diff --git a/src/test/java/org/json/junit/CookieListTest.java b/src/test/java/org/json/junit/CookieListTest.java deleted file mode 100644 index 0af96401b..000000000 --- a/src/test/java/org/json/junit/CookieListTest.java +++ /dev/null @@ -1,190 +0,0 @@ -package org.json.junit; - -/* -Public Domain. -*/ - -import static org.junit.Assert.*; - -import java.util.*; - -import org.json.*; -import org.junit.Test; - -import com.jayway.jsonpath.*; - -/** - * HTTP cookie specification RFC6265: http://tools.ietf.org/html/rfc6265 - *

    - * A cookie list is a JSONObject whose members are presumed to be cookie - * name/value pairs. Entries are unescaped while being added, and escaped in - * the toString() output. - * Unescaping means to convert %hh hex strings to the ascii equivalent - * and converting '+' to ' '. - * Escaping converts '+', '%', '=', ';' and ascii control chars to %hh hex strings. - *

    - * CookieList should not be considered as just a list of Cookie objects:
    - * - CookieList stores a cookie name/value pair as a single entry; Cookie stores - * it as 2 entries (key="name" and key="value").
    - * - CookieList requires multiple name/value pairs as input; Cookie allows the - * 'secure' name with no associated value
    - * - CookieList has no special handling for attribute name/value pairs.
    - */ -public class CookieListTest { - - /** - * Attempts to create a CookieList from a null string. - * Expects a NullPointerException. - */ - @Test(expected=NullPointerException.class) - public void nullCookieListException() { - String cookieStr = null; - CookieList.toJSONObject(cookieStr); - } - - /** - * Attempts to create a CookieList from a malformed string. - * Expects a JSONException. - */ - @Test - public void malFormedCookieListException() { - String cookieStr = "thisCookieHasNoEqualsChar"; - try { - CookieList.toJSONObject(cookieStr); - fail("should throw an exception"); - } catch (JSONException e) { - /** - * Not sure of the missing char, but full string compare fails - */ - assertEquals("Expecting an exception message", - "Expected '=' and instead saw '' at 25 [character 26 line 1]", - e.getMessage()); - } - } - - /** - * Creates a CookieList from an empty string. - */ - @Test - public void emptyStringCookieList() { - String cookieStr = ""; - JSONObject jsonObject = CookieList.toJSONObject(cookieStr); - assertTrue(jsonObject.isEmpty()); - } - - /** - * CookieList with the simplest cookie - a name/value pair with no delimiter. - */ - @Test - public void simpleCookieList() { - String cookieStr = "SID=31d4d96e407aad42"; - JSONObject jsonObject = CookieList.toJSONObject(cookieStr); - // validate JSON content - Object doc = Configuration.defaultConfiguration().jsonProvider().parse(jsonObject.toString()); - assertTrue("Expected 1 top level item", ((Map)(JsonPath.read(doc, "$"))).size() == 1); - assertTrue("expected 31d4d96e407aad42", "31d4d96e407aad42".equals(jsonObject.query("/SID"))); - } - - /** - * CookieList with a single a cookie which has a name/value pair and delimiter. - */ - @Test - public void simpleCookieListWithDelimiter() { - String cookieStr = "SID=31d4d96e407aad42;"; - JSONObject jsonObject = CookieList.toJSONObject(cookieStr); - // validate JSON content - Object doc = Configuration.defaultConfiguration().jsonProvider().parse(jsonObject.toString()); - assertTrue("Expected 1 top level item", ((Map)(JsonPath.read(doc, "$"))).size() == 1); - assertTrue("expected 31d4d96e407aad42", "31d4d96e407aad42".equals(jsonObject.query("/SID"))); - } - - /** - * CookieList with multiple cookies consisting of name/value pairs - * with delimiters. - */ - @Test - public void multiPartCookieList() { - String cookieStr = - "name1=myCookieValue1; "+ - " name2=myCookieValue2;"+ - "name3=myCookieValue3;"+ - " name4=myCookieValue4; "+ - "name5=myCookieValue5;"+ - " name6=myCookieValue6;"; - JSONObject jsonObject = CookieList.toJSONObject(cookieStr); - // validate JSON content - Object doc = Configuration.defaultConfiguration().jsonProvider().parse(jsonObject.toString()); - assertTrue("Expected 6 top level items", ((Map)(JsonPath.read(doc, "$"))).size() == 6); - assertTrue("expected myCookieValue1", "myCookieValue1".equals(jsonObject.query("/name1"))); - assertTrue("expected myCookieValue2", "myCookieValue2".equals(jsonObject.query("/name2"))); - assertTrue("expected myCookieValue3", "myCookieValue3".equals(jsonObject.query("/name3"))); - assertTrue("expected myCookieValue4", "myCookieValue4".equals(jsonObject.query("/name4"))); - assertTrue("expected myCookieValue5", "myCookieValue5".equals(jsonObject.query("/name5"))); - assertTrue("expected myCookieValue6", "myCookieValue6".equals(jsonObject.query("/name6"))); - } - - /** - * CookieList from a JSONObject with valid key and null value - */ - @Test - public void convertCookieListWithNullValueToString() { - JSONObject jsonObject = new JSONObject(); - jsonObject.put("key", JSONObject.NULL); - String cookieToStr = CookieList.toString(jsonObject); - assertTrue("toString() should be empty", "".equals(cookieToStr)); - } - - /** - * CookieList with multiple entries converted to a JSON document. - */ - @Test - public void convertCookieListToString() { - String cookieStr = - "name1=myCookieValue1; "+ - " name2=myCookieValue2;"+ - "name3=myCookieValue3;"+ - " name4=myCookieValue4; "+ - "name5=myCookieValue5;"+ - " name6=myCookieValue6;"; - JSONObject jsonObject = CookieList.toJSONObject(cookieStr); - // exercise CookieList.toString() - String cookieListString = CookieList.toString(jsonObject); - // have to convert it back for validation - jsonObject = CookieList.toJSONObject(cookieListString); - - // validate JSON content - Object doc = Configuration.defaultConfiguration().jsonProvider().parse(jsonObject.toString()); - assertTrue("Expected 6 top level items", ((Map)(JsonPath.read(doc, "$"))).size() == 6); - assertTrue("expected myCookieValue1", "myCookieValue1".equals(jsonObject.query("/name1"))); - assertTrue("expected myCookieValue2", "myCookieValue2".equals(jsonObject.query("/name2"))); - assertTrue("expected myCookieValue3", "myCookieValue3".equals(jsonObject.query("/name3"))); - assertTrue("expected myCookieValue4", "myCookieValue4".equals(jsonObject.query("/name4"))); - assertTrue("expected myCookieValue5", "myCookieValue5".equals(jsonObject.query("/name5"))); - assertTrue("expected myCookieValue6", "myCookieValue6".equals(jsonObject.query("/name6"))); - } - - /** - * CookieList with multiple entries and some '+' chars and URL-encoded - * values converted to a JSON document. - */ - @Test - public void convertEncodedCookieListToString() { - String cookieStr = - "name1=myCookieValue1; "+ - " name2=my+Cookie+Value+2;"+ - "name3=my%2BCookie%26Value%3B3%3D;"+ - " name4=my%25CookieValue4; "+ - "name5=myCookieValue5;"+ - " name6=myCookieValue6;"; - JSONObject jsonObject = CookieList.toJSONObject(cookieStr); - // validate JSON content - Object doc = Configuration.defaultConfiguration().jsonProvider().parse(jsonObject.toString()); - assertTrue("Expected 6 top level items", ((Map)(JsonPath.read(doc, "$"))).size() == 6); - assertTrue("expected myCookieValue1", "myCookieValue1".equals(jsonObject.query("/name1"))); - assertTrue("expected my Cookie Value 2", "my Cookie Value 2".equals(jsonObject.query("/name2"))); - assertTrue("expected my+Cookie&Value;3=", "my+Cookie&Value;3=".equals(jsonObject.query("/name3"))); - assertTrue("expected my%CookieValue4", "my%CookieValue4".equals(jsonObject.query("/name4"))); - assertTrue("expected my%CookieValue5", "myCookieValue5".equals(jsonObject.query("/name5"))); - assertTrue("expected myCookieValue6", "myCookieValue6".equals(jsonObject.query("/name6"))); - } -} diff --git a/src/test/java/org/json/junit/CookieTest.java b/src/test/java/org/json/junit/CookieTest.java deleted file mode 100644 index edd8a7eeb..000000000 --- a/src/test/java/org/json/junit/CookieTest.java +++ /dev/null @@ -1,242 +0,0 @@ -package org.json.junit; - -/* -Public Domain. -*/ - -import static org.junit.Assert.*; - -import org.json.*; -import org.junit.Test; - - -/** - * HTTP cookie specification: RFC6265 - *

    - * At its most basic, a cookie is a name=value pair. The value may be subdivided - * into other cookies, but that is not tested here. The cookie may also include - * certain named attributes, delimited by semicolons. - *

    - * The Cookie.toString() method emits certain attributes if present: expires, - * domain, path, secure. All but secure are name-value pairs. Other attributes - * are not included in the toString() output. - *

    - * A JSON-Java encoded cookie escapes '+', '%', '=', ';' with %hh values. - */ -public class CookieTest { - - /** - * Attempts to create a JSONObject from a null string. - * Expects a NullPointerException. - */ - @Test(expected=NullPointerException.class) - public void nullCookieException() { - String cookieStr = null; - Cookie.toJSONObject(cookieStr); - } - - /** - * Attempts to create a JSONObject from a cookie string with - * no '=' char. - * Expects a JSONException. - */ - @Test - public void malFormedNameValueException() { - String cookieStr = "thisCookieHasNoEqualsChar"; - try { - Cookie.toJSONObject(cookieStr); - fail("Expecting an exception"); - } catch (JSONException e) { - assertEquals("Expecting an exception message", - "Expected '=' and instead saw '' at 25 [character 26 line 1]", - e.getMessage()); - } - } - - /** - * Attempts to create a JSONObject from a cookie string - * with embedded ';' char. - * Expects a JSONException. - */ - @Test - public void booleanAttribute() { - String cookieStr = "this=Cookie;myAttribute"; - JSONObject jo = Cookie.toJSONObject(cookieStr); - assertTrue("has key 'name'", jo.has("name")); - assertTrue("has key 'value'", jo.has("value")); - assertTrue("has key 'myAttribute'", jo.has("myattribute")); - } - - /** - * Attempts to create a JSONObject from an empty cookie string.
    - * Note: Cookie throws an exception, but CookieList does not.
    - * Expects a JSONException - */ - @Test - public void emptyStringCookieException() { - String cookieStr = ""; - try { - Cookie.toJSONObject(cookieStr); - fail("Expecting an exception"); - } catch (JSONException e) { - assertEquals("Expecting an exception message", - "Cookies must have a 'name'", - e.getMessage()); - } - } - /** - * - * Attempts to create a JSONObject from an cookie string where the name is blank.
    - * Note: Cookie throws an exception, but CookieList does not.
    - * Expects a JSONException - */ - @Test - public void emptyNameCookieException() { - String cookieStr = " = value "; - try { - Cookie.toJSONObject(cookieStr); - fail("Expecting an exception"); - } catch (JSONException e) { - assertEquals("Expecting an exception message", - "Cookies must have a 'name'", - e.getMessage()); - } - } - - /** - * Cookie from a simple name/value pair with no delimiter - */ - @Test - public void simpleCookie() { - String cookieStr = "SID=31d4d96e407aad42"; - String expectedCookieStr = "{\"name\":\"SID\",\"value\":\"31d4d96e407aad42\"}"; - JSONObject jsonObject = Cookie.toJSONObject(cookieStr); - JSONObject expectedJsonObject = new JSONObject(expectedCookieStr); - Util.compareActualVsExpectedJsonObjects(jsonObject,expectedJsonObject); - } - - /** - * Store a cookie with all of the supported attributes in a - * JSONObject. The secure attribute, which has no value, is treated - * as a boolean. - */ - @Test - public void multiPartCookie() { - String cookieStr = - "PH=deleted; "+ - " expires=Wed, 19-Mar-2014 17:53:53 GMT;"+ - "path=/; "+ - " domain=.yahoo.com;"+ - "secure"; - String expectedCookieStr = - "{"+ - "\"name\":\"PH\","+ - "\"value\":\"deleted\","+ - "\"path\":\"/\","+ - "\"expires\":\"Wed, 19-Mar-2014 17:53:53 GMT\","+ - "\"domain\":\".yahoo.com\","+ - "\"secure\":true"+ - "}"; - JSONObject jsonObject = Cookie.toJSONObject(cookieStr); - JSONObject expectedJsonObject = new JSONObject(expectedCookieStr); - Util.compareActualVsExpectedJsonObjects(jsonObject,expectedJsonObject); - } - - /** - * Cookie.toString() will emit the non-standard "thiswont=beIncluded" - * attribute, and the attribute is still stored in the JSONObject. - * This test confirms both behaviors. - */ - @Test - public void convertCookieToString() { - String cookieStr = - "PH=deleted; "+ - " expires=Wed, 19-Mar-2014 17:53:53 GMT;"+ - "path=/; "+ - " domain=.yahoo.com;"+ - "thisWont=beIncluded;"+ - "secure"; - String expectedCookieStr = - "{\"thiswont\":\"beIncluded\","+ - "\"path\":\"/\","+ - "\"expires\":\"Wed, 19-Mar-2014 17:53:53 GMT\","+ - "\"domain\":\".yahoo.com\","+ - "\"name\":\"PH\","+ - "\"secure\":true,"+ - "\"value\":\"deleted\"}"; - // Add the nonstandard attribute to the expected cookie string - String expectedDirectCompareCookieStr = expectedCookieStr; - // convert all strings into JSONObjects - JSONObject jsonObject = Cookie.toJSONObject(cookieStr); - JSONObject expectedJsonObject = new JSONObject(expectedCookieStr); - JSONObject expectedDirectCompareJsonObject = - new JSONObject(expectedDirectCompareCookieStr); - // emit the string - String cookieToStr = Cookie.toString(jsonObject); - // create a final JSONObject from the string - JSONObject finalJsonObject = Cookie.toJSONObject(cookieToStr); - // JSONObject should contain the nonstandard string - Util.compareActualVsExpectedJsonObjects(jsonObject,expectedDirectCompareJsonObject); - // JSONObject -> string -> JSONObject should not contain the nonstandard string - Util.compareActualVsExpectedJsonObjects(finalJsonObject,expectedJsonObject); - } - - /** - * A string may be URL-encoded when converting to JSONObject. - * If found, '+' is converted to ' ', and %hh hex strings are converted - * to their ascii char equivalents. This test confirms the decoding - * behavior. - */ - @Test - public void convertEncodedCookieToString() { - String cookieStr = - "PH=deleted; "+ - " expires=Wed,+19-Mar-2014+17:53:53+GMT;"+ - "path=/%2Bthis/is%26/a/spec%3Bsegment%3D; "+ - " domain=.yahoo.com;"+ - "secure"; - String expectedCookieStr = - "{\"path\":\"/+this/is&/a/spec;segment=\","+ - "\"expires\":\"Wed, 19-Mar-2014 17:53:53 GMT\","+ - "\"domain\":\".yahoo.com\","+ - "\"name\":\"PH\","+ - "\"secure\":true,"+ - "\"value\":\"deleted\"}"; - JSONObject jsonObject = Cookie.toJSONObject(cookieStr); - JSONObject expectedJsonObject = new JSONObject(expectedCookieStr); - String cookieToStr = Cookie.toString(jsonObject); - JSONObject finalJsonObject = Cookie.toJSONObject(cookieToStr); - Util.compareActualVsExpectedJsonObjects(jsonObject,expectedJsonObject); - Util.compareActualVsExpectedJsonObjects(finalJsonObject,expectedJsonObject); - } - - /** - * A public API method performs a URL encoding for selected chars - * in a string. Control chars, '+', '%', '=', ';' are all encoded - * as %hh hex strings. The string is also trimmed. - * This test confirms that behavior. - */ - @Test - public void escapeString() { - String str = " +%\r\n\t\b%=;;; "; - String expectedStr = "%2b%25%0d%0a%09%08%25%3d%3b%3b%3b"; - String actualStr = Cookie.escape(str); - assertTrue("expect escape() to encode correctly. Actual: " +actualStr+ - " expected: " +expectedStr, expectedStr.equals(actualStr)); - } - - /** - * A public API method performs URL decoding for strings. - * '+' is converted to space and %hh hex strings are converted to - * their ascii equivalent values. The string is not trimmed. - * This test confirms that behavior. - */ - @Test - public void unescapeString() { - String str = " +%2b%25%0d%0a%09%08%25%3d%3b%3b%3b+ "; - String expectedStr = " +%\r\n\t\b%=;;; "; - String actualStr = Cookie.unescape(str); - assertTrue("expect unescape() to decode correctly. Actual: " +actualStr+ - " expected: " +expectedStr, expectedStr.equals(actualStr)); - } -} diff --git a/src/test/java/org/json/junit/EnumTest.java b/src/test/java/org/json/junit/EnumTest.java index 1496a636a..c608afe23 100644 --- a/src/test/java/org/json/junit/EnumTest.java +++ b/src/test/java/org/json/junit/EnumTest.java @@ -49,8 +49,8 @@ public void jsonObjectFromEnum() { Object doc = Configuration.defaultConfiguration().jsonProvider() .parse(jsonObject.toString()); assertTrue("expecting 2 items in top level object", ((Map)(JsonPath.read(doc, "$"))).size() == 2); - assertTrue("expecting val 2", "val 2".equals(jsonObject.query("/value"))); - assertTrue("expecting 2", Integer.valueOf(2).equals(jsonObject.query("/intVal"))); + assertTrue("expecting val 2", "val 2".equals(jsonObject.get("value"))); + assertTrue("expecting 2", Integer.valueOf(2).equals(jsonObject.get("intVal"))); /** * class which contains enum instances. Each enum should be stored @@ -67,8 +67,8 @@ public void jsonObjectFromEnum() { assertTrue("expected 2 myEnumField items", "VAL3".equals((JsonPath.read(doc, "$.myEnumField")))); assertTrue("expected 0 myEnum items", "VAL1".equals((JsonPath.read(doc, "$.myEnum")))); - assertTrue("expecting MyEnumField.VAL3", MyEnumField.VAL3.equals(jsonObject.query("/myEnumField"))); - assertTrue("expecting MyEnum.VAL1", MyEnum.VAL1.equals(jsonObject.query("/myEnum"))); + assertTrue("expecting MyEnumField.VAL3", MyEnumField.VAL3.equals(jsonObject.get("myEnumField"))); + assertTrue("expecting MyEnum.VAL1", MyEnum.VAL1.equals(jsonObject.get("myEnum"))); } /** @@ -88,9 +88,9 @@ public void jsonObjectFromEnumWithNames() { // validate JSON object Object doc = Configuration.defaultConfiguration().jsonProvider().parse(jsonObject.toString()); assertTrue("expected 3 top level items", ((Map)(JsonPath.read(doc, "$"))).size() == 3); - assertTrue("expected VAL1", MyEnum.VAL1.equals(jsonObject.query("/VAL1"))); - assertTrue("expected VAL2", MyEnum.VAL2.equals(jsonObject.query("/VAL2"))); - assertTrue("expected VAL3", MyEnum.VAL3.equals(jsonObject.query("/VAL3"))); + assertTrue("expected VAL1", MyEnum.VAL1.equals(jsonObject.get("VAL1"))); + assertTrue("expected VAL2", MyEnum.VAL2.equals(jsonObject.get("VAL2"))); + assertTrue("expected VAL3", MyEnum.VAL3.equals(jsonObject.get("VAL3"))); MyEnumField myEnumField = MyEnumField.VAL3; names = JSONObject.getNames(myEnumField); @@ -98,9 +98,9 @@ public void jsonObjectFromEnumWithNames() { jsonObject = new JSONObject(myEnumField, names); doc = Configuration.defaultConfiguration().jsonProvider().parse(jsonObject.toString()); assertTrue("expected 3 top level items", ((Map)(JsonPath.read(doc, "$"))).size() == 3); - assertTrue("expected VAL1", MyEnumField.VAL1.equals(jsonObject.query("/VAL1"))); - assertTrue("expected VAL2", MyEnumField.VAL2.equals(jsonObject.query("/VAL2"))); - assertTrue("expected VAL3", MyEnumField.VAL3.equals(jsonObject.query("/VAL3"))); + assertTrue("expected VAL1", MyEnumField.VAL1.equals(jsonObject.get("VAL1"))); + assertTrue("expected VAL2", MyEnumField.VAL2.equals(jsonObject.get("VAL2"))); + assertTrue("expected VAL3", MyEnumField.VAL3.equals(jsonObject.get("VAL3"))); } /** @@ -158,8 +158,8 @@ public void enumPut() { // validate JSON content Object doc = Configuration.defaultConfiguration().jsonProvider().parse(jsonObject.toString()); assertTrue("expected 2 top level objects", ((Map)(JsonPath.read(doc, "$"))).size() == 2); - assertTrue("expected VAL2", MyEnum.VAL2.equals(jsonObject.query("/myEnum"))); - assertTrue("expected VAL1", MyEnumField.VAL1.equals(jsonObject.query("/myEnumField"))); + assertTrue("expected VAL2", MyEnum.VAL2.equals(jsonObject.get("myEnum"))); + assertTrue("expected VAL1", MyEnumField.VAL1.equals(jsonObject.get("myEnumField"))); JSONArray jsonArray = new JSONArray(); jsonArray.put(myEnum); @@ -168,8 +168,8 @@ public void enumPut() { // validate JSON content doc = Configuration.defaultConfiguration().jsonProvider().parse(jsonArray.toString()); assertTrue("expected 2 top level objects", ((List)(JsonPath.read(doc, "$"))).size() == 2); - assertTrue("expected VAL2", MyEnum.VAL2.equals(jsonArray.query("/0"))); - assertTrue("expected VAL1", MyEnumField.VAL1.equals(jsonArray.query("/1"))); + assertTrue("expected VAL2", MyEnum.VAL2.equals(jsonArray.get(0))); + assertTrue("expected VAL1", MyEnumField.VAL1.equals(jsonArray.get(1))); /** * Leaving these tests because they exercise get, opt, and remove @@ -227,8 +227,8 @@ public void enumToString() { // validate JSON content Object doc = Configuration.defaultConfiguration().jsonProvider().parse(jsonObject.toString()); assertTrue("expected 2 top level items", ((Map)(JsonPath.read(doc, "$"))).size() == 2); - assertTrue("expected val 2", "val 2".equals(jsonObject.query("/value"))); - assertTrue("expected 2", Integer.valueOf(2).equals(jsonObject.query("/intVal"))); + assertTrue("expected val 2", "val 2".equals(jsonObject.get("value"))); + assertTrue("expected 2", Integer.valueOf(2).equals(jsonObject.get("intVal"))); MyEnumClass myEnumClass = new MyEnumClass(); myEnumClass.setMyEnum(MyEnum.VAL1); @@ -247,9 +247,9 @@ public void enumToString() { // validate JSON content doc = Configuration.defaultConfiguration().jsonProvider().parse(jsonObject.toString()); assertTrue("expected 3 top level items", ((Map)(JsonPath.read(doc, "$"))).size() == 3); - assertTrue("expected VAL1", MyEnum.VAL1.equals(jsonObject.query("/VAL1"))); - assertTrue("expected VAL2", MyEnum.VAL2.equals(jsonObject.query("/VAL2"))); - assertTrue("expected VAL3", MyEnum.VAL3.equals(jsonObject.query("/VAL3"))); + assertTrue("expected VAL1", MyEnum.VAL1.equals(jsonObject.get("VAL1"))); + assertTrue("expected VAL2", MyEnum.VAL2.equals(jsonObject.get("VAL2"))); + assertTrue("expected VAL3", MyEnum.VAL3.equals(jsonObject.get("VAL3"))); names = JSONObject.getNames(myEnumField); jsonObject = new JSONObject(myEnumField, names); @@ -257,9 +257,9 @@ public void enumToString() { // validate JSON content doc = Configuration.defaultConfiguration().jsonProvider().parse(jsonObject.toString()); assertTrue("expected 3 top level items", ((Map)(JsonPath.read(doc, "$"))).size() == 3); - assertTrue("expected VAL1", MyEnumField.VAL1.equals(jsonObject.query("/VAL1"))); - assertTrue("expected VAL2", MyEnumField.VAL2.equals(jsonObject.query("/VAL2"))); - assertTrue("expected VAL3", MyEnumField.VAL3.equals(jsonObject.query("/VAL3"))); + assertTrue("expected VAL1", MyEnumField.VAL1.equals(jsonObject.get("VAL1"))); + assertTrue("expected VAL2", MyEnumField.VAL2.equals(jsonObject.get("VAL2"))); + assertTrue("expected VAL3", MyEnumField.VAL3.equals(jsonObject.get("VAL3"))); expectedStr = "{\"myEnum\":\"VAL2\", \"myEnumField\":\"VAL2\"}"; jsonObject = new JSONObject(); @@ -269,8 +269,8 @@ public void enumToString() { // validate JSON content doc = Configuration.defaultConfiguration().jsonProvider().parse(jsonObject.toString()); assertTrue("expected 2 top level items", ((Map)(JsonPath.read(doc, "$"))).size() == 2); - assertTrue("expected VAL2", MyEnum.VAL2.equals(jsonObject.query("/myEnum"))); - assertTrue("expected VAL2", MyEnumField.VAL2.equals(jsonObject.query("/myEnumField"))); + assertTrue("expected VAL2", MyEnum.VAL2.equals(jsonObject.get("myEnum"))); + assertTrue("expected VAL2", MyEnumField.VAL2.equals(jsonObject.get("myEnumField"))); JSONArray jsonArray = new JSONArray(); jsonArray.put(myEnum); @@ -279,8 +279,8 @@ public void enumToString() { // validate JSON content doc = Configuration.defaultConfiguration().jsonProvider().parse(jsonArray.toString()); assertTrue("expected 2 top level items", ((List)(JsonPath.read(doc, "$"))).size() == 2); - assertTrue("expected VAL2", MyEnum.VAL2.equals(jsonArray.query("/0"))); - assertTrue("expected VAL2", MyEnumField.VAL2.equals(jsonArray.query("/1"))); + assertTrue("expected VAL2", MyEnum.VAL2.equals(jsonArray.get(0))); + assertTrue("expected VAL2", MyEnumField.VAL2.equals(jsonArray.get(1))); } /** @@ -297,7 +297,7 @@ public void wrap() { // validate JSON content Object doc = Configuration.defaultConfiguration().jsonProvider().parse(jsonObject.toString()); assertTrue("expected 1 top level items", ((Map)(JsonPath.read(doc, "$"))).size() == 1); - assertTrue("expected VAL2", MyEnumField.VAL2.equals(jsonObject.query("/enum"))); + assertTrue("expected VAL2", MyEnumField.VAL2.equals(jsonObject.get("enum"))); MyEnumClass myEnumClass = new MyEnumClass(); myEnumClass.setMyEnum(MyEnum.VAL1); @@ -310,8 +310,8 @@ public void wrap() { assertTrue("expected VAL3", "VAL3".equals((JsonPath.read(doc, "$.myEnumField")))); assertTrue("expected VAL1", "VAL1".equals((JsonPath.read(doc, "$.myEnum")))); - assertTrue("expecting MyEnumField.VAL3", MyEnumField.VAL3.equals(jsonObject.query("/myEnumField"))); - assertTrue("expecting MyEnum.VAL1", MyEnum.VAL1.equals(jsonObject.query("/myEnum"))); + assertTrue("expecting MyEnumField.VAL3", MyEnumField.VAL3.equals(jsonObject.get("myEnumField"))); + assertTrue("expecting MyEnum.VAL1", MyEnum.VAL1.equals(jsonObject.get("myEnum"))); } /** diff --git a/src/test/java/org/json/junit/HTTPTest.java b/src/test/java/org/json/junit/HTTPTest.java deleted file mode 100644 index 703d5ad2f..000000000 --- a/src/test/java/org/json/junit/HTTPTest.java +++ /dev/null @@ -1,200 +0,0 @@ -package org.json.junit; - -/* -Public Domain. -*/ - -import static org.junit.Assert.*; - -import org.json.*; -import org.junit.Test; - - -/** - * Unit tests for JSON-Java HTTP.java. See RFC7230. - */ -public class HTTPTest { - - /** - * Attempt to call HTTP.toJSONObject() with a null string - * Expects a NUllPointerException. - */ - @Test(expected=NullPointerException.class) - public void nullHTTPException() { - String httpStr = null; - HTTP.toJSONObject(httpStr); - } - - /** - * Attempt to call HTTP.toJSONObject() with a string containing - * an empty object. Expects a JSONException. - */ - @Test - public void notEnoughHTTPException() { - String httpStr = "{}"; - JSONObject jsonObject = new JSONObject(httpStr); - try { - HTTP.toString(jsonObject); - assertTrue("Expected to throw exception", false); - } catch (JSONException e) { - assertTrue("Expecting an exception message", - "Not enough material for an HTTP header.".equals(e.getMessage())); - } - } - - /** - * Calling HTTP.toJSONObject() with an empty string will result in a - * populated JSONObject with keys but no values for Request-URI, Method, - * and HTTP-Version. - */ - @Test - public void emptyStringHTTPRequest() { - String httpStr = ""; - String expectedHTTPStr = "{\"Request-URI\":\"\",\"Method\":\"\",\"HTTP-Version\":\"\"}"; - JSONObject jsonObject = HTTP.toJSONObject(httpStr); - JSONObject expectedJsonObject = new JSONObject(expectedHTTPStr); - Util.compareActualVsExpectedJsonObjects(jsonObject,expectedJsonObject); - } - - /** - * Call HTTP.toJSONObject() with a Request-URI, Method, - * and HTTP-Version. - */ - @Test - public void simpleHTTPRequest() { - String httpStr = "GET /hello.txt HTTP/1.1"; - String expectedHTTPStr = - "{\"Request-URI\":\"/hello.txt\",\"Method\":\"GET\",\"HTTP-Version\":\"HTTP/1.1\"}"; - JSONObject jsonObject = HTTP.toJSONObject(httpStr); - JSONObject expectedJsonObject = new JSONObject(expectedHTTPStr); - Util.compareActualVsExpectedJsonObjects(jsonObject,expectedJsonObject); - } - - /** - * Call HTTP.toJSONObject() with a response string containing a - * HTTP-Version, Status-Code, and Reason. - */ - @Test - public void simpleHTTPResponse() { - String httpStr = "HTTP/1.1 200 OK"; - String expectedHTTPStr = - "{\"HTTP-Version\":\"HTTP/1.1\",\"Status-Code\":\"200\",\"Reason-Phrase\":\"OK\"}"; - JSONObject jsonObject = HTTP.toJSONObject(httpStr); - JSONObject expectedJsonObject = new JSONObject(expectedHTTPStr); - Util.compareActualVsExpectedJsonObjects(jsonObject,expectedJsonObject); - } - - /** - * Call HTTP.toJSONObject() with a full request string including - * request headers. - */ - @Test - public void extendedHTTPRequest() { - String httpStr = - "POST /enlighten/calais.asmx HTTP/1.1\n"+ - "Host: api.opencalais.com\n"+ - "Content-Type: text/xml; charset=utf-8\n"+ - "Content-Length: 100\n"+ - "SOAPAction: \"http://clearforest.com/Enlighten\""; - String expectedHTTPStr = - "{"+ - "\"Request-URI\":\"/enlighten/calais.asmx\","+ - "\"Host\":\"api.opencalais.com\","+ - "\"Method\":\"POST\","+ - "\"HTTP-Version\":\"HTTP/1.1\","+ - "\"Content-Length\":\"100\","+ - "\"Content-Type\":\"text/xml; charset=utf-8\"}"; - JSONObject jsonObject = HTTP.toJSONObject(httpStr); - JSONObject expectedJsonObject = new JSONObject(expectedHTTPStr); - /** - * Not too easy for JSONObject to parse a string with embedded quotes. - * For the sake of the test, add it here. - */ - expectedJsonObject.put("SOAPAction","\"http://clearforest.com/Enlighten\""); - Util.compareActualVsExpectedJsonObjects(jsonObject,expectedJsonObject); - } - - /** - * Call HTTP.toJSONObject() with a full response string including - * response headers. - */ - @Test - public void extendedHTTPResponse() { - String httpStr = - "HTTP/1.1 200 OK\n"+ - "Content-Type: text/xml; charset=utf-8\n"+ - "Content-Length: 100\n"; - String expectedHTTPStr = - "{\"HTTP-Version\":\"HTTP/1.1\","+ - "\"Status-Code\":\"200\","+ - "\"Content-Length\":\"100\","+ - "\"Reason-Phrase\":\"OK\","+ - "\"Content-Type\":\"text/xml; charset=utf-8\"}"; - JSONObject jsonObject = HTTP.toJSONObject(httpStr); - JSONObject expectedJsonObject = new JSONObject(expectedHTTPStr); - Util.compareActualVsExpectedJsonObjects(jsonObject,expectedJsonObject); - } - - /** - * Call HTTP.toJSONObject() with a full POST request string including - * response headers, then convert it back into an HTTP string. - */ - @Test - public void convertHTTPRequestToString() { - String httpStr = - "POST /enlighten/calais.asmx HTTP/1.1\n"+ - "Host: api.opencalais.com\n"+ - "Content-Type: text/xml; charset=utf-8\n"+ - "Content-Length: 100"; - String expectedHTTPStr = - "{"+ - "\"Request-URI\":\"/enlighten/calais.asmx\","+ - "\"Host\":\"api.opencalais.com\","+ - "\"Method\":\"POST\","+ - "\"HTTP-Version\":\"HTTP/1.1\","+ - "\"Content-Length\":\"100\","+ - "\"Content-Type\":\"text/xml; charset=utf-8\"}"; - JSONObject jsonObject = HTTP.toJSONObject(httpStr); - JSONObject expectedJsonObject = new JSONObject(expectedHTTPStr); - String httpToStr = HTTP.toString(jsonObject); - /** - * JSONObject objects to crlfs and any trailing chars. - * For the sake of the test, simplify the resulting string - */ - httpToStr = httpToStr.replaceAll("("+HTTP.CRLF+HTTP.CRLF+")", ""); - httpToStr = httpToStr.replaceAll(HTTP.CRLF, "\n"); - JSONObject finalJsonObject = HTTP.toJSONObject(httpToStr); - Util.compareActualVsExpectedJsonObjects(jsonObject,expectedJsonObject); - Util.compareActualVsExpectedJsonObjects(finalJsonObject,expectedJsonObject); - } - - /** - * Call HTTP.toJSONObject() with a full response string including - * response headers, then convert it back into an HTTP string. - */ - @Test - public void convertHTTPResponseToString() { - String httpStr = - "HTTP/1.1 200 OK\n"+ - "Content-Type: text/xml; charset=utf-8\n"+ - "Content-Length: 100\n"; - String expectedHTTPStr = - "{\"HTTP-Version\":\"HTTP/1.1\","+ - "\"Status-Code\":\"200\","+ - "\"Content-Length\":\"100\","+ - "\"Reason-Phrase\":\"OK\","+ - "\"Content-Type\":\"text/xml; charset=utf-8\"}"; - JSONObject jsonObject = HTTP.toJSONObject(httpStr); - JSONObject expectedJsonObject = new JSONObject(expectedHTTPStr); - String httpToStr = HTTP.toString(jsonObject); - /** - * JSONObject objects to crlfs and any trailing chars. - * For the sake of the test, simplify the resulting string - */ - httpToStr = httpToStr.replaceAll("("+HTTP.CRLF+HTTP.CRLF+")", ""); - httpToStr = httpToStr.replaceAll(HTTP.CRLF, "\n"); - JSONObject finalJsonObject = HTTP.toJSONObject(httpToStr); - Util.compareActualVsExpectedJsonObjects(jsonObject,expectedJsonObject); - Util.compareActualVsExpectedJsonObjects(finalJsonObject,expectedJsonObject); - } -} diff --git a/src/test/java/org/json/junit/HTTPTokenerTest.java b/src/test/java/org/json/junit/HTTPTokenerTest.java deleted file mode 100644 index 28dd40353..000000000 --- a/src/test/java/org/json/junit/HTTPTokenerTest.java +++ /dev/null @@ -1,107 +0,0 @@ -package org.json.junit; - -import org.json.HTTPTokener; -import org.json.JSONException; -import org.junit.Test; - -import static org.junit.Assert.*; -/** - * Tests for JSON-Java HTTPTokener.java - */ -public class HTTPTokenerTest { - - /** - * Test parsing a simple unquoted token. - */ - @Test - public void parseSimpleToken() { - HTTPTokener tokener = new HTTPTokener("Content-Type"); - String token = tokener.nextToken(); - assertEquals("Content-Type", token); - } - - /** - * Test parsing multiple tokens separated by whitespace. - */ - @Test - public void parseMultipleTokens() { - HTTPTokener tokener = new HTTPTokener("Content-Type application/json"); - String token1 = tokener.nextToken(); - String token2 = tokener.nextToken(); - assertEquals("Content-Type", token1); - assertEquals("application/json", token2); - } - - /** - * Test parsing a double-quoted token. - */ - @Test - public void parseDoubleQuotedToken() { - HTTPTokener tokener = new HTTPTokener("\"application/json\""); - String token = tokener.nextToken(); - assertEquals("application/json", token); - } - - /** - * Test parsing a single-quoted token. - */ - @Test - public void parseSingleQuotedToken() { - HTTPTokener tokener = new HTTPTokener("'application/json'"); - String token = tokener.nextToken(); - assertEquals("application/json", token); - } - - /** - * Test parsing a quoted token that includes spaces and semicolons. - */ - @Test - public void parseQuotedTokenWithSpaces() { - HTTPTokener tokener = new HTTPTokener("\"text/html; charset=UTF-8\""); - String token = tokener.nextToken(); - assertEquals("text/html; charset=UTF-8", token); - } - - /** - * Test that unterminated quoted strings throw a JSONException. - */ - @Test - public void throwExceptionOnUnterminatedString() { - HTTPTokener tokener = new HTTPTokener("\"incomplete"); - JSONException exception = assertThrows(JSONException.class, tokener::nextToken); - assertTrue(exception.getMessage().contains("Unterminated string")); - } - - /** - * Test behavior with empty input string. - */ - @Test - public void parseEmptyInput() { - HTTPTokener tokener = new HTTPTokener(""); - String token = tokener.nextToken(); - assertEquals("", token); - } - - /** - * Test behavior with input consisting only of whitespace. - */ - @Test - public void parseWhitespaceOnly() { - HTTPTokener tokener = new HTTPTokener(" \t \n "); - String token = tokener.nextToken(); - assertEquals("", token); - } - - /** - * Test parsing tokens separated by multiple whitespace characters. - */ - @Test - public void parseTokensWithMultipleWhitespace() { - HTTPTokener tokener = new HTTPTokener("GET /index.html"); - String method = tokener.nextToken(); - String path = tokener.nextToken(); - assertEquals("GET", method); - assertEquals("/index.html", path); - } - -} \ No newline at end of file diff --git a/src/test/java/org/json/junit/JSONArrayTest.java b/src/test/java/org/json/junit/JSONArrayTest.java index 429620396..b638be1f3 100644 --- a/src/test/java/org/json/junit/JSONArrayTest.java +++ b/src/test/java/org/json/junit/JSONArrayTest.java @@ -27,10 +27,8 @@ import java.util.Map; import org.json.JSONArray; -import org.json.JSONException; import org.json.JSONObject; import org.json.JSONParserConfiguration; -import org.json.JSONPointerException; import org.json.JSONString; import org.json.JSONTokener; import org.json.ParserConfiguration; @@ -119,14 +117,14 @@ public void nullException() { /** * Attempt to create a JSONArray with an empty string. - * Expects a JSONException. + * Expects an IllegalArgumentException. */ @Test public void emptyStr() { String str = ""; try { assertNull("Should throw an exception", new JSONArray(str)); - } catch (JSONException e) { + } catch (IllegalArgumentException e) { assertEquals("Expected an exception message", "A JSONArray text must start with '[' at 0 [character 1 line 1]", e.getMessage()); @@ -141,7 +139,7 @@ public void emptyStr() { public void unclosedArray() { try { assertNull("Should throw an exception", new JSONArray("[")); - } catch (JSONException e) { + } catch (IllegalArgumentException e) { assertEquals("Expected an exception message", "Expected a ',' or ']' at 1 [character 2 line 1]", e.getMessage()); @@ -156,7 +154,7 @@ public void unclosedArray() { public void unclosedArray2() { try { assertNull("Should throw an exception", new JSONArray("[\"test\"")); - } catch (JSONException e) { + } catch (IllegalArgumentException e) { assertEquals("Expected an exception message", "Expected a ',' or ']' at 7 [character 8 line 1]", e.getMessage()); @@ -171,7 +169,7 @@ public void unclosedArray2() { public void unclosedArray3() { try { assertNull("Should throw an exception", new JSONArray("[\"test\",")); - } catch (JSONException e) { + } catch (IllegalArgumentException e) { assertEquals("Expected an exception message", "Expected a ',' or ']' at 8 [character 9 line 1]", e.getMessage()); @@ -181,14 +179,14 @@ public void unclosedArray3() { /** * Attempt to create a JSONArray with a string as object that is * not a JSON array doc. - * Expects a JSONException. + * Expects an IllegalArgumentException. */ @Test public void badObject() { String str = "abc"; try { assertNull("Should throw an exception", new JSONArray((Object)str)); - } catch (JSONException e) { + } catch (IllegalArgumentException e) { assertTrue("Expected an exception message", "JSONArray initial value should be a string or collection or array.". equals(e.getMessage())); @@ -418,7 +416,7 @@ public void getArrayValues() { /** * Create a JSONArray doc with a variety of different elements. * Confirm that attempting to get the wrong types via the get[type]() - * API methods result in JSONExceptions + * API methods result in IllegalArgumentExceptions */ @Test public void failedGetArrayValues() { @@ -426,56 +424,56 @@ public void failedGetArrayValues() { try { jsonArray.getBoolean(4); assertTrue("expected getBoolean to fail", false); - } catch (JSONException e) { + } catch (IllegalArgumentException e) { assertEquals("Expected an exception message", "JSONArray[4] is not a boolean (class java.lang.String : hello).",e.getMessage()); } try { jsonArray.get(-1); assertTrue("expected get to fail", false); - } catch (JSONException e) { + } catch (IllegalArgumentException e) { assertEquals("Expected an exception message", "JSONArray[-1] not found.",e.getMessage()); } try { jsonArray.getDouble(4); assertTrue("expected getDouble to fail", false); - } catch (JSONException e) { + } catch (IllegalArgumentException e) { assertEquals("Expected an exception message", "JSONArray[4] is not a double (class java.lang.String : hello).",e.getMessage()); } try { jsonArray.getInt(4); assertTrue("expected getInt to fail", false); - } catch (JSONException e) { + } catch (IllegalArgumentException e) { assertEquals("Expected an exception message", "JSONArray[4] is not a int (class java.lang.String : hello).",e.getMessage()); } try { jsonArray.getJSONArray(4); assertTrue("expected getJSONArray to fail", false); - } catch (JSONException e) { + } catch (IllegalArgumentException e) { assertEquals("Expected an exception message", "JSONArray[4] is not a JSONArray (class java.lang.String : hello).",e.getMessage()); } try { jsonArray.getJSONObject(4); assertTrue("expected getJSONObject to fail", false); - } catch (JSONException e) { + } catch (IllegalArgumentException e) { assertEquals("Expected an exception message", "JSONArray[4] is not a JSONObject (class java.lang.String : hello).",e.getMessage()); } try { jsonArray.getLong(4); assertTrue("expected getLong to fail", false); - } catch (JSONException e) { + } catch (IllegalArgumentException e) { assertEquals("Expected an exception message", "JSONArray[4] is not a long (class java.lang.String : hello).",e.getMessage()); } try { jsonArray.getString(5); assertTrue("expected getString to fail", false); - } catch (JSONException e) { + } catch (IllegalArgumentException e) { assertEquals("Expected an exception message", "JSONArray[5] is not a String (class java.math.BigDecimal : 0.002345).",e.getMessage()); } @@ -499,7 +497,7 @@ public void unquotedText() { try { JSONArray jsonArray = new JSONArray(str); assertEquals("Expected to throw exception due to invalid string", true, false); - } catch (JSONException e) { } + } catch (IllegalArgumentException e) { } } else { JSONArray jsonArray = new JSONArray(str); assertEquals(expected, jsonArray.toList()); @@ -522,24 +520,24 @@ public void join() { */ Object doc = Configuration.defaultConfiguration().jsonProvider().parse("["+joinStr+"]"); assertTrue("expected 13 items in top level object", ((List)(JsonPath.read(doc, "$"))).size() == 13); - assertTrue("expected true", Boolean.TRUE.equals(jsonArray.query("/0"))); - assertTrue("expected false", Boolean.FALSE.equals(jsonArray.query("/1"))); - assertTrue("expected \"true\"", "true".equals(jsonArray.query("/2"))); - assertTrue("expected \"false\"", "false".equals(jsonArray.query("/3"))); - assertTrue("expected hello", "hello".equals(jsonArray.query("/4"))); - assertTrue("expected 0.002345", BigDecimal.valueOf(0.002345).equals(jsonArray.query("/5"))); - assertTrue("expected \"23.45\"", "23.45".equals(jsonArray.query("/6"))); - assertTrue("expected 42", Integer.valueOf(42).equals(jsonArray.query("/7"))); - assertTrue("expected \"43\"", "43".equals(jsonArray.query("/8"))); + assertTrue("expected true", Boolean.TRUE.equals(jsonArray.get(0))); + assertTrue("expected false", Boolean.FALSE.equals(jsonArray.get(1))); + assertTrue("expected \"true\"", "true".equals(jsonArray.get(2))); + assertTrue("expected \"false\"", "false".equals(jsonArray.get(3))); + assertTrue("expected hello", "hello".equals(jsonArray.get(4))); + assertTrue("expected 0.002345", BigDecimal.valueOf(0.002345).equals(jsonArray.get(5))); + assertTrue("expected \"23.45\"", "23.45".equals(jsonArray.get(6))); + assertTrue("expected 42", Integer.valueOf(42).equals(jsonArray.get(7))); + assertTrue("expected \"43\"", "43".equals(jsonArray.get(8))); assertTrue("expected 1 item in [9]", ((List)(JsonPath.read(doc, "$[9]"))).size() == 1); - assertTrue("expected world", "world".equals(jsonArray.query("/9/0"))); + assertTrue("expected world", "world".equals(jsonArray.getJSONArray(9).get(0))); assertTrue("expected 4 items in [10]", ((Map)(JsonPath.read(doc, "$[10]"))).size() == 4); - assertTrue("expected value1", "value1".equals(jsonArray.query("/10/key1"))); - assertTrue("expected value2", "value2".equals(jsonArray.query("/10/key2"))); - assertTrue("expected value3", "value3".equals(jsonArray.query("/10/key3"))); - assertTrue("expected value4", "value4".equals(jsonArray.query("/10/key4"))); - assertTrue("expected 0", Integer.valueOf(0).equals(jsonArray.query("/11"))); - assertTrue("expected \"-1\"", "-1".equals(jsonArray.query("/12"))); + assertTrue("expected value1", "value1".equals(jsonArray.getJSONObject(10).get("key1"))); + assertTrue("expected value2", "value2".equals(jsonArray.getJSONObject(10).get("key2"))); + assertTrue("expected value3", "value3".equals(jsonArray.getJSONObject(10).get("key3"))); + assertTrue("expected value4", "value4".equals(jsonArray.getJSONObject(10).get("key4"))); + assertTrue("expected 0", Integer.valueOf(0).equals(jsonArray.get(11))); + assertTrue("expected \"-1\"", "-1".equals(jsonArray.get(12))); Util.checkJSONArrayMaps(jsonArray); } @@ -754,24 +752,24 @@ public void put() { // validate JSON Object doc = Configuration.defaultConfiguration().jsonProvider().parse(jsonArray.toString()); assertTrue("expected 10 top level items", ((List)(JsonPath.read(doc, "$"))).size() == 10); - assertTrue("expected true", Boolean.TRUE.equals(jsonArray.query("/0"))); - assertTrue("expected false", Boolean.FALSE.equals(jsonArray.query("/1"))); + assertTrue("expected true", Boolean.TRUE.equals(jsonArray.get(0))); + assertTrue("expected false", Boolean.FALSE.equals(jsonArray.get(1))); assertTrue("expected 2 items in [2]", ((List)(JsonPath.read(doc, "$[2]"))).size() == 2); - assertTrue("expected hello", "hello".equals(jsonArray.query("/2/0"))); - assertTrue("expected world", "world".equals(jsonArray.query("/2/1"))); - assertTrue("expected 2.5", Double.valueOf(2.5).equals(jsonArray.query("/3"))); - assertTrue("expected 1", Integer.valueOf(1).equals(jsonArray.query("/4"))); - assertTrue("expected 45", Long.valueOf(45).equals(jsonArray.query("/5"))); - assertTrue("expected objectPut", "objectPut".equals(jsonArray.query("/6"))); + assertTrue("expected hello", "hello".equals(jsonArray.getJSONArray(2).get(0))); + assertTrue("expected world", "world".equals(jsonArray.getJSONArray(2).get(1))); + assertTrue("expected 2.5", Double.valueOf(2.5).equals(jsonArray.get(3))); + assertTrue("expected 1", Integer.valueOf(1).equals(jsonArray.get(4))); + assertTrue("expected 45", Long.valueOf(45).equals(jsonArray.get(5))); + assertTrue("expected objectPut", "objectPut".equals(jsonArray.get(6))); assertTrue("expected 3 items in [7]", ((Map)(JsonPath.read(doc, "$[7]"))).size() == 3); - assertTrue("expected val10", "val10".equals(jsonArray.query("/7/key10"))); - assertTrue("expected val20", "val20".equals(jsonArray.query("/7/key20"))); - assertTrue("expected val30", "val30".equals(jsonArray.query("/7/key30"))); + assertTrue("expected val10", "val10".equals(jsonArray.getJSONObject(7).get("key10"))); + assertTrue("expected val20", "val20".equals(jsonArray.getJSONObject(7).get("key20"))); + assertTrue("expected val30", "val30".equals(jsonArray.getJSONObject(7).get("key30"))); assertTrue("expected 1 item in [8]", ((Map)(JsonPath.read(doc, "$[8]"))).size() == 1); - assertTrue("expected v1", "v1".equals(jsonArray.query("/8/k1"))); + assertTrue("expected v1", "v1".equals(jsonArray.getJSONObject(8).get("k1"))); assertTrue("expected 2 items in [9]", ((List)(JsonPath.read(doc, "$[9]"))).size() == 2); - assertTrue("expected 1", Integer.valueOf(1).equals(jsonArray.query("/9/0"))); - assertTrue("expected 2", Integer.valueOf(2).equals(jsonArray.query("/9/1"))); + assertTrue("expected 1", Integer.valueOf(1).equals(jsonArray.getJSONArray(9).get(0))); + assertTrue("expected 2", Integer.valueOf(2).equals(jsonArray.getJSONArray(9).get(1))); Util.checkJSONArrayMaps(jsonArray); Util.checkJSONObjectMaps(jsonObject); } @@ -834,25 +832,25 @@ public void putIndex() { // validate JSON Object doc = Configuration.defaultConfiguration().jsonProvider().parse(jsonArray.toString()); assertTrue("expected 11 top level items", ((List)(JsonPath.read(doc, "$"))).size() == 11); - assertTrue("expected true", Boolean.TRUE.equals(jsonArray.query("/0"))); - assertTrue("expected false", Boolean.FALSE.equals(jsonArray.query("/1"))); + assertTrue("expected true", Boolean.TRUE.equals(jsonArray.get(0))); + assertTrue("expected false", Boolean.FALSE.equals(jsonArray.get(1))); assertTrue("expected 2 items in [2]", ((List)(JsonPath.read(doc, "$[2]"))).size() == 2); - assertTrue("expected hello", "hello".equals(jsonArray.query("/2/0"))); - assertTrue("expected world", "world".equals(jsonArray.query("/2/1"))); - assertTrue("expected 2.5", Double.valueOf(2.5).equals(jsonArray.query("/3"))); - assertTrue("expected 1", Integer.valueOf(1).equals(jsonArray.query("/4"))); - assertTrue("expected 45", Long.valueOf(45).equals(jsonArray.query("/5"))); - assertTrue("expected objectPut", "objectPut".equals(jsonArray.query("/6"))); - assertTrue("expected null", JSONObject.NULL.equals(jsonArray.query("/7"))); + assertTrue("expected hello", "hello".equals(jsonArray.getJSONArray(2).get(0))); + assertTrue("expected world", "world".equals(jsonArray.getJSONArray(2).get(1))); + assertTrue("expected 2.5", Double.valueOf(2.5).equals(jsonArray.get(3))); + assertTrue("expected 1", Integer.valueOf(1).equals(jsonArray.get(4))); + assertTrue("expected 45", Long.valueOf(45).equals(jsonArray.get(5))); + assertTrue("expected objectPut", "objectPut".equals(jsonArray.get(6))); + assertTrue("expected null", JSONObject.NULL.equals(jsonArray.get(7))); assertTrue("expected 3 items in [8]", ((Map)(JsonPath.read(doc, "$[8]"))).size() == 3); - assertTrue("expected val10", "val10".equals(jsonArray.query("/8/key10"))); - assertTrue("expected val20", "val20".equals(jsonArray.query("/8/key20"))); - assertTrue("expected val30", "val30".equals(jsonArray.query("/8/key30"))); + assertTrue("expected val10", "val10".equals(jsonArray.getJSONObject(8).get("key10"))); + assertTrue("expected val20", "val20".equals(jsonArray.getJSONObject(8).get("key20"))); + assertTrue("expected val30", "val30".equals(jsonArray.getJSONObject(8).get("key30"))); assertTrue("expected 2 items in [9]", ((List)(JsonPath.read(doc, "$[9]"))).size() == 2); - assertTrue("expected 1", Integer.valueOf(1).equals(jsonArray.query("/9/0"))); - assertTrue("expected 2", Integer.valueOf(2).equals(jsonArray.query("/9/1"))); + assertTrue("expected 1", Integer.valueOf(1).equals(jsonArray.getJSONArray(9).get(0))); + assertTrue("expected 2", Integer.valueOf(2).equals(jsonArray.getJSONArray(9).get(1))); assertTrue("expected 1 item in [10]", ((Map)(JsonPath.read(doc, "$[10]"))).size() == 1); - assertTrue("expected v1", "v1".equals(jsonArray.query("/10/k1"))); + assertTrue("expected v1", "v1".equals(jsonArray.getJSONObject(10).get("k1"))); Util.checkJSONObjectMaps(jsonObject); Util.checkJSONArrayMaps(jsonArray); } @@ -1029,13 +1027,13 @@ public void objectArrayVsIsArray() { // validate JSON Object doc = Configuration.defaultConfiguration().jsonProvider().parse(jsonArray.toString()); assertTrue("expected 7 top level items", ((List)(JsonPath.read(doc, "$"))).size() == 7); - assertTrue("expected 1", Integer.valueOf(1).equals(jsonArray.query("/0"))); - assertTrue("expected 2", Integer.valueOf(2).equals(jsonArray.query("/1"))); - assertTrue("expected 3", Integer.valueOf(3).equals(jsonArray.query("/2"))); - assertTrue("expected 4", Integer.valueOf(4).equals(jsonArray.query("/3"))); - assertTrue("expected 5", Integer.valueOf(5).equals(jsonArray.query("/4"))); - assertTrue("expected 6", Integer.valueOf(6).equals(jsonArray.query("/5"))); - assertTrue("expected 7", Integer.valueOf(7).equals(jsonArray.query("/6"))); + assertTrue("expected 1", Integer.valueOf(1).equals(jsonArray.get(0))); + assertTrue("expected 2", Integer.valueOf(2).equals(jsonArray.get(1))); + assertTrue("expected 3", Integer.valueOf(3).equals(jsonArray.get(2))); + assertTrue("expected 4", Integer.valueOf(4).equals(jsonArray.get(3))); + assertTrue("expected 5", Integer.valueOf(5).equals(jsonArray.get(4))); + assertTrue("expected 6", Integer.valueOf(6).equals(jsonArray.get(5))); + assertTrue("expected 7", Integer.valueOf(7).equals(jsonArray.get(6))); Util.checkJSONArrayMaps(jsonArray); } @@ -1085,22 +1083,6 @@ public void iteratorTest() { Util.checkJSONObjectMaps(nestedJsonObject); } - @Test(expected = JSONPointerException.class) - public void queryWithNoResult() { - new JSONArray().query("/a/b"); - } - - @Test - public void optQueryWithNoResult() { - assertNull(new JSONArray().optQuery("/a/b")); - } - - @Test(expected = IllegalArgumentException.class) - public void optQueryWithSyntaxError() { - new JSONArray().optQuery("invalid"); - } - - /** * Exercise the JSONArray write() method */ @@ -1316,7 +1298,7 @@ public void testJSONArrayInt() { // assertEquals(0l, new JSONArray(10).length()); try { assertNotNull("Should throw an exception", new JSONArray(-1)); - } catch (JSONException e) { + } catch (IllegalArgumentException e) { assertEquals("Expected an exception message", "JSONArray initial capacity cannot be negative.", e.getMessage()); @@ -1344,7 +1326,7 @@ public void testObjectConstructor() { try { JSONArray a0 = new JSONArray(o); assertNull("Should error", a0); - } catch (JSONException ex) { + } catch (IllegalArgumentException ex) { } // should NOT copy the JSONArray @@ -1353,7 +1335,7 @@ public void testObjectConstructor() { try { JSONArray a1 = new JSONArray(o); assertNull("Should error", a1); - } catch (JSONException ex) { + } catch (IllegalArgumentException ex) { } Util.checkJSONArrayMaps(a); } @@ -1400,7 +1382,7 @@ public void testJSONArrayPutAll() { /** * Tests if calling JSONArray clear() method actually makes the JSONArray empty */ - @Test(expected = JSONException.class) + @Test(expected = IllegalArgumentException.class) public void jsonArrayClearMethodTest() { //Adds random stuff to the JSONArray JSONArray jsonArray = new JSONArray(); @@ -1409,7 +1391,7 @@ public void jsonArrayClearMethodTest() { jsonArray.put(new JSONArray()); jsonArray.clear(); //Clears the JSONArray assertTrue("expected jsonArray.length() == 0", jsonArray.length() == 0); //Check if its length is 0 - jsonArray.getInt(0); //Should throws org.json.JSONException: JSONArray[0] not found + jsonArray.getInt(0); //Should throw IllegalArgumentException: JSONArray[0] not found Util.checkJSONArrayMaps(jsonArray); } @@ -1417,7 +1399,7 @@ public void jsonArrayClearMethodTest() { * Tests for stack overflow. See https://github.com/stleary/JSON-java/issues/654 */ @Ignore("This test relies on system constraints and may not always pass. See: https://github.com/stleary/JSON-java/issues/821") - @Test(expected = JSONException.class) + @Test(expected = IllegalStateException.class) public void issue654StackOverflowInputWellFormed() { //String input = new String(java.util.Base64.getDecoder().decode(base64Bytes)); final InputStream resourceAsStream = JSONArrayTest.class.getClassLoader().getResourceAsStream("Issue654WellFormedArray.json"); @@ -1449,21 +1431,21 @@ public String toJSONString() { assertFalse(ja1.similar(ja3)); } - @Test(expected = JSONException.class) + @Test(expected = IllegalStateException.class) public void testRecursiveDepth() { HashMap map = new HashMap<>(); map.put("t", map); new JSONArray().put(map); } - @Test(expected = JSONException.class) + @Test(expected = IllegalStateException.class) public void testRecursiveDepthAtPosition() { HashMap map = new HashMap<>(); map.put("t", map); new JSONArray().put(0, map); } - @Test(expected = JSONException.class) + @Test(expected = IllegalStateException.class) public void testRecursiveDepthArray() { ArrayList array = new ArrayList<>(); array.add(array); @@ -1482,13 +1464,13 @@ public void testRecursiveDepthAtPosition1000Object() { new JSONArray().put(0, map, new JSONParserConfiguration().withMaxNestingDepth(1000)); } - @Test(expected = JSONException.class) + @Test(expected = IllegalStateException.class) public void testRecursiveDepthAtPosition1001Object() { HashMap map = JSONObjectTest.buildNestedMap(1001); new JSONArray().put(0, map); } - @Test(expected = JSONException.class) + @Test(expected = IllegalStateException.class) public void testRecursiveDepthArrayLimitedMaps() { ArrayList array = new ArrayList<>(); array.add(array); @@ -1522,7 +1504,7 @@ public void testRecursiveDepthArrayFor1000Levels() { } } - @Test(expected = JSONException.class) + @Test(expected = IllegalStateException.class) public void testRecursiveDepthArrayFor1001Levels() { ArrayList array = buildNestedArray(1001); new JSONArray(array); @@ -1533,7 +1515,7 @@ public void testStrictModeJSONTokener_expectException(){ JSONParserConfiguration jsonParserConfiguration = new JSONParserConfiguration().withStrictMode(); JSONTokener tokener = new JSONTokener("[\"value\"]invalidCharacters", jsonParserConfiguration); - assertThrows(JSONException.class, () -> { new JSONArray(tokener); }); + assertThrows(IllegalArgumentException.class, () -> { new JSONArray(tokener); }); } public static ArrayList buildNestedArray(int maxDepth) { diff --git a/src/test/java/org/json/junit/JSONCorePropertyTest.java b/src/test/java/org/json/junit/JSONCorePropertyTest.java new file mode 100644 index 000000000..fd1ee95b1 --- /dev/null +++ b/src/test/java/org/json/junit/JSONCorePropertyTest.java @@ -0,0 +1,191 @@ +package org.json.junit; + +import com.pholser.junit.quickcheck.Property; +import com.pholser.junit.quickcheck.runner.JUnitQuickcheck; +import org.json.JSONArray; +import org.json.JSONObject; +import org.junit.runner.RunWith; + +import java.util.Random; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +/** + * Property-based tests verifying core JSON API preservation after refactoring. + * Uses junit-quickcheck to validate universal properties across random inputs. + */ +@RunWith(JUnitQuickcheck.class) +public class JSONCorePropertyTest { + + /** + * Feature: json-core-refactoring, Property 1: JSONObject put/get round-trip + * + * For any valid key (non-null String) and any valid JSON value (String, Number, + * Boolean, JSONObject, JSONArray, or JSONObject.NULL), putting the value into a + * JSONObject under that key and then retrieving it via get(key) should return + * an equivalent value. + * + * Validates: Requirements 5.1, 5.2 + */ + @Property(trials = 100) + public void jsonObjectPutGetRoundTrip(String key, int valueSeed) { + JSONObject obj = new JSONObject(); + Object value = generateJsonValue(valueSeed); + + obj.put(key, value); + Object retrieved = obj.get(key); + + assertJsonValuesEquivalent(value, retrieved); + } + + /** + * Feature: json-core-refactoring, Property 2: JSONArray add/get round-trip + * + * For any valid JSON value, appending the value to a JSONArray and then + * retrieving it via get(length - 1) should return an equivalent value. + * + * Validates: Requirements 5.3, 5.4 + */ + @Property(trials = 100) + public void jsonArrayAddGetRoundTrip(int valueSeed) { + JSONArray arr = new JSONArray(); + Object value = generateJsonValue(valueSeed); + + arr.put(value); + Object retrieved = arr.get(arr.length() - 1); + + assertJsonValuesEquivalent(value, retrieved); + } + + /** + * Feature: json-core-refactoring, Property 3: JSON serialization round-trip + * + * For any JSONObject or JSONArray, serializing it via toString() and then parsing + * the resulting string back should produce a structure where all keys and values + * are equivalent to the original. + * + * Validates: Requirements 5.5, 5.6 + */ + @Property(trials = 100) + public void jsonSerializationRoundTrip(long seed) { + Random rng = new Random(seed); + boolean useObject = rng.nextBoolean(); + + if (useObject) { + JSONObject original = generateRandomJsonObject(rng, 2); + String serialized = original.toString(); + JSONObject parsed = new JSONObject(serialized); + assertTrue( + "JSONObject round-trip failed for: " + serialized, + original.similar(parsed) + ); + } else { + JSONArray original = generateRandomJsonArray(rng, 2); + String serialized = original.toString(); + JSONArray parsed = new JSONArray(serialized); + assertTrue( + "JSONArray round-trip failed for: " + serialized, + original.similar(parsed) + ); + } + } + + // --- Helper methods --- + + /** + * Generates a valid JSON value based on a seed, cycling through the six + * JSON value types: String, Integer, Double, Boolean, JSONObject, JSONArray, NULL. + */ + static Object generateJsonValue(int seed) { + int type = Math.abs(seed % 7); + switch (type) { + case 0: return "string_" + seed; + case 1: return seed; + case 2: return (double) seed / 3.0; + case 3: return seed % 2 == 0; + case 4: + JSONObject nested = new JSONObject(); + nested.put("inner", seed); + return nested; + case 5: + JSONArray arr = new JSONArray(); + arr.put(seed); + return arr; + case 6: return JSONObject.NULL; + default: return "fallback"; + } + } + + /** + * Generates a simple JSON-compatible value (no nested structures). + */ + static Object generateSimpleValue(Random rng) { + int type = rng.nextInt(5); + switch (type) { + case 0: return "val_" + rng.nextInt(1000); + case 1: return rng.nextInt(10000); + case 2: return rng.nextDouble() * 100; + case 3: return rng.nextBoolean(); + case 4: return JSONObject.NULL; + default: return "default"; + } + } + + /** + * Generates a random JSONObject with the given maximum nesting depth. + */ + static JSONObject generateRandomJsonObject(Random rng, int maxDepth) { + JSONObject obj = new JSONObject(); + int numKeys = 1 + rng.nextInt(4); + for (int i = 0; i < numKeys; i++) { + String key = "k" + i; + if (maxDepth > 0 && rng.nextInt(3) == 0) { + obj.put(key, generateRandomJsonObject(rng, maxDepth - 1)); + } else if (maxDepth > 0 && rng.nextInt(3) == 0) { + obj.put(key, generateRandomJsonArray(rng, maxDepth - 1)); + } else { + obj.put(key, generateSimpleValue(rng)); + } + } + return obj; + } + + /** + * Generates a random JSONArray with the given maximum nesting depth. + */ + static JSONArray generateRandomJsonArray(Random rng, int maxDepth) { + JSONArray arr = new JSONArray(); + int numElements = 1 + rng.nextInt(4); + for (int i = 0; i < numElements; i++) { + if (maxDepth > 0 && rng.nextInt(3) == 0) { + arr.put(generateRandomJsonObject(rng, maxDepth - 1)); + } else if (maxDepth > 0 && rng.nextInt(3) == 0) { + arr.put(generateRandomJsonArray(rng, maxDepth - 1)); + } else { + arr.put(generateSimpleValue(rng)); + } + } + return arr; + } + + /** + * Asserts that two JSON values are equivalent, handling JSONObject and JSONArray + * comparison via the similar() method. + */ + static void assertJsonValuesEquivalent(Object expected, Object actual) { + if (expected instanceof JSONObject) { + assertTrue( + "JSONObject values not similar", + ((JSONObject) expected).similar(actual) + ); + } else if (expected instanceof JSONArray) { + assertTrue( + "JSONArray values not similar", + ((JSONArray) expected).similar(actual) + ); + } else { + assertEquals(expected, actual); + } + } +} diff --git a/src/test/java/org/json/junit/JSONMLTest.java b/src/test/java/org/json/junit/JSONMLTest.java deleted file mode 100644 index 93a6821d8..000000000 --- a/src/test/java/org/json/junit/JSONMLTest.java +++ /dev/null @@ -1,1055 +0,0 @@ -package org.json.junit; - -/* -Public Domain. -*/ - -import static org.junit.Assert.*; - -import org.json.*; -import org.junit.Test; - -/** - * Tests for org.json.JSONML.java - * - * Certain inputs are expected to result in exceptions. These tests are - * executed first. JSONML provides an API to: - * Convert an XML string into a JSONArray or a JSONObject. - * Convert a JSONArray or JSONObject into an XML string. - * Both fromstring and tostring operations operations should be symmetrical - * within the limits of JSONML. - * It should be possible to perform the following operations, which should - * result in the original string being recovered, within the limits of the - * underlying classes: - * Convert a string -> JSONArray -> string -> JSONObject -> string - * Convert a string -> JSONObject -> string -> JSONArray -> string - * - */ -public class JSONMLTest { - - /** - * Attempts to transform a null XML string to JSON. - * Expects a NullPointerException - */ - @Test(expected=NullPointerException.class) - public void nullXMLException() { - String xmlStr = null; - JSONML.toJSONArray(xmlStr); - } - - /** - * Attempts to transform an empty string to JSON. - * Expects a JSONException - */ - @Test - public void emptyXMLException() { - String xmlStr = ""; - try { - JSONML.toJSONArray(xmlStr); - fail("Expecting an exception"); - } catch (JSONException e) { - assertEquals("Expecting an exception message", - "Bad XML at 0 [character 1 line 1]", - e.getMessage()); - } - } - - /** - * Attempts to call JSONML.toString() with a null JSONArray. - * Expects a NullPointerException. - */ - @Test(expected=NullPointerException.class) - public void nullJSONXMLException() { - /** - * Tries to convert a null JSONArray to XML. - */ - JSONArray jsonArray= null; - JSONML.toString(jsonArray); - } - - /** - * Attempts to call JSONML.toString() with a null JSONArray. - * Expects a JSONException. - */ - @Test - public void emptyJSONXMLException() { - /** - * Tries to convert an empty JSONArray to XML. - */ - JSONArray jsonArray = new JSONArray(); - try { - JSONML.toString(jsonArray); - assertTrue("Expecting an exception", false); - } catch (JSONException e) { - assertTrue("Expecting an exception message", - "JSONArray[0] not found.". - equals(e.getMessage())); - } - } - - /** - * Attempts to transform an non-XML string to JSON. - * Expects a JSONException - */ - @Test - public void nonXMLException() { - /** - * Attempts to transform a nonXML string to JSON - */ - String xmlStr = "{ \"this is\": \"not xml\"}"; - try { - JSONML.toJSONArray(xmlStr); - fail("Expecting an exception"); - } catch (JSONException e) { - assertEquals("Expecting an exception message", - "Bad XML at 23 [character 24 line 1]", - e.getMessage()); - } - } - - /** - * Attempts to transform a JSON document with XML content that - * does not follow JSONML conventions (element name is not first value - * in a nested JSONArray) to a JSONArray then back to string. - * Expects a JSONException - */ - @Test - public void emptyTagException() { - /** - * jsonArrayStr is used to build a JSONArray which is then - * turned into XML. For this transformation, all arrays represent - * elements and the first array entry is the name of the element. - * In this case, one of the arrays does not have a name - */ - String jsonArrayStr = - "[\"addresses\","+ - "{\"xsi:noNamespaceSchemaLocation\":\"test.xsd\","+ - "\"xmlns:xsi\":\"http://www.w3.org/2001/XMLSchema-instance\"},"+ - // this array has no name - "["+ - "[\"name\"],"+ - "[\"nocontent\"],"+ - "\">\""+ - "]"+ - "]"; - JSONArray jsonArray = new JSONArray(jsonArrayStr); - try { - JSONML.toString(jsonArray); - assertTrue("Expecting an exception", false); - } catch (JSONException e) { - assertEquals("Expecting an exception message", - "JSONArray[0] is not a String (class org.json.JSONArray).", - e.getMessage()); - } - } - - /** - * Attempts to transform a JSON document with XML content that - * does not follow JSONML conventions (element tag has an embedded space) - * to a JSONArray then back to string. Expects a JSONException - */ - @Test - public void spaceInTagException() { - /** - * jsonArrayStr is used to build a JSONArray which is then - * turned into XML. For this transformation, all arrays represent - * elements and the first array entry is the name of the element. - * In this case, one of the element names has an embedded space, - * which is not allowed. - */ - String jsonArrayStr = - "[\"addresses\","+ - "{\"xsi:noNamespaceSchemaLocation\":\"test.xsd\","+ - "\"xmlns:xsi\":\"http://www.w3.org/2001/XMLSchema-instance\"},"+ - // this array has an invalid name - "[\"addr esses\","+ - "[\"name\"],"+ - "[\"nocontent\"],"+ - "\">\""+ - "]"+ - "]"; - JSONArray jsonArray = new JSONArray(jsonArrayStr); - try { - JSONML.toString(jsonArray); - assertTrue("Expecting an exception", false); - } catch (JSONException e) { - assertTrue("Expecting an exception message", - "'addr esses' contains a space character.". - equals(e.getMessage())); - } - } - - /** - * Attempts to transform a malformed XML document - * (element tag has a frontslash) to a JSONArray.\ - * Expects a JSONException - */ - @Test - public void invalidSlashInTagException() { - /** - * xmlStr contains XML text which is transformed into a JSONArray. - * In this case, the XML is invalid because the 'name' element - * contains an invalid frontslash. - */ - String xmlStr = - "\n"+ - "\n"+ - "
    \n"+ - " \n"+ - " abc street\n"+ - "
    \n"+ - "
    "; - try { - JSONML.toJSONArray(xmlStr); - fail("Expecting an exception"); - } catch (JSONException e) { - assertEquals("Expecting an exception message", - "Misshaped tag at 176 [character 14 line 4]", - e.getMessage()); - } - } - - /** - * Malformed XML text (invalid tagname) is transformed into a JSONArray. - * Expects a JSONException. - */ - @Test - public void invalidBangInTagException() { - String xmlStr = - "\n"+ - "\n"+ - "
    \n"+ - " \n"+ - " \n"+ - "
    \n"+ - "
    "; - try { - JSONML.toJSONArray(xmlStr); - fail("Expecting an exception"); - } catch (JSONException e) { - assertEquals("Expecting an exception message", - "Misshaped meta tag at 215 [character 12 line 7]", - e.getMessage()); - } - } - - /** - * Malformed XML text (invalid tagname, no close bracket) is transformed\ - * into a JSONArray. Expects a JSONException. - */ - @Test - public void invalidBangNoCloseInTagException() { - /** - * xmlStr contains XML text which is transformed into a JSONArray. - * In this case, the XML is invalid because an element - * starts with '!' and has no closing tag - */ - String xmlStr = - "\n"+ - "\n"+ - "
    \n"+ - " \n"+ - " \n"+ - ""; - try { - JSONML.toJSONArray(xmlStr); - fail("Expecting an exception"); - } catch (JSONException e) { - assertEquals("Expecting an exception message", - "Misshaped meta tag at 214 [character 12 line 7]", - e.getMessage()); - } - } - - /** - * Malformed XML text (tagname with no close bracket) is transformed\ - * into a JSONArray. Expects a JSONException. - */ - @Test - public void noCloseStartTagException() { - /** - * xmlStr contains XML text which is transformed into a JSONArray. - * In this case, the XML is invalid because an element - * has no closing '>'. - */ - String xmlStr = - "\n"+ - "\n"+ - "
    \n"+ - " \n"+ - " \n"+ - ""; - try { - JSONML.toJSONArray(xmlStr); - fail("Expecting an exception"); - } catch (JSONException e) { - assertEquals("Expecting an exception message", - "Misplaced '<' at 194 [character 5 line 6]", - e.getMessage()); - } - } - - /** - * Malformed XML text (endtag with no name) is transformed\ - * into a JSONArray. Expects a JSONException. - */ - @Test - public void noCloseEndTagException() { - /** - * xmlStr contains XML text which is transformed into a JSONArray. - * In this case, the XML is invalid because an element - * has no name after the closing tag '\n"+ - "\n"+ - "
    \n"+ - " \n"+ - " \n"+ - " \n"+ - ""; - try { - JSONML.toJSONArray(xmlStr); - assertTrue("Expecting an exception", false); - } catch (JSONException e) { - assertTrue("Expecting an exception message", - "Expected a closing name instead of '>'.". - equals(e.getMessage())); - } - } - - /** - * Malformed XML text (endtag with no close bracket) is transformed\ - * into a JSONArray. Expects a JSONException. - */ - @Test - public void noCloseEndBraceException() { - /** - * xmlStr contains XML text which is transformed into a JSONArray. - * In this case, the XML is invalid because an element - * has '>' after the closing tag '\n"+ - "\n"+ - "
    \n"+ - " \n"+ - " \n"+ - " "; - try { - JSONML.toJSONArray(xmlStr); - fail("Expecting an exception"); - } catch (JSONException e) { - assertEquals("Expecting an exception message", - "Misplaced '<' at 206 [character 1 line 7]", - e.getMessage()); - } - } - - /** - * Malformed XML text (incomplete CDATA string) is transformed\ - * into a JSONArray. Expects a JSONException. - */ - @Test - public void invalidCDATABangInTagException() { - /** - * xmlStr contains XML text which is transformed into a JSONArray. - * In this case, the XML is invalid because an element - * does not have a complete CDATA string. - */ - String xmlStr = - "\n"+ - "\n"+ - "
    \n"+ - " Joe Tester\n"+ - " \n"+ - "
    \n"+ - "
    "; - try { - JSONML.toJSONArray(xmlStr); - fail("Expecting an exception"); - } catch (JSONException e) { - assertEquals("Expecting an exception message", - "Expected 'CDATA[' at 204 [character 11 line 5]", - e.getMessage()); - } - } - - /** - * Convert an XML document into a JSONArray, then use JSONML.toString() - * to convert it into a string. This string is then converted back into - * a JSONArray. Both JSONArrays are compared against a control to - * confirm the contents. - */ - @Test - public void toJSONArray() { - /** - * xmlStr contains XML text which is transformed into a JSONArray. - * Each element becomes a JSONArray: - * 1st entry = elementname - * 2nd entry = attributes object (if present) - * 3rd entry = content (if present) - * 4th entry = child element JSONArrays (if present) - * The result is compared against an expected JSONArray. - * The transformed JSONArray is then transformed back into a string - * which is used to create a final JSONArray, which is also compared - * against the expected JSONArray. - */ - String xmlStr = - "\n"+ - "\n"+ - "
    \n"+ - "myName\n"+ - ">\n"+ - "
    \n"+ - "
    "; - String expectedStr = - "[\"addresses\","+ - "{\"xsi:noNamespaceSchemaLocation\":\"test.xsd\","+ - "\"xmlns:xsi\":\"http://www.w3.org/2001/XMLSchema-instance\"},"+ - "[\"address\","+ - "{\"attr1\":\"attrValue1\",\"attr2\":\"attrValue2\",\"attr3\":\"attrValue3\"},"+ - "[\"name\", {\"nameType\":\"mine\"},\"myName\"],"+ - "[\"nocontent\"],"+ - "\">\""+ - "]"+ - "]"; - JSONArray jsonArray = JSONML.toJSONArray(xmlStr); - JSONArray expectedJsonArray = new JSONArray(expectedStr); - String xmlToStr = JSONML.toString(jsonArray); - JSONArray finalJsonArray = JSONML.toJSONArray(xmlToStr); - Util.compareActualVsExpectedJsonArrays(jsonArray, expectedJsonArray); - Util.compareActualVsExpectedJsonArrays(finalJsonArray, expectedJsonArray); - } - - /** - * Convert an XML document into a JSONObject. Use JSONML.toString() to - * convert it back into a string, and then re-convert it into a JSONObject. - * Both JSONObjects are compared against a control JSONObject to confirm - * the contents. - *

    - * Next convert the XML document into a JSONArray. Use JSONML.toString() to - * convert it back into a string, and then re-convert it into a JSONArray. - * Both JSONArrays are compared against a control JSONArray to confirm - * the contents. - *

    - * This test gives a comprehensive example of how the JSONML - * transformations work. - */ - @Test - public void toJSONObjectToJSONArray() { - /** - * xmlStr contains XML text which is transformed into a JSONObject, - * restored to XML, transformed into a JSONArray, and then restored - * to XML again. Both JSONObject and JSONArray should contain the same - * information and should produce the same XML, allowing for non-ordered - * attributes. - * - * Transformation to JSONObject: - * The elementName is stored as a string where key="tagName" - * Attributes are simply stored as key/value pairs - * If the element has either content or child elements, they are stored - * in a jsonArray with key="childNodes". - * - * Transformation to JSONArray: - * 1st entry = elementname - * 2nd entry = attributes object (if present) - * 3rd entry = content (if present) - * 4th entry = child element JSONArrays (if present) - */ - String xmlStr = - "\n"+ - "\n"+ - "

    \n"+ - "Joe Tester\n"+ - "\n"+ - "\n"+ - "true\n"+ - "false\n"+ - "null\n"+ - "42\n"+ - "-23\n"+ - "-23.45\n"+ - "-23x.45\n"+ - "\n"+ - "1\n"+ - "2\n"+ - "abc\n"+ - "3\n"+ - "4.1\n"+ - "5.2\n"+ - "\n"+ - "
    \n"+ - ""; - - String expectedJSONObjectStr = - "{"+ - "\"xsi:noNamespaceSchemaLocation\":\"test.xsd\","+ - "\"childNodes\":["+ - "{"+ - "\"childNodes\":["+ - "{"+ - "\"childNodes\":[\"Joe Tester\"],"+ - "\"nameType\":\"my name\","+ - "\"tagName\":\"name\""+ - "},"+ - "{"+ - "\"childNodes\":[\"Baker street 5\"],"+ - "\"tagName\":\"street\""+ - "},"+ - "{"+ - "\"tagName\":\"NothingHere\","+ - "\"except\":\"an attribute\""+ - "},"+ - "{"+ - "\"childNodes\":[true],"+ - "\"tagName\":\"TrueValue\""+ - "},"+ - "{"+ - "\"childNodes\":[false],"+ - "\"tagName\":\"FalseValue\""+ - "},"+ - "{"+ - "\"childNodes\":[null],"+ - "\"tagName\":\"NullValue\""+ - "},"+ - "{"+ - "\"childNodes\":[42],"+ - "\"tagName\":\"PositiveValue\""+ - "},"+ - "{"+ - "\"childNodes\":[-23],"+ - "\"tagName\":\"NegativeValue\""+ - "},"+ - "{"+ - "\"childNodes\":[-23.45],"+ - "\"tagName\":\"DoubleValue\""+ - "},"+ - "{"+ - "\"childNodes\":[\"-23x.45\"],"+ - "\"tagName\":\"Nan\""+ - "},"+ - "{"+ - "\"childNodes\":["+ - "{"+ - "\"childNodes\":[1],"+ - "\"tagName\":\"value\""+ - "},"+ - "{"+ - "\"childNodes\":[2],"+ - "\"tagName\":\"value\""+ - "},"+ - "{"+ - "\"childNodes\":["+ - "{"+ - "\"childNodes\":[\"abc\"],"+ - "\"svAttr\":\"svValue\","+ - "\"tagName\":\"subValue\""+ - "}"+ - "],"+ - "\"tagName\":\"value\""+ - "},"+ - "{"+ - "\"childNodes\":[3],"+ - "\"tagName\":\"value\""+ - "},"+ - "{"+ - "\"childNodes\":[4.1],"+ - "\"tagName\":\"value\""+ - "},"+ - "{"+ - "\"childNodes\":[5.2],"+ - "\"tagName\":\"value\""+ - "}"+ - "],"+ - "\"tagName\":\"ArrayOfNum\""+ - "}"+ - "],"+ - "\"addrType\":\"my address\","+ - "\"tagName\":\"address\""+ - "}"+ - "],"+ - "\"xmlns:xsi\":\"http://www.w3.org/2001/XMLSchema-instance\","+ - "\"tagName\":\"addresses\""+ - "}"; - - String expectedJSONArrayStr = - "["+ - "\"addresses\","+ - "{"+ - "\"xsi:noNamespaceSchemaLocation\":\"test.xsd\","+ - "\"xmlns:xsi\":\"http://www.w3.org/2001/XMLSchema-instance\""+ - "},"+ - "["+ - "\"address\","+ - "{"+ - "\"addrType\":\"my address\""+ - "},"+ - "["+ - "\"name\","+ - "{"+ - "\"nameType\":\"my name\""+ - "},"+ - "\"Joe Tester\""+ - "],"+ - "[\"street\",\"Baker street 5\"],"+ - "["+ - "\"NothingHere\","+ - "{\"except\":\"an attribute\"}"+ - "],"+ - "[\"TrueValue\",true],"+ - "[\"FalseValue\",false],"+ - "[\"NullValue\",null],"+ - "[\"PositiveValue\",42],"+ - "[\"NegativeValue\",-23],"+ - "[\"DoubleValue\",-23.45],"+ - "[\"Nan\",\"-23x.45\"],"+ - "["+ - "\"ArrayOfNum\","+ - "[\"value\",1],"+ - "[\"value\",2],"+ - "[\"value\","+ - "["+ - "\"subValue\","+ - "{\"svAttr\":\"svValue\"},"+ - "\"abc\""+ - "]"+ - "],"+ - "[\"value\",3],"+ - "[\"value\",4.1],"+ - "[\"value\",5.2]"+ - "]"+ - "]"+ - "]"; - - // make a JSONObject and make sure it looks as expected - JSONObject jsonObject = JSONML.toJSONObject(xmlStr); - JSONObject expectedJsonObject = new JSONObject(expectedJSONObjectStr); - Util.compareActualVsExpectedJsonObjects(jsonObject,expectedJsonObject); - - // restore the XML, then make another JSONObject and make sure it - // looks as expected - String jsonObjectXmlToStr = JSONML.toString(jsonObject); - JSONObject finalJsonObject = JSONML.toJSONObject(jsonObjectXmlToStr); - Util.compareActualVsExpectedJsonObjects(finalJsonObject, expectedJsonObject); - - // create a JSON array from the original string and make sure it - // looks as expected - JSONArray jsonArray = JSONML.toJSONArray(xmlStr); - JSONArray expectedJsonArray = new JSONArray(expectedJSONArrayStr); - Util.compareActualVsExpectedJsonArrays(jsonArray,expectedJsonArray); - - // restore the XML, then make another JSONArray and make sure it - // looks as expected - String jsonArrayXmlToStr = JSONML.toString(jsonArray); - JSONArray finalJsonArray = JSONML.toJSONArray(jsonArrayXmlToStr); - Util.compareActualVsExpectedJsonArrays(finalJsonArray, expectedJsonArray); - - // lastly, confirm the restored JSONObject XML and JSONArray XML look - // reasonably similar - JSONObject jsonObjectFromObject = JSONML.toJSONObject(jsonObjectXmlToStr); - JSONObject jsonObjectFromArray = JSONML.toJSONObject(jsonArrayXmlToStr); - Util.compareActualVsExpectedJsonObjects(jsonObjectFromObject, jsonObjectFromArray); - } - - /** - * Convert an XML document which contains embedded comments into - * a JSONArray. Use JSONML.toString() to turn it into a string, then - * reconvert it into a JSONArray. Compare both JSONArrays to a control - * JSONArray to confirm the contents. - *

    - * This test shows how XML comments are handled. - */ - @Test - public void commentsInXML() { - - String xmlStr = - "\n"+ - "\n"+ - "\n"+ - "

    \n"+ - "\n"+ - "Joe Tester\n"+ - "\n"+ - "Baker street 5\n"+ - "
    \n"+ - ""; - String expectedStr = - "[\"addresses\","+ - "[\"address\","+ - "[\"name\",\"Joe Tester\"],"+ - "[\"street\",\"Baker street 5\"]"+ - "]"+ - "]"; - JSONArray jsonArray = JSONML.toJSONArray(xmlStr); - JSONArray expectedJsonArray = new JSONArray(expectedStr); - String xmlToStr = JSONML.toString(jsonArray); - JSONArray finalJsonArray = JSONML.toJSONArray(xmlToStr); - Util.compareActualVsExpectedJsonArrays(jsonArray, expectedJsonArray); - Util.compareActualVsExpectedJsonArrays(finalJsonArray, expectedJsonArray); - } - - /** - * JSON string with lost leading zero and converted "True" to true. See test - * result in comment below. - */ - @Test - public void testToJSONArray_jsonOutput() { - final String originalXml = "011000True"; - final String expectedJsonString = "[\"root\",[\"id\",\"01\"],[\"id\",1],[\"id\",\"00\"],[\"id\",0],[\"item\",{\"id\":\"01\"}],[\"title\",true]]"; - final JSONArray actualJsonOutput = JSONML.toJSONArray(originalXml, false); - assertEquals(expectedJsonString, actualJsonOutput.toString()); - } - - /** - * JSON string cannot be reverted to original xml when type guessing is used. - */ - @Test - public void testToJSONArray_reversibility() { - final String originalXml = "011000True"; - final String revertedXml = JSONML.toString(JSONML.toJSONArray(originalXml, false)); - assertNotEquals(revertedXml, originalXml); - } - - /** - * JSON string cannot be reverted to original xml when type guessing is used. - * When we force all the values as string, the original text comes back. - */ - @Test - public void testToJSONArray_reversibility2() { - final String originalXml = "011000True"; - final String expectedJsonString = "[\"root\",[\"id\",\"01\"],[\"id\",\"1\"],[\"id\",\"00\"],[\"id\",\"0\"],[\"item\",{\"id\":\"01\"}],[\"title\",\"True\"]]"; - final JSONArray json = JSONML.toJSONArray(originalXml,true); - assertEquals(expectedJsonString, json.toString()); - - final String reverseXml = JSONML.toString(json); - assertEquals(originalXml, reverseXml); - } - - /** - * JSON can be reverted to original xml. - */ - @Test - public void testToJSONArray_reversibility3() { - final String originalXml = "400402"; - final JSONArray jsonArray = JSONML.toJSONArray(originalXml, false); - final String revertedXml = JSONML.toString(jsonArray); - assertEquals(revertedXml, originalXml); - } - - /** - * JSON string cannot be reverted to original xml. See test result in - * comment below. - */ - @Test - public void testToJSONObject_reversibility() { - final String originalXml = "400402"; - final JSONObject originalObject=JSONML.toJSONObject(originalXml,false); - final String originalJson = originalObject.toString(); - final String xml = JSONML.toString(originalObject); - final JSONObject revertedObject = JSONML.toJSONObject(xml, false); - final String newJson = revertedObject.toString(); - assertTrue("JSON Objects are not similar", originalObject.similar(revertedObject)); - assertTrue("JSON Strings are not similar", new JSONObject(originalJson).similar(new JSONObject(newJson))); - } - -// these tests do not pass for the following reasons: -// 1. Our XML parser does not handle generic HTML entities, only valid XML entities. Hence   -// or other HTML specific entities would fail on reversability -// 2. Our JSON implementation for storing the XML attributes uses the standard unordered map. -// This means that can not be reversed reliably. -// -// /** -// * Test texts taken from jsonml.org. Currently our implementation FAILS this conversion but shouldn't. -// * Technically JsonML should be able to transform any valid xhtml document, but ours only supports -// * standard XML entities, not HTML entities. -// */ -// @Test -// public void testAttributeConversionReversabilityHTML() { -// final String originalXml = "
    #5D28D1Example text here
    #AF44EF127310656
    #AAD034 © 
    "; -// final String expectedJsonString = "[\"table\",{\"class\" : \"MyTable\",\"style\" : \"background-color:yellow\"},[\"tr\",[\"td\",{\"class\" : \"MyTD\",\"style\" : \"border:1px solid black\"},\"#550758\"],[\"td\",{\"class\" : \"MyTD\",\"style\" : \"background-color:red\"},\"Example text here\"]],[\"tr\",[\"td\",{\"class\" : \"MyTD\",\"style\" : \"border:1px solid black\"},\"#993101\"],[\"td\",{\"class\" : \"MyTD\",\"style\" : \"background-color:green\"},\"127624015\"]],[\"tr\",[\"td\",{\"class\" : \"MyTD\",\"style\" : \"border:1px solid black\"},\"#E33D87\"],[\"td\",{\"class\" : \"MyTD\",\"style\" : \"background-color:blue\"},\"\u00A0\",[\"span\",{ \"style\" : \"background-color:maroon\" },\"\u00A9\"],\"\u00A0\"]]]"; -// final JSONArray json = JSONML.toJSONArray(originalXml,true); -// final String actualJsonString = json.toString(); -// -// final String reverseXml = JSONML.toString(json); -// assertNotEquals(originalXml, reverseXml); -// -// assertNotEquals(expectedJsonString, actualJsonString); -// } -// -// /** -// * Test texts taken from jsonml.org but modified to have XML entities only. -// */ -// @Test -// public void testAttributeConversionReversabilityXML() { -// final String originalXml = "
    #5D28D1Example text here
    #AF44EF127310656
    #AAD034&><
    "; -// final String expectedJsonString = "[\"table\",{\"class\" : \"MyTable\",\"style\" : \"background-color:yellow\"},[\"tr\",[\"td\",{\"class\" : \"MyTD\",\"style\" : \"border:1px solid black\"},\"#550758\"],[\"td\",{\"class\" : \"MyTD\",\"style\" : \"background-color:red\"},\"Example text here\"]],[\"tr\",[\"td\",{\"class\" : \"MyTD\",\"style\" : \"border:1px solid black\"},\"#993101\"],[\"td\",{\"class\" : \"MyTD\",\"style\" : \"background-color:green\"},\"127624015\"]],[\"tr\",[\"td\",{\"class\" : \"MyTD\",\"style\" : \"border:1px solid black\"},\"#E33D87\"],[\"td\",{\"class\" : \"MyTD\",\"style\" : \"background-color:blue\"},\"&\",[\"span\",{ \"style\" : \"background-color:maroon\" },\">\"],\"<\"]]]"; -// final JSONArray jsonML = JSONML.toJSONArray(originalXml,true); -// final String actualJsonString = jsonML.toString(); -// -// final String reverseXml = JSONML.toString(jsonML); -// // currently not equal because the hashing of the attribute objects makes the attribute -// // order not happen the same way twice -// assertEquals(originalXml, reverseXml); -// -// assertEquals(expectedJsonString, actualJsonString); -// } - - @Test (timeout = 6000) - public void testIssue484InfinteLoop1() { - try { - JSONML.toJSONObject("??*^M??|?CglR^F??`??>?w??PIlr^E??D^X^]?$?-^R?o??O?*??{OD?^FY??`2a????NM?b^Tq?:O?>S$^K?J?^FB.gUK?m^H??zE??^??!v]?^A???^[^A??^U?c??????h???s???g^Z???`?q^Dbi??:^QZl?)?}1^??k?0??:$V?$?Ovs(}J??^V????2;^QgQ?^_^A?^D?^U?Tg?K?`?h%c?hmGA??w??PIlr??D?$?-?o??O?*??{OD?Y??`2a????NM?bq?:O?>S$ ?J?B.gUK?m\b??zE???!v]???????c??????h???s???g???`?qbi??:Zl?)?}1^??k?0??:$V?$?Ovs(}J??????2;gQ????Tg?K?`?h%c?hmGA?"); - - final int maxNestingDepth = 42; - - try { - JSONML.toJSONArray(wayTooLongMalformedXML, JSONMLParserConfiguration.ORIGINAL.withMaxNestingDepth(maxNestingDepth)); - - fail("Expecting a JSONException"); - } catch (JSONException e) { - assertTrue("Wrong throwable thrown: not expecting message <" + e.getMessage() + ">", - e.getMessage().startsWith("Maximum nesting depth of " + maxNestingDepth)); - } - } - - - @Test - public void testToJSONArrayMaxNestingDepthIsRespectedWithValidXML() { - final String perfectlyFineXML = "\n" + - " \n" + - " sonoo\n" + - " 56000\n" + - " true\n" + - " \n" + - "\n"; - - final int maxNestingDepth = 1; - - try { - JSONML.toJSONArray(perfectlyFineXML, JSONMLParserConfiguration.ORIGINAL.withMaxNestingDepth(maxNestingDepth)); - - fail("Expecting a JSONException"); - } catch (JSONException e) { - assertTrue("Wrong throwable thrown: not expecting message <" + e.getMessage() + ">", - e.getMessage().startsWith("Maximum nesting depth of " + maxNestingDepth)); - } - } - - @Test - public void testToJSONArrayMaxNestingDepthWithValidFittingXML() { - final String perfectlyFineXML = "\n" + - " \n" + - " sonoo\n" + - " 56000\n" + - " true\n" + - " \n" + - "\n"; - - final int maxNestingDepth = 3; - - try { - JSONML.toJSONArray(perfectlyFineXML, JSONMLParserConfiguration.ORIGINAL.withMaxNestingDepth(maxNestingDepth)); - } catch (JSONException e) { - e.printStackTrace(); - fail("XML document should be parsed as its maximum depth fits the maxNestingDepth " + - "parameter of the JSONMLParserConfiguration used"); - } - } - - - @Test - public void testToJSONObjectMaxDefaultNestingDepthIsRespected() { - final String wayTooLongMalformedXML = new String(new char[6000]).replace("\0", ""); - - try { - JSONML.toJSONObject(wayTooLongMalformedXML, JSONMLParserConfiguration.ORIGINAL); - - fail("Expecting a JSONException"); - } catch (JSONException e) { - assertTrue("Wrong throwable thrown: not expecting message <" + e.getMessage() + ">", - e.getMessage().startsWith("Maximum nesting depth of " + JSONMLParserConfiguration.DEFAULT_MAXIMUM_NESTING_DEPTH)); - } - } - - @Test - public void testToJSONObjectUnlimitedNestingDepthIsPossible() { - int actualDepth = JSONMLParserConfiguration.DEFAULT_MAXIMUM_NESTING_DEPTH +10; - final String deeperThanDefaultMax = new String(new char[actualDepth]).replace("\0", "") + - "value" + - new String(new char[actualDepth]).replace("\0", ""); - - try { - JSONML.toJSONObject(deeperThanDefaultMax, JSONMLParserConfiguration.ORIGINAL - .withMaxNestingDepth(JSONMLParserConfiguration.UNDEFINED_MAXIMUM_NESTING_DEPTH)); - } catch (JSONException e) { - e.printStackTrace(); - fail("XML document should be parsed beyond the default maximum depth if maxNestingDepth " + - "parameter is set to -1 in JSONMLParserConfiguration"); - } - } - - - @Test - public void testToJSONObjectMaxNestingDepthOf42IsRespected() { - final String wayTooLongMalformedXML = new String(new char[6000]).replace("\0", ""); - - final int maxNestingDepth = 42; - - try { - JSONML.toJSONObject(wayTooLongMalformedXML, JSONMLParserConfiguration.ORIGINAL.withMaxNestingDepth(maxNestingDepth)); - - fail("Expecting a JSONException"); - } catch (JSONException e) { - assertTrue("Wrong throwable thrown: not expecting message <" + e.getMessage() + ">", - e.getMessage().startsWith("Maximum nesting depth of " + maxNestingDepth)); - } - } - - @Test - public void testToJSONObjectMaxNestingDepthIsRespectedWithValidXML() { - final String perfectlyFineXML = "\n" + - " \n" + - " sonoo\n" + - " 56000\n" + - " true\n" + - " \n" + - "\n"; - - final int maxNestingDepth = 1; - - try { - JSONML.toJSONObject(perfectlyFineXML, JSONMLParserConfiguration.ORIGINAL.withMaxNestingDepth(maxNestingDepth)); - - fail("Expecting a JSONException"); - } catch (JSONException e) { - assertTrue("Wrong throwable thrown: not expecting message <" + e.getMessage() + ">", - e.getMessage().startsWith("Maximum nesting depth of " + maxNestingDepth)); - } - } - - @Test - public void testToJSONObjectMaxNestingDepthWithValidFittingXML() { - final String perfectlyFineXML = "\n" + - " \n" + - " sonoo\n" + - " 56000\n" + - " true\n" + - " \n" + - "\n"; - - final int maxNestingDepth = 3; - - try { - JSONML.toJSONObject(perfectlyFineXML, JSONMLParserConfiguration.ORIGINAL.withMaxNestingDepth(maxNestingDepth)); - } catch (JSONException e) { - e.printStackTrace(); - fail("XML document should be parsed as its maximum depth fits the maxNestingDepth " + - "parameter of the JSONMLParserConfiguration used"); - } - } - - /** - * Tests that malformed XML causing type mismatch throws JSONException. - * Previously threw ClassCastException when parse() returned String instead of JSONArray. - * Related to issue #1034 - */ - @Test(expected = JSONException.class) - public void testMalformedXMLThrowsJSONExceptionNotClassCast() { - // This malformed XML causes parse() to return wrong type - byte[] data = {0x3c, 0x0a, 0x2f, (byte)0xff, (byte)0xff, (byte)0xff, - (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, - (byte)0xff, 0x3e, 0x42}; - String xmlStr = new String(data); - JSONML.toJSONArray(xmlStr); - } - - /** - * Tests that type mismatch in toJSONObject throws JSONException. - * Validates safe type casting in toJSONObject methods. - */ - @Test - public void testToJSONObjectTypeMismatch() { - // Create XML that would cause parse() to return wrong type - String xmlStr = "<\n/\u00ff\u00ff\u00ff\u00ff\u00ff\u00ff\u00ff\u00ff>B"; - try { - JSONML.toJSONObject(xmlStr); - fail("Expected JSONException for type mismatch"); - } catch (ClassCastException e) { - fail("Should throw JSONException, not ClassCastException"); - } catch (JSONException e) { - // Expected - verify it's about type mismatch - assertTrue("Exception message should mention type error", - e.getMessage().contains("Expected") || e.getMessage().contains("got")); - } - } - - /** - * Tests that valid XML still works correctly after the fix. - * Ensures the type checking doesn't break normal operation. - */ - @Test - public void testValidXMLStillWorks() { - String xmlStr = "value"; - try { - JSONArray jsonArray = JSONML.toJSONArray(xmlStr); - assertNotNull("JSONArray should not be null", jsonArray); - assertEquals("root", jsonArray.getString(0)); - } catch (Exception e) { - fail("Valid XML should not throw exception: " + e.getMessage()); - } - } - - /** - * Tests that valid XML to JSONObject still works correctly. - */ - @Test - public void testValidXMLToJSONObjectStillWorks() { - String xmlStr = "content"; - try { - JSONObject jsonObject = JSONML.toJSONObject(xmlStr); - assertNotNull("JSONObject should not be null", jsonObject); - assertEquals("root", jsonObject.getString("tagName")); - } catch (Exception e) { - fail("Valid XML should not throw exception: " + e.getMessage()); - } - } - -} diff --git a/src/test/java/org/json/junit/JSONObjectTest.java b/src/test/java/org/json/junit/JSONObjectTest.java index 5c1d1a2eb..29ae323fd 100644 --- a/src/test/java/org/json/junit/JSONObjectTest.java +++ b/src/test/java/org/json/junit/JSONObjectTest.java @@ -26,24 +26,18 @@ import java.util.concurrent.atomic.AtomicInteger; import java.util.regex.Pattern; -import org.json.CDL; import org.json.JSONArray; -import org.json.JSONException; import org.json.JSONObject; -import org.json.JSONPointerException; import org.json.JSONParserConfiguration; import org.json.JSONString; import org.json.JSONTokener; import org.json.ParserConfiguration; -import org.json.XML; import org.json.junit.data.BrokenToString; import org.json.junit.data.ExceptionalBean; import org.json.junit.data.Fraction; import org.json.junit.data.GenericBean; import org.json.junit.data.GenericBeanInt; import org.json.junit.data.MyBean; -import org.json.junit.data.MyBeanCustomName; -import org.json.junit.data.MyBeanCustomNameSubClass; import org.json.junit.data.MyBigNumberBean; import org.json.junit.data.MyEnum; import org.json.junit.data.MyEnumField; @@ -237,7 +231,7 @@ public void unquotedText() { try { JSONObject jsonObject = new JSONObject(str); assertEquals("Expected to throw exception due to invalid string", true, false); - } catch (JSONException e) { } + } catch (IllegalArgumentException e) { } } else { JSONObject jsonObject = new JSONObject(str); String textStr = jsonObject.toString(); @@ -313,10 +307,10 @@ public void jsonObjectByNames() { JSONObject jsonObjectByName = new JSONObject(jsonObject, keys); Object doc = Configuration.defaultConfiguration().jsonProvider().parse(jsonObjectByName.toString()); assertTrue("expected 4 top level items", ((Map)(JsonPath.read(doc, "$"))).size() == 4); - assertTrue("expected \"falseKey\":false", Boolean.FALSE.equals(jsonObjectByName.query("/falseKey"))); - assertTrue("expected \"nullKey\":null", JSONObject.NULL.equals(jsonObjectByName.query("/nullKey"))); - assertTrue("expected \"stringKey\":\"hello world!\"", "hello world!".equals(jsonObjectByName.query("/stringKey"))); - assertTrue("expected \"doubleKey\":-23.45e67", new BigDecimal("-23.45e67").equals(jsonObjectByName.query("/doubleKey"))); + assertTrue("expected \"falseKey\":false", Boolean.FALSE.equals(jsonObjectByName.get("falseKey"))); + assertTrue("expected \"nullKey\":null", JSONObject.NULL.equals(jsonObjectByName.get("nullKey"))); + assertTrue("expected \"stringKey\":\"hello world!\"", "hello world!".equals(jsonObjectByName.get("stringKey"))); + assertTrue("expected \"doubleKey\":-23.45e67", new BigDecimal("-23.45e67").equals(jsonObjectByName.get("doubleKey"))); Util.checkJSONObjectsMaps(new ArrayList(Arrays.asList(jsonObject, jsonObjectByName))); } @@ -352,11 +346,11 @@ public void jsonObjectByMap() { // validate JSON Object doc = Configuration.defaultConfiguration().jsonProvider().parse(jsonObject.toString()); assertTrue("expected 6 top level items", ((Map)(JsonPath.read(doc, "$"))).size() == 6); - assertTrue("expected \"trueKey\":true", Boolean.TRUE.equals(jsonObject.query("/trueKey"))); - assertTrue("expected \"falseKey\":false", Boolean.FALSE.equals(jsonObject.query("/falseKey"))); - assertTrue("expected \"stringKey\":\"hello world!\"", "hello world!".equals(jsonObject.query("/stringKey"))); - assertTrue("expected \"escapeStringKey\":\"h\be\tllo w\u1234orld!\"", "h\be\tllo w\u1234orld!".equals(jsonObject.query("/escapeStringKey"))); - assertTrue("expected \"doubleKey\":-23.45e67", Double.valueOf("-23.45e67").equals(jsonObject.query("/doubleKey"))); + assertTrue("expected \"trueKey\":true", Boolean.TRUE.equals(jsonObject.get("trueKey"))); + assertTrue("expected \"falseKey\":false", Boolean.FALSE.equals(jsonObject.get("falseKey"))); + assertTrue("expected \"stringKey\":\"hello world!\"", "hello world!".equals(jsonObject.get("stringKey"))); + assertTrue("expected \"escapeStringKey\":\"h\be\tllo w\u1234orld!\"", "h\be\tllo w\u1234orld!".equals(jsonObject.get("escapeStringKey"))); + assertTrue("expected \"doubleKey\":-23.45e67", Double.valueOf("-23.45e67").equals(jsonObject.get("doubleKey"))); Util.checkJSONObjectMaps(jsonObject); } @@ -470,8 +464,8 @@ public void verifyNumberOutput(){ JSONObject jsonObject4 = new JSONObject(Collections.singletonMap("myNumber", new Fraction(4,2))); assertEquals(1, jsonObject4.length()); assertEquals(2, ((JSONObject)(jsonObject4.get("myNumber"))).length()); - assertEquals("Numerator", BigInteger.valueOf(4) , jsonObject4.query("/myNumber/numerator")); - assertEquals("Denominator", BigInteger.valueOf(2) , jsonObject4.query("/myNumber/denominator")); + assertEquals("Numerator", BigInteger.valueOf(4) , jsonObject4.getJSONObject("myNumber").get("numerator")); + assertEquals("Denominator", BigInteger.valueOf(2) , jsonObject4.getJSONObject("myNumber").get("denominator")); /** * JSONObject.put() inserts the Fraction directly into the @@ -587,7 +581,7 @@ public void verifyPutMap() { public void jsonObjectByMapWithUnsupportedValues() { Map jsonMap = new HashMap(); // Just insert some random objects - jsonMap.put("key1", new CDL()); + jsonMap.put("key1", new HashMap()); jsonMap.put("key2", new Exception()); JSONObject jsonObject = new JSONObject(jsonMap); @@ -596,7 +590,7 @@ public void jsonObjectByMapWithUnsupportedValues() { Object doc = Configuration.defaultConfiguration().jsonProvider().parse(jsonObject.toString()); assertTrue("expected 2 top level items", ((Map)(JsonPath.read(doc, "$"))).size() == 2); assertTrue("expected 0 key1 items", ((Map)(JsonPath.read(doc, "$.key1"))).size() == 0); - assertTrue("expected \"key2\":java.lang.Exception","java.lang.Exception".equals(jsonObject.query("/key2"))); + assertTrue("expected \"key2\":java.lang.Exception","java.lang.Exception".equals(jsonObject.get("key2"))); Util.checkJSONObjectMaps(jsonObject); } @@ -619,12 +613,12 @@ public void jsonObjectByMapWithNullValue() { // validate JSON Object doc = Configuration.defaultConfiguration().jsonProvider().parse(jsonObject.toString()); assertTrue("expected 6 top level items", ((Map)(JsonPath.read(doc, "$"))).size() == 6); - assertTrue("expected \"trueKey\":true", Boolean.TRUE.equals(jsonObject.query("/trueKey"))); - assertTrue("expected \"falseKey\":false", Boolean.FALSE.equals(jsonObject.query("/falseKey"))); - assertTrue("expected \"stringKey\":\"hello world!\"", "hello world!".equals(jsonObject.query("/stringKey"))); - assertTrue("expected \"escapeStringKey\":\"h\be\tllo w\u1234orld!\"", "h\be\tllo w\u1234orld!".equals(jsonObject.query("/escapeStringKey"))); - assertTrue("expected \"intKey\":42", Long.valueOf("42").equals(jsonObject.query("/intKey"))); - assertTrue("expected \"doubleKey\":-23.45e67", Double.valueOf("-23.45e67").equals(jsonObject.query("/doubleKey"))); + assertTrue("expected \"trueKey\":true", Boolean.TRUE.equals(jsonObject.get("trueKey"))); + assertTrue("expected \"falseKey\":false", Boolean.FALSE.equals(jsonObject.get("falseKey"))); + assertTrue("expected \"stringKey\":\"hello world!\"", "hello world!".equals(jsonObject.get("stringKey"))); + assertTrue("expected \"escapeStringKey\":\"h\be\tllo w\u1234orld!\"", "h\be\tllo w\u1234orld!".equals(jsonObject.get("escapeStringKey"))); + assertTrue("expected \"intKey\":42", Long.valueOf("42").equals(jsonObject.get("intKey"))); + assertTrue("expected \"doubleKey\":-23.45e67", Double.valueOf("-23.45e67").equals(jsonObject.get("doubleKey"))); Util.checkJSONObjectMaps(jsonObject); } @@ -696,12 +690,12 @@ public void jsonObjectByBean1() { Object doc = Configuration.defaultConfiguration().jsonProvider().parse(jsonObject.toString()); assertTrue("expected 8 top level items", ((Map)(JsonPath.read(doc, "$"))).size() == 8); assertTrue("expected 0 items in stringReaderKey", ((Map) (JsonPath.read(doc, "$.stringReaderKey"))).size() == 0); - assertTrue("expected true", Boolean.TRUE.equals(jsonObject.query("/trueKey"))); - assertTrue("expected false", Boolean.FALSE.equals(jsonObject.query("/falseKey"))); - assertTrue("expected hello world!","hello world!".equals(jsonObject.query("/stringKey"))); - assertTrue("expected h\be\tllo w\u1234orld!", "h\be\tllo w\u1234orld!".equals(jsonObject.query("/escapeStringKey"))); - assertTrue("expected 42", Integer.valueOf("42").equals(jsonObject.query("/intKey"))); - assertTrue("expected -23.45e7", Double.valueOf("-23.45e7").equals(jsonObject.query("/doubleKey"))); + assertTrue("expected true", Boolean.TRUE.equals(jsonObject.get("trueKey"))); + assertTrue("expected false", Boolean.FALSE.equals(jsonObject.get("falseKey"))); + assertTrue("expected hello world!","hello world!".equals(jsonObject.get("stringKey"))); + assertTrue("expected h\be\tllo w\u1234orld!", "h\be\tllo w\u1234orld!".equals(jsonObject.get("escapeStringKey"))); + assertTrue("expected 42", Integer.valueOf("42").equals(jsonObject.get("intKey"))); + assertTrue("expected -23.45e7", Double.valueOf("-23.45e7").equals(jsonObject.get("doubleKey"))); // sorry, mockito artifact assertTrue("expected 2 mockitoInterceptor items", ((Map)(JsonPath.read(doc, "$.mockitoInterceptor"))).size() == 2); assertTrue("expected 0 mockitoInterceptor.serializationSupport items", @@ -709,92 +703,7 @@ public void jsonObjectByBean1() { Util.checkJSONObjectMaps(jsonObject); } - /** - * JSONObject built from a bean that has custom field names. - */ - @Test - public void jsonObjectByBean2() { - JSONObject jsonObject = new JSONObject(new MyBeanCustomName()); - assertNotNull(jsonObject); - assertEquals("Wrong number of keys found:", - 5, - jsonObject.keySet().size()); - assertFalse("Normal field name (someString) processing did not work", - jsonObject.has("someString")); - assertFalse("Normal field name (myDouble) processing did not work", - jsonObject.has("myDouble")); - assertFalse("Normal field name (someFloat) processing did not work", - jsonObject.has("someFloat")); - assertFalse("Ignored field not found!", - jsonObject.has("ignoredInt")); - // getSomeInt() has no user-defined annotation - assertTrue("Normal field name (someInt) should have been found", - jsonObject.has("someInt")); - // the user-defined annotation does not replace any value, so someLong should be found - assertTrue("Normal field name (someLong) should have been found", - jsonObject.has("someLong")); - // myStringField replaces someString property name via user-defined annotation - assertTrue("Overridden String field name (myStringField) should have been found", - jsonObject.has("myStringField")); - // weird name replaces myDouble property name via user-defined annotation - assertTrue("Overridden String field name (Some Weird NAme that Normally Wouldn't be possible!) should have been found", - jsonObject.has("Some Weird NAme that Normally Wouldn't be possible!")); - // InterfaceField replaces someFloat property name via user-defined annotation - assertTrue("Overridden String field name (InterfaceField) should have been found", - jsonObject.has("InterfaceField")); - Util.checkJSONObjectMaps(jsonObject); - } - - /** - * JSONObject built from a bean that has custom field names inherited from a parent class. - */ - @Test - public void jsonObjectByBean3() { - JSONObject jsonObject = new JSONObject(new MyBeanCustomNameSubClass()); - assertNotNull(jsonObject); - assertEquals("Wrong number of keys found:", - 7, - jsonObject.keySet().size()); - assertFalse("Normal int field name (someInt) found, but was overridden", - jsonObject.has("someInt")); - assertFalse("Normal field name (myDouble) processing did not work", - jsonObject.has("myDouble")); - // myDouble was replaced by weird name, and then replaced again by AMoreNormalName via user-defined annotation - assertFalse("Overridden String field name (Some Weird NAme that Normally Wouldn't be possible!) should not be FOUND!", - jsonObject.has("Some Weird NAme that Normally Wouldn't be possible!")); - assertFalse("Normal field name (someFloat) found, but was overridden", - jsonObject.has("someFloat")); - assertFalse("Ignored field found! but was overridden", - jsonObject.has("ignoredInt")); - // shouldNotBeJSON property name was first ignored, then replaced by ShouldBeIgnored via user-defined annotations - assertFalse("Ignored field at the same level as forced name should not have been found", - jsonObject.has("ShouldBeIgnored")); - // able property name was replaced by Getable via user-defined annotation - assertFalse("Normally ignored field (able) with explicit property name should not have been found", - jsonObject.has("able")); - // property name someInt was replaced by newIntFieldName via user-defined annotation - assertTrue("Overridden int field name (newIntFieldName) should have been found", - jsonObject.has("newIntFieldName")); - // property name someLong was not replaced via user-defined annotation - assertTrue("Normal field name (someLong) should have been found", - jsonObject.has("someLong")); - // property name someString was replaced by myStringField via user-defined annotation - assertTrue("Overridden String field name (myStringField) should have been found", - jsonObject.has("myStringField")); - // property name myDouble was replaced by a weird name, followed by AMoreNormalName via user-defined annotations - assertTrue("Overridden double field name (AMoreNormalName) should have been found", - jsonObject.has("AMoreNormalName")); - // property name someFloat was replaced by InterfaceField via user-defined annotation - assertTrue("Overridden String field name (InterfaceField) should have been found", - jsonObject.has("InterfaceField")); - // property name ignoredInt was replaced by none, followed by forcedInt via user-defined annotations - assertTrue("Forced field should have been found!", - jsonObject.has("forcedInt")); - // property name able was replaced by Getable via user-defined annotation - assertTrue("Overridden boolean field name (Getable) should have been found", - jsonObject.has("Getable")); - Util.checkJSONObjectMaps(jsonObject); - } + /** * A bean is also an object. But in order to test the JSONObject @@ -812,8 +721,8 @@ public void jsonObjectByObjectAndNames() { // validate JSON Object doc = Configuration.defaultConfiguration().jsonProvider().parse(jsonObject.toString()); assertTrue("expected 2 top level items", ((Map)(JsonPath.read(doc, "$"))).size() == 2); - assertTrue("expected \"publicString\":\"abc\"", "abc".equals(jsonObject.query("/publicString"))); - assertTrue("expected \"publicInt\":42", Integer.valueOf(42).equals(jsonObject.query("/publicInt"))); + assertTrue("expected \"publicString\":\"abc\"", "abc".equals(jsonObject.get("publicString"))); + assertTrue("expected \"publicInt\":42", Integer.valueOf(42).equals(jsonObject.get("publicInt"))); Util.checkJSONObjectMaps(jsonObject); } @@ -831,11 +740,11 @@ public void jsonObjectByResourceBundle() { Object doc = Configuration.defaultConfiguration().jsonProvider().parse(jsonObject.toString()); assertTrue("expected 2 top level items", ((Map)(JsonPath.read(doc, "$"))).size() == 2); assertTrue("expected 2 greetings items", ((Map)(JsonPath.read(doc, "$.greetings"))).size() == 2); - assertTrue("expected \"hello\":\"Hello, \"", "Hello, ".equals(jsonObject.query("/greetings/hello"))); - assertTrue("expected \"world\":\"World!\"", "World!".equals(jsonObject.query("/greetings/world"))); + assertTrue("expected \"hello\":\"Hello, \"", "Hello, ".equals(jsonObject.getJSONObject("greetings").get("hello"))); + assertTrue("expected \"world\":\"World!\"", "World!".equals(jsonObject.getJSONObject("greetings").get("world"))); assertTrue("expected 2 farewells items", ((Map)(JsonPath.read(doc, "$.farewells"))).size() == 2); - assertTrue("expected \"later\":\"Later, \"", "Later, ".equals(jsonObject.query("/farewells/later"))); - assertTrue("expected \"world\":\"World!\"", "Alligator!".equals(jsonObject.query("/farewells/gator"))); + assertTrue("expected \"later\":\"Later, \"", "Later, ".equals(jsonObject.getJSONObject("farewells").get("later"))); + assertTrue("expected \"world\":\"World!\"", "Alligator!".equals(jsonObject.getJSONObject("farewells").get("gator"))); Util.checkJSONObjectMaps(jsonObject); } @@ -857,18 +766,18 @@ public void jsonObjectAccumulate() { try { jsonObject.accumulate("myArray", Double.NaN); fail("Expected exception"); - } catch (JSONException ignored) {} + } catch (IllegalArgumentException ignored) {} // validate JSON Object doc = Configuration.defaultConfiguration().jsonProvider().parse(jsonObject.toString()); assertTrue("expected 1 top level item", ((Map)(JsonPath.read(doc, "$"))).size() == 1); assertTrue("expected 6 myArray items", ((List)(JsonPath.read(doc, "$.myArray"))).size() == 6); - assertTrue("expected true", Boolean.TRUE.equals(jsonObject.query("/myArray/0"))); - assertTrue("expected false", Boolean.FALSE.equals(jsonObject.query("/myArray/1"))); - assertTrue("expected hello world!", "hello world!".equals(jsonObject.query("/myArray/2"))); - assertTrue("expected h\be\tllo w\u1234orld!", "h\be\tllo w\u1234orld!".equals(jsonObject.query("/myArray/3"))); - assertTrue("expected 42", Integer.valueOf(42).equals(jsonObject.query("/myArray/4"))); - assertTrue("expected -23.45e7", Double.valueOf(-23.45e7).equals(jsonObject.query("/myArray/5"))); + assertTrue("expected true", Boolean.TRUE.equals(jsonObject.getJSONArray("myArray").get(0))); + assertTrue("expected false", Boolean.FALSE.equals(jsonObject.getJSONArray("myArray").get(1))); + assertTrue("expected hello world!", "hello world!".equals(jsonObject.getJSONArray("myArray").get(2))); + assertTrue("expected h\be\tllo w\u1234orld!", "h\be\tllo w\u1234orld!".equals(jsonObject.getJSONArray("myArray").get(3))); + assertTrue("expected 42", Integer.valueOf(42).equals(jsonObject.getJSONArray("myArray").get(4))); + assertTrue("expected -23.45e7", Double.valueOf(-23.45e7).equals(jsonObject.getJSONArray("myArray").get(5))); Util.checkJSONObjectMaps(jsonObject); } @@ -889,18 +798,18 @@ public void jsonObjectAppend() { try { jsonObject.append("myArray", Double.NaN); fail("Expected exception"); - } catch (JSONException ignored) {} + } catch (IllegalArgumentException ignored) {} // validate JSON Object doc = Configuration.defaultConfiguration().jsonProvider().parse(jsonObject.toString()); assertTrue("expected 1 top level item", ((Map)(JsonPath.read(doc, "$"))).size() == 1); assertTrue("expected 6 myArray items", ((List)(JsonPath.read(doc, "$.myArray"))).size() == 6); - assertTrue("expected true", Boolean.TRUE.equals(jsonObject.query("/myArray/0"))); - assertTrue("expected false", Boolean.FALSE.equals(jsonObject.query("/myArray/1"))); - assertTrue("expected hello world!", "hello world!".equals(jsonObject.query("/myArray/2"))); - assertTrue("expected h\be\tllo w\u1234orld!", "h\be\tllo w\u1234orld!".equals(jsonObject.query("/myArray/3"))); - assertTrue("expected 42", Integer.valueOf(42).equals(jsonObject.query("/myArray/4"))); - assertTrue("expected -23.45e7", Double.valueOf(-23.45e7).equals(jsonObject.query("/myArray/5"))); + assertTrue("expected true", Boolean.TRUE.equals(jsonObject.getJSONArray("myArray").get(0))); + assertTrue("expected false", Boolean.FALSE.equals(jsonObject.getJSONArray("myArray").get(1))); + assertTrue("expected hello world!", "hello world!".equals(jsonObject.getJSONArray("myArray").get(2))); + assertTrue("expected h\be\tllo w\u1234orld!", "h\be\tllo w\u1234orld!".equals(jsonObject.getJSONArray("myArray").get(3))); + assertTrue("expected 42", Integer.valueOf(42).equals(jsonObject.getJSONArray("myArray").get(4))); + assertTrue("expected -23.45e7", Double.valueOf(-23.45e7).equals(jsonObject.getJSONArray("myArray").get(5))); Util.checkJSONObjectMaps(jsonObject); } @@ -1151,7 +1060,7 @@ public void jsonInvalidNumberValues() { try { JSONObject jsonObject = new JSONObject(str); assertEquals("Expected to throw exception due to invalid string", true, false); - } catch (JSONException e) { } + } catch (IllegalArgumentException e) { } } else { JSONObject jsonObject = new JSONObject(str); Object obj; @@ -1209,14 +1118,14 @@ public void jsonObjectNonAndWrongValues() { try { jsonObject.getBoolean("nonKey"); fail("Expected an exception"); - } catch (JSONException e) { + } catch (IllegalArgumentException e) { assertEquals("expecting an exception message", "JSONObject[\"nonKey\"] not found.", e.getMessage()); } try { jsonObject.getBoolean("stringKey"); fail("Expected an exception"); - } catch (JSONException e) { + } catch (IllegalArgumentException e) { assertEquals("Expecting an exception message", "JSONObject[\"stringKey\"] is not a Boolean (class java.lang.String : hello world!).", e.getMessage()); @@ -1224,7 +1133,7 @@ public void jsonObjectNonAndWrongValues() { try { jsonObject.getString("nonKey"); fail("Expected an exception"); - } catch (JSONException e) { + } catch (IllegalArgumentException e) { assertEquals("Expecting an exception message", "JSONObject[\"nonKey\"] not found.", e.getMessage()); @@ -1232,7 +1141,7 @@ public void jsonObjectNonAndWrongValues() { try { jsonObject.getString("trueKey"); fail("Expected an exception"); - } catch (JSONException e) { + } catch (IllegalArgumentException e) { assertEquals("Expecting an exception message", "JSONObject[\"trueKey\"] is not a string (class java.lang.Boolean : true).", e.getMessage()); @@ -1240,7 +1149,7 @@ public void jsonObjectNonAndWrongValues() { try { jsonObject.getDouble("nonKey"); fail("Expected an exception"); - } catch (JSONException e) { + } catch (IllegalArgumentException e) { assertEquals("Expecting an exception message", "JSONObject[\"nonKey\"] not found.", e.getMessage()); @@ -1248,7 +1157,7 @@ public void jsonObjectNonAndWrongValues() { try { jsonObject.getDouble("stringKey"); fail("Expected an exception"); - } catch (JSONException e) { + } catch (IllegalArgumentException e) { assertEquals("Expecting an exception message", "JSONObject[\"stringKey\"] is not a double (class java.lang.String : hello world!).", e.getMessage()); @@ -1256,7 +1165,7 @@ public void jsonObjectNonAndWrongValues() { try { jsonObject.getFloat("nonKey"); fail("Expected an exception"); - } catch (JSONException e) { + } catch (IllegalArgumentException e) { assertEquals("Expecting an exception message", "JSONObject[\"nonKey\"] not found.", e.getMessage()); @@ -1264,7 +1173,7 @@ public void jsonObjectNonAndWrongValues() { try { jsonObject.getFloat("stringKey"); fail("Expected an exception"); - } catch (JSONException e) { + } catch (IllegalArgumentException e) { assertEquals("Expecting an exception message", "JSONObject[\"stringKey\"] is not a float (class java.lang.String : hello world!).", e.getMessage()); @@ -1272,7 +1181,7 @@ public void jsonObjectNonAndWrongValues() { try { jsonObject.getInt("nonKey"); fail("Expected an exception"); - } catch (JSONException e) { + } catch (IllegalArgumentException e) { assertEquals("Expecting an exception message", "JSONObject[\"nonKey\"] not found.", e.getMessage()); @@ -1280,7 +1189,7 @@ public void jsonObjectNonAndWrongValues() { try { jsonObject.getInt("stringKey"); fail("Expected an exception"); - } catch (JSONException e) { + } catch (IllegalArgumentException e) { assertEquals("Expecting an exception message", "JSONObject[\"stringKey\"] is not a int (class java.lang.String : hello world!).", e.getMessage()); @@ -1288,7 +1197,7 @@ public void jsonObjectNonAndWrongValues() { try { jsonObject.getLong("nonKey"); fail("Expected an exception"); - } catch (JSONException e) { + } catch (IllegalArgumentException e) { assertEquals("Expecting an exception message", "JSONObject[\"nonKey\"] not found.", e.getMessage()); @@ -1296,7 +1205,7 @@ public void jsonObjectNonAndWrongValues() { try { jsonObject.getLong("stringKey"); fail("Expected an exception"); - } catch (JSONException e) { + } catch (IllegalArgumentException e) { assertEquals("Expecting an exception message", "JSONObject[\"stringKey\"] is not a long (class java.lang.String : hello world!).", e.getMessage()); @@ -1304,7 +1213,7 @@ public void jsonObjectNonAndWrongValues() { try { jsonObject.getJSONArray("nonKey"); fail("Expected an exception"); - } catch (JSONException e) { + } catch (IllegalArgumentException e) { assertEquals("Expecting an exception message", "JSONObject[\"nonKey\"] not found.", e.getMessage()); @@ -1312,7 +1221,7 @@ public void jsonObjectNonAndWrongValues() { try { jsonObject.getJSONArray("stringKey"); fail("Expected an exception"); - } catch (JSONException e) { + } catch (IllegalArgumentException e) { assertEquals("Expecting an exception message", "JSONObject[\"stringKey\"] is not a JSONArray (class java.lang.String : hello world!).", e.getMessage()); @@ -1320,7 +1229,7 @@ public void jsonObjectNonAndWrongValues() { try { jsonObject.getJSONObject("nonKey"); fail("Expected an exception"); - } catch (JSONException e) { + } catch (IllegalArgumentException e) { assertEquals("Expecting an exception message", "JSONObject[\"nonKey\"] not found.", e.getMessage()); @@ -1328,7 +1237,7 @@ public void jsonObjectNonAndWrongValues() { try { jsonObject.getJSONObject("stringKey"); fail("Expected an exception"); - } catch (JSONException e) { + } catch (IllegalArgumentException e) { assertEquals("Expecting an exception message", "JSONObject[\"stringKey\"] is not a JSONObject (class java.lang.String : hello world!).", e.getMessage()); @@ -1434,14 +1343,14 @@ public void bigNumberOperations() { // bigInt key does not exist jsonObject3.getBigDecimal("bigInt"); fail("expected an exeption"); - } catch (JSONException ignored) {} + } catch (IllegalArgumentException ignored) {} obj = jsonObject3.optBigDecimal("bigInt", BigDecimal.ONE); assertTrue("expected BigDecimal", obj.equals(BigDecimal.ONE)); jsonObject3.put("stringKey", "abc"); try { jsonObject3.getBigDecimal("stringKey"); fail("expected an exeption"); - } catch (JSONException ignored) {} + } catch (IllegalArgumentException ignored) {} obj = jsonObject3.optBigInteger("bigDec", BigInteger.ONE); assertTrue("expected BigInteger", obj instanceof BigInteger); assertEquals(bigDecimal.toBigInteger(), obj); @@ -1744,11 +1653,11 @@ public void jsonObjectIncrement() { // validate JSON Object doc = Configuration.defaultConfiguration().jsonProvider().parse(jsonObject.toString()); assertTrue("expected 6 top level items", ((Map)(JsonPath.read(doc, "$"))).size() == 6); - assertTrue("expected 3", Integer.valueOf(3).equals(jsonObject.query("/keyInt"))); - assertTrue("expected 9999999993", Long.valueOf(9999999993L).equals(jsonObject.query("/keyLong"))); - assertTrue("expected 3.1", BigDecimal.valueOf(3.1).equals(jsonObject.query("/keyDouble"))); - assertTrue("expected 123456789123456789123456789123456781", new BigInteger("123456789123456789123456789123456781").equals(jsonObject.query("/keyBigInt"))); - assertTrue("expected 123456789123456789123456789123456781.1", new BigDecimal("123456789123456789123456789123456781.1").equals(jsonObject.query("/keyBigDec"))); + assertTrue("expected 3", Integer.valueOf(3).equals(jsonObject.get("keyInt"))); + assertTrue("expected 9999999993", Long.valueOf(9999999993L).equals(jsonObject.get("keyLong"))); + assertTrue("expected 3.1", BigDecimal.valueOf(3.1).equals(jsonObject.get("keyDouble"))); + assertTrue("expected 123456789123456789123456789123456781", new BigInteger("123456789123456789123456789123456781").equals(jsonObject.get("keyBigInt"))); + assertTrue("expected 123456789123456789123456789123456781.1", new BigDecimal("123456789123456789123456789123456781.1").equals(jsonObject.get("keyBigDec"))); /** * Should work the same way on any platform! @see https://docs.oracle @@ -1773,7 +1682,7 @@ public void jsonObjectIncrement() { * missing bits would not fit into the 32 bit float, i.e. the * information needed simply is not there! */ - assertEquals(Float.valueOf(3.1f), jsonObject.query("/keyFloat")); + assertEquals(Float.valueOf(3.1f), jsonObject.get("keyFloat")); /** * float f = 3.1f; double df = (double) f; double d = 3.1d; @@ -1887,17 +1796,17 @@ public void jsonObjectPut() { // validate JSON Object doc = Configuration.defaultConfiguration().jsonProvider().parse(jsonObject.toString()); assertTrue("expected 4 top level items", ((Map)(JsonPath.read(doc, "$"))).size() == 4); - assertTrue("expected true", Boolean.TRUE.equals(jsonObject.query("/trueKey"))); - assertTrue("expected false", Boolean.FALSE.equals(jsonObject.query("/falseKey"))); + assertTrue("expected true", Boolean.TRUE.equals(jsonObject.get("trueKey"))); + assertTrue("expected false", Boolean.FALSE.equals(jsonObject.get("falseKey"))); assertTrue("expected 3 arrayKey items", ((List)(JsonPath.read(doc, "$.arrayKey"))).size() == 3); - assertTrue("expected 0", Integer.valueOf(0).equals(jsonObject.query("/arrayKey/0"))); - assertTrue("expected 1", Integer.valueOf(1).equals(jsonObject.query("/arrayKey/1"))); - assertTrue("expected 2", Integer.valueOf(2).equals(jsonObject.query("/arrayKey/2"))); + assertTrue("expected 0", Integer.valueOf(0).equals(jsonObject.getJSONArray("arrayKey").get(0))); + assertTrue("expected 1", Integer.valueOf(1).equals(jsonObject.getJSONArray("arrayKey").get(1))); + assertTrue("expected 2", Integer.valueOf(2).equals(jsonObject.getJSONArray("arrayKey").get(2))); assertTrue("expected 4 objectKey items", ((Map)(JsonPath.read(doc, "$.objectKey"))).size() == 4); - assertTrue("expected myVal1", "myVal1".equals(jsonObject.query("/objectKey/myKey1"))); - assertTrue("expected myVal2", "myVal2".equals(jsonObject.query("/objectKey/myKey2"))); - assertTrue("expected myVal3", "myVal3".equals(jsonObject.query("/objectKey/myKey3"))); - assertTrue("expected myVal4", "myVal4".equals(jsonObject.query("/objectKey/myKey4"))); + assertTrue("expected myVal1", "myVal1".equals(jsonObject.getJSONObject("objectKey").get("myKey1"))); + assertTrue("expected myVal2", "myVal2".equals(jsonObject.getJSONObject("objectKey").get("myKey2"))); + assertTrue("expected myVal3", "myVal3".equals(jsonObject.getJSONObject("objectKey").get("myKey3"))); + assertTrue("expected myVal4", "myVal4".equals(jsonObject.getJSONObject("objectKey").get("myKey4"))); jsonObject.remove("trueKey"); JSONObject expectedJsonObject = new JSONObject(expectedStr); @@ -1956,17 +1865,17 @@ public void jsonObjectToString() { // validate JSON Object doc = Configuration.defaultConfiguration().jsonProvider().parse(jsonObject.toString()); assertTrue("expected 4 top level items", ((Map)(JsonPath.read(doc, "$"))).size() == 4); - assertTrue("expected true", Boolean.TRUE.equals(jsonObject.query("/trueKey"))); - assertTrue("expected false", Boolean.FALSE.equals(jsonObject.query("/falseKey"))); + assertTrue("expected true", Boolean.TRUE.equals(jsonObject.get("trueKey"))); + assertTrue("expected false", Boolean.FALSE.equals(jsonObject.get("falseKey"))); assertTrue("expected 3 arrayKey items", ((List)(JsonPath.read(doc, "$.arrayKey"))).size() == 3); - assertTrue("expected 0", Integer.valueOf(0).equals(jsonObject.query("/arrayKey/0"))); - assertTrue("expected 1", Integer.valueOf(1).equals(jsonObject.query("/arrayKey/1"))); - assertTrue("expected 2", Integer.valueOf(2).equals(jsonObject.query("/arrayKey/2"))); + assertTrue("expected 0", Integer.valueOf(0).equals(jsonObject.getJSONArray("arrayKey").get(0))); + assertTrue("expected 1", Integer.valueOf(1).equals(jsonObject.getJSONArray("arrayKey").get(1))); + assertTrue("expected 2", Integer.valueOf(2).equals(jsonObject.getJSONArray("arrayKey").get(2))); assertTrue("expected 4 objectKey items", ((Map)(JsonPath.read(doc, "$.objectKey"))).size() == 4); - assertTrue("expected myVal1", "myVal1".equals(jsonObject.query("/objectKey/myKey1"))); - assertTrue("expected myVal2", "myVal2".equals(jsonObject.query("/objectKey/myKey2"))); - assertTrue("expected myVal3", "myVal3".equals(jsonObject.query("/objectKey/myKey3"))); - assertTrue("expected myVal4", "myVal4".equals(jsonObject.query("/objectKey/myKey4"))); + assertTrue("expected myVal1", "myVal1".equals(jsonObject.getJSONObject("objectKey").get("myKey1"))); + assertTrue("expected myVal2", "myVal2".equals(jsonObject.getJSONObject("objectKey").get("myKey2"))); + assertTrue("expected myVal3", "myVal3".equals(jsonObject.getJSONObject("objectKey").get("myKey3"))); + assertTrue("expected myVal4", "myVal4".equals(jsonObject.getJSONObject("objectKey").get("myKey4"))); Util.checkJSONObjectMaps(jsonObject); } @@ -2064,7 +1973,7 @@ public void jsonObjectToStringSuppressWarningOnCastToMap() { Object doc = Configuration.defaultConfiguration().jsonProvider().parse(jsonObject.toString()); assertTrue("expected 1 top level item", ((Map)(JsonPath.read(doc, "$"))).size() == 1); assertTrue("expected 1 key item", ((Map)(JsonPath.read(doc, "$.key"))).size() == 1); - assertTrue("expected def", "def".equals(jsonObject.query("/key/abc"))); + assertTrue("expected def", "def".equals(jsonObject.getJSONObject("key").get("abc"))); Util.checkJSONObjectMaps(jsonObject); } @@ -2087,7 +1996,7 @@ public void jsonObjectToStringSuppressWarningOnCastToCollection() { Object doc = Configuration.defaultConfiguration().jsonProvider().parse(jsonObject.toString()); assertTrue("expected 1 top level item", ((Map)(JsonPath.read(doc, "$"))).size() == 1); assertTrue("expected 1 key item", ((List)(JsonPath.read(doc, "$.key"))).size() == 1); - assertTrue("expected abc", "abc".equals(jsonObject.query("/key/0"))); + assertTrue("expected abc", "abc".equals(jsonObject.getJSONArray("key").get(0))); Util.checkJSONObjectMaps(jsonObject); } @@ -2210,9 +2119,9 @@ public void wrapObject() { // validate JSON Object doc = Configuration.defaultConfiguration().jsonProvider().parse(jsonArray.toString()); assertTrue("expected 3 top level items", ((List)(JsonPath.read(doc, "$"))).size() == 3); - assertTrue("expected 1", Integer.valueOf(1).equals(jsonArray.query("/0"))); - assertTrue("expected 2", Integer.valueOf(2).equals(jsonArray.query("/1"))); - assertTrue("expected 3", Integer.valueOf(3).equals(jsonArray.query("/2"))); + assertTrue("expected 1", Integer.valueOf(1).equals(jsonArray.get(0))); + assertTrue("expected 2", Integer.valueOf(2).equals(jsonArray.get(1))); + assertTrue("expected 3", Integer.valueOf(3).equals(jsonArray.get(2))); // wrap Array returns JSONArray Integer[] array = { Integer.valueOf(1), Integer.valueOf(2), Integer.valueOf(3) }; @@ -2221,16 +2130,16 @@ public void wrapObject() { // validate JSON doc = Configuration.defaultConfiguration().jsonProvider().parse(jsonArray.toString()); assertTrue("expected 3 top level items", ((List)(JsonPath.read(doc, "$"))).size() == 3); - assertTrue("expected 1", Integer.valueOf(1).equals(jsonArray.query("/0"))); - assertTrue("expected 2", Integer.valueOf(2).equals(jsonArray.query("/1"))); - assertTrue("expected 3", Integer.valueOf(3).equals(jsonArray.query("/2"))); + assertTrue("expected 1", Integer.valueOf(1).equals(jsonArray.get(0))); + assertTrue("expected 2", Integer.valueOf(2).equals(jsonArray.get(1))); + assertTrue("expected 3", Integer.valueOf(3).equals(jsonArray.get(2))); // validate JSON doc = Configuration.defaultConfiguration().jsonProvider().parse(integerArrayJsonArray.toString()); assertTrue("expected 3 top level items", ((List)(JsonPath.read(doc, "$"))).size() == 3); - assertTrue("expected 1", Integer.valueOf(1).equals(jsonArray.query("/0"))); - assertTrue("expected 2", Integer.valueOf(2).equals(jsonArray.query("/1"))); - assertTrue("expected 3", Integer.valueOf(3).equals(jsonArray.query("/2"))); + assertTrue("expected 1", Integer.valueOf(1).equals(jsonArray.get(0))); + assertTrue("expected 2", Integer.valueOf(2).equals(jsonArray.get(1))); + assertTrue("expected 3", Integer.valueOf(3).equals(jsonArray.get(2))); // wrap map returns JSONObject Map map = new HashMap(); @@ -2242,9 +2151,9 @@ public void wrapObject() { // validate JSON doc = Configuration.defaultConfiguration().jsonProvider().parse(mapJsonObject.toString()); assertTrue("expected 3 top level items", ((Map)(JsonPath.read(doc, "$"))).size() == 3); - assertTrue("expected val1", "val1".equals(mapJsonObject.query("/key1"))); - assertTrue("expected val2", "val2".equals(mapJsonObject.query("/key2"))); - assertTrue("expected val3", "val3".equals(mapJsonObject.query("/key3"))); + assertTrue("expected val1", "val1".equals(mapJsonObject.get("key1"))); + assertTrue("expected val2", "val2".equals(mapJsonObject.get("key2"))); + assertTrue("expected val3", "val3".equals(mapJsonObject.get("key3"))); Util.checkJSONObjectsMaps(new ArrayList(Arrays.asList( jsonObject, mapJsonObject ))); @@ -2265,7 +2174,7 @@ public void jsonObjectParseControlCharacters(){ JSONObject jo = new JSONObject(source); assertTrue("Expected "+charString+"("+i+") in the JSON Object but did not find it.",charString.equals(jo.getString("key"))); Util.checkJSONObjectMaps(jo); - } catch (JSONException ex) { + } catch (IllegalArgumentException ex) { assertTrue("Only \\0 (U+0000), \\n (U+000A), and \\r (U+000D) should cause an error. Instead "+charString+"("+i+") caused an error", i=='\0' || i=='\n' || i=='\r' ); @@ -2279,8 +2188,8 @@ public void jsonObjectParseControlCharacterEOFAssertExceptionMessage(){ final String source = "{\"key\":\"" + c + "\"}"; try { JSONObject jo = new JSONObject(source); - fail("JSONException should be thrown"); - } catch (JSONException ex) { + fail("IllegalArgumentException should be thrown"); + } catch (IllegalArgumentException ex) { assertEquals("Unterminated string. " + "Character with int code 0" + " is not allowed within a quoted string. at 8 [character 9 line 1]", ex.getMessage()); } @@ -2293,8 +2202,8 @@ public void jsonObjectParseControlCharacterNewLineAssertExceptionMessage(){ final String source = "{\"key\":\"" + c + "\"}"; try { JSONObject jo = new JSONObject(source); - fail("JSONException should be thrown"); - } catch (JSONException ex) { + fail("IllegalArgumentException should be thrown"); + } catch (IllegalArgumentException ex) { assertEquals("Unterminated string. " + "Character with int code " + (int) c + " is not allowed within a quoted string. at 9 [character 0 line 2]", ex.getMessage()); } @@ -2307,8 +2216,8 @@ public void jsonObjectParseUTF8EncodingAssertExceptionMessage(){ final String source = "{\"key\":\"" + c + "\"}"; try { JSONObject jo = new JSONObject(source); - fail("JSONException should be thrown"); - } catch (JSONException ex) { + fail("IllegalArgumentException should be thrown"); + } catch (IllegalArgumentException ex) { assertEquals("Illegal escape. \\u must be followed by a 4 digit hexadecimal number. " + "\\123x is not valid. at 14 [character 15 line 1]", ex.getMessage()); } @@ -2320,8 +2229,8 @@ public void jsonObjectParseIllegalEscapeAssertExceptionMessage(){ final String source = "{\"key\":\"" + c + "\"}"; try { JSONObject jo = new JSONObject(source); - fail("JSONException should be thrown"); - } catch (JSONException ex) { + fail("IllegalArgumentException should be thrown"); + } catch (IllegalArgumentException ex) { assertEquals("Illegal escape. Escape sequence " + c + " is not valid." + " at 10 [character 11 line 1]", ex.getMessage()); } @@ -2333,7 +2242,7 @@ public void parsingErrorTrailingCurlyBrace () { // does not end with '}' String str = "{"; assertNull("Expected an exception", new JSONObject(str)); - } catch (JSONException e) { + } catch (IllegalArgumentException e) { assertEquals("Expecting an exception message", "A JSONObject text must end with '}' at 1 [character 2 line 1]", e.getMessage()); @@ -2346,7 +2255,7 @@ public void parsingErrorInitialCurlyBrace() { // does not start with '{' String str = "abc"; assertNull("Expected an exception", new JSONObject(str)); - } catch (JSONException e) { + } catch (IllegalArgumentException e) { assertEquals("Expecting an exception message", "A JSONObject text must begin with '{' at 1 [character 2 line 1]", e.getMessage()); @@ -2359,7 +2268,7 @@ public void parsingErrorNoColon() { // key with no ':' String str = "{\"myKey\" = true}"; assertNull("Expected an exception", new JSONObject(str)); - } catch (JSONException e) { + } catch (IllegalArgumentException e) { assertEquals("Expecting an exception message", "Expected a ':' after a key at 10 [character 11 line 1]", e.getMessage()); @@ -2372,7 +2281,7 @@ public void parsingErrorNoCommaSeparator() { // entries with no ',' separator String str = "{\"myKey\":true \"myOtherKey\":false}"; assertNull("Expected an exception", new JSONObject(str)); - } catch (JSONException e) { + } catch (IllegalArgumentException e) { assertEquals("Expecting an exception message", "Expected a ',' or '}' at 15 [character 16 line 1]", e.getMessage()); @@ -2385,7 +2294,7 @@ public void parsingErrorKeyIsNestedMap() { // key is a nested map String str = "{{\"foo\": \"bar\"}: \"baz\"}"; assertNull("Expected an exception", new JSONObject(str)); - } catch (JSONException e) { + } catch (IllegalArgumentException e) { assertEquals("Expecting an exception message", "Missing value at 1 [character 2 line 1]", e.getMessage()); @@ -2398,7 +2307,7 @@ public void parsingErrorKeyIsNestedArrayWithMap() { // key is a nested array containing a map String str = "{\"a\": 1, [{\"foo\": \"bar\"}]: \"baz\"}"; assertNull("Expected an exception", new JSONObject(str)); - } catch (JSONException e) { + } catch (IllegalArgumentException e) { assertEquals("Expecting an exception message", "Missing value at 9 [character 10 line 1]", e.getMessage()); @@ -2411,7 +2320,7 @@ public void parsingErrorKeyContainsCurlyBrace() { // key contains } String str = "{foo}: 2}"; assertNull("Expected an exception", new JSONObject(str)); - } catch (JSONException e) { + } catch (IllegalArgumentException e) { // assertEquals("Expecting an exception message", // "Expected a ':' after a key at 5 [character 6 line 1]", // e.getMessage()); @@ -2424,7 +2333,7 @@ public void parsingErrorKeyContainsSquareBrace() { // key contains ] String str = "{foo]: 2}"; assertNull("Expected an exception", new JSONObject(str)); - } catch (JSONException e) { + } catch (IllegalArgumentException e) { // assertEquals("Expecting an exception message", // "Expected a ':' after a key at 5 [character 6 line 1]", // e.getMessage()); @@ -2437,7 +2346,7 @@ public void parsingErrorKeyContainsBinaryZero() { // \0 after , String str = "{\"myKey\":true, \0\"myOtherKey\":false}"; assertNull("Expected an exception", new JSONObject(str)); - } catch (JSONException e) { + } catch (IllegalArgumentException e) { assertEquals("Expecting an exception message", "A JSONObject text must end with '}' at 15 [character 16 line 1]", e.getMessage()); @@ -2452,7 +2361,7 @@ public void parsingErrorAppendToWrongValue() { JSONObject jsonObject = new JSONObject(str); jsonObject.append("myKey", "hello"); fail("Expected an exception"); - } catch (JSONException e) { + } catch (IllegalArgumentException e) { assertEquals("Expecting an exception message", "JSONObject[\"myKey\"] is not a JSONArray (null).", e.getMessage()); @@ -2467,7 +2376,7 @@ public void parsingErrorIncrementWrongValue() { JSONObject jsonObject = new JSONObject(str); jsonObject.increment("myKey"); fail("Expected an exception"); - } catch (JSONException e) { + } catch (IllegalStateException e) { assertEquals("Expecting an exception message", "Unable to increment [\"myKey\"].", e.getMessage()); @@ -2481,7 +2390,7 @@ public void parsingErrorInvalidKey() { JSONObject jsonObject = new JSONObject(str); jsonObject.get(null); fail("Expected an exception"); - } catch (JSONException e) { + } catch (IllegalArgumentException e) { assertEquals("Expecting an exception message", "Null key.", e.getMessage()); @@ -2494,7 +2403,7 @@ public void parsingErrorNumberToString() { // invalid numberToString() JSONObject.numberToString((Number) null); fail("Expected an exception"); - } catch (JSONException e) { + } catch (IllegalArgumentException e) { assertEquals("Expecting an exception message", "Null pointer", e.getMessage()); @@ -2509,7 +2418,7 @@ public void parsingErrorPutOnceDuplicateKey() { jsonObject.putOnce("hello", "world"); jsonObject.putOnce("hello", "world!"); fail("Expected an exception"); - } catch (JSONException e) { + } catch (IllegalArgumentException e) { assertTrue("", true); } } @@ -2520,7 +2429,7 @@ public void parsingErrorInvalidDouble() { // test validity of invalid double JSONObject.testValidity(Double.NaN); fail("Expected an exception"); - } catch (JSONException e) { + } catch (IllegalArgumentException e) { assertTrue("", true); } } @@ -2531,7 +2440,7 @@ public void parsingErrorInvalidFloat() { // test validity of invalid float JSONObject.testValidity(Float.NEGATIVE_INFINITY); fail("Expected an exception"); - } catch (JSONException e) { + } catch (IllegalArgumentException e) { assertTrue("", true); } } @@ -2548,7 +2457,7 @@ public void parsingErrorDuplicateKeyException() { + "}"; new JSONObject(str); fail("Expected an exception"); - } catch (JSONException e) { + } catch (IllegalArgumentException e) { assertEquals("Expecting an expection message", "Duplicate key \"attr03\" at 90 [character 13 line 5]", e.getMessage()); @@ -2571,7 +2480,7 @@ public void parsingErrorNestedDuplicateKeyException() { + "}"; new JSONObject(str); fail("Expected an exception"); - } catch (JSONException e) { + } catch (IllegalArgumentException e) { assertEquals("Expecting an expection message", "Duplicate key \"attr03\" at 90 [character 13 line 5]", e.getMessage()); @@ -2596,7 +2505,7 @@ public void parsingErrorNestedDuplicateKeyWithArrayException() { + "}"; new JSONObject(str); fail("Expected an exception"); - } catch (JSONException e) { + } catch (IllegalArgumentException e) { assertEquals("Expecting an expection message", "Duplicate key \"attr03\" at 90 [character 13 line 5]", e.getMessage()); @@ -2620,7 +2529,7 @@ public void parsingErrorDuplicateKeyWithinNestedDictExceptionMessage() { + "}"; new JSONObject(str); fail("Expected an exception"); - } catch (JSONException e) { + } catch (IllegalArgumentException e) { assertEquals("Expecting an expection message", "Duplicate key \"attr04-03\" at 215 [character 20 line 9]", e.getMessage()); @@ -2649,7 +2558,7 @@ public void parsingErrorDuplicateKeyDoubleNestedDictExceptionMessage() { + "}"; new JSONObject(str); fail("Expected an exception"); - } catch (JSONException e) { + } catch (IllegalArgumentException e) { assertEquals("Expecting an expection message", "Duplicate key \"attr04-03\" at 215 [character 20 line 9]", e.getMessage()); @@ -2680,7 +2589,7 @@ public void parsingErrorDuplicateKeyNestedWithArrayExceptionMessage() { + "}"; new JSONObject(str); fail("Expected an exception"); - } catch (JSONException e) { + } catch (IllegalArgumentException e) { assertEquals("Expecting an expection message", "Duplicate key \"attr04-03\" at 215 [character 20 line 9]", e.getMessage()); @@ -2704,7 +2613,7 @@ public void parsingErrorDuplicateKeyWithinArrayExceptionMessage() { + "]"; new JSONArray(str); fail("Expected an exception"); - } catch (JSONException e) { + } catch (IllegalArgumentException e) { assertEquals("Expecting an expection message", "Duplicate key \"attr01\" at 124 [character 17 line 8]", e.getMessage()); @@ -2734,7 +2643,7 @@ public void parsingErrorDuplicateKeyDoubleNestedWithinArrayExceptionMessage() { + "]"; new JSONArray(str); fail("Expected an exception"); - } catch (JSONException e) { + } catch (IllegalArgumentException e) { assertEquals("Expecting an expection message", "Duplicate key \"attr02-01\" at 269 [character 24 line 13]", e.getMessage()); @@ -3088,10 +2997,10 @@ public void testJSONWriterException() { try { jsonObject.write(writer).toString(); fail("Expected an exception, got a String value"); - } catch (JSONException e) { + } catch (IllegalStateException e) { assertEquals("Unable to write JSONObject value for key: someKey", e.getMessage()); } catch(Exception e) { - fail("Expected JSONException"); + fail("Expected IllegalStateException"); } finally { try { writer.close(); @@ -3105,10 +3014,10 @@ public void testJSONWriterException() { try { jsonObject.write(writer).toString(); fail("Expected an exception, got a String value"); - } catch (JSONException e) { + } catch (IllegalStateException e) { assertEquals("Unable to write JSONObject value for key: someKey", e.getMessage()); } catch(Exception e) { - fail("Expected JSONException"); + fail("Expected IllegalStateException"); } finally { try { writer.close(); @@ -3125,10 +3034,10 @@ public void testJSONWriterException() { try { object.write(writer).toString(); fail("Expected an exception, got a String value"); - } catch (JSONException e) { + } catch (IllegalStateException e) { assertEquals("Unable to write JSONObject value for key: someKey", e.getMessage()); } catch(Exception e) { - fail("Expected JSONException"); + fail("Expected IllegalStateException"); } finally { try { writer.close(); @@ -3147,10 +3056,10 @@ public void testJSONWriterException() { try { object.write(writer).toString(); fail("Expected an exception, got a String value"); - } catch (JSONException e) { + } catch (IllegalStateException e) { assertEquals("Unable to write JSONObject value for key: someKey", e.getMessage()); } catch(Exception e) { - fail("Expected JSONException"); + fail("Expected IllegalStateException"); } finally { try { writer.close(); @@ -3340,40 +3249,13 @@ public void jsonObjectNullOperations() { fail("get() null should throw exception"); } catch (Exception ignored) {} - /** - * XML.toString() then goes on to do something with the value - * if the key val is "content", then value.toString() will be - * called. This will evaluate to "null" for JSONObject.NULL, - * and the empty string for null. - * But if the key is anything else, then JSONObject.NULL will be emitted - * as null and null will be emitted as "" - */ - String sJONull = XML.toString(jsonObjectJONull); - assertTrue("JSONObject.NULL should emit a null value", - "null".equals(sJONull)); - String sNull = XML.toString(jsonObjectNull); - assertTrue("null should emit an empty string", "".equals(sNull)); Util.checkJSONObjectsMaps(new ArrayList(Arrays.asList( jsonObjectJONull, jsonObjectNull ))); } - @Test(expected = JSONPointerException.class) - public void queryWithNoResult() { - new JSONObject().query("/a/b"); - } - - @Test - public void optQueryWithNoResult() { - assertNull(new JSONObject().optQuery("/a/b")); - } - - @Test(expected = IllegalArgumentException.class) - public void optQueryWithSyntaxError() { - new JSONObject().optQuery("invalid"); - } - @Test(expected = JSONException.class) + @Test(expected = IllegalArgumentException.class) public void invalidEscapeSequence() { String json = "{ \"\\url\": \"value\" }"; assertNull("Expected an exception",new JSONObject(json)); @@ -3651,7 +3533,7 @@ public void testPutNullObject() { jsonObject.put(null, new Object()); fail("Expected an exception"); } - @Test(expected=JSONException.class) + @Test(expected=IllegalStateException.class) public void testSelfRecursiveObject() { // A -> A ... RecursiveBean ObjA = new RecursiveBean("ObjA"); @@ -3659,7 +3541,7 @@ public void testSelfRecursiveObject() { new JSONObject(ObjA); fail("Expected an exception"); } - @Test(expected=JSONException.class) + @Test(expected=IllegalStateException.class) public void testLongSelfRecursiveObject() { // B -> A -> A ... RecursiveBean ObjA = new RecursiveBean("ObjA"); @@ -3669,7 +3551,7 @@ public void testLongSelfRecursiveObject() { new JSONObject(ObjB); fail("Expected an exception"); } - @Test(expected=JSONException.class) + @Test(expected=IllegalStateException.class) public void testSimpleRecursiveObject() { // B -> A -> B ... RecursiveBean ObjA = new RecursiveBean("ObjA"); @@ -3679,7 +3561,7 @@ public void testSimpleRecursiveObject() { new JSONObject(ObjA); fail("Expected an exception"); } - @Test(expected=JSONException.class) + @Test(expected=IllegalStateException.class) public void testLongRecursiveObject() { // D -> C -> B -> A -> D ... RecursiveBean ObjA = new RecursiveBean("ObjA"); @@ -3693,7 +3575,7 @@ public void testLongRecursiveObject() { new JSONObject(ObjB); fail("Expected an exception"); } - @Test(expected=JSONException.class) + @Test(expected=IllegalStateException.class) public void testRepeatObjectRecursive() { // C -> B -> A -> D -> C ... // -> D -> C ... @@ -3749,7 +3631,7 @@ public void testLongRepeatObjectNotRecursive() { j0, j1, j2, j3, j4 ))); } - @Test(expected=JSONException.class) + @Test(expected=IllegalStateException.class) public void testRecursiveEquals() { RecursiveBeanEquals a = new RecursiveBeanEquals("same"); a.setRef(a); @@ -3780,7 +3662,7 @@ public void testIssue548ObjectWithEmptyJsonArray() { /** * Tests if calling JSONObject clear() method actually makes the JSONObject empty */ - @Test(expected = JSONException.class) + @Test(expected = IllegalArgumentException.class) public void jsonObjectClearMethodTest() { //Adds random stuff to the JSONObject JSONObject jsonObject = new JSONObject(); @@ -3789,14 +3671,14 @@ public void jsonObjectClearMethodTest() { jsonObject.put("key3", new JSONObject()); jsonObject.clear(); //Clears the JSONObject assertTrue("expected jsonObject.length() == 0", jsonObject.length() == 0); //Check if its length is 0 - jsonObject.getInt("key1"); //Should throws org.json.JSONException: JSONObject["asd"] not found + jsonObject.getInt("key1"); //Should throws IllegalArgumentException: JSONObject["asd"] not found Util.checkJSONObjectMaps(jsonObject); } /** * Tests for stack overflow. See https://github.com/stleary/JSON-java/issues/654 */ - @Test(expected = JSONException.class) + @Test(expected = IllegalArgumentException.class) public void issue654StackOverflowInput() { //String base64Bytes ="eyJHWiI6Wy0wLTAse3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e1stMC0wLHt7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3tbLTAtMCx7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3tbLTAtMCx7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7Wy0wLTAse3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3tbLTAtMCx7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7ewl7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7Wy0wLTAse3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e1stMCkwLHt7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e1stMC0wLHt7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7CXt7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3tbLTAtMCx7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7Wy0wLTAse3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3tbLTAtMCx7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7ewl7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7Wy0wLTAse3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e1stMCkwLHt7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e1stMC0wLHt7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7CXt7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3tbLTAtMCx7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3tbLTAtMCx7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e1stMC0wLHt7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e1stMC0wLHt7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7Wy0wLTAse3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3sJe3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e1stMC0wLHt7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3tbLTApMCx7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3tbLTAtMCx7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7ewl7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7Wy0wLTAse3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e1stMC0wLHt7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7Wy0wLTAse3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3sJe3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e1stMC0wLHt7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3tbLTApMCx7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3tbLTAtMCx7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7Wy0wLTAse3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e1stMCkwLHt7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e1stMC0wLHt7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7CXt7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3tbLTAtMCx7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7Wy0wLTAse3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3tbLTAtMCx7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7ewl7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7Wy0wLTAse3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e1stMCkwLHt7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e1stMC0wLHt7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7CXt7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3tbLTAtMCx7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3tbLTAtMCx7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e1stMC0wLHt7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e1stMC0wLHt7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7Wy0wLTAse3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3sJe3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e1stMC0wLHt7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3tbLTApMCx7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3tbLTAtMCx7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7ewl7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7Wy0wLTAse3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e1stMC0wLHt7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7Wy0wLTAse3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3sJe3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e1stMC0wLHt7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3tbLTApMCx7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3tbLTAtMCx7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7ewl7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7Wy0wLTAse3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7Wy0wLTAse3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3tbLTAtMCx7e3t7e3t7e3t7c3t7e3t7e3vPAAAAAAAAAHt7e3t7e3t7e3t7e3t7e3t7e3t7e1ste3t7e3t7e3t7e3t7e3t7e3t7e3t7CXt7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3tbLTAtMCx7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3tbLTAtMCx7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e1stMC0wLHt7e3t7e3t7e3t7e3t7e3t7e88AAAAAAAAAe3t7e3t7e3t7e3t7e3t7e3t7e3t7Wy0wLTAse3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7e3t7f3syMv//e3t7e3t7e3t7e3t7e3sx//////8="; //String input = new String(java.util.Base64.getDecoder().decode(base64Bytes)); @@ -3810,7 +3692,7 @@ public void issue654StackOverflowInput() { /** * Tests for incorrect object/array nesting. See https://github.com/stleary/JSON-java/issues/654 */ - @Test(expected = JSONException.class) + @Test(expected = IllegalArgumentException.class) public void issue654IncorrectNestingNoKey1() { JSONObject json_input = new JSONObject("{{\"a\":0}}"); assertNotNull(json_input); @@ -3820,7 +3702,7 @@ public void issue654IncorrectNestingNoKey1() { /** * Tests for incorrect object/array nesting. See https://github.com/stleary/JSON-java/issues/654 */ - @Test(expected = JSONException.class) + @Test(expected = IllegalArgumentException.class) public void issue654IncorrectNestingNoKey2() { JSONObject json_input = new JSONObject("{[\"a\"]}"); assertNotNull(json_input); @@ -3831,7 +3713,7 @@ public void issue654IncorrectNestingNoKey2() { * Tests for stack overflow. See https://github.com/stleary/JSON-java/issues/654 */ @Ignore("This test relies on system constraints and may not always pass. See: https://github.com/stleary/JSON-java/issues/821") - @Test(expected = JSONException.class) + @Test(expected = IllegalStateException.class) public void issue654StackOverflowInputWellFormed() { //String input = new String(java.util.Base64.getDecoder().decode(base64Bytes)); final InputStream resourceAsStream = JSONObjectTest.class.getClassLoader().getResourceAsStream("Issue654WellFormedObject.json"); @@ -3871,7 +3753,7 @@ public void issue713MapConstructorWithNonFiniteNumbers() { Map map = new HashMap<>(); map.put("a", nonFinite); - assertThrows(JSONException.class, () -> new JSONObject(map)); + assertThrows(IllegalArgumentException.class, () -> new JSONObject(map)); } } @@ -3879,11 +3761,11 @@ public void issue713MapConstructorWithNonFiniteNumbers() { public void issue713BeanConstructorWithNonFiniteNumbers() { for (Number nonFinite : NON_FINITE_NUMBERS) { GenericBean bean = new GenericBean<>(nonFinite); - assertThrows(JSONException.class, () -> new JSONObject(bean)); + assertThrows(IllegalArgumentException.class, () -> new JSONObject(bean)); } } - @Test(expected = JSONException.class) + @Test(expected = IllegalStateException.class) public void issue743SerializationMap() { HashMap map = new HashMap<>(); map.put("t", map); @@ -3891,7 +3773,7 @@ public void issue743SerializationMap() { String jsonString = object.toString(); } - @Test(expected = JSONException.class) + @Test(expected = IllegalStateException.class) public void testCircularReferenceMultipleLevel() { HashMap inside = new HashMap<>(); HashMap jsonObject = new HashMap<>(); @@ -3916,14 +3798,14 @@ public void issue743SerializationMapWith500Objects() { String jsonString = object.toString(); } - @Test(expected = JSONException.class) + @Test(expected = IllegalStateException.class) public void issue743SerializationMapWith1001Objects() { HashMap map = buildNestedMap(1001); JSONObject object = new JSONObject(map); String jsonString = object.toString(); } - @Test(expected = JSONException.class) + @Test(expected = IllegalStateException.class) public void testCircleReferenceFirstLevel() { Map jsonObject = new HashMap<>(); @@ -3943,8 +3825,8 @@ public void testCircleReferenceMultiplyLevel_notConfigured_expectedStackOverflow new JSONObject(jsonObject, new JSONParserConfiguration().withMaxNestingDepth(99999)); } - @Test(expected = JSONException.class) - public void testCircleReferenceMultiplyLevel_configured_expectedJSONException() { + @Test(expected = IllegalStateException.class) + public void testCircleReferenceMultiplyLevel_configured_expectedIllegalStateException() { Map inside = new HashMap<>(); Map jsonObject = new HashMap<>(); @@ -4008,7 +3890,7 @@ public void testStrictModeJSONTokener_expectException(){ JSONParserConfiguration jsonParserConfiguration = new JSONParserConfiguration().withStrictMode(); JSONTokener tokener = new JSONTokener("{\"key\":\"value\"}invalidCharacters", jsonParserConfiguration); - assertThrows(JSONException.class, () -> { new JSONObject(tokener); }); + assertThrows(IllegalArgumentException.class, () -> { new JSONObject(tokener); }); } @Test @@ -4017,19 +3899,19 @@ public void test_strictModeWithMisCasedBooleanOrNullValue(){ try{ new JSONObject("{\"a\":True}", jsonParserConfiguration); fail("Expected an exception"); - } catch (JSONException e) { + } catch (IllegalArgumentException e) { // No action, expected outcome } try{ new JSONObject("{\"a\":TRUE}", jsonParserConfiguration); fail("Expected an exception"); - } catch (JSONException e) { + } catch (IllegalArgumentException e) { // No action, expected outcome } try{ new JSONObject("{\"a\":nUlL}", jsonParserConfiguration); fail("Expected an exception"); - } catch (JSONException e) { + } catch (IllegalArgumentException e) { // No action, expected outcome } } @@ -4042,19 +3924,19 @@ public void test_strictModeWithInappropriateKey(){ try{ new JSONObject("{true : 3}", jsonParserConfiguration); fail("Expected an exception"); - } catch (JSONException e) { + } catch (IllegalArgumentException e) { // No action, expected outcome } try{ new JSONObject("{TRUE : 3}", jsonParserConfiguration); fail("Expected an exception"); - } catch (JSONException e) { + } catch (IllegalArgumentException e) { // No action, expected outcome } try{ new JSONObject("{1 : 3}", jsonParserConfiguration); fail("Expected an exception"); - } catch (JSONException e) { + } catch (IllegalArgumentException e) { // No action, expected outcome } diff --git a/src/test/java/org/json/junit/JSONParserConfigurationTest.java b/src/test/java/org/json/junit/JSONParserConfigurationTest.java index 926c49f41..c0587a493 100644 --- a/src/test/java/org/json/junit/JSONParserConfigurationTest.java +++ b/src/test/java/org/json/junit/JSONParserConfigurationTest.java @@ -1,7 +1,6 @@ package org.json.junit; import org.json.JSONArray; -import org.json.JSONException; import org.json.JSONObject; import org.json.JSONParserConfiguration; import org.json.JSONTokener; @@ -23,7 +22,7 @@ public class JSONParserConfigurationTest { private static final String TEST_SOURCE = "{\"key\": \"value1\", \"key\": \"value2\"}"; - @Test(expected = JSONException.class) + @Test(expected = IllegalArgumentException.class) public void testThrowException() { new JSONObject(TEST_SOURCE); } @@ -195,8 +194,8 @@ public void givenValidEmptyArrayInsideArray_testStrictModeFalse_shouldNotThrowJs JSONParserConfiguration jsonParserConfiguration = new JSONParserConfiguration() .withStrictMode(false); String testCase = "[[]]"; - JSONArray jsonArray = new JSONArray(testCase, jsonParserConfiguration); - assertEquals(testCase, jsonArray.toString()); + JSONArray jsonArray2 = new JSONArray(testCase, jsonParserConfiguration); + assertEquals(testCase, jsonArray2.toString()); } @Test @@ -213,9 +212,8 @@ public void givenInvalidStringArray_testStrictModeTrue_shouldThrowJsonException( JSONParserConfiguration jsonParserConfiguration = new JSONParserConfiguration() .withStrictMode(true); String testCase = "[badString]"; - JSONException je = assertThrows(JSONException.class, () -> new JSONArray(testCase, jsonParserConfiguration)); - assertEquals("Strict mode error: Value 'badString' is not surrounded by quotes at 10 [character 11 line 1]", - je.getMessage()); + IllegalArgumentException je = assertThrows(IllegalArgumentException.class, () -> new JSONArray(testCase, jsonParserConfiguration)); + assertEquals("Strict mode error: Value 'badString' is not surrounded by quotes at 10 [character 11 line 1]", je.getMessage()); } @Test @@ -223,9 +221,8 @@ public void givenInvalidStringObject_testStrictModeTrue_shouldThrowJsonException JSONParserConfiguration jsonParserConfiguration = new JSONParserConfiguration() .withStrictMode(true); String testCase = "{\"a0\":badString}"; - JSONException je = assertThrows(JSONException.class, () -> new JSONObject(testCase, jsonParserConfiguration)); - assertEquals("Strict mode error: Value 'badString' is not surrounded by quotes at 15 [character 16 line 1]", - je.getMessage()); + IllegalArgumentException je = assertThrows(IllegalArgumentException.class, () -> new JSONObject(testCase, jsonParserConfiguration)); + assertEquals("Strict mode error: Value 'badString' is not surrounded by quotes at 15 [character 16 line 1]", je.getMessage()); } @Test @@ -319,10 +316,9 @@ public void givenInvalidInputArray_testStrictModeTrue_shouldThrowInvalidCharacte JSONParserConfiguration jsonParserConfiguration = new JSONParserConfiguration() .withStrictMode(true); String testCase = "[1,2];[3,4]"; - JSONException je = assertThrows("expected non-compliant array but got instead: " + testCase, - JSONException.class, () -> new JSONArray(testCase, jsonParserConfiguration)); - assertEquals("Strict mode error: Unparsed characters found at end of input text at 6 [character 7 line 1]", - je.getMessage()); + IllegalArgumentException je = assertThrows("expected non-compliant array but got instead: " + testCase, + IllegalArgumentException.class, () -> new JSONArray(testCase, jsonParserConfiguration)); + assertEquals("Strict mode error: Unparsed characters found at end of input text at 6 [character 7 line 1]", je.getMessage()); } @Test @@ -330,8 +326,8 @@ public void givenInvalidInputObject_testStrictModeTrue_shouldThrowInvalidCharact JSONParserConfiguration jsonParserConfiguration = new JSONParserConfiguration() .withStrictMode(true); String testCase = "{\"a0\":[1,2];\"a1\":[3,4]}"; - JSONException je = assertThrows("expected non-compliant array but got instead: " + testCase, - JSONException.class, () -> new JSONObject(testCase, jsonParserConfiguration)); + IllegalArgumentException je = assertThrows("expected non-compliant array but got instead: " + testCase, + IllegalArgumentException.class, () -> new JSONObject(testCase, jsonParserConfiguration)); assertEquals("Strict mode error: Invalid character ';' found at 12 [character 13 line 1]", je.getMessage()); } @@ -340,10 +336,9 @@ public void givenInvalidInputArrayWithNumericStrings_testStrictModeTrue_shouldTh JSONParserConfiguration jsonParserConfiguration = new JSONParserConfiguration() .withStrictMode(true); String testCase = "[\"1\",\"2\"];[3,4]"; - JSONException je = assertThrows("expected non-compliant array but got instead: " + testCase, - JSONException.class, () -> new JSONArray(testCase, jsonParserConfiguration)); - assertEquals("Strict mode error: Unparsed characters found at end of input text at 10 [character 11 line 1]", - je.getMessage()); + IllegalArgumentException je = assertThrows("expected non-compliant array but got instead: " + testCase, + IllegalArgumentException.class, () -> new JSONArray(testCase, jsonParserConfiguration)); + assertEquals("Strict mode error: Unparsed characters found at end of input text at 10 [character 11 line 1]", je.getMessage()); } @Test @@ -351,8 +346,8 @@ public void givenInvalidInputObjectWithNumericStrings_testStrictModeTrue_shouldT JSONParserConfiguration jsonParserConfiguration = new JSONParserConfiguration() .withStrictMode(true); String testCase = "{\"a0\":[\"1\",\"2\"];\"a1\":[3,4]}"; - JSONException je = assertThrows("expected non-compliant array but got instead: " + testCase, - JSONException.class, () -> new JSONObject(testCase, jsonParserConfiguration)); + IllegalArgumentException je = assertThrows("expected non-compliant array but got instead: " + testCase, + IllegalArgumentException.class, () -> new JSONObject(testCase, jsonParserConfiguration)); assertEquals("Strict mode error: Invalid character ';' found at 16 [character 17 line 1]", je.getMessage()); } @@ -361,10 +356,9 @@ public void givenInvalidInputArray_testStrictModeTrue_shouldThrowValueNotSurroun JSONParserConfiguration jsonParserConfiguration = new JSONParserConfiguration() .withStrictMode(true); String testCase = "[{\"test\": implied}]"; - JSONException je = assertThrows("expected non-compliant array but got instead: " + testCase, - JSONException.class, () -> new JSONArray(testCase, jsonParserConfiguration)); - assertEquals("Strict mode error: Value 'implied' is not surrounded by quotes at 17 [character 18 line 1]", - je.getMessage()); + IllegalArgumentException je = assertThrows("expected non-compliant array but got instead: " + testCase, + IllegalArgumentException.class, () -> new JSONArray(testCase, jsonParserConfiguration)); + assertEquals("Strict mode error: Value 'implied' is not surrounded by quotes at 17 [character 18 line 1]", je.getMessage()); } @Test @@ -372,10 +366,9 @@ public void givenInvalidInputObject_testStrictModeTrue_shouldThrowValueNotSurrou JSONParserConfiguration jsonParserConfiguration = new JSONParserConfiguration() .withStrictMode(true); String testCase = "{\"a0\":{\"test\": implied}]}"; - JSONException je = assertThrows("expected non-compliant array but got instead: " + testCase, - JSONException.class, () -> new JSONObject(testCase, jsonParserConfiguration)); - assertEquals("Strict mode error: Value 'implied' is not surrounded by quotes at 22 [character 23 line 1]", - je.getMessage()); + IllegalArgumentException je = assertThrows("expected non-compliant array but got instead: " + testCase, + IllegalArgumentException.class, () -> new JSONObject(testCase, jsonParserConfiguration)); + assertEquals("Strict mode error: Value 'implied' is not surrounded by quotes at 22 [character 23 line 1]", je.getMessage()); } @Test @@ -404,13 +397,13 @@ public void givenNonCompliantQuotesArray_testStrictModeTrue_shouldThrowJsonExcep String testCaseThree = "['abc']"; String testCaseFour = "[{'testField': \"testValue\"}]"; - JSONException jeOne = assertThrows(JSONException.class, + IllegalArgumentException jeOne = assertThrows(IllegalArgumentException.class, () -> new JSONArray(testCaseOne, jsonParserConfiguration)); - JSONException jeTwo = assertThrows(JSONException.class, + IllegalArgumentException jeTwo = assertThrows(IllegalArgumentException.class, () -> new JSONArray(testCaseTwo, jsonParserConfiguration)); - JSONException jeThree = assertThrows(JSONException.class, + IllegalArgumentException jeThree = assertThrows(IllegalArgumentException.class, () -> new JSONArray(testCaseThree, jsonParserConfiguration)); - JSONException jeFour = assertThrows(JSONException.class, + IllegalArgumentException jeFour = assertThrows(IllegalArgumentException.class, () -> new JSONArray(testCaseFour, jsonParserConfiguration)); assertEquals( @@ -437,13 +430,13 @@ public void givenNonCompliantQuotesObject_testStrictModeTrue_shouldThrowJsonExce String testCaseThree = "{\"a\":'abc'}"; String testCaseFour = "{'testField': \"testValue\"}"; - JSONException jeOne = assertThrows(JSONException.class, + IllegalArgumentException jeOne = assertThrows(IllegalArgumentException.class, () -> new JSONObject(testCaseOne, jsonParserConfiguration)); - JSONException jeTwo = assertThrows(JSONException.class, + IllegalArgumentException jeTwo = assertThrows(IllegalArgumentException.class, () -> new JSONObject(testCaseTwo, jsonParserConfiguration)); - JSONException jeThree = assertThrows(JSONException.class, + IllegalArgumentException jeThree = assertThrows(IllegalArgumentException.class, () -> new JSONObject(testCaseThree, jsonParserConfiguration)); - JSONException jeFour = assertThrows(JSONException.class, + IllegalArgumentException jeFour = assertThrows(IllegalArgumentException.class, () -> new JSONObject(testCaseFour, jsonParserConfiguration)); assertEquals( @@ -468,9 +461,9 @@ public void givenUnbalancedQuotesArray_testStrictModeFalse_shouldThrowJsonExcept String testCaseOne = "[\"abc', \"test\"]"; String testCaseTwo = "['abc\", \"test\"]"; - JSONException jeOne = assertThrows(JSONException.class, + IllegalArgumentException jeOne = assertThrows(IllegalArgumentException.class, () -> new JSONArray(testCaseOne, jsonParserConfiguration)); - JSONException jeTwo = assertThrows(JSONException.class, + IllegalArgumentException jeTwo = assertThrows(IllegalArgumentException.class, () -> new JSONArray(testCaseTwo, jsonParserConfiguration)); assertEquals("Expected a ',' or ']' at 10 [character 11 line 1]", jeOne.getMessage()); @@ -485,9 +478,9 @@ public void givenUnbalancedQuotesObject_testStrictModeFalse_shouldThrowJsonExcep String testCaseOne = "{\"abc': \"test\"}"; String testCaseTwo = "{'abc\": \"test\"}"; - JSONException jeOne = assertThrows(JSONException.class, + IllegalArgumentException jeOne = assertThrows(IllegalArgumentException.class, () -> new JSONObject(testCaseOne, jsonParserConfiguration)); - JSONException jeTwo = assertThrows(JSONException.class, + IllegalArgumentException jeTwo = assertThrows(IllegalArgumentException.class, () -> new JSONObject(testCaseTwo, jsonParserConfiguration)); assertEquals("Expected a ':' after a key at 10 [character 11 line 1]", jeOne.getMessage()); @@ -500,11 +493,10 @@ public void givenInvalidInputArray_testStrictModeTrue_shouldThrowKeyNotSurrounde .withStrictMode(true); String testCase = "[{test: implied}]"; - JSONException je = assertThrows("expected non-compliant array but got instead: " + testCase, - JSONException.class, () -> new JSONArray(testCase, jsonParserConfiguration)); + IllegalArgumentException je = assertThrows("expected non-compliant array but got instead: " + testCase, + IllegalArgumentException.class, () -> new JSONArray(testCase, jsonParserConfiguration)); - assertEquals("Strict mode error: Value 'test' is not surrounded by quotes at 6 [character 7 line 1]", - je.getMessage()); + assertEquals("Strict mode error: Value 'test' is not surrounded by quotes at 6 [character 7 line 1]", je.getMessage()); } @Test @@ -513,16 +505,15 @@ public void givenInvalidInputObject_testStrictModeTrue_shouldThrowKeyNotSurround .withStrictMode(true); String testCase = "{test: implied}"; - JSONException je = assertThrows("expected non-compliant json but got instead: " + testCase, - JSONException.class, () -> new JSONObject(testCase, jsonParserConfiguration)); + IllegalArgumentException je = assertThrows("expected non-compliant json but got instead: " + testCase, + IllegalArgumentException.class, () -> new JSONObject(testCase, jsonParserConfiguration)); - assertEquals("Strict mode error: Value 'test' is not surrounded by quotes at 5 [character 6 line 1]", - je.getMessage()); + assertEquals("Strict mode error: Value 'test' is not surrounded by quotes at 5 [character 6 line 1]", je.getMessage()); } @Test public void givenInvalidInputObject_testStrictModeTrue_JSONObjectUsingJSONTokener_shouldThrowJSONException() { - JSONException exception = assertThrows(JSONException.class, () -> { + IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> { new JSONObject(new JSONTokener("{\"key\":\"value\"} invalid trailing text"), new JSONParserConfiguration().withStrictMode(true)); }); @@ -531,7 +522,7 @@ public void givenInvalidInputObject_testStrictModeTrue_JSONObjectUsingJSONTokene @Test public void givenInvalidInputObject_testStrictModeTrue_JSONObjectUsingString_shouldThrowJSONException() { - JSONException exception = assertThrows(JSONException.class, () -> { + IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> { new JSONObject("{\"key\":\"value\"} invalid trailing text", new JSONParserConfiguration().withStrictMode(true)); }); assertEquals("Strict mode error: Unparsed characters found at end of input text at 17 [character 18 line 1]", exception.getMessage()); @@ -539,7 +530,7 @@ public void givenInvalidInputObject_testStrictModeTrue_JSONObjectUsingString_sho @Test public void givenInvalidInputObject_testStrictModeTrue_JSONArrayUsingJSONTokener_shouldThrowJSONException() { - JSONException exception = assertThrows(JSONException.class, () -> { + IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> { new JSONArray(new JSONTokener("[\"value\"] invalid trailing text"), new JSONParserConfiguration().withStrictMode(true)); }); @@ -548,7 +539,7 @@ public void givenInvalidInputObject_testStrictModeTrue_JSONArrayUsingJSONTokener @Test public void givenInvalidInputObject_testStrictModeTrue_JSONArrayUsingString_shouldThrowJSONException() { - JSONException exception = assertThrows(JSONException.class, () -> { + IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> { new JSONArray("[\"value\"] invalid trailing text", new JSONParserConfiguration().withStrictMode(true)); }); assertEquals("Strict mode error: Unparsed characters found at end of input text at 11 [character 12 line 1]", exception.getMessage()); diff --git a/src/test/java/org/json/junit/JSONPointerTest.java b/src/test/java/org/json/junit/JSONPointerTest.java deleted file mode 100644 index a420b297f..000000000 --- a/src/test/java/org/json/junit/JSONPointerTest.java +++ /dev/null @@ -1,398 +0,0 @@ -package org.json.junit; - -/* -Public Domain. -*/ - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -import java.io.InputStream; - -import org.json.JSONArray; -import org.json.JSONObject; -import org.json.JSONPointer; -import org.json.JSONPointerException; -import org.json.JSONTokener; -import org.junit.Test; - -public class JSONPointerTest { - - private static final JSONObject document; - private static final String EXPECTED_COMPLETE_DOCUMENT = "{\"\":0,\" \":7,\"g|h\":4,\"c%d\":2,\"k\\\"l\":6,\"a/b\":1,\"i\\\\j\":5," + - "\"obj\":{\"\":{\"\":\"empty key of an object with an empty key\",\"subKey\":\"Some other value\"}," + - "\"other~key\":{\"another/key\":[\"val\"]},\"key\":\"value\"},\"foo\":[\"bar\",\"baz\"],\"e^f\":3," + - "\"m~n\":8}"; - - - static { - @SuppressWarnings("resource") - InputStream resourceAsStream = JSONPointerTest.class.getClassLoader().getResourceAsStream("jsonpointer-testdoc.json"); - if(resourceAsStream == null) { - throw new ExceptionInInitializerError("Unable to locate test file. Please check your development environment configuration"); - } - document = new JSONObject(new JSONTokener(resourceAsStream)); - } - - private Object query(String pointer) { - return new JSONPointer(pointer).queryFrom(document); - } - - @Test - public void emptyPointer() { - assertTrue(new JSONObject(EXPECTED_COMPLETE_DOCUMENT).similar(query(""))); - } - - @SuppressWarnings("unused") - @Test(expected = NullPointerException.class) - public void nullPointer() { - new JSONPointer((String) null); - } - - @Test - public void objectPropertyQuery() { - assertEquals("[\"bar\",\"baz\"]", query("/foo").toString()); - } - - @Test - public void arrayIndexQuery() { - assertEquals("bar", query("/foo/0")); - } - - @Test(expected = JSONPointerException.class) - public void stringPropOfArrayFailure() { - query("/foo/bar"); - } - - @Test - public void queryByEmptyKey() { - assertEquals(0, query("/")); - } - - @Test - public void queryByEmptyKeySubObject() { - JSONObject json = new JSONObject("{\"\":\"empty key of an object with an empty key\",\"subKey\":\"Some" + - " other value\"}"); - JSONObject obj = (JSONObject) query("/obj/"); - assertTrue(json.similar(obj)); - } - - @Test - public void queryByEmptyKeySubObjectSubOject() { - assertEquals("empty key of an object with an empty key", query("/obj//")); - } - - @Test - public void queryByEmptyKeySubObjectValue() { - assertEquals("Some other value", query("/obj//subKey")); - } - - @Test - public void slashEscaping() { - assertEquals(1, query("/a~1b")); - } - - @Test - public void tildeEscaping() { - assertEquals(8, query("/m~0n")); - } - - /** - * We pass backslashes as-is - * - * @see rfc6901 section 3 - */ - @Test - public void backslashHandling() { - assertEquals(5, query("/i\\j")); - } - - /** - * We pass quotations as-is - * - * @see rfc6901 section 3 - */ - @Test - public void quotationHandling() { - assertEquals(6, query("/k\"l")); - } - - @Test - public void whitespaceKey() { - assertEquals(7, query("/ ")); - } - - @Test - public void uriFragmentNotation() { - assertEquals("[\"bar\",\"baz\"]", query("#/foo").toString()); - } - - @Test - public void uriFragmentNotationRoot() { - assertTrue(new JSONObject(EXPECTED_COMPLETE_DOCUMENT).similar(query("#"))); - } - - @Test - public void uriFragmentPercentHandling() { - assertEquals(2, query("#/c%25d")); - assertEquals(3, query("#/e%5Ef")); - assertEquals(4, query("#/g%7Ch")); - assertEquals(8, query("#/m~0n")); - } - - @SuppressWarnings("unused") - @Test(expected = IllegalArgumentException.class) - public void syntaxError() { - new JSONPointer("key"); - } - - @Test(expected = JSONPointerException.class) - public void arrayIndexFailure() { - query("/foo/2"); - } - - @Test(expected = JSONPointerException.class) - public void primitiveFailure() { - query("/obj/key/failure"); - } - - @Test - public void builderTest() { - JSONPointer pointer = JSONPointer.builder() - .append("obj") - .append("other~key").append("another/key") - .append(0) - .build(); - assertEquals("val", pointer.queryFrom(document)); - } - - @Test(expected = NullPointerException.class) - public void nullToken() { - JSONPointer.builder().append(null); - } - - @Test - public void toStringEscaping() { - JSONPointer pointer = JSONPointer.builder() - .append("obj") - .append("other~key").append("another/key") - .append("\"") - .append(0) - .build(); - assertEquals("/obj/other~0key/another~1key/\"/0", pointer.toString()); - } - - @Test - public void emptyPointerToString() { - assertEquals("", new JSONPointer("").toString()); - } - - @Test - public void toURIFragment() { - assertEquals("#/c%25d", new JSONPointer("/c%d").toURIFragment()); - assertEquals("#/e%5Ef", new JSONPointer("/e^f").toURIFragment()); - assertEquals("#/g%7Ch", new JSONPointer("/g|h").toURIFragment()); - assertEquals("#/m%7En", new JSONPointer("/m~n").toURIFragment()); - } - - @Test - public void tokenListIsCopiedInConstructor() { - JSONPointer.Builder b = JSONPointer.builder().append("key1"); - JSONPointer jp1 = b.build(); - b.append("key2"); - JSONPointer jp2 = b.build(); - if(jp1.toString().equals(jp2.toString())) { - fail("Oops, my pointers are sharing a backing array"); - } - } - - /** - * Coverage for JSONObject query(String) - */ - @Test - public void queryFromJSONObject() { - String str = "{"+ - "\"stringKey\":\"hello world!\","+ - "\"arrayKey\":[0,1,2],"+ - "\"objectKey\": {"+ - "\"a\":\"aVal\","+ - "\"b\":\"bVal\""+ - "}"+ - "}"; - JSONObject jsonObject = new JSONObject(str); - Object obj = jsonObject.query("/stringKey"); - assertTrue("Expected 'hello world!'", "hello world!".equals(obj)); - obj = jsonObject.query("/arrayKey/1"); - assertTrue("Expected 1", Integer.valueOf(1).equals(obj)); - obj = jsonObject.query("/objectKey/b"); - assertTrue("Expected bVal", "bVal".equals(obj)); - try { - obj = jsonObject.query("/a/b/c"); - assertTrue("Expected JSONPointerException", false); - } catch (JSONPointerException e) { - assertTrue("Expected bad key/value exception", - "value [null] is not an array or object therefore its key b cannot be resolved". - equals(e.getMessage())); - } - } - - /** - * Coverage for JSONObject query(JSONPointer) - */ - @Test - public void queryFromJSONObjectUsingPointer() { - String str = "{"+ - "\"stringKey\":\"hello world!\","+ - "\"arrayKey\":[0,1,2],"+ - "\"objectKey\": {"+ - "\"a\":\"aVal\","+ - "\"b\":\"bVal\""+ - "}"+ - "}"; - JSONObject jsonObject = new JSONObject(str); - Object obj = jsonObject.query(new JSONPointer("/stringKey")); - assertTrue("Expected 'hello world!'", "hello world!".equals(obj)); - obj = jsonObject.query(new JSONPointer("/arrayKey/1")); - assertTrue("Expected 1", Integer.valueOf(1).equals(obj)); - obj = jsonObject.query(new JSONPointer("/objectKey/b")); - assertTrue("Expected bVal", "bVal".equals(obj)); - try { - obj = jsonObject.query(new JSONPointer("/a/b/c")); - assertTrue("Expected JSONPointerException", false); - } catch (JSONPointerException e) { - assertTrue("Expected bad key/value exception", - "value [null] is not an array or object therefore its key b cannot be resolved". - equals(e.getMessage())); - } - } - - /** - * Coverage for JSONObject optQuery(JSONPointer) - */ - @Test - public void optQueryFromJSONObjectUsingPointer() { - String str = "{"+ - "\"stringKey\":\"hello world!\","+ - "\"arrayKey\":[0,1,2],"+ - "\"objectKey\": {"+ - "\"a\":\"aVal\","+ - "\"b\":\"bVal\""+ - "}"+ - "}"; - JSONObject jsonObject = new JSONObject(str); - Object obj = jsonObject.optQuery(new JSONPointer("/stringKey")); - assertTrue("Expected 'hello world!'", "hello world!".equals(obj)); - obj = jsonObject.optQuery(new JSONPointer("/arrayKey/1")); - assertTrue("Expected 1", Integer.valueOf(1).equals(obj)); - obj = jsonObject.optQuery(new JSONPointer("/objectKey/b")); - assertTrue("Expected bVal", "bVal".equals(obj)); - obj = jsonObject.optQuery(new JSONPointer("/a/b/c")); - assertTrue("Expected null", obj == null); - } - - /** - * Coverage for JSONArray query(String) - */ - @Test - public void queryFromJSONArray() { - String str = "["+ - "\"hello world!\","+ - "[0,1,2],"+ - "{"+ - "\"a\":\"aVal\","+ - "\"b\":\"bVal\""+ - "}"+ - "]"; - JSONArray jsonArray = new JSONArray(str); - Object obj = jsonArray.query("/0"); - assertTrue("Expected 'hello world!'", "hello world!".equals(obj)); - obj = jsonArray.query("/1/1"); - assertTrue("Expected 1", Integer.valueOf(1).equals(obj)); - obj = jsonArray.query("/2/b"); - assertTrue("Expected bVal", "bVal".equals(obj)); - try { - obj = jsonArray.query("/a/b/c"); - assertTrue("Expected JSONPointerException", false); - } catch (JSONPointerException e) { - assertTrue("Expected bad index exception", - "a is not an array index".equals(e.getMessage())); - } - } - - /** - * Coverage for JSONArray query(JSONPointer) - */ - @Test - public void queryFromJSONArrayUsingPointer() { - String str = "["+ - "\"hello world!\","+ - "[0,1,2],"+ - "{"+ - "\"a\":\"aVal\","+ - "\"b\":\"bVal\""+ - "}"+ - "]"; - JSONArray jsonArray = new JSONArray(str); - Object obj = jsonArray.query(new JSONPointer("/0")); - assertTrue("Expected 'hello world!'", "hello world!".equals(obj)); - obj = jsonArray.query(new JSONPointer("/1/1")); - assertTrue("Expected 1", Integer.valueOf(1).equals(obj)); - obj = jsonArray.query(new JSONPointer("/2/b")); - assertTrue("Expected bVal", "bVal".equals(obj)); - try { - obj = jsonArray.query(new JSONPointer("/a/b/c")); - assertTrue("Expected JSONPointerException", false); - } catch (JSONPointerException e) { - assertTrue("Expected bad index exception", - "a is not an array index".equals(e.getMessage())); - } - } - - /** - * Coverage for JSONArray optQuery(JSONPointer) - */ - @Test - public void optQueryFromJSONArrayUsingPointer() { - String str = "["+ - "\"hello world!\","+ - "[0,1,2],"+ - "{"+ - "\"a\":\"aVal\","+ - "\"b\":\"bVal\""+ - "}"+ - "]"; - JSONArray jsonArray = new JSONArray(str); - Object obj = jsonArray.optQuery(new JSONPointer("/0")); - assertTrue("Expected 'hello world!'", "hello world!".equals(obj)); - obj = jsonArray.optQuery(new JSONPointer("/1/1")); - assertTrue("Expected 1", Integer.valueOf(1).equals(obj)); - obj = jsonArray.optQuery(new JSONPointer("/2/b")); - assertTrue("Expected bVal", "bVal".equals(obj)); - obj = jsonArray.optQuery(new JSONPointer("/a/b/c")); - assertTrue("Expected null", obj == null); - } - - /** - * When creating a jsonObject we need to parse escaped characters "\\\\" - * --> it's the string representation of "\\", so when query'ing via the JSONPointer - * we DON'T escape them - * - */ - @Test - public void queryFromJSONObjectUsingPointer0() { - String str = "{"+ - "\"string\\\\\\\\Key\":\"hello world!\","+ - - "\"\\\\\":\"slash test\"" + - "}"; - JSONObject jsonObject = new JSONObject(str); - //Summary of issue: When a KEY in the jsonObject is "\\\\" --> it's held - // as "\\" which means when querying, we need to use "\\" - Object twoBackslahObj = jsonObject.optQuery(new JSONPointer("/\\")); - assertEquals("slash test", twoBackslahObj); - - Object fourBackslashObj = jsonObject.optQuery(new JSONPointer("/string\\\\Key")); - assertEquals("hello world!", fourBackslashObj); - } -} diff --git a/src/test/java/org/json/junit/JSONStringTest.java b/src/test/java/org/json/junit/JSONStringTest.java index 235df1806..219b9fe7c 100644 --- a/src/test/java/org/json/junit/JSONStringTest.java +++ b/src/test/java/org/json/junit/JSONStringTest.java @@ -209,7 +209,7 @@ public void testJSONStringValue() throws Exception { /** * Test what happens when toJSONString() returns null. In one case, - * use the object's toString() method. In the other, throw a JSONException. + * use the object's toString() method. In the other, throw an IllegalStateException. */ @Test public void testJSONNullStringValue() throws Exception { @@ -223,13 +223,12 @@ public void testJSONNullStringValue() throws Exception { String output = jsonArray.write(writer).toString(); assertTrue("String values should be equal", "[\"the toString value\"]".equals(output)); - // The only different between writeValue() and valueToString(): - // in this case, valueToString throws a JSONException + // The only difference between writeValue() and valueToString(): + // in this case, valueToString throws an IllegalStateException try { output = JSONObject.valueToString(jsonString); fail("Expected an exception, got a String value"); - } catch (Exception e) { - assertTrue("Expected JSONException", e instanceof JSONException); + } catch (IllegalStateException e) { assertTrue("Exception message does not match", "Bad value from toJSONString: null".equals(e.getMessage())); } } finally { @@ -239,7 +238,7 @@ public void testJSONNullStringValue() throws Exception { /** * Test what happens when toJSONString() returns an exception. In both - * cases, a JSONException is thrown, with the cause and message set from + * cases, an IllegalStateException is thrown, with the cause and message set from * the original exception. */ @Test @@ -253,10 +252,10 @@ public void testJSONStringExceptionValue() { try { jsonArray.write(writer).toString(); fail("Expected an exception, got a String value"); - } catch (JSONException e) { + } catch (IllegalStateException e) { assertEquals("Unable to write JSONArray value at index: 0", e.getMessage()); } catch(Exception e) { - fail("Expected JSONException"); + fail("Expected IllegalStateException"); } finally { try { writer.close(); @@ -266,10 +265,10 @@ public void testJSONStringExceptionValue() { try { JSONObject.valueToString(jsonString); fail("Expected an exception, got a String value"); - } catch (JSONException e) { - assertTrue("Exception message does not match", "the exception value".equals(e.getMessage())); + } catch (IllegalStateException e) { + assertEquals("the exception value", e.getCause().getMessage()); } catch(Exception e) { - fail("Expected JSONException"); + fail("Expected IllegalStateException"); } } diff --git a/src/test/java/org/json/junit/JSONStringerTest.java b/src/test/java/org/json/junit/JSONStringerTest.java index 0ecb9d662..129901650 100644 --- a/src/test/java/org/json/junit/JSONStringerTest.java +++ b/src/test/java/org/json/junit/JSONStringerTest.java @@ -22,7 +22,7 @@ public class JSONStringerTest { /** * Object with a null key. - * Expects a JSONException. + * Expects an IllegalArgumentException. */ @Test public void nullKeyException() { @@ -31,7 +31,7 @@ public void nullKeyException() { try { jsonStringer.key(null); assertTrue("Expected an exception", false); - } catch (JSONException e) { + } catch (IllegalArgumentException e) { assertTrue("Expected an exception message", "Null key.". equals(e.getMessage())); @@ -40,7 +40,7 @@ public void nullKeyException() { /** * Add a key with no object. - * Expects a JSONException. + * Expects an IllegalStateException. */ @Test public void outOfSequenceException() { @@ -48,7 +48,7 @@ public void outOfSequenceException() { try { jsonStringer.key("hi"); assertTrue("Expected an exception", false); - } catch (JSONException e) { + } catch (IllegalStateException e) { assertTrue("Expected an exception message", "Misplaced key.". equals(e.getMessage())); @@ -57,7 +57,7 @@ public void outOfSequenceException() { /** * Missplace an array. - * Expects a JSONException + * Expects an IllegalStateException. */ @Test public void missplacedArrayException() { @@ -66,7 +66,7 @@ public void missplacedArrayException() { try { jsonStringer.array(); assertTrue("Expected an exception", false); - } catch (JSONException e) { + } catch (IllegalStateException e) { assertTrue("Expected an exception message", "Misplaced array.". equals(e.getMessage())); @@ -74,8 +74,8 @@ public void missplacedArrayException() { } /** - * Missplace an endErray. - * Expects a JSONException + * Missplace an endArray. + * Expects an IllegalStateException. */ @Test public void missplacedEndArrayException() { @@ -84,7 +84,7 @@ public void missplacedEndArrayException() { try { jsonStringer.endArray(); assertTrue("Expected an exception", false); - } catch (JSONException e) { + } catch (IllegalStateException e) { assertTrue("Expected an exception message", "Misplaced endArray.". equals(e.getMessage())); @@ -93,7 +93,7 @@ public void missplacedEndArrayException() { /** * Missplace an endObject. - * Expects a JSONException + * Expects an IllegalStateException. */ @Test public void missplacedEndObjectException() { @@ -102,7 +102,7 @@ public void missplacedEndObjectException() { try { jsonStringer.endObject(); assertTrue("Expected an exception", false); - } catch (JSONException e) { + } catch (IllegalStateException e) { assertTrue("Expected an exception message", "Misplaced endObject.". equals(e.getMessage())); @@ -111,7 +111,7 @@ public void missplacedEndObjectException() { /** * Missplace an object. - * Expects a JSONException. + * Expects an IllegalStateException. */ @Test public void missplacedObjectException() { @@ -120,7 +120,7 @@ public void missplacedObjectException() { try { jsonStringer.object(); assertTrue("Expected an exception", false); - } catch (JSONException e) { + } catch (IllegalStateException e) { assertTrue("Expected an exception message", "Misplaced object.". equals(e.getMessage())); @@ -129,7 +129,7 @@ public void missplacedObjectException() { /** * Exceeds implementation max nesting depth. - * Expects a JSONException + * Expects an IllegalStateException. */ @Test public void exceedNestDepthException() { @@ -215,7 +215,7 @@ public void exceedNestDepthException() { key("k").object().key("k").object().key("k").object().key("k").object().key("k").object(). key("k").object().key("k").object().key("k").object().key("k").object().key("k").object(); fail("Expected an exception message"); - } catch (JSONException e) { + } catch (IllegalStateException e) { assertTrue("Expected an exception message", "Nesting too deep.". equals(e.getMessage())); @@ -244,13 +244,13 @@ public void simpleObjectString() { // validate JSON content Object doc = Configuration.defaultConfiguration().jsonProvider().parse(jsonObject.toString()); assertTrue("expected 7 top level items", ((Map)(JsonPath.read(doc, "$"))).size() == 7); - assertTrue("expected true", Boolean.TRUE.equals(jsonObject.query("/trueValue"))); - assertTrue("expected false", Boolean.FALSE.equals(jsonObject.query("/falseValue"))); - assertTrue("expected null", JSONObject.NULL.equals(jsonObject.query("/nullValue"))); - assertTrue("expected hello world!", "hello world!".equals(jsonObject.query("/stringValue"))); - assertTrue("expected h\be\tllo w\u1234orld!", "h\be\tllo w\u1234orld!".equals(jsonObject.query("/complexStringValue"))); - assertTrue("expected 42", Integer.valueOf(42).equals(jsonObject.query("/intValue"))); - assertTrue("expected -23.45e67", BigDecimal.valueOf(-23.45e67).equals(jsonObject.query("/doubleValue"))); + assertTrue("expected true", Boolean.TRUE.equals(jsonObject.get("trueValue"))); + assertTrue("expected false", Boolean.FALSE.equals(jsonObject.get("falseValue"))); + assertTrue("expected null", JSONObject.NULL.equals(jsonObject.get("nullValue"))); + assertTrue("expected hello world!", "hello world!".equals(jsonObject.get("stringValue"))); + assertTrue("expected h\be\tllo w\u1234orld!", "h\be\tllo w\u1234orld!".equals(jsonObject.get("complexStringValue"))); + assertTrue("expected 42", Integer.valueOf(42).equals(jsonObject.get("intValue"))); + assertTrue("expected -23.45e67", BigDecimal.valueOf(-23.45e67).equals(jsonObject.get("doubleValue"))); } /** @@ -274,12 +274,12 @@ public void simpleArrayString() { // validate JSON content Object doc = Configuration.defaultConfiguration().jsonProvider().parse(jsonArray.toString()); assertTrue("expected 6 top level items", ((List)(JsonPath.read(doc, "$"))).size() == 6); - assertTrue("expected true", Boolean.TRUE.equals(jsonArray.query("/0"))); - assertTrue("expected false", Boolean.FALSE.equals(jsonArray.query("/1"))); - assertTrue("expected null", JSONObject.NULL.equals(jsonArray.query("/2"))); - assertTrue("expected hello world!", "hello world!".equals(jsonArray.query("/3"))); - assertTrue("expected 42", Integer.valueOf(42).equals(jsonArray.query("/4"))); - assertTrue("expected -23.45e67", BigDecimal.valueOf(-23.45e67).equals(jsonArray.query("/5"))); + assertTrue("expected true", Boolean.TRUE.equals(jsonArray.get(0))); + assertTrue("expected false", Boolean.FALSE.equals(jsonArray.get(1))); + assertTrue("expected null", JSONObject.NULL.equals(jsonArray.get(2))); + assertTrue("expected hello world!", "hello world!".equals(jsonArray.get(3))); + assertTrue("expected 42", Integer.valueOf(42).equals(jsonArray.get(4))); + assertTrue("expected -23.45e67", BigDecimal.valueOf(-23.45e67).equals(jsonArray.get(5))); } /** @@ -331,27 +331,27 @@ public void complexObjectString() { assertTrue("expected 5 array1 items", ((List)(JsonPath.read(doc, "$.object2.array1"))).size() == 5); assertTrue("expected 4 array[2] items", ((Map)(JsonPath.read(doc, "$.object2.array1[2]"))).size() == 4); assertTrue("expected 4 array1[2].array2 items", ((List)(JsonPath.read(doc, "$.object2.array1[2].array2"))).size() == 4); - assertTrue("expected true", Boolean.TRUE.equals(jsonObject.query("/trueValue"))); - assertTrue("expected false", Boolean.FALSE.equals(jsonObject.query("/falseValue"))); - assertTrue("expected null", JSONObject.NULL.equals(jsonObject.query("/nullValue"))); - assertTrue("expected hello world!", "hello world!".equals(jsonObject.query("/stringValue"))); - assertTrue("expected 42", Integer.valueOf(42).equals(jsonObject.query("/intValue"))); - assertTrue("expected -23.45e67", BigDecimal.valueOf(-23.45e67).equals(jsonObject.query("/doubleValue"))); - assertTrue("expected h\be\tllo w\u1234orld!", "h\be\tllo w\u1234orld!".equals(jsonObject.query("/complexStringValue"))); - assertTrue("expected v1", "v1".equals(jsonObject.query("/object2/k1"))); - assertTrue("expected v2", "v2".equals(jsonObject.query("/object2/k2"))); - assertTrue("expected v3", "v3".equals(jsonObject.query("/object2/k3"))); - assertTrue("expected 1", Integer.valueOf(1).equals(jsonObject.query("/object2/array1/0"))); - assertTrue("expected 2", Integer.valueOf(2).equals(jsonObject.query("/object2/array1/1"))); - assertTrue("expected v4", "v4".equals(jsonObject.query("/object2/array1/2/k4"))); - assertTrue("expected v5", "v5".equals(jsonObject.query("/object2/array1/2/k5"))); - assertTrue("expected v6", "v6".equals(jsonObject.query("/object2/array1/2/k6"))); - assertTrue("expected 5", Integer.valueOf(5).equals(jsonObject.query("/object2/array1/2/array2/0"))); - assertTrue("expected 6", Integer.valueOf(6).equals(jsonObject.query("/object2/array1/2/array2/1"))); - assertTrue("expected 7", Integer.valueOf(7).equals(jsonObject.query("/object2/array1/2/array2/2"))); - assertTrue("expected 8", Integer.valueOf(8).equals(jsonObject.query("/object2/array1/2/array2/3"))); - assertTrue("expected 3", Integer.valueOf(3).equals(jsonObject.query("/object2/array1/3"))); - assertTrue("expected 4", Integer.valueOf(4).equals(jsonObject.query("/object2/array1/4"))); + assertTrue("expected true", Boolean.TRUE.equals(jsonObject.get("trueValue"))); + assertTrue("expected false", Boolean.FALSE.equals(jsonObject.get("falseValue"))); + assertTrue("expected null", JSONObject.NULL.equals(jsonObject.get("nullValue"))); + assertTrue("expected hello world!", "hello world!".equals(jsonObject.get("stringValue"))); + assertTrue("expected 42", Integer.valueOf(42).equals(jsonObject.get("intValue"))); + assertTrue("expected -23.45e67", BigDecimal.valueOf(-23.45e67).equals(jsonObject.get("doubleValue"))); + assertTrue("expected h\be\tllo w\u1234orld!", "h\be\tllo w\u1234orld!".equals(jsonObject.get("complexStringValue"))); + assertTrue("expected v1", "v1".equals(jsonObject.getJSONObject("object2").get("k1"))); + assertTrue("expected v2", "v2".equals(jsonObject.getJSONObject("object2").get("k2"))); + assertTrue("expected v3", "v3".equals(jsonObject.getJSONObject("object2").get("k3"))); + assertTrue("expected 1", Integer.valueOf(1).equals(jsonObject.getJSONObject("object2").getJSONArray("array1").get(0))); + assertTrue("expected 2", Integer.valueOf(2).equals(jsonObject.getJSONObject("object2").getJSONArray("array1").get(1))); + assertTrue("expected v4", "v4".equals(jsonObject.getJSONObject("object2").getJSONArray("array1").getJSONObject(2).get("k4"))); + assertTrue("expected v5", "v5".equals(jsonObject.getJSONObject("object2").getJSONArray("array1").getJSONObject(2).get("k5"))); + assertTrue("expected v6", "v6".equals(jsonObject.getJSONObject("object2").getJSONArray("array1").getJSONObject(2).get("k6"))); + assertTrue("expected 5", Integer.valueOf(5).equals(jsonObject.getJSONObject("object2").getJSONArray("array1").getJSONObject(2).getJSONArray("array2").get(0))); + assertTrue("expected 6", Integer.valueOf(6).equals(jsonObject.getJSONObject("object2").getJSONArray("array1").getJSONObject(2).getJSONArray("array2").get(1))); + assertTrue("expected 7", Integer.valueOf(7).equals(jsonObject.getJSONObject("object2").getJSONArray("array1").getJSONObject(2).getJSONArray("array2").get(2))); + assertTrue("expected 8", Integer.valueOf(8).equals(jsonObject.getJSONObject("object2").getJSONArray("array1").getJSONObject(2).getJSONArray("array2").get(3))); + assertTrue("expected 3", Integer.valueOf(3).equals(jsonObject.getJSONObject("object2").getJSONArray("array1").get(3))); + assertTrue("expected 4", Integer.valueOf(4).equals(jsonObject.getJSONObject("object2").getJSONArray("array1").get(4))); } } diff --git a/src/test/java/org/json/junit/JSONTokenerTest.java b/src/test/java/org/json/junit/JSONTokenerTest.java index b0b45cb7c..cba364158 100644 --- a/src/test/java/org/json/junit/JSONTokenerTest.java +++ b/src/test/java/org/json/junit/JSONTokenerTest.java @@ -15,6 +15,7 @@ import java.io.InputStreamReader; import java.io.Reader; import java.io.StringReader; +import java.io.UncheckedIOException; import org.json.*; import org.junit.Test; @@ -32,23 +33,24 @@ public class JSONTokenerTest { */ @Test public void verifyBackFailureZeroIndex() throws IOException { - Reader reader = new StringReader("some test string"); + Reader reader = new StringReader("some test string"); try { final JSONTokener tokener = new JSONTokener(reader); try { // this should fail since the index is 0; tokener.back(); fail("Expected an exception"); - } catch (JSONException e) { + } catch (IllegalStateException e) { assertEquals("Stepping back two steps is not supported", e.getMessage()); } catch (Exception e) { - fail("Unknown Exception type " + e.getClass().getCanonicalName()+" with message "+e.getMessage()); + fail("Unknown Exception type " + e.getClass().getCanonicalName() + " with message " + e.getMessage()); } - + } finally { reader.close(); } } + /** * verify that back() fails as expected. * @throws IOException thrown if something unexpected happens. @@ -64,37 +66,37 @@ public void verifyBackFailureDoubleBack() throws IOException { // this should fail since the index is 0; tokener.back(); fail("Expected an exception"); - } catch (JSONException e) { + } catch (IllegalStateException e) { assertEquals("Stepping back two steps is not supported", e.getMessage()); } catch (Exception e) { - fail("Unknown Exception type " + e.getClass().getCanonicalName()+" with message "+e.getMessage()); + fail("Unknown Exception type " + e.getClass().getCanonicalName() + " with message " + e.getMessage()); } - } finally { - reader.close(); - } + } finally { + reader.close(); + } } - + @Test public void testValid() { - checkValid("0",Number.class); - checkValid(" 0 ",Number.class); - checkValid("23",Number.class); - checkValid("23.5",Number.class); - checkValid(" 23.5 ",Number.class); - checkValid("null",null); - checkValid(" null ",null); - checkValid("true",Boolean.class); - checkValid(" true\n",Boolean.class); - checkValid("false",Boolean.class); - checkValid("\nfalse ",Boolean.class); - checkValid("{}",JSONObject.class); - checkValid(" {} ",JSONObject.class); - checkValid("{\"a\":1}",JSONObject.class); - checkValid(" {\"a\":1} ",JSONObject.class); - checkValid("[]",JSONArray.class); - checkValid(" [] ",JSONArray.class); - checkValid("[1,2]",JSONArray.class); - checkValid("\n\n[1,2]\n\n",JSONArray.class); + checkValid("0", Number.class); + checkValid(" 0 ", Number.class); + checkValid("23", Number.class); + checkValid("23.5", Number.class); + checkValid(" 23.5 ", Number.class); + checkValid("null", null); + checkValid(" null ", null); + checkValid("true", Boolean.class); + checkValid(" true\n", Boolean.class); + checkValid("false", Boolean.class); + checkValid("\nfalse ", Boolean.class); + checkValid("{}", JSONObject.class); + checkValid(" {} ", JSONObject.class); + checkValid("{\"a\":1}", JSONObject.class); + checkValid(" {\"a\":1} ", JSONObject.class); + checkValid("[]", JSONArray.class); + checkValid(" [] ", JSONArray.class); + checkValid("[1,2]", JSONArray.class); + checkValid("\n\n[1,2]\n\n", JSONArray.class); // Test should fail if default strictMode is true, pass if false JSONParserConfiguration jsonParserConfiguration = new JSONParserConfiguration(); @@ -102,12 +104,12 @@ public void testValid() { try { checkValid("1 2", String.class); assertEquals("Expected to throw exception due to invalid string", true, false); - } catch (JSONException e) { } + } catch (IllegalArgumentException e) { } } else { checkValid("1 2", String.class); } } - + @Test public void testErrors() { // Check that stream can detect that a value is found after @@ -116,83 +118,81 @@ public void testErrors() { checkError("null \"a\""); checkError("{} true"); } - - private Object checkValid(String testStr, Class aClass) { + + private Object checkValid(String testStr, Class aClass) { Object result = nextValue(testStr); // Check class of object returned - if( null == aClass ) { - if(JSONObject.NULL.equals(result)) { + if (null == aClass) { + if (JSONObject.NULL.equals(result)) { // OK } else { - throw new JSONException("Unexpected class: "+result.getClass().getSimpleName()); + throw new IllegalArgumentException("Unexpected class: " + result.getClass().getSimpleName()); } } else { - if( null == result ) { - throw new JSONException("Unexpected null result"); - } else if(!aClass.isAssignableFrom(result.getClass()) ) { - throw new JSONException("Unexpected class: "+result.getClass().getSimpleName()); + if (null == result) { + throw new IllegalArgumentException("Unexpected null result"); + } else if (!aClass.isAssignableFrom(result.getClass())) { + throw new IllegalArgumentException("Unexpected class: " + result.getClass().getSimpleName()); } } - + return result; } private void checkError(String testStr) { try { nextValue(testStr); - - fail("Error should be triggered: (\""+testStr+"\")"); - } catch (JSONException e) { + + fail("Error should be triggered: (\"" + testStr + "\")"); + } catch (IllegalArgumentException e) { // OK } } - + /** * Verifies that JSONTokener can read a stream that contains a value. After * the reading is done, check that the stream is left in the correct state * by reading the characters after. All valid cases should reach end of stream. * @param testStr * @return - * @throws Exception */ - private Object nextValue(String testStr) throws JSONException { + private Object nextValue(String testStr) { StringReader sr = new StringReader(testStr); try { JSONTokener tokener = new JSONTokener(sr); - + Object result = tokener.nextValue(); - - if( result == null ) { - throw new JSONException("Unable to find value token in JSON stream: ("+tokener+"): "+testStr); + + if (result == null) { + throw new IllegalArgumentException("Unable to find value token in JSON stream: (" + tokener + "): " + testStr); } - + char c = tokener.nextClean(); - if( 0 != c ) { - throw new JSONException("Unexpected character found at end of JSON stream: "+c+ " ("+tokener+"): "+testStr); + if (0 != c) { + throw new IllegalArgumentException("Unexpected character found at end of JSON stream: " + c + " (" + tokener + "): " + testStr); } - + return result; } finally { sr.close(); } - } - + /** * Tests the failure of the skipTo method with a buffered reader. Preferably * we'd like this not to fail but at this time we don't have a good recovery. - * + * * @throws IOException thrown if something unexpected happens. */ @Test public void testSkipToFailureWithBufferedReader() throws IOException { final byte[] superLongBuffer = new byte[1000001]; // fill our buffer - for(int i=0;i\n"+ - "\n"+ - "
    \n"+ - " \n"+ - " abc street\n"+ - "
    \n"+ - "
    "; - try { - XML.toJSONObject(xmlStr, XMLParserConfiguration.KEEP_STRINGS); - fail("Expecting a JSONException"); - } catch (JSONException e) { - assertEquals("Expecting an exception message", - "Misshaped tag at 176 [character 14 line 4]", - e.getMessage()); - } - } - - /** - * Invalid XML string ('!' char in tag) - * Expects a JSONException - */ - @Test - public void shouldHandleInvalidBangInTag() { - String xmlStr = - "\n"+ - "\n"+ - "
    \n"+ - " \n"+ - " \n"+ - "
    \n"+ - "
    "; - try { - XML.toJSONObject(xmlStr, XMLParserConfiguration.KEEP_STRINGS); - fail("Expecting a JSONException"); - } catch (JSONException e) { - assertEquals("Expecting an exception message", - "Misshaped meta tag at 214 [character 12 line 7]", - e.getMessage()); - } - } - - /** - * Invalid XML string ('!' char and no closing tag brace) - * Expects a JSONException - */ - @Test - public void shouldHandleInvalidBangNoCloseInTag() { - String xmlStr = - "\n"+ - "\n"+ - "
    \n"+ - " \n"+ - " \n"+ - ""; - try { - XML.toJSONObject(xmlStr, XMLParserConfiguration.KEEP_STRINGS); - fail("Expecting a JSONException"); - } catch (JSONException e) { - assertEquals("Expecting an exception message", - "Misshaped meta tag at 213 [character 12 line 7]", - e.getMessage()); - } - } - - /** - * Invalid XML string (no end brace for tag) - * Expects JSONException - */ - @Test - public void shouldHandleNoCloseStartTag() { - String xmlStr = - "\n"+ - "\n"+ - "
    \n"+ - " \n"+ - " \n"+ - ""; - try { - XML.toJSONObject(xmlStr, XMLParserConfiguration.KEEP_STRINGS); - fail("Expecting a JSONException"); - } catch (JSONException e) { - assertEquals("Expecting an exception message", - "Misplaced '<' at 193 [character 4 line 6]", - e.getMessage()); - } - } - - /** - * Invalid XML string (partial CDATA chars in tag name) - * Expects JSONException - */ - @Test - public void shouldHandleInvalidCDATABangInTag() { - String xmlStr = - "\n"+ - "\n"+ - "
    \n"+ - " Joe Tester\n"+ - " \n"+ - "
    \n"+ - "
    "; - try { - XMLParserConfiguration config = - new XMLParserConfiguration().withcDataTagName("altContent"); - XML.toJSONObject(xmlStr, config); - fail("Expecting a JSONException"); - } catch (JSONException e) { - assertEquals("Expecting an exception message", - "Expected 'CDATA[' at 204 [character 11 line 5]", - e.getMessage()); - } - } - - /** - * Null JSONObject in XML.toString() - */ - @Test - public void shouldHandleNullJSONXML() { - JSONObject jsonObject= null; - String actualXml = XML.toString(jsonObject, null, - XMLParserConfiguration.KEEP_STRINGS); - assertEquals("generated XML does not equal expected XML","\"null\"",actualXml); - } - - /** - * Empty JSONObject in XML.toString() - */ - @Test - public void shouldHandleEmptyJSONXML() { - JSONObject jsonObject= new JSONObject(); - String xmlStr = XML.toString(jsonObject, null, - XMLParserConfiguration.KEEP_STRINGS); - assertTrue("xml string should be empty", xmlStr.isEmpty()); - } - - /** - * No SML start tag. The ending tag ends up being treated as content. - */ - @Test - public void shouldHandleNoStartTag() { - String xmlStr = - "\n"+ - "\n"+ - "
    \n"+ - " \n"+ - " >\n"+ - "
    \n"+ - "
    "; - String expectedStr = - "{\"addresses\":{\"address\":{\"name\":\"\",\"nocontent\":\"\",\""+ - "content\":\">\"},\"xsi:noNamespaceSchemaLocation\":\"test.xsd\",\""+ - "xmlns:xsi\":\"http://www.w3.org/2001/XMLSchema-instance\"}}"; - JSONObject jsonObject = XML.toJSONObject(xmlStr, - XMLParserConfiguration.KEEP_STRINGS); - JSONObject expectedJsonObject = new JSONObject(expectedStr); - Util.compareActualVsExpectedJsonObjects(jsonObject,expectedJsonObject); - } - - /** - * Valid XML to JSONObject - */ - @Test - public void shouldHandleSimpleXML() { - String xmlStr = - "\n"+ - "\n"+ - "
    \n"+ - " Joe Tester\n"+ - " [CDATA[Baker street 5]\n"+ - " \n"+ - " true\n"+ - " false\n"+ - " null\n"+ - " 42\n"+ - " -23\n"+ - " -23.45\n"+ - " -23x.45\n"+ - " 1, 2, 3, 4.1, 5.2\n"+ - "
    \n"+ - "
    "; - - String expectedStr = - "{\"addresses\":{\"address\":{\"street\":\"[CDATA[Baker street 5]\","+ - "\"name\":\"Joe Tester\",\"NothingHere\":\"\",\"TrueValue\":true,\n"+ - "\"FalseValue\":false,\"NullValue\":null,\"PositiveValue\":42,\n"+ - "\"NegativeValue\":-23,\"DoubleValue\":-23.45,\"Nan\":\"-23x.45\",\n"+ - "\"ArrayOfNum\":\"1, 2, 3, 4.1, 5.2\"\n"+ - "},\"xsi:noNamespaceSchemaLocation\":"+ - "\"test.xsd\",\"xmlns:xsi\":\"http://www.w3.org/2001/"+ - "XMLSchema-instance\"}}"; - - XMLParserConfiguration config = - new XMLParserConfiguration().withcDataTagName("altContent"); - compareStringToJSONObject(xmlStr, expectedStr, config); - compareReaderToJSONObject(xmlStr, expectedStr, config); - compareFileToJSONObject(xmlStr, expectedStr); - } - - /** - * Valid XML with comments to JSONObject - */ - @Test - public void shouldHandleCommentsInXML() { - - String xmlStr = - "\n"+ - "\n"+ - "\n"+ - "
    \n"+ - " comment ]]>\n"+ - " Joe Tester\n"+ - " \n"+ - " Baker street 5\n"+ - "
    \n"+ - "
    "; - XMLParserConfiguration config = - new XMLParserConfiguration().withcDataTagName("altContent"); - JSONObject jsonObject = XML.toJSONObject(xmlStr, config); - String expectedStr = "{\"addresses\":{\"address\":{\"street\":\"Baker "+ - "street 5\",\"name\":\"Joe Tester\",\"altContent\":\" this is -- "+ - " comment \"}}}"; - JSONObject expectedJsonObject = new JSONObject(expectedStr); - Util.compareActualVsExpectedJsonObjects(jsonObject,expectedJsonObject); - } - - /** - * Valid XML to XML.toString() - */ - @Test - public void shouldHandleToString() { - String xmlStr = - "\n"+ - "\n"+ - "
    \n"+ - " [CDATA[Joe & T > e < s " t ' er]]\n"+ - " Baker street 5\n"+ - " 1, 2, 3, 4.1, 5.2\n"+ - "
    \n"+ - "
    "; - - String expectedStr = - "{\"addresses\":{\"address\":{\"street\":\"Baker street 5\","+ - "\"name\":\"[CDATA[Joe & T > e < s \\\" t \\\' er]]\","+ - "\"ArrayOfNum\":\"1, 2, 3, 4.1, 5.2\"\n"+ - "},\"xsi:noNamespaceSchemaLocation\":"+ - "\"test.xsd\",\"xmlns:xsi\":\"http://www.w3.org/2001/"+ - "XMLSchema-instance\"}}"; - - JSONObject jsonObject = XML.toJSONObject(xmlStr, - XMLParserConfiguration.KEEP_STRINGS); - String xmlToStr = XML.toString(jsonObject, null, - XMLParserConfiguration.KEEP_STRINGS); - JSONObject finalJsonObject = XML.toJSONObject(xmlToStr, - XMLParserConfiguration.KEEP_STRINGS); - JSONObject expectedJsonObject = new JSONObject(expectedStr); - Util.compareActualVsExpectedJsonObjects(jsonObject,expectedJsonObject); - Util.compareActualVsExpectedJsonObjects(finalJsonObject,expectedJsonObject); - } - - /** - * Converting a JSON doc containing '>' content to JSONObject, then - * XML.toString() should result in valid XML. - */ - @Test - public void shouldHandleContentNoArraytoString() { - String expectedStr = - "{\"addresses\":{\"altContent\":\">\"}}"; - JSONObject expectedJsonObject = new JSONObject(expectedStr); - XMLParserConfiguration config = new XMLParserConfiguration().withcDataTagName("altContent"); - String finalStr = XML.toString(expectedJsonObject, null, config); - String expectedFinalStr = ">"; - assertTrue("Should handle expectedFinal: ["+expectedStr+"] final: ["+ - finalStr+"]", expectedFinalStr.equals(finalStr)); - } - - /** - * Converting a JSON doc containing a 'content' array to JSONObject, then - * XML.toString() should result in valid XML. - * TODO: This is probably an error in how the 'content' keyword is used. - */ - @Test - public void shouldHandleContentArraytoString() { - String expectedStr = - "{\"addresses\":{\"altContent\":[1, 2, 3]}}"; - JSONObject expectedJsonObject = new JSONObject(expectedStr); - XMLParserConfiguration config = new XMLParserConfiguration().withcDataTagName("altContent"); - String finalStr = XML.toString(expectedJsonObject, null, config); - String expectedFinalStr = ""+ - "1\n2\n3"+ - ""; - assertTrue("Should handle expectedFinal: ["+expectedStr+"] final: ["+ - finalStr+"]", expectedFinalStr.equals(finalStr)); - } - - /** - * Converting a JSON doc containing a named array to JSONObject, then - * XML.toString() should result in valid XML. - */ - @Test - public void shouldHandleArraytoString() { - String expectedStr = - "{\"addresses\":{"+ - "\"something\":[1, 2, 3]}}"; - JSONObject expectedJsonObject = new JSONObject(expectedStr); - String finalStr = XML.toString(expectedJsonObject, null, - XMLParserConfiguration.KEEP_STRINGS); - String expectedFinalStr = ""+ - "123"+ - ""; - assertTrue("Should handle expectedFinal: ["+expectedStr+"] final: ["+ - finalStr+"]", expectedFinalStr.equals(finalStr)); - } - - /** - * Tests that the XML output for empty arrays is consistent. - */ - @Test - public void shouldHandleEmptyArray(){ - final JSONObject jo1 = new JSONObject(); - jo1.put("array",new Object[]{}); - final JSONObject jo2 = new JSONObject(); - jo2.put("array",new JSONArray()); - - final String expected = ""; - String output1 = XML.toString(jo1, "jo", - XMLParserConfiguration.KEEP_STRINGS); - assertEquals("Expected an empty root tag", expected, output1); - String output2 = XML.toString(jo2, "jo", - XMLParserConfiguration.KEEP_STRINGS); - assertEquals("Expected an empty root tag", expected, output2); - } - - /** - * Tests that the XML output for arrays is consistent when an internal array is empty. - */ - @Test - public void shouldHandleEmptyMultiArray(){ - final JSONObject jo1 = new JSONObject(); - jo1.put("arr",new Object[]{"One", new String[]{}, "Four"}); - final JSONObject jo2 = new JSONObject(); - jo2.put("arr",new JSONArray(new Object[]{"One", new JSONArray(new String[]{}), "Four"})); - - final String expected = "OneFour"; - String output1 = XML.toString(jo1, "jo", - XMLParserConfiguration.KEEP_STRINGS); - assertEquals("Expected a matching array", expected, output1); - String output2 = XML.toString(jo2, "jo", - XMLParserConfiguration.KEEP_STRINGS); - - assertEquals("Expected a matching array", expected, output2); - } - - /** - * Tests that the XML output for arrays is consistent when arrays are not empty. - */ - @Test - public void shouldHandleNonEmptyArray(){ - final JSONObject jo1 = new JSONObject(); - jo1.put("arr",new String[]{"One", "Two", "Three"}); - final JSONObject jo2 = new JSONObject(); - jo2.put("arr",new JSONArray(new String[]{"One", "Two", "Three"})); - - final String expected = "OneTwoThree"; - String output1 = XML.toString(jo1, "jo", - XMLParserConfiguration.KEEP_STRINGS); - assertEquals("Expected a non empty root tag", expected, output1); - String output2 = XML.toString(jo2, "jo", - XMLParserConfiguration.KEEP_STRINGS); - assertEquals("Expected a non empty root tag", expected, output2); - } - - /** - * Tests that the XML output for arrays is consistent when arrays are not empty and contain internal arrays. - */ - @Test - public void shouldHandleMultiArray(){ - final JSONObject jo1 = new JSONObject(); - jo1.put("arr",new Object[]{"One", new String[]{"Two", "Three"}, "Four"}); - final JSONObject jo2 = new JSONObject(); - jo2.put("arr",new JSONArray(new Object[]{"One", new JSONArray(new String[]{"Two", "Three"}), "Four"})); - - final String expected = "OneTwoThreeFour"; - String output1 = XML.toString(jo1, "jo", - XMLParserConfiguration.KEEP_STRINGS); - assertEquals("Expected a matching array", expected, output1); - String output2 = XML.toString(jo2, "jo", - XMLParserConfiguration.KEEP_STRINGS); - assertEquals("Expected a matching array", expected, output2); - } - - /** - * Converting a JSON doc containing a named array of nested arrays to - * JSONObject, then XML.toString() should result in valid XML. - */ - @Test - public void shouldHandleNestedArraytoString() { - String xmlStr = - "{\"addresses\":{\"address\":{\"name\":\"\",\"nocontent\":\"\","+ - "\"outer\":[[1], [2], [3]]},\"xsi:noNamespaceSchemaLocation\":\"test.xsd\",\""+ - "xmlns:xsi\":\"http://www.w3.org/2001/XMLSchema-instance\"}}"; - JSONObject jsonObject = new JSONObject(xmlStr); - String finalStr = XML.toString(jsonObject, null, - XMLParserConfiguration.ORIGINAL); - JSONObject finalJsonObject = XML.toJSONObject(finalStr); - String expectedStr = "
    "+ - "12"+ - "3"+ - "
    test.xsdhttp://www.w3.org/2001/XMLSche"+ - "ma-instance
    "; - JSONObject expectedJsonObject = XML.toJSONObject(expectedStr, - XMLParserConfiguration.ORIGINAL); - Util.compareActualVsExpectedJsonObjects(finalJsonObject,expectedJsonObject); - } - - - /** - * Possible bug: - * Illegal node-names must be converted to legal XML-node-names. - * The given example shows 2 nodes which are valid for JSON, but not for XML. - * Therefore illegal arguments should be converted to e.g. an underscore (_). - */ - @Test - public void shouldHandleIllegalJSONNodeNames() - { - JSONObject inputJSON = new JSONObject(); - inputJSON.append("123IllegalNode", "someValue1"); - inputJSON.append("Illegal@node", "someValue2"); - - String result = XML.toString(inputJSON, null, - XMLParserConfiguration.KEEP_STRINGS); - - /* - * This is invalid XML. Names should not begin with digits or contain - * certain values, including '@'. One possible solution is to replace - * illegal chars with '_', in which case the expected output would be: - * <___IllegalNode>someValue1someValue2 - */ - String expected = "<123IllegalNode>someValue1someValue2"; - - assertEquals("Length", expected.length(), result.length()); - assertTrue("123IllegalNode", result.contains("<123IllegalNode>someValue1")); - assertTrue("Illegal@node", result.contains("someValue2")); - } - - /** - * JSONObject with NULL value, to XML.toString() - */ - @Test - public void shouldHandleNullNodeValue() - { - JSONObject inputJSON = new JSONObject(); - inputJSON.put("nullValue", JSONObject.NULL); - // This is a possible preferred result - // String expectedXML = ""; - /** - * This is the current behavior. JSONObject.NULL is emitted as - * the string, "null". - */ - String actualXML = "null"; - String resultXML = XML.toString(inputJSON, null, - XMLParserConfiguration.KEEP_STRINGS); - assertEquals(actualXML, resultXML); - } - - @Test - public void shouldHandleEmptyNodeValue() - { - JSONObject inputJSON = new JSONObject(); - inputJSON.put("Emptyness", ""); - String expectedXmlWithoutExplicitEndTag = ""; - String expectedXmlWithExplicitEndTag = ""; - assertEquals(expectedXmlWithoutExplicitEndTag, XML.toString(inputJSON, null, - new XMLParserConfiguration().withCloseEmptyTag(false))); - assertEquals(expectedXmlWithExplicitEndTag, XML.toString(inputJSON, null, - new XMLParserConfiguration().withCloseEmptyTag(true))); - } - - @Test - public void shouldKeepConfigurationIntactAndUpdateCloseEmptyTagChoice() - { - XMLParserConfiguration keepStrings = XMLParserConfiguration.KEEP_STRINGS; - XMLParserConfiguration keepStringsAndCloseEmptyTag = keepStrings.withCloseEmptyTag(true); - XMLParserConfiguration keepDigits = keepStringsAndCloseEmptyTag.withKeepStrings(false); - XMLParserConfiguration keepDigitsAndNoCloseEmptyTag = keepDigits.withCloseEmptyTag(false); - assertTrue(keepStrings.isKeepNumberAsString()); - assertTrue(keepStrings.isKeepBooleanAsString()); - assertFalse(keepStrings.isCloseEmptyTag()); - assertTrue(keepStringsAndCloseEmptyTag.isKeepNumberAsString()); - assertTrue(keepStringsAndCloseEmptyTag.isKeepBooleanAsString()); - assertTrue(keepStringsAndCloseEmptyTag.isCloseEmptyTag()); - assertFalse(keepDigits.isKeepNumberAsString()); - assertFalse(keepDigits.isKeepBooleanAsString()); - assertTrue(keepDigits.isCloseEmptyTag()); - assertFalse(keepDigitsAndNoCloseEmptyTag.isKeepNumberAsString()); - assertFalse(keepDigitsAndNoCloseEmptyTag.isKeepBooleanAsString()); - assertFalse(keepDigitsAndNoCloseEmptyTag.isCloseEmptyTag()); - } - - /** - * Investigate exactly how the "content" keyword works - */ - @Test - public void contentOperations() { - /* - * When a standalone 0) then return]]>"; - JSONObject jsonObject = XML.toJSONObject(xmlStr, - XMLParserConfiguration.KEEP_STRINGS); - assertTrue("1. 3 items", 3 == jsonObject.length()); - assertTrue("1. empty tag1", "".equals(jsonObject.get("tag1"))); - assertTrue("1. empty tag2", "".equals(jsonObject.get("tag2"))); - assertTrue("1. content found", "if (a < b && a > 0) then return".equals(jsonObject.get("content"))); - - // multiple consecutive standalone cdatas are accumulated into an array - xmlStr = " 0) then return]]>"; - jsonObject = XML.toJSONObject(xmlStr, - new XMLParserConfiguration() - .withKeepStrings(true) - .withcDataTagName("altContent")); - assertTrue("2. 3 items", 3 == jsonObject.length()); - assertTrue("2. empty tag1", "".equals(jsonObject.get("tag1"))); - assertTrue("2. empty tag2", "".equals(jsonObject.get("tag2"))); - assertTrue("2. content array found", jsonObject.get("altContent") instanceof JSONArray); - JSONArray jsonArray = jsonObject.getJSONArray("altContent"); - assertTrue("2. array size", jsonArray.length() == 2); - assertTrue("2. content array entry 0", "if (a < b && a > 0) then return".equals(jsonArray.get(0))); - assertTrue("2. content array entry 1", "here is another cdata".equals(jsonArray.get(1))); - - /* - * text content is accumulated in a "content" inside a local JSONObject. - * If there is only one instance, it is saved in the context (a different JSONObject - * from the calling code. and the content element is discarded. - */ - xmlStr = "value 1"; - jsonObject = XML.toJSONObject(xmlStr, - new XMLParserConfiguration() - .withKeepStrings(true) - .withcDataTagName("altContent")); - assertTrue("3. 2 items", 1 == jsonObject.length()); - assertTrue("3. value tag1", "value 1".equals(jsonObject.get("tag1"))); - - /* - * array-style text content (multiple tags with the same name) is - * accumulated in a local JSONObject with key="content" and value=JSONArray, - * saved in the context, and then the local JSONObject is discarded. - */ - xmlStr = "value 12true"; - jsonObject = XML.toJSONObject(xmlStr, - new XMLParserConfiguration() - .withKeepStrings(true) - .withcDataTagName("altContent")); - assertTrue("4. 1 item", 1 == jsonObject.length()); - assertTrue("4. content array found", jsonObject.get("tag1") instanceof JSONArray); - jsonArray = jsonObject.getJSONArray("tag1"); - assertTrue("4. array size", jsonArray.length() == 3); - assertTrue("4. content array entry 0", "value 1".equals(jsonArray.get(0))); - assertTrue("4. content array entry 1", jsonArray.getInt(1) == 2); - assertTrue("4. content array entry 2", jsonArray.getBoolean(2) == true); - - /* - * Complex content is accumulated in a "content" field. For example, an element - * may contain a mix of child elements and text. Each text segment is - * accumulated to content. - */ - xmlStr = "val1val2"; - jsonObject = XML.toJSONObject(xmlStr, - new XMLParserConfiguration() - .withKeepStrings(true) - .withcDataTagName("altContent")); - assertTrue("5. 1 item", 1 == jsonObject.length()); - assertTrue("5. jsonObject found", jsonObject.get("tag1") - instanceof JSONObject); - jsonObject = jsonObject.getJSONObject("tag1"); - assertTrue("5. 2 contained items", 2 == jsonObject.length()); - assertTrue("5. contained tag", "".equals(jsonObject.get("tag2"))); - assertTrue("5. contained content jsonArray found", - jsonObject.get("altContent") instanceof JSONArray); - jsonArray = jsonObject.getJSONArray("altContent"); - assertTrue("5. array size", jsonArray.length() == 2); - assertTrue("5. content array entry 0", "val1".equals(jsonArray.get(0))); - assertTrue("5. content array entry 1", "val2".equals(jsonArray.get(1))); - - /* - * If there is only 1 complex text content, then it is accumulated in a - * "content" field as a string. - */ - xmlStr = "val1"; - jsonObject = XML.toJSONObject(xmlStr, - new XMLParserConfiguration() - .withKeepStrings(true) - .withcDataTagName("altContent")); - assertTrue("6. 1 item", 1 == jsonObject.length()); - assertTrue("6. jsonObject found", jsonObject.get("tag1") instanceof JSONObject); - jsonObject = jsonObject.getJSONObject("tag1"); - assertTrue("6. contained content found", - "val1".equals(jsonObject.get("altContent"))); - assertTrue("6. contained tag2", "".equals(jsonObject.get("tag2"))); - - /* - * In this corner case, the content sibling happens to have key=content - * We end up with an array within an array, and no content element. - * This is probably a bug. - */ - xmlStr = "val1"; - jsonObject = XML.toJSONObject(xmlStr, - new XMLParserConfiguration() - .withKeepStrings(true) - .withcDataTagName("altContent")); - assertTrue("7. 1 item", 1 == jsonObject.length()); - assertTrue("7. jsonArray found", - jsonObject.get("tag1") instanceof JSONArray); - jsonArray = jsonObject.getJSONArray("tag1"); - assertTrue("array size 1", jsonArray.length() == 1); - assertTrue("7. contained array found", jsonArray.get(0) - instanceof JSONArray); - jsonArray = jsonArray.getJSONArray(0); - assertTrue("7. inner array size 2", jsonArray.length() == 2); - assertTrue("7. inner array item 0", "val1".equals(jsonArray.get(0))); - assertTrue("7. inner array item 1", "".equals(jsonArray.get(1))); - - /* - * Confirm behavior of original issue - */ - String jsonStr = - "{"+ - "\"Profile\": {"+ - "\"list\": {"+ - "\"history\": {"+ - "\"entries\": ["+ - "{"+ - "\"deviceId\": \"id\","+ - "\"altContent\": {"+ - "\"material\": ["+ - "{"+ - "\"stuff\": false"+ - "}"+ - "]"+ - "}"+ - "}"+ - "]"+ - "}"+ - "}"+ - "}"+ - "}"; - jsonObject = new JSONObject(jsonStr); - xmlStr = XML.toString(jsonObject, null, - new XMLParserConfiguration() - .withKeepStrings(true) - .withcDataTagName("altContent")); - /* - * This is the created XML. Looks like content was mistaken for - * complex (child node + text) XML. - * - * - * - * - * id - * {"material":[{"stuff":false}]} - * - * - * - * - */ - assertTrue("nothing to test here, see comment on created XML, above", true); - } - - /** - * JSON string lost leading zero and converted "True" to true. - */ - @Test - public void testToJSONArray_jsonOutput() { - final String originalXml = "011000True"; - final JSONObject expected = new JSONObject("{\"root\":{\"item\":{\"id\":\"01\"},\"id\":[\"01\",1,\"00\",0],\"title\":true}}"); - final JSONObject actualJsonOutput = XML.toJSONObject(originalXml, - new XMLParserConfiguration().withKeepStrings(false)); - Util.compareActualVsExpectedJsonObjects(actualJsonOutput,expected); - } - - /** - * JSON string lost leading zero and converted "True" to true. - */ - @Test - public void testToJSONArray_jsonOutput_withKeepNumberAsString() { - final String originalXml = "011000nullTrue"; - final JSONObject expected = new JSONObject("{\"root\":{\"item\":{\"id\":\"01\"},\"id\":[\"01\",\"1\",\"00\",\"0\",null],\"title\":true}}"); - final JSONObject actualJsonOutput = XML.toJSONObject(originalXml, - new XMLParserConfiguration().withKeepNumberAsString(true)); - Util.compareActualVsExpectedJsonObjects(actualJsonOutput,expected); - } - - /** - * JSON string lost leading zero and converted "True" to true. - */ - @Test - public void testToJSONArray_jsonOutput_withKeepBooleanAsString() { - final String originalXml = "011000nullTrue"; - final JSONObject expected = new JSONObject("{\"root\":{\"item\":{\"id\":\"01\"},\"id\":[\"01\",1,\"00\",0,null],\"title\":\"True\"}}"); - final JSONObject actualJsonOutput = XML.toJSONObject(originalXml, - new XMLParserConfiguration().withKeepBooleanAsString(true)); - Util.compareActualVsExpectedJsonObjects(actualJsonOutput,expected); - } - - /** - * null is "null" when keepStrings == true - */ - @Test - public void testToJSONArray_jsonOutput_null_withKeepString() { - final String originalXml = "011000null"; - final JSONObject expected = new JSONObject("{\"root\":{\"item\":{\"id\":\"01\"},\"id\":[\"01\",\"1\",\"00\",\"0\"],\"title\":\"null\"}}"); - final JSONObject actualJsonOutput = XML.toJSONObject(originalXml, - new XMLParserConfiguration().withKeepStrings(true)); - Util.compareActualVsExpectedJsonObjects(actualJsonOutput,expected); - } - - /** - * Test keepStrings behavior when setting keepBooleanAsString, keepNumberAsString - */ - @Test - public void test_keepStringBehavior() { - XMLParserConfiguration xpc = new XMLParserConfiguration().withKeepStrings(true); - assertEquals(xpc.isKeepStrings(), true); - - xpc = xpc.withKeepBooleanAsString(true); - xpc = xpc.withKeepNumberAsString(false); - assertEquals(xpc.isKeepStrings(), false); - - xpc = xpc.withKeepBooleanAsString(false); - xpc = xpc.withKeepNumberAsString(true); - assertEquals(xpc.isKeepStrings(), false); - - xpc = xpc.withKeepBooleanAsString(true); - xpc = xpc.withKeepNumberAsString(true); - assertEquals(xpc.isKeepStrings(), true); - - xpc = xpc.withKeepBooleanAsString(false); - xpc = xpc.withKeepNumberAsString(false); - assertEquals(xpc.isKeepStrings(), false); - } - - /** - * JSON string cannot be reverted to original xml. - */ - @Test - public void testToJSONArray_reversibility() { - final String originalXml = "011000True"; - XMLParserConfiguration config = new XMLParserConfiguration().withKeepStrings(false); - final String revertedXml = - XML.toString(XML.toJSONObject(originalXml, config), - null, config); - assertNotEquals(revertedXml, originalXml); - } - - /** - * test passes when using the new method toJsonArray. - */ - @Test - public void testToJsonXML() { - final String originalXml = "011000True"; - final JSONObject expected = new JSONObject("{\"root\":{\"item\":{\"id\":\"01\"},\"id\":[\"01\",\"1\",\"00\",\"0\"],\"title\":\"True\"}}"); - - final JSONObject json = XML.toJSONObject(originalXml, - new XMLParserConfiguration().withKeepStrings(true)); - Util.compareActualVsExpectedJsonObjects(json, expected); - - final String reverseXml = XML.toString(json); - // this reversal isn't exactly the same. use JSONML for an exact reversal - final String expectedReverseXml = "01011000True"; - - assertEquals("length",expectedReverseXml.length(), reverseXml.length()); - assertTrue("array contents", reverseXml.contains("011000")); - assertTrue("item contents", reverseXml.contains("01")); - assertTrue("title contents", reverseXml.contains("True")); - } - - /** - * test to validate certain conditions of XML unescaping. - */ - @Test - public void testUnescape() { - assertEquals("{\"xml\":\"Can cope <;\"}", - XML.toJSONObject("Can cope <; ", - XMLParserConfiguration.KEEP_STRINGS).toString()); - assertEquals("Can cope <; ", XML.unescape("Can cope <; ")); - - assertEquals("{\"xml\":\"Can cope & ;\"}", - XML.toJSONObject("Can cope & ; ", - XMLParserConfiguration.KEEP_STRINGS).toString()); - assertEquals("Can cope & ; ", XML.unescape("Can cope & ; ")); - - assertEquals("{\"xml\":\"Can cope &;\"}", - XML.toJSONObject("Can cope &; ", - XMLParserConfiguration.KEEP_STRINGS).toString()); - assertEquals("Can cope &; ", XML.unescape("Can cope &; ")); - - // unicode entity - assertEquals("{\"xml\":\"Can cope 4;\"}", - XML.toJSONObject("Can cope 4; ", - XMLParserConfiguration.KEEP_STRINGS).toString()); - assertEquals("Can cope 4; ", XML.unescape("Can cope 4; ")); - - // double escaped - assertEquals("{\"xml\":\"Can cope <\"}", - XML.toJSONObject("Can cope &lt; ", - XMLParserConfiguration.KEEP_STRINGS).toString()); - assertEquals("Can cope < ", XML.unescape("Can cope &lt; ")); - - assertEquals("{\"xml\":\"Can cope 4\"}", - XML.toJSONObject("Can cope &#x34; ", - XMLParserConfiguration.KEEP_STRINGS).toString()); - assertEquals("Can cope 4 ", XML.unescape("Can cope &#x34; ")); - - } - - /** - * Confirm XMLParserConfiguration functionality - */ - @Test - public void testConfig() { - /** - * 1st param is whether to keep the raw string, or call - * XML.stringToValue(), which may convert the token to - * boolean, null, or number. - * 2nd param is what JSON name to use for strings that are - * evaluated as xml content data in complex objects, e.g. - * - * value - * content data - * - */ - - String xmlStr = - "\n"+ - "\n"+ - "
    \n"+ - " content 1\n"+ - " Sherlock Holmes\n"+ - " content 2\n"+ - " Baker street 5\n"+ - " content 3\n"+ - " 1\n"+ - "
    \n"+ - "
    "; - - // keep strings, use the altContent tag - XMLParserConfiguration config = - new XMLParserConfiguration() - .withKeepStrings(true) - .withcDataTagName("altContent"); - JSONObject jsonObject = XML.toJSONObject(xmlStr, config); - // num is parsed as a string - assertEquals(jsonObject.getJSONObject("addresses"). - getJSONObject("address").getString("num"), "1"); - // complex content is collected in an 'altContent' array - JSONArray jsonArray = jsonObject.getJSONObject("addresses"). - getJSONObject("address").getJSONArray("altContent"); - String expectedStr = "[\"content 1\", \"content 2\", \"content 3\"]"; - JSONArray expectedJsonArray = new JSONArray(expectedStr); - Util.compareActualVsExpectedJsonArrays(jsonArray, expectedJsonArray); - - // keepstrings only - jsonObject = XML.toJSONObject(xmlStr, - XMLParserConfiguration.KEEP_STRINGS); - // num is parsed as a string - assertEquals(jsonObject.getJSONObject("addresses"). - getJSONObject("address").getString("num"), "1"); - // complex content is collected in an 'content' array - jsonArray = jsonObject.getJSONObject("addresses"). - getJSONObject("address").getJSONArray("content"); - expectedJsonArray = new JSONArray(expectedStr); - Util.compareActualVsExpectedJsonArrays(jsonArray, expectedJsonArray); - - // use alternate content name - config = new XMLParserConfiguration().withcDataTagName("altContent"); - jsonObject = XML.toJSONObject(xmlStr, config); - // num is parsed as a number - assertEquals(jsonObject.getJSONObject("addresses"). - getJSONObject("address").getInt("num"), 1); - // complex content is collected in an 'altContent' array - jsonArray = jsonObject.getJSONObject("addresses"). - getJSONObject("address").getJSONArray("altContent"); - expectedJsonArray = new JSONArray(expectedStr); - Util.compareActualVsExpectedJsonArrays(jsonArray, expectedJsonArray); - - } - - /** - * Test forceList parameter - */ - @Test - public void testSimpleForceList() { - String xmlStr = - "\n"+ - "\n"+ - "
    \n"+ - " Sherlock Holmes\n"+ - "
    \n"+ - "
    "; - - String expectedStr = - "{\"addresses\":[{\"address\":{\"name\":\"Sherlock Holmes\"}}]}"; - - Set forceList = new HashSet(); - forceList.add("addresses"); - - XMLParserConfiguration config = - new XMLParserConfiguration() - .withForceList(forceList); - JSONObject jsonObject = XML.toJSONObject(xmlStr, config); - JSONObject expetedJsonObject = new JSONObject(expectedStr); - - Util.compareActualVsExpectedJsonObjects(jsonObject, expetedJsonObject); - } - @Test - public void testLongForceList() { - String xmlStr = - ""+ - ""+ - "host1"+ - "Linux"+ - ""+ - ""+ - "em0"+ - "10.0.0.1"+ - ""+ - ""+ - ""+ - ""; - - String expectedStr = - "{"+ - "\"servers\": ["+ - "{"+ - "\"server\": {"+ - "\"name\": \"host1\","+ - "\"os\": \"Linux\","+ - "\"interfaces\": ["+ - "{"+ - "\"interface\": {"+ - "\"name\": \"em0\","+ - "\"ip_address\": \"10.0.0.1\""+ - "}}]}}]}"; - - Set forceList = new HashSet(); - forceList.add("servers"); - forceList.add("interfaces"); - - XMLParserConfiguration config = - new XMLParserConfiguration() - .withForceList(forceList); - JSONObject jsonObject = XML.toJSONObject(xmlStr, config); - JSONObject expetedJsonObject = new JSONObject(expectedStr); - - Util.compareActualVsExpectedJsonObjects(jsonObject, expetedJsonObject); - } - @Test - public void testMultipleTagForceList() { - String xmlStr = - "\n"+ - "
    \n"+ - " Sherlock Holmes\n"+ - " John H. Watson\n"+ - "
    \n"+ - "
    "; - - String expectedStr = - "{"+ - "\"addresses\":["+ - "{"+ - "\"address\":["+ - "{"+ - "\"name\":["+ - "\"Sherlock Holmes\","+ - "\"John H. Watson\""+ - "]"+ - "}"+ - "]"+ - "}"+ - "]"+ - "}"; - - Set forceList = new HashSet(); - forceList.add("addresses"); - forceList.add("address"); - forceList.add("name"); - - XMLParserConfiguration config = - new XMLParserConfiguration() - .withForceList(forceList); - JSONObject jsonObject = XML.toJSONObject(xmlStr, config); - JSONObject expetedJsonObject = new JSONObject(expectedStr); - - Util.compareActualVsExpectedJsonObjects(jsonObject, expetedJsonObject); - } - @Test - public void testEmptyForceList() { - String xmlStr = - ""; - - String expectedStr = - "{\"addresses\":[\"\"]}"; - - Set forceList = new HashSet(); - forceList.add("addresses"); - - XMLParserConfiguration config = - new XMLParserConfiguration() - .withForceList(forceList); - JSONObject jsonObject = XML.toJSONObject(xmlStr, config); - JSONObject expetedJsonObject = new JSONObject(expectedStr); - - Util.compareActualVsExpectedJsonObjects(jsonObject, expetedJsonObject); - } - @Test - public void testContentForceList() { - String xmlStr = - "Baker Street"; - - String expectedStr = - "{\"addresses\":[\"Baker Street\"]}"; - - Set forceList = new HashSet(); - forceList.add("addresses"); - - XMLParserConfiguration config = - new XMLParserConfiguration() - .withForceList(forceList); - JSONObject jsonObject = XML.toJSONObject(xmlStr, config); - JSONObject expetedJsonObject = new JSONObject(expectedStr); - - Util.compareActualVsExpectedJsonObjects(jsonObject, expetedJsonObject); - } - @Test - public void testEmptyTagForceList() { - String xmlStr = - ""; - - String expectedStr = - "{\"addresses\":[\"\"]}"; - - Set forceList = new HashSet(); - forceList.add("addresses"); - - XMLParserConfiguration config = - new XMLParserConfiguration() - .withForceList(forceList); - JSONObject jsonObject = XML.toJSONObject(xmlStr, config); - JSONObject expetedJsonObject = new JSONObject(expectedStr); - - Util.compareActualVsExpectedJsonObjects(jsonObject, expetedJsonObject); - } - - @Test - public void testForceListWithLastElementAsEmptyTag(){ - final String originalXml = "1"; - final String expectedJsonString = "{\"root\":{\"id\":[1,\"\"]}}"; - - HashSet forceListCandidates = new HashSet<>(); - forceListCandidates.add("id"); - final JSONObject json = XML.toJSONObject(originalXml, - new XMLParserConfiguration() - .withKeepStrings(false) - .withcDataTagName("content") - .withForceList(forceListCandidates) - .withConvertNilAttributeToNull(true)); - assertEquals(expectedJsonString, json.toString()); - } - - @Test - public void testForceListWithFirstElementAsEmptyTag(){ - final String originalXml = "1"; - final String expectedJsonString = "{\"root\":{\"id\":[\"\",1]}}"; - - HashSet forceListCandidates = new HashSet<>(); - forceListCandidates.add("id"); - final JSONObject json = XML.toJSONObject(originalXml, - new XMLParserConfiguration() - .withKeepStrings(false) - .withcDataTagName("content") - .withForceList(forceListCandidates) - .withConvertNilAttributeToNull(true)); - assertEquals(expectedJsonString, json.toString()); - } - - @Test - public void testForceListWithMiddleElementAsEmptyTag(){ - final String originalXml = "12"; - final String expectedJsonString = "{\"root\":{\"id\":[1,\"\",2]}}"; - - HashSet forceListCandidates = new HashSet<>(); - forceListCandidates.add("id"); - final JSONObject json = XML.toJSONObject(originalXml, - new XMLParserConfiguration() - .withKeepStrings(false) - .withcDataTagName("content") - .withForceList(forceListCandidates) - .withConvertNilAttributeToNull(true)); - assertEquals(expectedJsonString, json.toString()); - } - - @Test - public void testForceListWithLastElementAsEmpty(){ - final String originalXml = "1"; - final String expectedJsonString = "{\"root\":{\"id\":[1,\"\"]}}"; - HashSet forceListCandidates = new HashSet<>(); - forceListCandidates.add("id"); - final JSONObject json = XML.toJSONObject(originalXml, - new XMLParserConfiguration() - .withKeepStrings(false) - .withForceList(forceListCandidates) - .withConvertNilAttributeToNull(true)); - assertEquals(expectedJsonString, json.toString()); - } - - @Test - public void testForceListWithFirstElementAsEmpty(){ - final String originalXml = "1"; - final String expectedJsonString = "{\"root\":{\"id\":[\"\",1]}}"; - - HashSet forceListCandidates = new HashSet<>(); - forceListCandidates.add("id"); - final JSONObject json = XML.toJSONObject(originalXml, - new XMLParserConfiguration() - .withKeepStrings(false) - .withForceList(forceListCandidates) - .withConvertNilAttributeToNull(true)); - assertEquals(expectedJsonString, json.toString()); - } - - @Test - public void testForceListWithMiddleElementAsEmpty(){ - final String originalXml = "12"; - final String expectedJsonString = "{\"root\":{\"id\":[1,\"\",2]}}"; - - HashSet forceListCandidates = new HashSet<>(); - forceListCandidates.add("id"); - final JSONObject json = XML.toJSONObject(originalXml, - new XMLParserConfiguration() - .withKeepStrings(false) - .withForceList(forceListCandidates) - .withConvertNilAttributeToNull(true)); - assertEquals(expectedJsonString, json.toString()); - } - - @Test - public void testForceListEmptyAndEmptyTagsMixed(){ - final String originalXml = "12"; - final String expectedJsonString = "{\"root\":{\"id\":[\"\",\"\",1,\"\",\"\",2]}}"; - - HashSet forceListCandidates = new HashSet<>(); - forceListCandidates.add("id"); - final JSONObject json = XML.toJSONObject(originalXml, - new XMLParserConfiguration() - .withKeepStrings(false) - .withForceList(forceListCandidates) - .withConvertNilAttributeToNull(true)); - assertEquals(expectedJsonString, json.toString()); - } - - @Test - public void testForceListConsistencyWithDefault() { - final String originalXml = "01"; - final String expectedJsonString = "{\"root\":{\"id\":[0,1,\"\",\"\"]}}"; - - // confirm expected result of default array-of-tags processing - JSONObject json = XML.toJSONObject(originalXml); - assertEquals(expectedJsonString, json.toString()); - - // confirm forceList array-of-tags processing is consistent with default processing - HashSet forceListCandidates = new HashSet<>(); - forceListCandidates.add("id"); - json = XML.toJSONObject(originalXml, - new XMLParserConfiguration() - .withForceList(forceListCandidates)); - assertEquals(expectedJsonString, json.toString()); - } - - @Test - public void testForceListInitializesAnArrayWithAnEmptyElement(){ - final String originalXml = ""; - final String expectedJsonString = "{\"root\":{\"id\":[\"\"]}}"; - - HashSet forceListCandidates = new HashSet<>(); - forceListCandidates.add("id"); - JSONObject json = XML.toJSONObject(originalXml, - new XMLParserConfiguration() - .withForceList(forceListCandidates)); - assertEquals(expectedJsonString, json.toString()); - } - - @Test - public void testForceListInitializesAnArrayWithAnEmptyTag(){ - final String originalXml = ""; - final String expectedJsonString = "{\"root\":{\"id\":[\"\"]}}"; - - HashSet forceListCandidates = new HashSet<>(); - forceListCandidates.add("id"); - JSONObject json = XML.toJSONObject(originalXml, - new XMLParserConfiguration() - .withForceList(forceListCandidates)); - assertEquals(expectedJsonString, json.toString()); - } - - @Test - public void testMaxNestingDepthIsSet() { - XMLParserConfiguration xmlParserConfiguration = XMLParserConfiguration.ORIGINAL; - - assertEquals(xmlParserConfiguration.getMaxNestingDepth(), XMLParserConfiguration.DEFAULT_MAXIMUM_NESTING_DEPTH); - - xmlParserConfiguration = xmlParserConfiguration.withMaxNestingDepth(42); - - assertEquals(xmlParserConfiguration.getMaxNestingDepth(), 42); - - xmlParserConfiguration = xmlParserConfiguration.withMaxNestingDepth(0); - - assertEquals(xmlParserConfiguration.getMaxNestingDepth(), 0); - - xmlParserConfiguration = xmlParserConfiguration.withMaxNestingDepth(-31415926); - - assertEquals(xmlParserConfiguration.getMaxNestingDepth(), XMLParserConfiguration.UNDEFINED_MAXIMUM_NESTING_DEPTH); - - xmlParserConfiguration = xmlParserConfiguration.withMaxNestingDepth(Integer.MIN_VALUE); - - assertEquals(xmlParserConfiguration.getMaxNestingDepth(), XMLParserConfiguration.UNDEFINED_MAXIMUM_NESTING_DEPTH); - } - - /** - * Convenience method, given an input string and expected result, - * convert to JSONObject and compare actual to expected result. - * @param xmlStr the string to parse - * @param expectedStr the expected JSON string - * @param config provides more flexible XML parsing - * flexible XML parsing. - */ - private void compareStringToJSONObject(String xmlStr, String expectedStr, - XMLParserConfiguration config) { - JSONObject expectedJsonObject = new JSONObject(expectedStr); - JSONObject jsonObject = XML.toJSONObject(xmlStr, config); - Util.compareActualVsExpectedJsonObjects(jsonObject,expectedJsonObject); - } - - /** - * Convenience method, given an input string and expected result, - * convert to JSONObject via reader and compare actual to expected result. - * @param xmlStr the string to parse - * @param expectedStr the expected JSON string - * @param config provides more flexible XML parsing - */ - private void compareReaderToJSONObject(String xmlStr, String expectedStr, - XMLParserConfiguration config) { - /* - * Commenting out this method until the JSON-java code is updated - * to support XML.toJSONObject(reader) - */ - JSONObject expectedJsonObject = new JSONObject(expectedStr); - Reader reader = new StringReader(xmlStr); - try { - JSONObject jsonObject = XML.toJSONObject(reader, config); - Util.compareActualVsExpectedJsonObjects(jsonObject,expectedJsonObject); - } catch (Exception e) { - assertTrue("Reader error: " +e.getMessage(), false); - } finally { - try { - reader.close(); - } catch (Exception e) {} - } - } - - /** - * Convenience method, given an input string and expected result, convert to - * JSONObject via file and compare actual to expected result. - * - * @param xmlStr - * the string to parse - * @param expectedStr - * the expected JSON string - * @throws IOException - */ - private void compareFileToJSONObject(String xmlStr, String expectedStr) { - /* - * Commenting out this method until the JSON-java code is updated - * to support XML.toJSONObject(reader) - */ - try { - JSONObject expectedJsonObject = new JSONObject(expectedStr); - File tempFile = this.testFolder.newFile("fileToJSONObject.xml"); - FileWriter fileWriter = new FileWriter(tempFile); - try { - fileWriter.write(xmlStr); - } finally { - fileWriter.close(); - } - - Reader reader = new FileReader(tempFile); - try { - JSONObject jsonObject = XML.toJSONObject(reader); - Util.compareActualVsExpectedJsonObjects(jsonObject,expectedJsonObject); - } finally { - reader.close(); - } - } catch (IOException e) { - assertTrue("Error: " +e.getMessage(), false); - } - } -} diff --git a/src/test/java/org/json/junit/XMLTest.java b/src/test/java/org/json/junit/XMLTest.java deleted file mode 100644 index 25b0a0e42..000000000 --- a/src/test/java/org/json/junit/XMLTest.java +++ /dev/null @@ -1,1507 +0,0 @@ -package org.json.junit; - -/* -Public Domain. -*/ - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotEquals; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -import java.io.File; -import java.io.FileReader; -import java.io.FileWriter; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.Reader; -import java.io.StringReader; -import java.nio.charset.Charset; -import java.util.HashMap; -import java.util.Map; - -import org.json.*; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TemporaryFolder; - - -/** - * Tests for JSON-Java XML.java - * Note: noSpace() will be tested by JSONMLTest - */ -public class XMLTest { - /** - * JUnit supports temporary files and folders that are cleaned up after the test. - * https://garygregory.wordpress.com/2010/01/20/junit-tip-use-rules-to-manage-temporary-files-and-folders/ - */ - @Rule - public TemporaryFolder testFolder = new TemporaryFolder(); - - - /** - * JSONObject from a null XML string. - * Expects a NullPointerException - */ - @Test(expected=NullPointerException.class) - public void shouldHandleNullXML() { - String xmlStr = null; - JSONObject jsonObject = XML.toJSONObject(xmlStr); - assertTrue("jsonObject should be empty", jsonObject.isEmpty()); - } - - /** - * Empty JSONObject from an empty XML string. - */ - @Test - public void shouldHandleEmptyXML() { - - String xmlStr = ""; - JSONObject jsonObject = XML.toJSONObject(xmlStr); - assertTrue("jsonObject should be empty", jsonObject.isEmpty()); - } - - /** - * Empty JSONObject from a non-XML string. - */ - @Test - public void shouldHandleNonXML() { - String xmlStr = "{ \"this is\": \"not xml\"}"; - JSONObject jsonObject = XML.toJSONObject(xmlStr); - assertTrue("xml string should be empty", jsonObject.isEmpty()); - } - - /** - * Invalid XML string (tag contains a frontslash). - * Expects a JSONException - */ - @Test - public void shouldHandleInvalidSlashInTag() { - String xmlStr = - "\n"+ - "\n"+ - "
    \n"+ - " \n"+ - " abc street\n"+ - "
    \n"+ - "
    "; - try { - XML.toJSONObject(xmlStr); - fail("Expecting a JSONException"); - } catch (JSONException e) { - assertEquals("Expecting an exception message", - "Misshaped tag at 176 [character 14 line 4]", - e.getMessage()); - } - } - - /** - * Invalid XML string ('!' char in tag) - * Expects a JSONException - */ - @Test - public void shouldHandleInvalidBangInTag() { - String xmlStr = - "\n"+ - "\n"+ - "
    \n"+ - " \n"+ - " \n"+ - "
    \n"+ - "
    "; - try { - XML.toJSONObject(xmlStr); - fail("Expecting a JSONException"); - } catch (JSONException e) { - assertEquals("Expecting an exception message", - "Misshaped meta tag at 214 [character 12 line 7]", - e.getMessage()); - } - } - - /** - * Invalid XML string ('!' char and no closing tag brace) - * Expects a JSONException - */ - @Test - public void shouldHandleInvalidBangNoCloseInTag() { - String xmlStr = - "\n"+ - "\n"+ - "
    \n"+ - " \n"+ - " \n"+ - ""; - try { - XML.toJSONObject(xmlStr); - fail("Expecting a JSONException"); - } catch (JSONException e) { - assertEquals("Expecting an exception message", - "Misshaped meta tag at 213 [character 12 line 7]", - e.getMessage()); - } - } - - /** - * Invalid XML string (no end brace for tag) - * Expects JSONException - */ - @Test - public void shouldHandleNoCloseStartTag() { - String xmlStr = - "\n"+ - "\n"+ - "
    \n"+ - " \n"+ - " \n"+ - ""; - try { - XML.toJSONObject(xmlStr); - fail("Expecting a JSONException"); - } catch (JSONException e) { - assertEquals("Expecting an exception message", - "Misplaced '<' at 193 [character 4 line 6]", - e.getMessage()); - } - } - - /** - * Invalid XML string (partial CDATA chars in tag name) - * Expects JSONException - */ - @Test - public void shouldHandleInvalidCDATABangInTag() { - String xmlStr = - "\n"+ - "\n"+ - "
    \n"+ - " Joe Tester\n"+ - " \n"+ - "
    \n"+ - "
    "; - try { - XML.toJSONObject(xmlStr); - fail("Expecting a JSONException"); - } catch (JSONException e) { - assertEquals("Expecting an exception message", - "Expected 'CDATA[' at 204 [character 11 line 5]", - e.getMessage()); - } - } - - /** - * Null JSONObject in XML.toString() - */ - @Test - public void shouldHandleNullJSONXML() { - JSONObject jsonObject= null; - String actualXml=XML.toString(jsonObject); - assertEquals("generated XML does not equal expected XML","\"null\"",actualXml); - } - - /** - * Empty JSONObject in XML.toString() - */ - @Test - public void shouldHandleEmptyJSONXML() { - JSONObject jsonObject= new JSONObject(); - String xmlStr = XML.toString(jsonObject); - assertTrue("xml string should be empty", xmlStr.isEmpty()); - } - - /** - * No SML start tag. The ending tag ends up being treated as content. - */ - @Test - public void shouldHandleNoStartTag() { - String xmlStr = - "\n"+ - "\n"+ - "
    \n"+ - " \n"+ - " >\n"+ - "
    \n"+ - "
    "; - String expectedStr = - "{\"addresses\":{\"address\":{\"name\":\"\",\"nocontent\":\"\",\""+ - "content\":\">\"},\"xsi:noNamespaceSchemaLocation\":\"test.xsd\",\""+ - "xmlns:xsi\":\"http://www.w3.org/2001/XMLSchema-instance\"}}"; - JSONObject jsonObject = XML.toJSONObject(xmlStr); - JSONObject expectedJsonObject = new JSONObject(expectedStr); - Util.compareActualVsExpectedJsonObjects(jsonObject,expectedJsonObject); - } - - /** - * Valid XML to JSONObject - */ - @Test - public void shouldHandleSimpleXML() { - String xmlStr = - "\n"+ - "\n"+ - "
    \n"+ - " Joe Tester\n"+ - " [CDATA[Baker street 5]\n"+ - " \n"+ - " true\n"+ - " false\n"+ - " null\n"+ - " 42\n"+ - " -23\n"+ - " -23.45\n"+ - " -23x.45\n"+ - " 1, 2, 3, 4.1, 5.2\n"+ - "
    \n"+ - "
    "; - - String expectedStr = - "{\"addresses\":{\"address\":{\"street\":\"[CDATA[Baker street 5]\","+ - "\"name\":\"Joe Tester\",\"NothingHere\":\"\",\"TrueValue\":true,\n"+ - "\"FalseValue\":false,\"NullValue\":null,\"PositiveValue\":42,\n"+ - "\"NegativeValue\":-23,\"DoubleValue\":-23.45,\"Nan\":\"-23x.45\",\n"+ - "\"ArrayOfNum\":\"1, 2, 3, 4.1, 5.2\"\n"+ - "},\"xsi:noNamespaceSchemaLocation\":"+ - "\"test.xsd\",\"xmlns:xsi\":\"http://www.w3.org/2001/"+ - "XMLSchema-instance\"}}"; - - compareStringToJSONObject(xmlStr, expectedStr); - compareReaderToJSONObject(xmlStr, expectedStr); - compareFileToJSONObject(xmlStr, expectedStr); - } - - /** - * Tests to verify that supported escapes in XML are converted to actual values. - */ - @Test - public void testXmlEscapeToJson(){ - String xmlStr = - "\n"+ - ""+ - "\""+ - "A €33"+ - "A €22€"+ - "some text ©"+ - "" " & ' < >"+ - "𝄢 𐅥" + - ""; - String expectedStr = - "{\"root\":{" + - "\"rawQuote\":\"\\\"\"," + - "\"euro\":\"A €33\"," + - "\"euroX\":\"A €22€\"," + - "\"unknown\":\"some text ©\"," + - "\"known\":\"\\\" \\\" & ' < >\"," + - "\"high\":\"𝄢 𐅥\""+ - "}}"; - - compareStringToJSONObject(xmlStr, expectedStr); - compareReaderToJSONObject(xmlStr, expectedStr); - compareFileToJSONObject(xmlStr, expectedStr); - } - - /** - * Tests that control characters are escaped. - */ - @Test - public void testJsonToXmlEscape(){ - final String jsonSrc = "{\"amount\":\"10,00 €\"," - + "\"description\":\"Ação Válida\u0085\"," - + "\"xmlEntities\":\"\\\" ' & < >\"" - + "}"; - JSONObject json = new JSONObject(jsonSrc); - String xml = XML.toString(json); - //test control character not existing - assertFalse("Escaping \u0085 failed. Found in XML output.", xml.contains("\u0085")); - assertTrue("Escaping \u0085 failed. Entity not found in XML output.", xml.contains("…")); - // test normal unicode existing - assertTrue("Escaping € failed. Not found in XML output.", xml.contains("€")); - assertTrue("Escaping ç failed. Not found in XML output.", xml.contains("ç")); - assertTrue("Escaping ã failed. Not found in XML output.", xml.contains("ã")); - assertTrue("Escaping á failed. Not found in XML output.", xml.contains("á")); - // test XML Entities converted - assertTrue("Escaping \" failed. Not found in XML output.", xml.contains(""")); - assertTrue("Escaping ' failed. Not found in XML output.", xml.contains("'")); - assertTrue("Escaping & failed. Not found in XML output.", xml.contains("&")); - assertTrue("Escaping < failed. Not found in XML output.", xml.contains("<")); - assertTrue("Escaping > failed. Not found in XML output.", xml.contains(">")); - } - - /** - * Valid XML with comments to JSONObject - */ - @Test - public void shouldHandleCommentsInXML() { - - String xmlStr = - "\n"+ - "\n"+ - "\n"+ - "
    \n"+ - " comment ]]>\n"+ - " Joe Tester\n"+ - " \n"+ - " Baker street 5\n"+ - "
    \n"+ - "
    "; - JSONObject jsonObject = XML.toJSONObject(xmlStr); - String expectedStr = "{\"addresses\":{\"address\":{\"street\":\"Baker "+ - "street 5\",\"name\":\"Joe Tester\",\"content\":\" this is -- "+ - " comment \"}}}"; - JSONObject expectedJsonObject = new JSONObject(expectedStr); - Util.compareActualVsExpectedJsonObjects(jsonObject,expectedJsonObject); - } - - /** - * Valid XML to XML.toString() - */ - @Test - public void shouldHandleToString() { - String xmlStr = - "\n"+ - "\n"+ - "
    \n"+ - " [CDATA[Joe & T > e < s " t ' er]]\n"+ - " Baker street 5\n"+ - " 1, 2, 3, 4.1, 5.2\n"+ - "
    \n"+ - "
    "; - - String expectedStr = - "{\"addresses\":{\"address\":{\"street\":\"Baker street 5\","+ - "\"name\":\"[CDATA[Joe & T > e < s \\\" t \\\' er]]\","+ - "\"ArrayOfNum\":\"1, 2, 3, 4.1, 5.2\"\n"+ - "},\"xsi:noNamespaceSchemaLocation\":"+ - "\"test.xsd\",\"xmlns:xsi\":\"http://www.w3.org/2001/"+ - "XMLSchema-instance\"}}"; - - JSONObject jsonObject = XML.toJSONObject(xmlStr); - String xmlToStr = XML.toString(jsonObject); - JSONObject finalJsonObject = XML.toJSONObject(xmlToStr); - JSONObject expectedJsonObject = new JSONObject(expectedStr); - Util.compareActualVsExpectedJsonObjects(jsonObject,expectedJsonObject); - Util.compareActualVsExpectedJsonObjects(finalJsonObject,expectedJsonObject); - } - - /** - * Converting a JSON doc containing '>' content to JSONObject, then - * XML.toString() should result in valid XML. - */ - @Test - public void shouldHandleContentNoArraytoString() { - String expectedStr = "{\"addresses\":{\"content\":\">\"}}"; - JSONObject expectedJsonObject = new JSONObject(expectedStr); - String finalStr = XML.toString(expectedJsonObject); - String expectedFinalStr = ">"; - assertEquals("Should handle expectedFinal: ["+expectedStr+"] final: ["+ - finalStr+"]", expectedFinalStr, finalStr); - } - - /** - * Converting a JSON doc containing a 'content' array to JSONObject, then - * XML.toString() should result in valid XML. - * TODO: This is probably an error in how the 'content' keyword is used. - */ - @Test - public void shouldHandleContentArraytoString() { - String expectedStr = - "{\"addresses\":{" + - "\"content\":[1, 2, 3]}}"; - JSONObject expectedJsonObject = new JSONObject(expectedStr); - String finalStr = XML.toString(expectedJsonObject); - String expectedFinalStr = ""+ - "1\n2\n3"; - assertEquals("Should handle expectedFinal: ["+expectedStr+"] final: ["+ - finalStr+"]", expectedFinalStr, finalStr); - } - - /** - * Converting a JSON doc containing a named array to JSONObject, then - * XML.toString() should result in valid XML. - */ - @Test - public void shouldHandleArraytoString() { - String expectedStr = - "{\"addresses\":{"+ - "\"something\":[1, 2, 3]}}"; - JSONObject expectedJsonObject = new JSONObject(expectedStr); - String finalStr = XML.toString(expectedJsonObject); - String expectedFinalStr = ""+ - "123"+ - ""; - assertEquals("Should handle expectedFinal: ["+expectedStr+"] final: ["+ - finalStr+"]", expectedFinalStr, finalStr); - } - - /** - * Tests that the XML output for empty arrays is consistent. - */ - @Test - public void shouldHandleEmptyArray(){ - final JSONObject jo1 = new JSONObject(); - jo1.put("array",new Object[]{}); - final JSONObject jo2 = new JSONObject(); - jo2.put("array",new JSONArray()); - - final String expected = ""; - String output1 = XML.toString(jo1,"jo"); - assertEquals("Expected an empty root tag", expected, output1); - String output2 = XML.toString(jo2,"jo"); - assertEquals("Expected an empty root tag", expected, output2); - } - - /** - * Tests that the XML output for arrays is consistent when an internal array is empty. - */ - @Test - public void shouldHandleEmptyMultiArray(){ - final JSONObject jo1 = new JSONObject(); - jo1.put("arr",new Object[]{"One", new String[]{}, "Four"}); - final JSONObject jo2 = new JSONObject(); - jo2.put("arr",new JSONArray(new Object[]{"One", new JSONArray(new String[]{}), "Four"})); - - final String expected = "OneFour"; - String output1 = XML.toString(jo1,"jo"); - assertEquals("Expected a matching array", expected, output1); - String output2 = XML.toString(jo2,"jo"); - assertEquals("Expected a matching array", expected, output2); - } - - /** - * Tests that the XML output for arrays is consistent when arrays are not empty. - */ - @Test - public void shouldHandleNonEmptyArray(){ - final JSONObject jo1 = new JSONObject(); - jo1.put("arr",new String[]{"One", "Two", "Three"}); - final JSONObject jo2 = new JSONObject(); - jo2.put("arr",new JSONArray(new String[]{"One", "Two", "Three"})); - - final String expected = "OneTwoThree"; - String output1 = XML.toString(jo1,"jo"); - assertEquals("Expected a non empty root tag", expected, output1); - String output2 = XML.toString(jo2,"jo"); - assertEquals("Expected a non empty root tag", expected, output2); - } - - /** - * Tests that the XML output for arrays is consistent when arrays are not empty and contain internal arrays. - */ - @Test - public void shouldHandleMultiArray(){ - final JSONObject jo1 = new JSONObject(); - jo1.put("arr",new Object[]{"One", new String[]{"Two", "Three"}, "Four"}); - final JSONObject jo2 = new JSONObject(); - jo2.put("arr",new JSONArray(new Object[]{"One", new JSONArray(new String[]{"Two", "Three"}), "Four"})); - - final String expected = "OneTwoThreeFour"; - String output1 = XML.toString(jo1,"jo"); - assertEquals("Expected a matching array", expected, output1); - String output2 = XML.toString(jo2,"jo"); - assertEquals("Expected a matching array", expected, output2); - } - - /** - * Converting a JSON doc containing a named array of nested arrays to - * JSONObject, then XML.toString() should result in valid XML. - */ - @Test - public void shouldHandleNestedArraytoString() { - String xmlStr = - "{\"addresses\":{\"address\":{\"name\":\"\",\"nocontent\":\"\","+ - "\"outer\":[[1], [2], [3]]},\"xsi:noNamespaceSchemaLocation\":\"test.xsd\",\""+ - "xmlns:xsi\":\"http://www.w3.org/2001/XMLSchema-instance\"}}"; - JSONObject jsonObject = new JSONObject(xmlStr); - String finalStr = XML.toString(jsonObject); - JSONObject finalJsonObject = XML.toJSONObject(finalStr); - String expectedStr = "
    "+ - "12"+ - "3"+ - "
    test.xsdhttp://www.w3.org/2001/XMLSche"+ - "ma-instance
    "; - JSONObject expectedJsonObject = XML.toJSONObject(expectedStr); - Util.compareActualVsExpectedJsonObjects(finalJsonObject,expectedJsonObject); - } - - - /** - * Possible bug: - * Illegal node-names must be converted to legal XML-node-names. - * The given example shows 2 nodes which are valid for JSON, but not for XML. - * Therefore illegal arguments should be converted to e.g. an underscore (_). - */ - @Test - public void shouldHandleIllegalJSONNodeNames() - { - JSONObject inputJSON = new JSONObject(); - inputJSON.append("123IllegalNode", "someValue1"); - inputJSON.append("Illegal@node", "someValue2"); - - String result = XML.toString(inputJSON); - - /* - * This is invalid XML. Names should not begin with digits or contain - * certain values, including '@'. One possible solution is to replace - * illegal chars with '_', in which case the expected output would be: - * <___IllegalNode>someValue1someValue2 - */ - String expected = "<123IllegalNode>someValue1someValue2"; - - assertEquals("length",expected.length(), result.length()); - assertTrue("123IllegalNode",result.contains("<123IllegalNode>someValue1")); - assertTrue("Illegal@node",result.contains("someValue2")); - } - - /** - * JSONObject with NULL value, to XML.toString() - */ - @Test - public void shouldHandleNullNodeValue() - { - JSONObject inputJSON = new JSONObject(); - inputJSON.put("nullValue", JSONObject.NULL); - // This is a possible preferred result - // String expectedXML = ""; - /** - * This is the current behavior. JSONObject.NULL is emitted as - * the string, "null". - */ - String actualXML = "null"; - String resultXML = XML.toString(inputJSON); - assertEquals(actualXML, resultXML); - } - - /** - * Investigate exactly how the "content" keyword works - */ - @Test - public void contentOperations() { - /* - * When a standalone 0) then return]]>"; - JSONObject jsonObject = XML.toJSONObject(xmlStr); - assertTrue("1. 3 items", 3 == jsonObject.length()); - assertTrue("1. empty tag1", "".equals(jsonObject.get("tag1"))); - assertTrue("1. empty tag2", "".equals(jsonObject.get("tag2"))); - assertTrue("1. content found", "if (a < b && a > 0) then return".equals(jsonObject.get("content"))); - - // multiple consecutive standalone cdatas are accumulated into an array - xmlStr = " 0) then return]]>"; - jsonObject = XML.toJSONObject(xmlStr); - assertTrue("2. 3 items", 3 == jsonObject.length()); - assertTrue("2. empty tag1", "".equals(jsonObject.get("tag1"))); - assertTrue("2. empty tag2", "".equals(jsonObject.get("tag2"))); - assertTrue("2. content array found", jsonObject.get("content") instanceof JSONArray); - JSONArray jsonArray = jsonObject.getJSONArray("content"); - assertTrue("2. array size", jsonArray.length() == 2); - assertTrue("2. content array entry 0", "if (a < b && a > 0) then return".equals(jsonArray.get(0))); - assertTrue("2. content array entry 1", "here is another cdata".equals(jsonArray.get(1))); - - /* - * text content is accumulated in a "content" inside a local JSONObject. - * If there is only one instance, it is saved in the context (a different JSONObject - * from the calling code. and the content element is discarded. - */ - xmlStr = "value 1"; - jsonObject = XML.toJSONObject(xmlStr); - assertTrue("3. 2 items", 1 == jsonObject.length()); - assertTrue("3. value tag1", "value 1".equals(jsonObject.get("tag1"))); - - /* - * array-style text content (multiple tags with the same name) is - * accumulated in a local JSONObject with key="content" and value=JSONArray, - * saved in the context, and then the local JSONObject is discarded. - */ - xmlStr = "value 12true"; - jsonObject = XML.toJSONObject(xmlStr); - assertTrue("4. 1 item", 1 == jsonObject.length()); - assertTrue("4. content array found", jsonObject.get("tag1") instanceof JSONArray); - jsonArray = jsonObject.getJSONArray("tag1"); - assertTrue("4. array size", jsonArray.length() == 3); - assertTrue("4. content array entry 0", "value 1".equals(jsonArray.get(0))); - assertTrue("4. content array entry 1", jsonArray.getInt(1) == 2); - assertTrue("4. content array entry 2", jsonArray.getBoolean(2) == true); - - /* - * Complex content is accumulated in a "content" field. For example, an element - * may contain a mix of child elements and text. Each text segment is - * accumulated to content. - */ - xmlStr = "val1val2"; - jsonObject = XML.toJSONObject(xmlStr); - assertTrue("5. 1 item", 1 == jsonObject.length()); - assertTrue("5. jsonObject found", jsonObject.get("tag1") instanceof JSONObject); - jsonObject = jsonObject.getJSONObject("tag1"); - assertTrue("5. 2 contained items", 2 == jsonObject.length()); - assertTrue("5. contained tag", "".equals(jsonObject.get("tag2"))); - assertTrue("5. contained content jsonArray found", jsonObject.get("content") instanceof JSONArray); - jsonArray = jsonObject.getJSONArray("content"); - assertTrue("5. array size", jsonArray.length() == 2); - assertTrue("5. content array entry 0", "val1".equals(jsonArray.get(0))); - assertTrue("5. content array entry 1", "val2".equals(jsonArray.get(1))); - - /* - * If there is only 1 complex text content, then it is accumulated in a - * "content" field as a string. - */ - xmlStr = "val1"; - jsonObject = XML.toJSONObject(xmlStr); - assertTrue("6. 1 item", 1 == jsonObject.length()); - assertTrue("6. jsonObject found", jsonObject.get("tag1") instanceof JSONObject); - jsonObject = jsonObject.getJSONObject("tag1"); - assertTrue("6. contained content found", "val1".equals(jsonObject.get("content"))); - assertTrue("6. contained tag2", "".equals(jsonObject.get("tag2"))); - - /* - * In this corner case, the content sibling happens to have key=content - * We end up with an array within an array, and no content element. - * This is probably a bug. - */ - xmlStr = "val1"; - jsonObject = XML.toJSONObject(xmlStr); - assertTrue("7. 1 item", 1 == jsonObject.length()); - assertTrue("7. jsonArray found", jsonObject.get("tag1") instanceof JSONArray); - jsonArray = jsonObject.getJSONArray("tag1"); - assertTrue("array size 1", jsonArray.length() == 1); - assertTrue("7. contained array found", jsonArray.get(0) instanceof JSONArray); - jsonArray = jsonArray.getJSONArray(0); - assertTrue("7. inner array size 2", jsonArray.length() == 2); - assertTrue("7. inner array item 0", "val1".equals(jsonArray.get(0))); - assertTrue("7. inner array item 1", "".equals(jsonArray.get(1))); - - /* - * Confirm behavior of original issue - */ - String jsonStr = - "{"+ - "\"Profile\": {"+ - "\"list\": {"+ - "\"history\": {"+ - "\"entries\": ["+ - "{"+ - "\"deviceId\": \"id\","+ - "\"content\": {"+ - "\"material\": ["+ - "{"+ - "\"stuff\": false"+ - "}"+ - "]"+ - "}"+ - "}"+ - "]"+ - "}"+ - "}"+ - "}"+ - "}"; - jsonObject = new JSONObject(jsonStr); - xmlStr = XML.toString(jsonObject); - /* - * This is the created XML. Looks like content was mistaken for - * complex (child node + text) XML. - * - * - * - * - * id - * {"material":[{"stuff":false}]} - * - * - * - * - */ - assertTrue("nothing to test here, see comment on created XML, above", true); - } - - /** - * Convenience method, given an input string and expected result, - * convert to JSONObject and compare actual to expected result. - * @param xmlStr the string to parse - * @param expectedStr the expected JSON string - */ - private void compareStringToJSONObject(String xmlStr, String expectedStr) { - JSONObject jsonObject = XML.toJSONObject(xmlStr); - JSONObject expectedJsonObject = new JSONObject(expectedStr); - Util.compareActualVsExpectedJsonObjects(jsonObject,expectedJsonObject); - } - - /** - * Convenience method, given an input string and expected result, - * convert to JSONObject via reader and compare actual to expected result. - * @param xmlStr the string to parse - * @param expectedStr the expected JSON string - */ - private void compareReaderToJSONObject(String xmlStr, String expectedStr) { - JSONObject expectedJsonObject = new JSONObject(expectedStr); - Reader reader = new StringReader(xmlStr); - JSONObject jsonObject = XML.toJSONObject(reader); - Util.compareActualVsExpectedJsonObjects(jsonObject,expectedJsonObject); - } - - /** - * Convenience method, given an input string and expected result, convert to - * JSONObject via file and compare actual to expected result. - * - * @param xmlStr - * the string to parse - * @param expectedStr - * the expected JSON string - * @throws IOException - */ - private void compareFileToJSONObject(String xmlStr, String expectedStr) { - try { - JSONObject expectedJsonObject = new JSONObject(expectedStr); - File tempFile = this.testFolder.newFile("fileToJSONObject.xml"); - FileWriter fileWriter = new FileWriter(tempFile); - try { - fileWriter.write(xmlStr); - } finally { - fileWriter.close(); - } - - Reader reader = new FileReader(tempFile); - try { - JSONObject jsonObject = XML.toJSONObject(reader); - Util.compareActualVsExpectedJsonObjects(jsonObject,expectedJsonObject); - } finally { - reader.close(); - } - } catch (IOException e) { - fail("Error: " +e.getMessage()); - } - } - - /** - * JSON string lost leading zero and converted "True" to true. - */ - @Test - public void testToJSONArray_jsonOutput() { - final String originalXml = "011000True"; - final JSONObject expectedJson = new JSONObject("{\"root\":{\"item\":{\"id\":\"01\"},\"id\":[\"01\",1,\"00\",0],\"title\":true}}"); - final JSONObject actualJsonOutput = XML.toJSONObject(originalXml, false); - - Util.compareActualVsExpectedJsonObjects(actualJsonOutput,expectedJson); - } - - /** - * JSON string cannot be reverted to original xml. - */ - @Test - public void testToJSONArray_reversibility() { - final String originalXml = "011000True"; - final String revertedXml = XML.toString(XML.toJSONObject(originalXml, false)); - - assertNotEquals(revertedXml, originalXml); - } - - /** - * test passes when using the new method toJsonArray. - */ - @Test - public void testToJsonXML() { - final String originalXml = "011000True"; - final JSONObject expected = new JSONObject("{\"root\":{\"item\":{\"id\":\"01\"},\"id\":[\"01\",\"1\",\"00\",\"0\"],\"title\":\"True\"}}"); - - final JSONObject actual = XML.toJSONObject(originalXml,true); - - Util.compareActualVsExpectedJsonObjects(actual, expected); - - final String reverseXml = XML.toString(actual); - // this reversal isn't exactly the same. use JSONML for an exact reversal - // the order of the elements may be differnet as well. - final String expectedReverseXml = "01011000True"; - - assertEquals("length",expectedReverseXml.length(), reverseXml.length()); - assertTrue("array contents", reverseXml.contains("011000")); - assertTrue("item contents", reverseXml.contains("01")); - assertTrue("title contents", reverseXml.contains("True")); - } - - /** - * test to validate certain conditions of XML unescaping. - */ - @Test - public void testUnescape() { - assertEquals("{\"xml\":\"Can cope <;\"}", - XML.toJSONObject("Can cope <; ").toString()); - assertEquals("Can cope <; ", XML.unescape("Can cope <; ")); - - assertEquals("{\"xml\":\"Can cope & ;\"}", - XML.toJSONObject("Can cope & ; ").toString()); - assertEquals("Can cope & ; ", XML.unescape("Can cope & ; ")); - - assertEquals("{\"xml\":\"Can cope &;\"}", - XML.toJSONObject("Can cope &; ").toString()); - assertEquals("Can cope &; ", XML.unescape("Can cope &; ")); - - // unicode entity - assertEquals("{\"xml\":\"Can cope 4;\"}", - XML.toJSONObject("Can cope 4; ").toString()); - assertEquals("Can cope 4; ", XML.unescape("Can cope 4; ")); - - // double escaped - assertEquals("{\"xml\":\"Can cope <\"}", - XML.toJSONObject("Can cope &lt; ").toString()); - assertEquals("Can cope < ", XML.unescape("Can cope &lt; ")); - - assertEquals("{\"xml\":\"Can cope 4\"}", - XML.toJSONObject("Can cope &#x34; ").toString()); - assertEquals("Can cope 4 ", XML.unescape("Can cope &#x34; ")); - - } - - /** - * test passes when xsi:nil="true" converting to null (JSON specification-like nil conversion enabled) - */ - @Test - public void testToJsonWithNullWhenNilConversionEnabled() { - final String originalXml = ""; - final String expectedJsonString = "{\"root\":{\"id\":null}}"; - - final JSONObject json = XML.toJSONObject(originalXml, - new XMLParserConfiguration() - .withKeepStrings(false) - .withcDataTagName("content") - .withConvertNilAttributeToNull(true)); - assertEquals(expectedJsonString, json.toString()); - } - - /** - * test passes when xsi:nil="true" not converting to null (JSON specification-like nil conversion disabled) - */ - @Test - public void testToJsonWithNullWhenNilConversionDisabled() { - final String originalXml = ""; - final String expectedJsonString = "{\"root\":{\"id\":{\"xsi:nil\":true}}}"; - - final JSONObject json = XML.toJSONObject(originalXml, new XMLParserConfiguration()); - assertEquals(expectedJsonString, json.toString()); - } - - /** - * Tests to verify that supported escapes in XML are converted to actual values. - */ - @Test - public void testIssue537CaseSensitiveHexEscapeMinimal(){ - String xmlStr = - "\n"+ - "Neutrophils.Hypersegmented | Bld-Ser-Plas"; - String expectedStr = - "{\"root\":\"Neutrophils.Hypersegmented | Bld-Ser-Plas\"}"; - JSONObject xmlJSONObj = XML.toJSONObject(xmlStr, true); - JSONObject expected = new JSONObject(expectedStr); - Util.compareActualVsExpectedJsonObjects(xmlJSONObj, expected); - } - - /** - * Tests to verify that supported escapes in XML are converted to actual values. - */ - @Test - public void testIssue537CaseSensitiveHexEscapeFullFile(){ - try { - InputStream xmlStream = null; - try { - xmlStream = XMLTest.class.getClassLoader().getResourceAsStream("Issue537.xml"); - Reader xmlReader = new InputStreamReader(xmlStream, Charset.forName("UTF-8")); - JSONObject actual = XML.toJSONObject(xmlReader, true); - InputStream jsonStream = null; - try { - jsonStream = XMLTest.class.getClassLoader().getResourceAsStream("Issue537.json"); - final JSONObject expected = new JSONObject(new JSONTokener(jsonStream)); - Util.compareActualVsExpectedJsonObjects(actual,expected); - } finally { - if (jsonStream != null) { - jsonStream.close(); - } - } - } finally { - if (xmlStream != null) { - xmlStream.close(); - } - } - } catch (IOException e) { - fail("file writer error: " +e.getMessage()); - } - } - - /** - * Tests to verify that supported escapes in XML are converted to actual values. - */ - @Test - public void testIssue537CaseSensitiveHexUnEscapeDirect(){ - String origStr = - "Neutrophils.Hypersegmented | Bld-Ser-Plas"; - String expectedStr = - "Neutrophils.Hypersegmented | Bld-Ser-Plas"; - String actualStr = XML.unescape(origStr); - - assertEquals("Case insensitive Entity unescape", expectedStr, actualStr); - } - - /** - * test passes when xsi:type="java.lang.String" not converting to string - */ - @Test - public void testToJsonWithTypeWhenTypeConversionDisabled() { - String originalXml = "1234"; - String expectedJsonString = "{\"root\":{\"id\":{\"xsi:type\":\"string\",\"content\":1234}}}"; - JSONObject expectedJson = new JSONObject(expectedJsonString); - JSONObject actualJson = XML.toJSONObject(originalXml, new XMLParserConfiguration()); - Util.compareActualVsExpectedJsonObjects(actualJson,expectedJson); - } - - /** - * test passes when xsi:type="java.lang.String" converting to String - */ - @Test - public void testToJsonWithTypeWhenTypeConversionEnabled() { - String originalXml = "1234" - + "1234"; - String expectedJsonString = "{\"root\":{\"id2\":1234,\"id1\":\"1234\"}}"; - JSONObject expectedJson = new JSONObject(expectedJsonString); - Map> xsiTypeMap = new HashMap>(); - xsiTypeMap.put("string", new XMLXsiTypeConverter() { - @Override public String convert(final String value) { - return value; - } - }); - xsiTypeMap.put("integer", new XMLXsiTypeConverter() { - @Override public Integer convert(final String value) { - return Integer.valueOf(value); - } - }); - JSONObject actualJson = XML.toJSONObject(originalXml, new XMLParserConfiguration().withXsiTypeMap(xsiTypeMap)); - Util.compareActualVsExpectedJsonObjects(actualJson,expectedJson); - } - - @Test - public void testToJsonWithXSITypeWhenTypeConversionEnabled() { - String originalXml = "1234554321"; - String expectedJsonString = "{\"root\":{\"asString\":\"12345\",\"asInt\":54321}}"; - JSONObject expectedJson = new JSONObject(expectedJsonString); - Map> xsiTypeMap = new HashMap>(); - xsiTypeMap.put("string", new XMLXsiTypeConverter() { - @Override public String convert(final String value) { - return value; - } - }); - xsiTypeMap.put("integer", new XMLXsiTypeConverter() { - @Override public Integer convert(final String value) { - return Integer.valueOf(value); - } - }); - JSONObject actualJson = XML.toJSONObject(originalXml, new XMLParserConfiguration().withXsiTypeMap(xsiTypeMap)); - Util.compareActualVsExpectedJsonObjects(actualJson,expectedJson); - } - - @Test - public void testToJsonWithXSITypeWhenTypeConversionNotEnabledOnOne() { - String originalXml = "1234554321"; - String expectedJsonString = "{\"root\":{\"asString\":\"12345\",\"asInt\":54321}}"; - JSONObject expectedJson = new JSONObject(expectedJsonString); - Map> xsiTypeMap = new HashMap>(); - xsiTypeMap.put("string", new XMLXsiTypeConverter() { - @Override public String convert(final String value) { - return value; - } - }); - JSONObject actualJson = XML.toJSONObject(originalXml, new XMLParserConfiguration().withXsiTypeMap(xsiTypeMap)); - Util.compareActualVsExpectedJsonObjects(actualJson,expectedJson); - } - - @Test - public void testXSITypeMapNotModifiable() { - Map> xsiTypeMap = new HashMap>(); - XMLParserConfiguration config = new XMLParserConfiguration().withXsiTypeMap(xsiTypeMap); - xsiTypeMap.put("string", new XMLXsiTypeConverter() { - @Override public String convert(final String value) { - return value; - } - }); - assertEquals("Config Conversion Map size is expected to be 0", 0, config.getXsiTypeMap().size()); - - try { - config.getXsiTypeMap().put("boolean", new XMLXsiTypeConverter() { - @Override public Boolean convert(final String value) { - return Boolean.valueOf(value); - } - }); - fail("Expected to be unable to modify the config"); - } catch (Exception ignored) { } - } - - @Test - public void testIndentComplicatedJsonObject(){ - String str = "{\n" + - " \"success\": true,\n" + - " \"error\": null,\n" + - " \"response\": [\n" + - " {\n" + - " \"timestamp\": 1664917200,\n" + - " \"dateTimeISO\": \"2022-10-05T00:00:00+03:00\",\n" + - " \"loc\": {\n" + - " \"lat\": 39.91987,\n" + - " \"long\": 32.85427\n" + - " },\n" + - " \"place\": {\n" + - " \"name\": \"ankara\",\n" + - " \"state\": \"an\",\n" + - " \"country\": \"tr\"\n" + - " },\n" + - " \"profile\": {\n" + - " \"tz\": \"Europe/Istanbul\"\n" + - " },\n" + - " \"sun\": {\n" + - " \"rise\": 1664941721,\n" + - " \"riseISO\": \"2022-10-05T06:48:41+03:00\",\n" + - " \"set\": 1664983521,\n" + - " \"setISO\": \"2022-10-05T18:25:21+03:00\",\n" + - " \"transit\": 1664962621,\n" + - " \"transitISO\": \"2022-10-05T12:37:01+03:00\",\n" + - " \"midnightSun\": false,\n" + - " \"polarNight\": false,\n" + - " \"twilight\": {\n" + - " \"civilBegin\": 1664940106,\n" + - " \"civilBeginISO\": \"2022-10-05T06:21:46+03:00\",\n" + - " \"civilEnd\": 1664985136,\n" + - " \"civilEndISO\": \"2022-10-05T18:52:16+03:00\",\n" + - " \"nauticalBegin\": 1664938227,\n" + - " \"nauticalBeginISO\": \"2022-10-05T05:50:27+03:00\",\n" + - " \"nauticalEnd\": 1664987015,\n" + - " \"nauticalEndISO\": \"2022-10-05T19:23:35+03:00\",\n" + - " \"astronomicalBegin\": 1664936337,\n" + - " \"astronomicalBeginISO\": \"2022-10-05T05:18:57+03:00\",\n" + - " \"astronomicalEnd\": 1664988905,\n" + - " \"astronomicalEndISO\": \"2022-10-05T19:55:05+03:00\"\n" + - " }\n" + - " },\n" + - " \"moon\": {\n" + - " \"rise\": 1664976480,\n" + - " \"riseISO\": \"2022-10-05T16:28:00+03:00\",\n" + - " \"set\": 1664921520,\n" + - " \"setISO\": \"2022-10-05T01:12:00+03:00\",\n" + - " \"transit\": 1664994240,\n" + - " \"transitISO\": \"2022-10-05T21:24:00+03:00\",\n" + - " \"underfoot\": 1664949360,\n" + - " \"underfootISO\": \"2022-10-05T08:56:00+03:00\",\n" + - " \"phase\": {\n" + - " \"phase\": 0.3186,\n" + - " \"name\": \"waxing gibbous\",\n" + - " \"illum\": 71,\n" + - " \"age\": 9.41,\n" + - " \"angle\": 0.55\n" + - " }\n" + - " }\n" + - " }\n" + - " ]\n" + - "}" ; - JSONObject jsonObject = new JSONObject(str); - String actualIndentedXmlString = XML.toString(jsonObject, 1); - JSONObject actualJsonObject = XML.toJSONObject(actualIndentedXmlString); - String expected = "true\n" + - "\n" + - " 2022-10-05T00:00:00+03:00\n" + - " \n" + - " 39.91987\n" + - " 32.85427\n" + - " \n" + - " \n" + - " \n" + - " 0.3186\n" + - " waxing gibbous\n" + - " 0.55\n" + - " 71\n" + - " 9.41\n" + - " \n" + - " 2022-10-05T01:12:00+03:00\n" + - " 1664949360\n" + - " 1664921520\n" + - " 1664994240\n" + - " 2022-10-05T21:24:00+03:00\n" + - " 2022-10-05T16:28:00+03:00\n" + - " 1664976480\n" + - " 2022-10-05T08:56:00+03:00\n" + - " \n" + - " \n" + - " Europe/Istanbul\n" + - " \n" + - " \n" + - " tr\n" + - " ankara\n" + - " an\n" + - " \n" + - " \n" + - " 2022-10-05T18:25:21+03:00\n" + - " false\n" + - " 1664983521\n" + - " 1664962621\n" + - " false\n" + - " 2022-10-05T12:37:01+03:00\n" + - " 2022-10-05T06:48:41+03:00\n" + - " 1664941721\n" + - " \n" + - " 1664985136\n" + - " 1664936337\n" + - " 1664988905\n" + - " 2022-10-05T05:18:57+03:00\n" + - " 1664940106\n" + - " 2022-10-05T19:23:35+03:00\n" + - " 2022-10-05T19:55:05+03:00\n" + - " 1664938227\n" + - " 1664987015\n" + - " 2022-10-05T05:50:27+03:00\n" + - " 2022-10-05T06:21:46+03:00\n" + - " 2022-10-05T18:52:16+03:00\n" + - " \n" + - " \n" + - " 1664917200\n" + - "\n" + - "null\n"; - JSONObject expectedJsonObject = XML.toJSONObject(expected); - assertTrue(expectedJsonObject.similar(actualJsonObject)); - - - } - - @Test - public void shouldCreateExplicitEndTagWithEmptyValueWhenConfigured(){ - String jsonString = "{\"outer\":{\"innerOne\":\"\", \"innerTwo\":\"two\"}}"; - JSONObject jsonObject = new JSONObject(jsonString); - String expectedXmlString = "two"; - String xmlForm = XML.toString(jsonObject,"encloser", new XMLParserConfiguration().withCloseEmptyTag(true)); - JSONObject actualJsonObject = XML.toJSONObject(xmlForm); - JSONObject expectedJsonObject = XML.toJSONObject(expectedXmlString); - assertTrue(expectedJsonObject.similar(actualJsonObject)); - } - - @Test - public void shouldNotCreateExplicitEndTagWithEmptyValueWhenNotConfigured(){ - String jsonString = "{\"outer\":{\"innerOne\":\"\", \"innerTwo\":\"two\"}}"; - JSONObject jsonObject = new JSONObject(jsonString); - String expectedXmlString = "two"; - String xmlForm = XML.toString(jsonObject,"encloser", new XMLParserConfiguration().withCloseEmptyTag(false)); - JSONObject actualJsonObject = XML.toJSONObject(xmlForm); - JSONObject expectedJsonObject = XML.toJSONObject(expectedXmlString); - assertTrue(expectedJsonObject.similar(actualJsonObject)); - } - - - @Test - public void testIndentSimpleJsonObject(){ - String str = "{ \"employee\": { \n" + - " \"name\": \"sonoo\", \n" + - " \"salary\": 56000, \n" + - " \"married\": true \n" + - " }}"; - JSONObject jsonObject = new JSONObject(str); - String actual = XML.toString(jsonObject, "Test", 2); - JSONObject actualJsonObject = XML.toJSONObject(actual); - String expected = "\n" + - " \n" + - " sonoo\n" + - " 56000\n" + - " true\n" + - " \n" + - "\n"; - JSONObject expectedJsonObject = XML.toJSONObject(expected); - assertTrue(expectedJsonObject.similar(actualJsonObject)); - } - - @Test - public void testIndentSimpleJsonArray(){ - String str = "[ \n" + - " {\"name\":\"Ram\", \"email\":\"Ram@gmail.com\"}, \n" + - " {\"name\":\"Bob\", \"email\":\"bob32@gmail.com\"} \n" + - "] "; - JSONArray jsonObject = new JSONArray(str); - String actual = XML.toString(jsonObject, 2); - JSONObject actualJsonObject = XML.toJSONObject(actual); - String expected = "\n" + - " Ram\n" + - " Ram@gmail.com\n" + - "\n" + - "\n" + - " Bob\n" + - " bob32@gmail.com\n" + - "\n"; - JSONObject expectedJsonObject = XML.toJSONObject(expected); - assertTrue(expectedJsonObject.similar(actualJsonObject)); - - - } - - @Test - public void testIndentComplicatedJsonObjectWithArrayAndWithConfig(){ - try (InputStream jsonStream = XMLTest.class.getClassLoader().getResourceAsStream("Issue593.json")) { - final JSONObject object = new JSONObject(new JSONTokener(jsonStream)); - String actualString = XML.toString(object, null, XMLParserConfiguration.KEEP_STRINGS, 2); - try (InputStream xmlStream = XMLTest.class.getClassLoader().getResourceAsStream("Issue593.xml")) { - int bufferSize = 1024; - char[] buffer = new char[bufferSize]; - StringBuilder expected = new StringBuilder(); - Reader in = new InputStreamReader(xmlStream, "UTF-8"); - for (int numRead; (numRead = in.read(buffer, 0, buffer.length)) > 0; ) { - expected.append(buffer, 0, numRead); - } - assertTrue(XML.toJSONObject(expected.toString()).similar(XML.toJSONObject(actualString))); - } - } catch (IOException e) { - fail("file writer error: " +e.getMessage()); - } - } - - @Test - public void testMaxNestingDepthOf42IsRespected() { - final String wayTooLongMalformedXML = new String(new char[6000]).replace("\0", ""); - - final int maxNestingDepth = 42; - - try { - XML.toJSONObject(wayTooLongMalformedXML, XMLParserConfiguration.ORIGINAL.withMaxNestingDepth(maxNestingDepth)); - - fail("Expecting a JSONException"); - } catch (JSONException e) { - assertTrue("Wrong throwable thrown: not expecting message <" + e.getMessage() + ">", - e.getMessage().startsWith("Maximum nesting depth of " + maxNestingDepth)); - } - } - - @Test - public void testMaxNestingDepthIsRespectedWithValidXML() { - final String perfectlyFineXML = "\n" + - " \n" + - " sonoo\n" + - " 56000\n" + - " true\n" + - " \n" + - "\n"; - - final int maxNestingDepth = 1; - - try { - XML.toJSONObject(perfectlyFineXML, XMLParserConfiguration.ORIGINAL.withMaxNestingDepth(maxNestingDepth)); - - fail("Expecting a JSONException"); - } catch (JSONException e) { - assertTrue("Wrong throwable thrown: not expecting message <" + e.getMessage() + ">", - e.getMessage().startsWith("Maximum nesting depth of " + maxNestingDepth)); - } - } - - @Test - public void testMaxNestingDepthWithValidFittingXML() { - final String perfectlyFineXML = "\n" + - " \n" + - " sonoo\n" + - " 56000\n" + - " true\n" + - " \n" + - "\n"; - - final int maxNestingDepth = 3; - - try { - XML.toJSONObject(perfectlyFineXML, XMLParserConfiguration.ORIGINAL.withMaxNestingDepth(maxNestingDepth)); - } catch (JSONException e) { - e.printStackTrace(); - fail("XML document should be parsed as its maximum depth fits the maxNestingDepth " + - "parameter of the XMLParserConfiguration used"); - } - } - @Test - public void testWithWhitespaceTrimmingDisabled() { - String originalXml = " Test Whitespace String \t "; - - JSONObject actualJson = XML.toJSONObject(originalXml, new XMLParserConfiguration().withShouldTrimWhitespace(false)); - String expectedJsonString = "{\"testXml\":\" Test Whitespace String \t \"}"; - JSONObject expectedJson = new JSONObject(expectedJsonString); - Util.compareActualVsExpectedJsonObjects(actualJson,expectedJson); - } - @Test - public void testNestedWithWhitespaceTrimmingDisabled() { - String originalXml = - "\n"+ - "\n"+ - "
    \n"+ - " Sherlock Holmes \n"+ - "
    \n"+ - "
    "; - - JSONObject actualJson = XML.toJSONObject(originalXml, new XMLParserConfiguration().withShouldTrimWhitespace(false)); - String expectedJsonString = "{\"addresses\":{\"address\":{\"name\":\" Sherlock Holmes \"}}}"; - JSONObject expectedJson = new JSONObject(expectedJsonString); - Util.compareActualVsExpectedJsonObjects(actualJson,expectedJson); - } - @Test - public void shouldTrimWhitespaceDoesNotSupportTagsEqualingCDataTagName() { - // When using withShouldTrimWhitespace = true, input containing tags with same name as cDataTagName is unsupported and should not be used in conjunction - String originalXml = - "\n"+ - "\n"+ - "
    \n"+ - " Sherlock Holmes \n"+ - "
    \n"+ - "
    "; - - JSONObject actualJson = XML.toJSONObject(originalXml, new XMLParserConfiguration().withShouldTrimWhitespace(false).withcDataTagName("content")); - String expectedJsonString = "{\"addresses\":{\"address\":[[\"\\n \",\" Sherlock Holmes \",\"\\n \"]]}}"; - JSONObject expectedJson = new JSONObject(expectedJsonString); - Util.compareActualVsExpectedJsonObjects(actualJson,expectedJson); - } - @Test - public void shouldTrimWhitespaceEnabledDropsTagsEqualingCDataTagNameButValueRemains() { - String originalXml = - "\n"+ - "\n"+ - "
    \n"+ - " Sherlock Holmes \n"+ - "
    \n"+ - "
    "; - - JSONObject actualJson = XML.toJSONObject(originalXml, new XMLParserConfiguration().withShouldTrimWhitespace(true).withcDataTagName("content")); - String expectedJsonString = "{\"addresses\":{\"address\":\"Sherlock Holmes\"}}"; - JSONObject expectedJson = new JSONObject(expectedJsonString); - Util.compareActualVsExpectedJsonObjects(actualJson,expectedJson); - } - @Test - public void testWithWhitespaceTrimmingEnabled() { - String originalXml = " Test Whitespace String \t "; - - JSONObject actualJson = XML.toJSONObject(originalXml, new XMLParserConfiguration().withShouldTrimWhitespace(true)); - String expectedJsonString = "{\"testXml\":\"Test Whitespace String\"}"; - JSONObject expectedJson = new JSONObject(expectedJsonString); - Util.compareActualVsExpectedJsonObjects(actualJson,expectedJson); - } - @Test - public void testWithWhitespaceTrimmingEnabledByDefault() { - String originalXml = " Test Whitespace String \t "; - - JSONObject actualJson = XML.toJSONObject(originalXml, new XMLParserConfiguration()); - String expectedJsonString = "{\"testXml\":\"Test Whitespace String\"}"; - JSONObject expectedJson = new JSONObject(expectedJsonString); - Util.compareActualVsExpectedJsonObjects(actualJson,expectedJson); - } - - @Test - public void clarifyCurrentBehavior() { - - // Behavior documented in #826 - // After reverting the code, amount is stored as numeric, and phone is stored as string - String str1 = - " \n" + - " 0123456789\n" + - " 0.1230\n" + - " true\n" + - " "; - JSONObject jsonObject1 = XML.toJSONObject(str1, - new XMLParserConfiguration().withKeepStrings(false)); - assertEquals(jsonObject1.getJSONObject("datatypes").getFloat("amount"), 0.123, .1); - assertEquals(jsonObject1.getJSONObject("datatypes").getString("telephone"), "0123456789"); - - - // Behavior documented in #852 - // After reverting the code, value is still stored as a number. This is due to how XML.isDecimalNotation() works - // and is probably a bug. JSONObject has a similar problem. - String str2 = " primary 008E97 "; - JSONObject jsonObject2 = XML.toJSONObject(str2); - assertEquals(jsonObject2.getJSONObject("color").getLong("value"), 0e897, .1); - - // Workaround for now is to use keepStrings - JSONObject jsonObject3 = XML.toJSONObject(str2, new XMLParserConfiguration().withKeepStrings(true)); - assertEquals(jsonObject3.getJSONObject("color").getString("value"), "008E97"); - } - - /** - * Tests that empty numeric character reference &#; throws JSONException. - * Previously threw StringIndexOutOfBoundsException. - * Related to issue #1035 - */ - @Test(expected = JSONException.class) - public void testEmptyNumericEntityThrowsJSONException() { - String xmlStr = "
    &#;"; - XML.toJSONObject(xmlStr); - } - - /** - * Tests that malformed decimal entity &#txx; throws JSONException. - * Previously threw NumberFormatException. - * Related to issue #1036 - */ - @Test(expected = JSONException.class) - public void testInvalidDecimalEntityThrowsJSONException() { - String xmlStr = "&#txx;"; - XML.toJSONObject(xmlStr); - } - - /** - * Tests that empty hex entity &#x; throws JSONException. - * Validates proper input validation for hex entities. - */ - @Test(expected = JSONException.class) - public void testEmptyHexEntityThrowsJSONException() { - String xmlStr = "&#x;"; - XML.toJSONObject(xmlStr); - } - - /** - * Tests that invalid hex entity &#xGGG; throws JSONException. - * Validates hex digit validation. - */ - @Test(expected = JSONException.class) - public void testInvalidHexEntityThrowsJSONException() { - String xmlStr = "&#xGGG;"; - XML.toJSONObject(xmlStr); - } - - /** - * Tests that valid decimal numeric entity A works correctly. - * Should decode to character 'A'. - */ - @Test - public void testValidDecimalEntity() { - String xmlStr = "A"; - JSONObject jsonObject = XML.toJSONObject(xmlStr); - assertEquals("A", jsonObject.getString("a")); - } - - /** - * Tests that valid hex numeric entity A works correctly. - * Should decode to character 'A'. - */ - @Test - public void testValidHexEntity() { - String xmlStr = "A"; - JSONObject jsonObject = XML.toJSONObject(xmlStr); - assertEquals("A", jsonObject.getString("a")); - } - - /** - * Tests that valid uppercase hex entity A works correctly. - * Should decode to character 'A'. - */ - @Test - public void testValidUppercaseHexEntity() { - String xmlStr = "A"; - JSONObject jsonObject = XML.toJSONObject(xmlStr); - assertEquals("A", jsonObject.getString("a")); - } - -} - - - diff --git a/src/test/java/org/json/junit/XMLTokenerTest.java b/src/test/java/org/json/junit/XMLTokenerTest.java deleted file mode 100644 index ca2f2075e..000000000 --- a/src/test/java/org/json/junit/XMLTokenerTest.java +++ /dev/null @@ -1,81 +0,0 @@ -package org.json.junit; - -import org.json.XMLTokener; -import org.junit.Test; - -import java.io.StringReader; - -import static org.junit.Assert.*; - -/** - * Tests for JSON-Java XMLTokener.java - */ -public class XMLTokenerTest { - - /** - * Tests that nextCDATA() correctly extracts content from within a CDATA section. - */ - @Test - public void testNextCDATA() { - String xml = "This is content ]]> after"; - XMLTokener tokener = new XMLTokener(new StringReader(xml)); - tokener.skipPast(" content ", cdata); - } - - /** - * Tests that nextContent() returns plain text content before a tag. - */ - @Test - public void testNextContentWithText() { - String xml = "Some content"; - XMLTokener tokener = new XMLTokener(xml); - Object content = tokener.nextContent(); - assertEquals("Some content", content); - } - - /** - * Tests that nextContent() returns '<' character when starting with a tag. - */ - @Test - public void testNextContentWithTag() { - String xml = ""; - XMLTokener tokener = new XMLTokener(xml); - Object content = tokener.nextContent(); - assertEquals('<', content); - } - - /** - * Tests that nextEntity() resolves a known entity like & correctly. - */ - @Test - public void testNextEntityKnown() { - XMLTokener tokener = new XMLTokener("amp;"); - Object result = tokener.nextEntity('&'); - assertEquals("&", result); - } - - /** - * Tests that nextEntity() preserves unknown entities by returning them unchanged. - */ - @Test - public void testNextEntityUnknown() { - XMLTokener tokener = new XMLTokener("unknown;"); - tokener.next(); // skip 'u' - Object result = tokener.nextEntity('&'); - assertEquals("&nknown;", result); // malformed start to simulate unknown - } - - /** - * Tests skipPast() to ensure the cursor moves past the specified string. - */ - @Test - public void testSkipPast() { - String xml = "Ignore this... endHere more text"; - XMLTokener tokener = new XMLTokener(xml); - tokener.skipPast("endHere"); - assertEquals(' ', tokener.next()); // should be the space after "endHere" - } - -} \ No newline at end of file diff --git a/src/test/java/org/json/junit/data/MyBeanCustomName.java b/src/test/java/org/json/junit/data/MyBeanCustomName.java deleted file mode 100644 index 56756c2b3..000000000 --- a/src/test/java/org/json/junit/data/MyBeanCustomName.java +++ /dev/null @@ -1,20 +0,0 @@ -package org.json.junit.data; - -import org.json.JSONPropertyName; - -/** - * Test bean for the {@link JSONPropertyName} annotation. - */ -public class MyBeanCustomName implements MyBeanCustomNameInterface { - public int getSomeInt() { return 42; } - @JSONPropertyName("") - public long getSomeLong() { return 42L; } - @JSONPropertyName("myStringField") - public String getSomeString() { return "someStringValue"; } - @JSONPropertyName("Some Weird NAme that Normally Wouldn't be possible!") - public double getMyDouble() { return 0.0d; } - @Override - public float getSomeFloat() { return 2.0f; } - @Override - public int getIgnoredInt() { return 40; } -} diff --git a/src/test/java/org/json/junit/data/MyBeanCustomNameInterface.java b/src/test/java/org/json/junit/data/MyBeanCustomNameInterface.java deleted file mode 100644 index b25b57873..000000000 --- a/src/test/java/org/json/junit/data/MyBeanCustomNameInterface.java +++ /dev/null @@ -1,11 +0,0 @@ -package org.json.junit.data; - -import org.json.JSONPropertyIgnore; -import org.json.JSONPropertyName; - -public interface MyBeanCustomNameInterface { - @JSONPropertyName("InterfaceField") - float getSomeFloat(); - @JSONPropertyIgnore - int getIgnoredInt(); -} \ No newline at end of file diff --git a/src/test/java/org/json/junit/data/MyBeanCustomNameSubClass.java b/src/test/java/org/json/junit/data/MyBeanCustomNameSubClass.java deleted file mode 100644 index 8f0500cce..000000000 --- a/src/test/java/org/json/junit/data/MyBeanCustomNameSubClass.java +++ /dev/null @@ -1,32 +0,0 @@ -/** - * - */ -package org.json.junit.data; - -import org.json.JSONPropertyIgnore; -import org.json.JSONPropertyName; - -/** - * Test bean to verify that the {@link org.json.JSONPropertyName} annotation - * is inherited. - */ -public class MyBeanCustomNameSubClass extends MyBeanCustomName { - @Override - @JSONPropertyName("forcedInt") - public int getIgnoredInt() { return 42*42; } - @Override - @JSONPropertyName("newIntFieldName") - public int getSomeInt() { return 43; } - @Override - public String getSomeString() { return "subClassString"; } - @Override - @JSONPropertyName("AMoreNormalName") - public double getMyDouble() { return 1.0d; } - @Override - public float getSomeFloat() { return 3.0f; } - @JSONPropertyIgnore - @JSONPropertyName("ShouldBeIgnored") - public boolean getShouldNotBeJSON() { return true; } - @JSONPropertyName("Getable") - public boolean getable() { return true; } -} diff --git a/src/test/resources/jsonpointer-testdoc.json b/src/test/resources/jsonpointer-testdoc.json deleted file mode 100644 index 657ccdd34..000000000 --- a/src/test/resources/jsonpointer-testdoc.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "foo": - [ - "bar", - "baz" - ], - "": 0, - "a/b": 1, - "c%d": 2, - "e^f": 3, - "g|h": 4, - "i\\j": 5, - "k\"l": 6, - " ": 7, - "m~n": 8, - "obj" : { - "key" : "value", - "other~key" : { - "another/key" : [ - "val" - ] - }, - "" : { - "" : "empty key of an object with an empty key", - "subKey" : "Some other value" - } - } -} \ No newline at end of file