diff --git a/.github/workflows/pipeline.yml b/.github/workflows/pipeline.yml index ce91174b50a3988c68eaa719dc3aa1f6b2060152..08352a085fd69569695c5990c1f0ade102de3c77 100644 --- a/.github/workflows/pipeline.yml +++ b/.github/workflows/pipeline.yml @@ -42,7 +42,7 @@ jobs: strategy: matrix: # build against supported Java LTS versions: - java: [ 1.7, 8, 11 ] + java: [ 8, 11 ] name: Java ${{ matrix.java }} steps: - uses: actions/checkout@v2 diff --git a/Examples.md b/Examples.md index 3f45e78d98dc3837d4c658ac82910e0fe0f11505..fb010d5dc7cf0371c83e1acad31df2672230397f 100644 --- a/Examples.md +++ b/Examples.md @@ -1,7 +1,7 @@

Examples

Imports used in the examples:

-``` +```java import java.util.HashMap; import java.util.Map; import java.util.Properties; @@ -14,353 +14,353 @@ import java.util.Properties;

Using JSONArray

-``` - private static void JSONExampleArray1() { - //We create a JSONObject from a String containing an array using JSONArray - //Firstly, we declare an Array in a String - - String arrayStr = - "["+"true,"+"false,"+ "\"true\","+ "\"false\","+"\"hello\","+"23.45e-4,"+ - "\"23.45\","+"42,"+"\"43\","+"["+"\"world\""+"],"+ - "{"+ - "\"key1\":\"value1\","+ - "\"key2\":\"value2\","+ - "\"key3\":\"value3\","+ - "\"key4\":\"value4\""+ - "},"+ - "0,"+"\"-1\""+ - "]"; - - //Then, we initializate the JSONArray thanks to its constructor - - JSONArray array = new JSONArray(arrayStr); - System.out.println("Values array: "+ array); - - //We convert that array into a JSONObject, but first, we need the labels, so we need another JSONArray with the labels. - //Here we will use an auxiliary function to get one for the example. - - JSONArray list = listNumberArray(array.length()); - System.out.println("Label Array: "+ list.toString()); - //Now, we construct the JSONObject using both the value array and the label array. - JSONObject object = array.toJSONObject(list); - System.out.println("Final JSONOBject: " + object); - } +```java +private static void JSONExampleArray1() { + //We create a JSONObject from a String containing an array using JSONArray + //Firstly, we declare an Array in a String + + String arrayStr = + "["+"true,"+"false,"+ "\"true\","+ "\"false\","+"\"hello\","+"23.45e-4,"+ + "\"23.45\","+"42,"+"\"43\","+"["+"\"world\""+"],"+ + "{"+ + "\"key1\":\"value1\","+ + "\"key2\":\"value2\","+ + "\"key3\":\"value3\","+ + "\"key4\":\"value4\""+ + "},"+ + "0,"+"\"-1\""+ + "]"; + + //Then, we initializate the JSONArray thanks to its constructor + + JSONArray array = new JSONArray(arrayStr); + System.out.println("Values array: "+ array); + + //We convert that array into a JSONObject, but first, we need the labels, so we need another JSONArray with the labels. + //Here we will use an auxiliary function to get one for the example. + + JSONArray list = listNumberArray(array.length()); + System.out.println("Label Array: "+ list.toString()); + //Now, we construct the JSONObject using both the value array and the label array. + JSONObject object = array.toJSONObject(list); + System.out.println("Final JSONOBject: " + object); +} - //This method creates an JSONArray of labels in which those are generated by their positions +//This method creates an JSONArray of labels in which those are generated by their positions - private static JSONArray listNumberArray(int max){ - JSONArray res = new JSONArray(); - for (int i=0; iUsing JSONStringer -``` - private static void JSONExampleStringer() { +```java +private static void JSONExampleStringer() { - //We initializate the JSONStringer + //We initializate the JSONStringer - JSONStringer jsonStringer = new JSONStringer(); + JSONStringer jsonStringer = new JSONStringer(); - //Now we start the process of adding elements with .object() + //Now we start the process of adding elements with .object() - jsonStringer.object(); + jsonStringer.object(); - //We can now add elements as keys and values with .values () and .key() + //We can now add elements as keys and values with .values () and .key() - jsonStringer.key("trueValue").value(true); - jsonStringer.key("falseValue").value(false); - jsonStringer.key("nullValue").value(null); - jsonStringer.key("stringValue").value("hello world!"); - jsonStringer.key("complexStringValue").value("h\be\tllo w\u1234orld!"); - jsonStringer.key("intValue").value(42); - jsonStringer.key("doubleValue").value(-23.45e67); + jsonStringer.key("trueValue").value(true); + jsonStringer.key("falseValue").value(false); + jsonStringer.key("nullValue").value(null); + jsonStringer.key("stringValue").value("hello world!"); + jsonStringer.key("complexStringValue").value("h\be\tllo w\u1234orld!"); + jsonStringer.key("intValue").value(42); + jsonStringer.key("doubleValue").value(-23.45e67); - //We end this prcedure with .ednObject + //We end this prcedure with .ednObject - jsonStringer.endObject(); + jsonStringer.endObject(); - //Once we have a JSONStringer, we convert it to JSONObject generating a String and using JSONObject's contructor. + //Once we have a JSONStringer, we convert it to JSONObject generating a String and using JSONObject's contructor. - String str = jsonStringer.toString(); - JSONObject jsonObject = new JSONObject(str); - - System.out.println("Final JSONOBject: " + jsonObject); - } + String str = jsonStringer.toString(); + JSONObject jsonObject = new JSONObject(str); + + System.out.println("Final JSONOBject: " + jsonObject); +} ```

Using JSONObject

-``` - private static void JSONExampleObject1() { +```java +private static void JSONExampleObject1() { - //We can create a JSONObject from a String with the class builder + //We can create a JSONObject from a String with the class builder - String string = "{\"0\":\"value\",\"1\":5,\"2\":-2.345E68,\"3\":true}"; - JSONObject example = new JSONObject(string); - System.out.println("Final JSONObject: " + example); - - } -``` + String string = "{\"0\":\"value\",\"1\":5,\"2\":-2.345E68,\"3\":true}"; + JSONObject example = new JSONObject(string); + System.out.println("Final JSONObject: " + example); + +} ``` - private static void JSONExampleObject2() { +```java +private static void JSONExampleObject2() { - //We can also create a JSONObject directly without messing around with any of the other functions. + //We can also create a JSONObject directly without messing around with any of the other functions. - JSONObject example = new JSONObject(); + JSONObject example = new JSONObject(); - //Now we add the keys and values in a similar way as the Stringer method - example.put("key", "value"); + //Now we add the keys and values in a similar way as the Stringer method + example.put("key", "value"); - //As you can see, the first entry is the key and the second would be its associeted value. + //As you can see, the first entry is the key and the second would be its associeted value. - example.put("key2", 5); - example.put("key3", -23.45e67); - example.put("trueValue", true); + example.put("key2", 5); + example.put("key3", -23.45e67); + example.put("trueValue", true); - //We can't add null values thougth + //We can't add null values thougth - //example.put("nullValue", null); //This is not possible - - System.out.println("Final JSONOBject: " + example); - } -``` + //example.put("nullValue", null); //This is not possible + + System.out.println("Final JSONOBject: " + example); +} ``` - private static void JSONExampleObject3() { +```java +private static void JSONExampleObject3() { - //We can also create a JSONObject with a Java Map - //YoU will need a Map whose keys are Strings. The values can be whatever you want + //We can also create a JSONObject with a Java Map + //YoU will need a Map whose keys are Strings. The values can be whatever you want - Map map = new HashMap(); - - map.put("key1", 1.0); - map.put("key2", -23.45e67); - - //We create the JSONObject with the map with its class builder + Map map = new HashMap(); - JSONObject example = new JSONObject(map); - System.out.println("Final JSONOBject: " + example); - } + map.put("key1", 1.0); + map.put("key2", -23.45e67); + + //We create the JSONObject with the map with its class builder + + JSONObject example = new JSONObject(map); + System.out.println("Final JSONOBject: " + example); +} ```

Using JSONWriter

-``` - private static void JSONExamplWriter() { - - //This method works in a very similar way to Object and Stringer in the construction of the JSON. - //The difference is that it needs a Java object called "Appendable" like StringBuilder - - StringBuilder write = new StringBuilder(); - JSONWriter jsonWriter = new JSONWriter(write); - - //We behave now the same way as Stringer - - jsonWriter.object(); - - jsonWriter.key("trueValue").value(true); - jsonWriter.key("falseValue").value(false); - jsonWriter.key("nullValue").value(null); - jsonWriter.key("stringValue").value("hello world!"); - jsonWriter.key("complexStringValue").value("h\be\tllo w\u1234orld!"); - jsonWriter.key("intValue").value(42); - jsonWriter.key("doubleValue").value(-23.45e67); - - jsonWriter.endObject(); - - //The resoult should be in the "write" object - - System.out.println("JSON: " + write.toString()); - - //The difference is that we don't get a JSONObject in this one. - - - } +```java +private static void JSONExamplWriter() { + + //This method works in a very similar way to Object and Stringer in the construction of the JSON. + //The difference is that it needs a Java object called "Appendable" like StringBuilder + + StringBuilder write = new StringBuilder(); + JSONWriter jsonWriter = new JSONWriter(write); + + //We behave now the same way as Stringer + + jsonWriter.object(); + + jsonWriter.key("trueValue").value(true); + jsonWriter.key("falseValue").value(false); + jsonWriter.key("nullValue").value(null); + jsonWriter.key("stringValue").value("hello world!"); + jsonWriter.key("complexStringValue").value("h\be\tllo w\u1234orld!"); + jsonWriter.key("intValue").value(42); + jsonWriter.key("doubleValue").value(-23.45e67); + + jsonWriter.endObject(); + + //The resoult should be in the "write" object + + System.out.println("JSON: " + write.toString()); + + //The difference is that we don't get a JSONObject in this one. + + +} ``` -``` - private static void JSONExampleTokener() { +```java +private static void JSONExampleTokener() { - //A partir de una String podemos crear un JSONTokener, que lo podemos usar alternativamente para JSONArray,JSONObject + //A partir de una String podemos crear un JSONTokener, que lo podemos usar alternativamente para JSONArray,JSONObject - String string = "this is not a valid JSON string"; - JSONTokener token = new JSONTokener(string); - - //Now you can use the token in JSONObject and Array the same way as a String + String string = "this is not a valid JSON string"; + JSONTokener token = new JSONTokener(string); - JSONObject object = new JSONObject(token); - JSONArray array = new JSONArray(token); - - } + //Now you can use the token in JSONObject and Array the same way as a String + + JSONObject object = new JSONObject(token); + JSONArray array = new JSONArray(token); + +} ```

Part 2: Conversion methods

-

We don't need to have a JSON docuemnt to work. This project also admits conversions from other type of files.

+

We don't need to have a JSON document to work. This project also admits conversions from other type of files.

Secondly, we can also convert from JSON to those type of files.

Extra: Conversion to JSONArray

-``` - private static void JSONObjectToArray() { - //We start with a JSONObject - - String string = "{\"0\":\"value\",\"1\":5,\"2\":-2.345E68,\"3\":true}"; - - JSONObject example = new JSONObject(string); - - //We need a list of key strings like the reverse operation - - JSONArray keyStrings = listNumberArray(example.length()); - - //Then we convert to the Array using both elelements - - JSONArray array = example.toJSONArray(keyStrings); - - System.out.println("Final JSONArray: " + array); - } +```java +private static void JSONObjectToArray() { + //We start with a JSONObject + + String string = "{\"0\":\"value\",\"1\":5,\"2\":-2.345E68,\"3\":true}"; + + JSONObject example = new JSONObject(string); + + //We need a list of key strings like the reverse operation + + JSONArray keyStrings = listNumberArray(example.length()); + + //Then we convert to the Array using both elelements + + JSONArray array = example.toJSONArray(keyStrings); + + System.out.println("Final JSONArray: " + array); +} ```

XML Conversions

-``` - private static void XMLToExampleConversion() { +```java +private static void XMLToExampleConversion() { + + //We start with a JSONObject - //We start with a JSONObject - - String string = "{\"0\":\"value\",\"1\":5,\"2\":-2.345E68,\"3\":true}"; - JSONObject example = new JSONObject(string); + String string = "{\"0\":\"value\",\"1\":5,\"2\":-2.345E68,\"3\":true}"; + JSONObject example = new JSONObject(string); - //We obtain a String with XML format with toString() + //We obtain a String with XML format with toString() - String output = XML.toString(example); - System.out.println("Final XML: " + output); - } + String output = XML.toString(example); + System.out.println("Final XML: " + output); +} ``` -``` - private static void XMLFromExampleConversion() { +```java +private static void XMLFromExampleConversion() { - //We start with a string with the XML format + //We start with a string with the XML format - String string = "<0>value<1>5<2>-2.345E+68<3>true"; + String string = "<0>value<1>5<2>-2.345E+68<3>true"; - //We obtain a JSONObject with toJSONOBject() + //We obtain a JSONObject with toJSONOBject() - JSONObject output = XML.toJSONObject(string); - - System.out.println("Final JSONObject: " + output); - } + JSONObject output = XML.toJSONObject(string); + + System.out.println("Final JSONObject: " + output); +} ```

Cookie Conversions

-``` - private static void CookieToExampleConversion() { +```java +private static void CookieToExampleConversion() { - //We start with a JSONObject - //The JSONOBject needs to entries that gives the cookie a name and gives the field "name" a name too. - //The Cokkie format doesn't support booleans + //We start with a JSONObject + //The JSONOBject needs to entries that gives the cookie a name and gives the field "name" a name too. + //The Cokkie format doesn't support booleans - String string = "{\"name\":\"Cookie-Name\",\"value\":\"name\",\"1\":5,\"2\":-2.345E68,\"3\":'true'}"; - JSONObject example = new JSONObject(string); - - //We obtain a String with Cookie format with toString() + String string = "{\"name\":\"Cookie-Name\",\"value\":\"name\",\"1\":5,\"2\":-2.345E68,\"3\":'true'}"; + JSONObject example = new JSONObject(string); - String output = Cookie.toString(example); - System.out.println("Final Cookie: " + output); - } -``` + //We obtain a String with Cookie format with toString() + + String output = Cookie.toString(example); + System.out.println("Final Cookie: " + output); +} ``` - private static void CookieFromExampleConversion() { +```java +private static void CookieFromExampleConversion() { - //We start with a string with the Cookie format + //We start with a string with the Cookie format - String string = "Cookie-Name=name;1=5;2=-2.345E%2b68;3=true"; + String string = "Cookie-Name=name;1=5;2=-2.345E%2b68;3=true"; - //We obtain a JSONObject with toJSONOBject() + //We obtain a JSONObject with toJSONOBject() - JSONObject output = Cookie.toJSONObject(string); - System.out.println("Final JSONObject: " + output); - } + JSONObject output = Cookie.toJSONObject(string); + System.out.println("Final JSONObject: " + output); +} ```

HTTP Conversions

-``` - private static void HTTPToExampleConversion() { +```java +private static void HTTPToExampleConversion() { - //We start with a JSONObject - //The JSONObject must have the minimun header for a HTTP request or header + //We start with a JSONObject + //The JSONObject must have the minimun header for a HTTP request or header - String string = "{\"Method\":\"POST\",\"Request-URI\":'/',\"HTTP-Version\":'HTTP/1.1',\"Value1\":true,\"Value2\":2,\"Value3\":-2.345E68}"; + String string = "{\"Method\":\"POST\",\"Request-URI\":'/',\"HTTP-Version\":'HTTP/1.1',\"Value1\":true,\"Value2\":2,\"Value3\":-2.345E68}"; - JSONObject example = new JSONObject(string); + JSONObject example = new JSONObject(string); - //We obtain a String with HTTP format with toString() + //We obtain a String with HTTP format with toString() - String output = HTTP.toString(example); - System.out.println("Final HTTP: " + output); - } + String output = HTTP.toString(example); + System.out.println("Final HTTP: " + output); +} ``` -``` - private static void HTTPFromExampleConversion() { +```java +private static void HTTPFromExampleConversion() { - //We start with a string with the HTTP format + //We start with a string with the HTTP format - String string = "Final HTTP: POST '/' HTTP/1.1 Value3: -2.345E+68 Value1: true Value2: 2"; + String string = "Final HTTP: POST '/' HTTP/1.1 Value3: -2.345E+68 Value1: true Value2: 2"; - //We obtain a JSONObject with toJSONOBject() + //We obtain a JSONObject with toJSONOBject() - JSONObject output = HTTP.toJSONObject(string); - System.out.println("Final JSONObject: " + output); - } + JSONObject output = HTTP.toJSONObject(string); + System.out.println("Final JSONObject: " + output); +} ```

CDL Conversions

-``` +```java private static void CDLToExampleConversion() { - //We start with some JSONObjects with the same values in the keys but different values in the "values" + //We start with some JSONObjects with the same values in the keys but different values in the "values" - String string = "{\"0\":\"value\",\"1\":5,\"2\":-2.345E68,\"3\":true}"; - JSONObject example = new JSONObject(string); - - String string2 = "{\"0\":\"value2\",\"1\":6,\"2\":-8.345E68,\"3\":false}"; - JSONObject example2 = new JSONObject(string2); - - //We need now a JSONArray with those JSONObjects + String string = "{\"0\":\"value\",\"1\":5,\"2\":-2.345E68,\"3\":true}"; + JSONObject example = new JSONObject(string); - JSONArray array = new JSONArray(); - array.put(example); - array.put(example2); + String string2 = "{\"0\":\"value2\",\"1\":6,\"2\":-8.345E68,\"3\":false}"; + JSONObject example2 = new JSONObject(string2); - //We obtain a String with XML format with toString() + //We need now a JSONArray with those JSONObjects - String output = CDL.toString(array); - System.out.println("Final CDL: \r\n" + output); - } -``` + JSONArray array = new JSONArray(); + array.put(example); + array.put(example2); + + //We obtain a String with XML format with toString() + + String output = CDL.toString(array); + System.out.println("Final CDL: \r\n" + output); +} ``` +```java private static void CDLFromExampleConversion() { //We start wtih a String with the CDL format @@ -368,7 +368,7 @@ private static void CDLFromExampleConversion() { String string = "0,1,2,3\n" + "value,5,-2.345E+68,true\n" + "value2,6,-8.345E+68,false"; - + //We obtain a JSONArray with toJSONOBject() JSONArray output = CDL.toJSONArray(string); @@ -377,8 +377,8 @@ private static void CDLFromExampleConversion() { ```

Properties Conversions

-``` - private static Properties PropertyToExampleConversion() { +```java +private static Properties PropertyToExampleConversion() { //We start with a JSONObject @@ -391,43 +391,43 @@ private static void CDLFromExampleConversion() { System.out.println("Final Properties: " + output); return output; - } +} ``` -``` - private static void PropertyFromExampleConversion() { +```java +private static void PropertyFromExampleConversion() { - //We start with a Properties object + //We start with a Properties object - Properties input = PropertyToExampleConversion(); + Properties input = PropertyToExampleConversion(); - //We obtain a JSONObject with toJSONOBject() - - JSONObject output = Property.toJSONObject(input); - System.out.println("Final JSONObject: " + output); - } -``` -

List of all examples methods

+ //We obtain a JSONObject with toJSONOBject() + JSONObject output = Property.toJSONObject(input); + System.out.println("Final JSONObject: " + output); +} ``` - public static void main(String[] args) { - //JSONObjectToArray(); - //JSONExampleArray1(); - //JSONExampleArray2(); - //JSONExampleStringer(); - //JSONExampleObject1(); - //JSONExampleObject2(); - //JSONExampleObject3(); - //JSONExamplWriter(); - //XMLToExampleConversion(); - //XMLFromExampleConversion(); - //CookieToExampleConversion(); - //CookieFromExampleConversion(); - //HTTPToExampleConversion(); - //HTTPFromExampleConversion(); - //CDLToExampleConversion(); - //CDLFromExampleConversion(); - //PropertyToExampleConversion(); - //PropertyFromExampleConversion(); - } +

List of all examples methods

+ +```java +public static void main(String[] args) { + //JSONObjectToArray(); + //JSONExampleArray1(); + //JSONExampleArray2(); + //JSONExampleStringer(); + //JSONExampleObject1(); + //JSONExampleObject2(); + //JSONExampleObject3(); + //JSONExamplWriter(); + //XMLToExampleConversion(); + //XMLFromExampleConversion(); + //CookieToExampleConversion(); + //CookieFromExampleConversion(); + //HTTPToExampleConversion(); + //HTTPFromExampleConversion(); + //CDLToExampleConversion(); + //CDLFromExampleConversion(); + //PropertyToExampleConversion(); + //PropertyFromExampleConversion(); +} ``` diff --git a/LICENSE b/LICENSE index 6cfb9b2d078c8c77286bc043c648a7675f2dbcb0..2ef9799e082fa18e62fc5f1fd5ec853e7547bb8e 100644 --- a/LICENSE +++ b/LICENSE @@ -1,23 +1,2 @@ - -Copyright (c) 2002 JSON.org - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -The Software shall be used for Good, not Evil. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +Public Domain. diff --git a/README.md b/README.md index 69869cdf67961135f68942a687ad280ff78b8ad1..e999230ba14d958fcea2daf4aabd81ae33d9485e 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ JSON in Java [package org.json] [![Maven Central](https://img.shields.io/maven-central/v/org.json/json.svg)](https://mvnrepository.com/artifact/org.json/json) -**[Click here if you just want the latest release jar file.](https://search.maven.org/remotecontent?filepath=org/json/json/20220320/json-20220320.jar)** +**[Click here if you just want the latest release jar file.](https://search.maven.org/remotecontent?filepath=org/json/json/20230618/json-20230618.jar)** # Overview @@ -28,8 +28,6 @@ Project goals include: The files in this package implement JSON encoders and decoders. The package can also convert between JSON and XML, HTTP headers, Cookies, and CDL. -The license includes this restriction: ["The software shall be used for good, not evil."](https://en.wikipedia.org/wiki/Douglas_Crockford#%22Good,_not_Evil%22) If your conscience cannot live with that, then choose a different package. - # If you would like to contribute to this project For more information on contributions, please see [CONTRIBUTING.md](https://github.com/stleary/JSON-java/blob/master/docs/CONTRIBUTING.md) diff --git a/docs/RELEASES.md b/docs/RELEASES.md index 149525d5e412ccbcf74d0472640d9b24140fc5e4..ae439831ca053319d4adea7722347fb39aed654a 100644 --- a/docs/RELEASES.md +++ b/docs/RELEASES.md @@ -5,6 +5,12 @@ and artifactId "json". For example: [https://search.maven.org/search?q=g:org.json%20AND%20a:json&core=gav](https://search.maven.org/search?q=g:org.json%20AND%20a:json&core=gav) ~~~ +20230618 Final release with Java 1.6 compatibility. Future releases will require Java 1.8 or greater. + +20230227 Fix for CVE-2022-45688 and recent commits + +20220924 New License - public domain, and some minor updates + 20220320 Wrap StackOverflow with JSONException 20211205 Recent commits and some bug fixes for similar() @@ -18,6 +24,7 @@ and artifactId "json". For example: 20190722 Recent commits 20180813 POM change to include Automatic-Module-Name (#431) + JSONObject(Map) now throws an exception if any of a map keys are null (#405) 20180130 Recent commits diff --git a/pom.xml b/pom.xml index e4a3503e4f9840ba6029b7ad6c466858c5f3c7c6..b9e0e608d978beaf0878e851c44117e7d8a98b21 100644 --- a/pom.xml +++ b/pom.xml @@ -3,7 +3,7 @@ org.json json - 20220320 + 20230618 bundle JSON in Java @@ -18,10 +18,6 @@ This is a reference implementation. There is a large number of JSON packages in Java. Perhaps someday the Java community will standardize on one. Until then, choose carefully. - - The license includes this restriction: "The software shall be used for good, - not evil." If your conscience cannot live with that, then choose a different - package. https://github.com/douglascrockford/JSON-java @@ -39,28 +35,9 @@ - The JSON License - http://json.org/license.html + Public Domain + https://github.com/stleary/JSON-java/blob/master/LICENSE repo - Copyright (c) 2002 JSON.org - - Permission is hereby granted, free of charge, to any person obtaining a copy of this software and - associated documentation files (the "Software"), to deal in the Software without restriction, including - without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the - following conditions: - - The above copyright notice and this permission notice shall be included in all copies or substantial - portions of the Software. - - The Software shall be used for Good, not Evil. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT - LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN - NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, - WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - @@ -162,6 +139,12 @@ sign + + + --pinentry-mode + loopback + + diff --git a/src/main/java/org/json/CDL.java b/src/main/java/org/json/CDL.java index f12cfc05417fa15ab8ca6af9b24e6ca5ab534116..848831d3bef7eb0b3cda9cb715472ae2efb2defa 100644 --- a/src/main/java/org/json/CDL.java +++ b/src/main/java/org/json/CDL.java @@ -1,27 +1,7 @@ package org.json; /* -Copyright (c) 2002 JSON.org - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -The Software shall be used for Good, not Evil. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +Public Domain. */ /** diff --git a/src/main/java/org/json/Cookie.java b/src/main/java/org/json/Cookie.java index 1c5fb788c1aa4a1660acbda1d27d415fc0271305..7a7e02846c6fce7678ed9ea7b5eb573832083e9c 100644 --- a/src/main/java/org/json/Cookie.java +++ b/src/main/java/org/json/Cookie.java @@ -3,27 +3,7 @@ package org.json; import java.util.Locale; /* -Copyright (c) 2002 JSON.org - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -The Software shall be used for Good, not Evil. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +Public Domain. */ /** diff --git a/src/main/java/org/json/CookieList.java b/src/main/java/org/json/CookieList.java index 83b2630e51dfd0eeab63e0078a038477de69824d..8ad8b589dbd9fa1c12c3e6fca5d53d8223619689 100644 --- a/src/main/java/org/json/CookieList.java +++ b/src/main/java/org/json/CookieList.java @@ -1,27 +1,7 @@ package org.json; /* -Copyright (c) 2002 JSON.org - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -The Software shall be used for Good, not Evil. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +Public Domain. */ /** diff --git a/src/main/java/org/json/HTTP.java b/src/main/java/org/json/HTTP.java index cc01167c6546283397e5fed588341dda937f6dc6..6fee6ba16137574f7b259b00d5c1a561cfd3da58 100644 --- a/src/main/java/org/json/HTTP.java +++ b/src/main/java/org/json/HTTP.java @@ -1,27 +1,7 @@ package org.json; /* -Copyright (c) 2002 JSON.org - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -The Software shall be used for Good, not Evil. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +Public Domain. */ import java.util.Locale; diff --git a/src/main/java/org/json/HTTPTokener.java b/src/main/java/org/json/HTTPTokener.java index 16c7081a9debf309fca8f96e11480622119f12d1..48cad31a340ae37ca4a8f7f4836903f7c1f3dbee 100644 --- a/src/main/java/org/json/HTTPTokener.java +++ b/src/main/java/org/json/HTTPTokener.java @@ -1,27 +1,7 @@ package org.json; /* -Copyright (c) 2002 JSON.org - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -The Software shall be used for Good, not Evil. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +Public Domain. */ /** diff --git a/src/main/java/org/json/JSONArray.java b/src/main/java/org/json/JSONArray.java index 2b33e1db856a76e54643de566a79a79d9560bf66..3be3e145139923513394532466bed845ef45276f 100644 --- a/src/main/java/org/json/JSONArray.java +++ b/src/main/java/org/json/JSONArray.java @@ -1,27 +1,7 @@ package org.json; /* - Copyright (c) 2002 JSON.org - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in all - copies or substantial portions of the Software. - - The Software shall be used for Good, not Evil. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. +Public Domain. */ import java.io.IOException; @@ -1386,6 +1366,10 @@ public class JSONArray implements Iterable { if (!JSONObject.isNumberSimilar((Number)valueThis, (Number)valueOther)) { return false; } + } else if (valueThis instanceof JSONString && valueOther instanceof JSONString) { + if (!((JSONString) valueThis).toJSONString().equals(((JSONString) valueOther).toJSONString())) { + return false; + } } else if (!valueThis.equals(valueOther)) { return false; } diff --git a/src/main/java/org/json/JSONException.java b/src/main/java/org/json/JSONException.java index ab7ff77dc8444859516eb3469b23356bf1ae910f..02c29f3fc4f340c7e2a9766ed2f3341ef90c7993 100644 --- a/src/main/java/org/json/JSONException.java +++ b/src/main/java/org/json/JSONException.java @@ -1,27 +1,7 @@ package org.json; /* -Copyright (c) 2002 JSON.org - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -The Software shall be used for Good, not Evil. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +Public Domain. */ /** diff --git a/src/main/java/org/json/JSONML.java b/src/main/java/org/json/JSONML.java index aafdf7277477c5d3cad268e37be0b096546b801c..4aea014d1ec85af123e6041f273651a623a26b5a 100644 --- a/src/main/java/org/json/JSONML.java +++ b/src/main/java/org/json/JSONML.java @@ -1,27 +1,7 @@ package org.json; /* -Copyright (c) 2008 JSON.org - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -The Software shall be used for Good, not Evil. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +Public Domain. */ /** @@ -47,7 +27,32 @@ public class JSONML { XMLTokener x, boolean arrayForm, JSONArray ja, - boolean keepStrings + 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; @@ -172,7 +177,7 @@ public class JSONML { if (!(token instanceof String)) { throw x.syntaxError("Missing value"); } - newjo.accumulate(attribute, keepStrings ? ((String)token) :XML.stringToValue((String)token)); + newjo.accumulate(attribute, config.isKeepStrings() ? ((String)token) :XML.stringToValue((String)token)); token = null; } else { newjo.accumulate(attribute, ""); @@ -201,7 +206,12 @@ public class JSONML { if (token != XML.GT) { throw x.syntaxError("Misshaped tag"); } - closeTag = (String)parse(x, arrayForm, newja, keepStrings); + + 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 + @@ -223,7 +233,7 @@ public class JSONML { } else { if (ja != null) { ja.put(token instanceof String - ? keepStrings ? XML.unescape((String)token) :XML.stringToValue((String)token) + ? (config.isKeepStrings() ? XML.unescape((String)token) : XML.stringToValue((String)token)) : token); } } @@ -244,7 +254,7 @@ public class JSONML { * @throws JSONException Thrown on error converting to a JSONArray */ public static JSONArray toJSONArray(String string) throws JSONException { - return (JSONArray)parse(new XMLTokener(string), true, null, false); + return (JSONArray)parse(new XMLTokener(string), true, null, JSONMLParserConfiguration.ORIGINAL, 0); } @@ -255,8 +265,8 @@ public class JSONML { * 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 + * 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. @@ -266,7 +276,56 @@ public class JSONML { * @throws JSONException Thrown on error converting to a JSONArray */ public static JSONArray toJSONArray(String string, boolean keepStrings) throws JSONException { - return (JSONArray)parse(new XMLTokener(string), true, null, keepStrings); + return (JSONArray)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 (JSONArray)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 (JSONArray)parse(x, true, null, config, 0); } @@ -277,8 +336,8 @@ public class JSONML { * 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 + * 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. @@ -288,7 +347,7 @@ public class JSONML { * @throws JSONException Thrown on error converting to a JSONArray */ public static JSONArray toJSONArray(XMLTokener x, boolean keepStrings) throws JSONException { - return (JSONArray)parse(x, true, null, keepStrings); + return (JSONArray)parse(x, true, null, keepStrings, 0); } @@ -305,7 +364,7 @@ public class JSONML { * @throws JSONException Thrown on error converting to a JSONArray */ public static JSONArray toJSONArray(XMLTokener x) throws JSONException { - return (JSONArray)parse(x, true, null, false); + return (JSONArray)parse(x, true, null, false, 0); } @@ -323,10 +382,10 @@ public class JSONML { * @throws JSONException Thrown on error converting to a JSONObject */ public static JSONObject toJSONObject(String string) throws JSONException { - return (JSONObject)parse(new XMLTokener(string), false, null, false); + return (JSONObject)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 @@ -343,10 +402,32 @@ public class JSONML { * @throws JSONException Thrown on error converting to a JSONObject */ public static JSONObject toJSONObject(String string, boolean keepStrings) throws JSONException { - return (JSONObject)parse(new XMLTokener(string), false, null, keepStrings); + return (JSONObject)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 (JSONObject)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 @@ -361,7 +442,7 @@ public class JSONML { * @throws JSONException Thrown on error converting to a JSONObject */ public static JSONObject toJSONObject(XMLTokener x) throws JSONException { - return (JSONObject)parse(x, false, null, false); + return (JSONObject)parse(x, false, null, false, 0); } @@ -381,7 +462,29 @@ public class JSONML { * @throws JSONException Thrown on error converting to a JSONObject */ public static JSONObject toJSONObject(XMLTokener x, boolean keepStrings) throws JSONException { - return (JSONObject)parse(x, false, null, keepStrings); + return (JSONObject)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 (JSONObject)parse(x, false, null, config, 0); } @@ -462,6 +565,7 @@ public class JSONML { 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, diff --git a/src/main/java/org/json/JSONMLParserConfiguration.java b/src/main/java/org/json/JSONMLParserConfiguration.java new file mode 100644 index 0000000000000000000000000000000000000000..b2514ab6e0b5b9be3fb7e54d15cfc8387d646066 --- /dev/null +++ b/src/main/java/org/json/JSONMLParserConfiguration.java @@ -0,0 +1,67 @@ +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 + ); + } + + @Override + public JSONMLParserConfiguration withKeepStrings(final boolean newVal) { + return super.withKeepStrings(newVal); + } + + @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 ea549e3f7afd5a1768ad8ed0a47fba7c87700e59..97906b629a5cd2819143b7643f25447adc9f9177 100644 --- a/src/main/java/org/json/JSONObject.java +++ b/src/main/java/org/json/JSONObject.java @@ -1,31 +1,10 @@ package org.json; -import java.io.Closeable; - /* - Copyright (c) 2002 JSON.org - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in all - copies or substantial portions of the Software. - - The Software shall be used for Good, not Evil. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. - */ +Public Domain. +*/ +import java.io.Closeable; import java.io.IOException; import java.io.StringWriter; import java.io.Writer; @@ -166,6 +145,10 @@ public class JSONObject { */ private final Map map; + public Class getMapType() { + return map.getClass(); + } + /** * It is sometimes more convenient and less ambiguous to have a * NULL object than to use Java's null value. @@ -1307,11 +1290,7 @@ public class JSONObject { if (val == null) { return defaultValue; } - final double doubleValue = val.doubleValue(); - // if (Double.isNaN(doubleValue) || Double.isInfinite(doubleValue)) { - // return defaultValue; - // } - return doubleValue; + return val.doubleValue(); } /** @@ -2142,6 +2121,10 @@ public class JSONObject { if (!isNumberSimilar((Number)valueThis, (Number)valueOther)) { return false; } + } else if (valueThis instanceof JSONString && valueOther instanceof JSONString) { + if (!((JSONString) valueThis).toJSONString().equals(((JSONString) valueOther).toJSONString())) { + return false; + } } else if (!valueThis.equals(valueOther)) { return false; } diff --git a/src/main/java/org/json/JSONPointer.java b/src/main/java/org/json/JSONPointer.java index f1f7f3314be41bf4bfda339a4b18886ba0efbbcb..963fdec3e14b6eb63b5b864b2fa88eaa8d278840 100644 --- a/src/main/java/org/json/JSONPointer.java +++ b/src/main/java/org/json/JSONPointer.java @@ -10,27 +10,7 @@ import java.util.Collections; import java.util.List; /* -Copyright (c) 2002 JSON.org - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -The Software shall be used for Good, not Evil. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +Public Domain. */ /** diff --git a/src/main/java/org/json/JSONPointerException.java b/src/main/java/org/json/JSONPointerException.java index 0ce1aeb297ee1fdd2beab49302fcc24a00e00085..a0e128cd587c170798e6c7f06a85da283507b6cc 100644 --- a/src/main/java/org/json/JSONPointerException.java +++ b/src/main/java/org/json/JSONPointerException.java @@ -1,27 +1,7 @@ package org.json; /* -Copyright (c) 2002 JSON.org - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -The Software shall be used for Good, not Evil. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +Public Domain. */ /** diff --git a/src/main/java/org/json/JSONPropertyIgnore.java b/src/main/java/org/json/JSONPropertyIgnore.java index 682de7447042ac2a1a9926662484dc5015516080..d3a5bc5a1821a0b10cf8129ae1726e5dea07d806 100644 --- a/src/main/java/org/json/JSONPropertyIgnore.java +++ b/src/main/java/org/json/JSONPropertyIgnore.java @@ -1,27 +1,7 @@ package org.json; /* -Copyright (c) 2018 JSON.org - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -The Software shall be used for Good, not Evil. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +Public Domain. */ import static java.lang.annotation.ElementType.METHOD; @@ -31,13 +11,13 @@ import java.lang.annotation.Documented; import java.lang.annotation.Retention; import java.lang.annotation.Target; -@Documented -@Retention(RUNTIME) -@Target({METHOD}) /** * 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 index a1bcd58bf1046e26f586ad8c0563c6326e66fe26..4391bb76c2fb1cd8852f50f56b9fdc372777d040 100644 --- a/src/main/java/org/json/JSONPropertyName.java +++ b/src/main/java/org/json/JSONPropertyName.java @@ -1,27 +1,7 @@ package org.json; /* -Copyright (c) 2018 JSON.org - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -The Software shall be used for Good, not Evil. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +Public Domain. */ import static java.lang.annotation.ElementType.METHOD; @@ -31,14 +11,14 @@ import java.lang.annotation.Documented; import java.lang.annotation.Retention; import java.lang.annotation.Target; -@Documented -@Retention(RUNTIME) -@Target({METHOD}) /** * 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 { /** * @return The name of the property as to be used in the JSON Object. diff --git a/src/main/java/org/json/JSONString.java b/src/main/java/org/json/JSONString.java index bcd9a8128f01a29915461f12712fca8c75d045fb..cd8d1847d84e67f12e92f5e9f22fdb2dd87d4b07 100644 --- a/src/main/java/org/json/JSONString.java +++ b/src/main/java/org/json/JSONString.java @@ -1,27 +1,7 @@ package org.json; /* -Copyright (c) 2002 JSON.org - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -The Software shall be used for Good, not Evil. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +Public Domain. */ /** diff --git a/src/main/java/org/json/JSONStringer.java b/src/main/java/org/json/JSONStringer.java index d2a4dfba546574ffaf2b06dd37e24388da320fd0..2f6cf9ed8b73c504b55f2d3b29b5c6d05051d396 100644 --- a/src/main/java/org/json/JSONStringer.java +++ b/src/main/java/org/json/JSONStringer.java @@ -1,27 +1,7 @@ package org.json; /* -Copyright (c) 2006 JSON.org - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -The Software shall be used for Good, not Evil. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +Public Domain. */ import java.io.StringWriter; diff --git a/src/main/java/org/json/JSONTokener.java b/src/main/java/org/json/JSONTokener.java index 7f0c86a7bc359e01831ca235f07db0c0f47e0741..5dc8ae85a6574cb5efe482d7119b34c6acda8681 100644 --- a/src/main/java/org/json/JSONTokener.java +++ b/src/main/java/org/json/JSONTokener.java @@ -1,34 +1,10 @@ package org.json; -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.Reader; -import java.io.StringReader; +import java.io.*; +import java.nio.charset.Charset; /* -Copyright (c) 2002 JSON.org - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -The Software shall be used for Good, not Evil. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +Public Domain. */ /** @@ -81,7 +57,7 @@ public class JSONTokener { * @param inputStream The source. */ public JSONTokener(InputStream inputStream) { - this(new InputStreamReader(inputStream)); + this(new InputStreamReader(inputStream, Charset.forName("UTF-8"))); } @@ -145,7 +121,7 @@ public class JSONTokener { /** * Checks if the end of the input has been reached. - * + * * @return true if at the end of the file and we didn't step back */ public boolean end() { @@ -209,7 +185,7 @@ public class JSONTokener { this.previous = (char) c; return this.previous; } - + /** * Get the last character read from the input or '\0' if nothing has been read yet. * @return the last character read from the input. @@ -542,4 +518,10 @@ public class JSONTokener { return " at " + this.index + " [character " + this.character + " line " + this.line + "]"; } + + public void close() throws IOException { + if(reader!=null){ + reader.close(); + } + } } diff --git a/src/main/java/org/json/JSONWriter.java b/src/main/java/org/json/JSONWriter.java index dafb1b26479d45c013c05b240a55a0fe9ae5dbf3..11f4a5c7ea03156839280c9eb539f38422298819 100644 --- a/src/main/java/org/json/JSONWriter.java +++ b/src/main/java/org/json/JSONWriter.java @@ -5,27 +5,7 @@ import java.util.Collection; import java.util.Map; /* -Copyright (c) 2006 JSON.org - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -The Software shall be used for Good, not Evil. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +Public Domain. */ /** diff --git a/src/main/java/org/json/ParserConfiguration.java b/src/main/java/org/json/ParserConfiguration.java new file mode 100644 index 0000000000000000000000000000000000000000..519e2099d9d2e2b674e5e3d4a96fcf339fb54fc5 --- /dev/null +++ b/src/main/java/org/json/ParserConfiguration.java @@ -0,0 +1,112 @@ +package org.json; +/* +Public Domain. +*/ + +/** + * Configuration base object for parsers. The configuration is immutable. + */ +@SuppressWarnings({""}) +public class ParserConfiguration { + /** + * Used to indicate there's no defined limit to the maximum nesting depth when parsing a document. + */ + public static final int UNDEFINED_MAXIMUM_NESTING_DEPTH = -1; + + /** + * The default maximum nesting depth when parsing a document. + */ + public static final int DEFAULT_MAXIMUM_NESTING_DEPTH = 512; + + /** + * Specifies if values should be kept as strings (true), or if + * they should try to be guessed into JSON values (numeric, boolean, string) + */ + protected boolean keepStrings; + + /** + * The maximum nesting depth when parsing a document. + */ + protected int maxNestingDepth; + + public ParserConfiguration() { + this.keepStrings = false; + this.maxNestingDepth = DEFAULT_MAXIMUM_NESTING_DEPTH; + } + + protected ParserConfiguration(final boolean keepStrings, final int maxNestingDepth) { + this.keepStrings = keepStrings; + this.maxNestingDepth = maxNestingDepth; + } + + /** + * Provides a new instance of the same configuration. + */ + @Override + protected ParserConfiguration 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 ParserConfiguration( + this.keepStrings, + this.maxNestingDepth + ); + } + + /** + * When parsing the XML into JSONML, specifies if values 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 isKeepStrings() { + return this.keepStrings; + } + + /** + * When parsing the XML into JSONML, 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. + */ + public T withKeepStrings(final boolean newVal) { + T newConfig = (T)this.clone(); + newConfig.keepStrings = newVal; + return newConfig; + } + + /** + * The maximum nesting depth that the parser will descend before throwing an exception + * when parsing the XML into JSONML. + * @return the maximum nesting depth set for this configuration + */ + public int getMaxNestingDepth() { + return maxNestingDepth; + } + + /** + * Defines the maximum nesting depth that the parser will descend before throwing an exception + * when parsing the XML into JSONML. 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. + */ + public T withMaxNestingDepth(int maxNestingDepth) { + T newConfig = (T)this.clone(); + + if (maxNestingDepth > UNDEFINED_MAXIMUM_NESTING_DEPTH) { + newConfig.maxNestingDepth = maxNestingDepth; + } else { + newConfig.maxNestingDepth = UNDEFINED_MAXIMUM_NESTING_DEPTH; + } + + return newConfig; + } +} diff --git a/src/main/java/org/json/Property.java b/src/main/java/org/json/Property.java index 7caeebb076bd31f59be2a328511d58ea0a22bfaa..83694c055afd93a31032ad451acc36ffd8a86c8e 100644 --- a/src/main/java/org/json/Property.java +++ b/src/main/java/org/json/Property.java @@ -1,27 +1,7 @@ package org.json; /* -Copyright (c) 2002 JSON.org - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -The Software shall be used for Good, not Evil. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +Public Domain. */ import java.util.Enumeration; diff --git a/src/main/java/org/json/XML.java b/src/main/java/org/json/XML.java index 33838a15c25d88ae6e67aa9f85e843ac3a1d14fe..925f056b1aec91d7745c17c2e2af5561afe5c726 100644 --- a/src/main/java/org/json/XML.java +++ b/src/main/java/org/json/XML.java @@ -1,27 +1,7 @@ package org.json; /* -Copyright (c) 2015 JSON.org - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -The Software shall be used for Good, not Evil. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +Public Domain. */ import java.io.Reader; @@ -118,7 +98,7 @@ public class XML { /** * Replace special characters with XML escapes: * - *
{@code 
+     * 
{@code
      * & (ampersand) is replaced by &amp;
      * < (less than) is replaced by &lt;
      * > (greater than) is replaced by &gt;
@@ -249,10 +229,14 @@ public class XML {
      *            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
+     * @throws JSONException Thrown if any parsing error occurs.
      */
-    private static boolean parse(XMLTokener x, JSONObject context, String name, XMLParserConfiguration config)
+    private static boolean parse(XMLTokener x, JSONObject context, String name, XMLParserConfiguration config, int currentNestingDepth)
             throws JSONException {
         char c;
         int i;
@@ -422,7 +406,11 @@ public class XML {
 
                         } else if (token == LT) {
                             // Nested element
-                            if (parse(x, jsonObject, tagName, config)) {
+                            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) {
@@ -443,7 +431,7 @@ public class XML {
                                         context.accumulate(tagName, jsonObject);
                                     }
                                 }
-                                
+
                                 return false;
                             }
                         }
@@ -507,7 +495,7 @@ public class XML {
         }
         return string;
     }
-    
+
     /**
      * direct copy of {@link JSONObject#stringToNumber(String)} to maintain Android support.
      */
@@ -554,7 +542,7 @@ public class XML {
             // 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
@@ -570,7 +558,7 @@ public class XML {
         }
         throw new NumberFormatException("val ["+val+"] is not a valid number.");
     }
-    
+
     /**
      * direct copy of {@link JSONObject#isDecimalNotation(String)} to maintain Android support.
      */
@@ -588,7 +576,7 @@ public class XML {
      * 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 
+     * "content" member. Comments, prologs, DTDs, and 
{@code
      * <[ [ ]]>}
* are ignored. * @@ -609,7 +597,7 @@ public class XML { * 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 
+     * "content" member. Comments, prologs, DTDs, and 
{@code
      * <[ [ ]]>}
* are ignored. * @@ -675,7 +663,7 @@ public class XML { while (x.more()) { x.skipPast("<"); if(x.more()) { - parse(x, jo, null, config); + parse(x, jo, null, config, 0); } } return jo; @@ -689,7 +677,7 @@ public class XML { * 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 
+     * "content" member. Comments, prologs, DTDs, and 
{@code
      * <[ [ ]]>}
* are ignored. * @@ -715,7 +703,7 @@ public class XML { * 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 
+     * "content" member. Comments, prologs, DTDs, and 
{@code
      * <[ [ ]]>}
* are ignored. * @@ -772,6 +760,28 @@ public class XML { */ 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; @@ -781,9 +791,14 @@ public class XML { // 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. @@ -826,31 +841,39 @@ public class XML { sb.append('<'); sb.append(key); sb.append('>'); - sb.append(toString(val, null, config)); + sb.append(toString(val, null, config, indentFactor, indent)); sb.append("'); } else { - sb.append(toString(val, key, config)); + sb.append(toString(val, key, config, indentFactor, indent)); } } } else if ("".equals(value)) { + 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)); + 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(); @@ -869,15 +892,85 @@ public class XML { // 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)); + sb.append(toString(val, tagName == null ? "array" : tagName, config, indentFactor, indent)); } return sb.toString(); } + string = (object == null) ? "null" : escape(object.toString()); - return (tagName == null) ? "\"" + string + "\"" - : (string.length() == 0) ? "<" + tagName + "/>" : "<" + tagName - + ">" + string + ""; + if(tagName == null){ + return indent(indent) + "\"" + string + "\"" + ((indentFactor > 0) ? "\n" : ""); + } else if(string.length() == 0){ + return indent(indent) + "<" + tagName + "/>" + ((indentFactor > 0) ? "\n" : ""); + } else { + return indent(indent) + "<" + tagName + + ">" + string + "" + ((indentFactor > 0) ? "\n" : ""); + } + } + + /** + * 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 index a1fd63eb7c7a3d04779192e92d2db712d986abc0..566146d6daa1a7cb6ea42ada9642687a841a9cad 100644 --- a/src/main/java/org/json/XMLParserConfiguration.java +++ b/src/main/java/org/json/XMLParserConfiguration.java @@ -1,26 +1,6 @@ package org.json; /* -Copyright (c) 2002 JSON.org - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -The Software shall be used for Good, not Evil. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +Public Domain. */ import java.util.Collections; @@ -35,7 +15,13 @@ import java.util.Set; * @author AylwardJ */ @SuppressWarnings({""}) -public class XMLParserConfiguration { +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 + /** Original Configuration of the XML Parser. */ public static final XMLParserConfiguration ORIGINAL = new XMLParserConfiguration(); @@ -43,19 +29,13 @@ public class XMLParserConfiguration { public static final XMLParserConfiguration KEEP_STRINGS = new XMLParserConfiguration().withKeepStrings(true); - /** - * 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) - */ - private boolean keepStrings; - /** * 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 @@ -79,7 +59,7 @@ public class XMLParserConfiguration { * values), and the CDATA Tag Name is "content". */ public XMLParserConfiguration () { - this.keepStrings = false; + super(); this.cDataTagName = "content"; this.convertNilAttributeToNull = false; this.xsiTypeMap = Collections.emptyMap(); @@ -126,7 +106,7 @@ public class XMLParserConfiguration { */ @Deprecated public XMLParserConfiguration (final boolean keepStrings, final String cDataTagName) { - this.keepStrings = keepStrings; + super(keepStrings, DEFAULT_MAXIMUM_NESTING_DEPTH); this.cDataTagName = cDataTagName; this.convertNilAttributeToNull = false; } @@ -145,7 +125,7 @@ public class XMLParserConfiguration { */ @Deprecated public XMLParserConfiguration (final boolean keepStrings, final String cDataTagName, final boolean convertNilAttributeToNull) { - this.keepStrings = keepStrings; + super(keepStrings, DEFAULT_MAXIMUM_NESTING_DEPTH); this.cDataTagName = cDataTagName; this.convertNilAttributeToNull = convertNilAttributeToNull; } @@ -160,11 +140,13 @@ public class XMLParserConfiguration { * 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 forceList new HashSet() to parse the provided tags' values as arrays + * @param maxNestingDepth int to limit the nesting depth */ private XMLParserConfiguration (final boolean keepStrings, final String cDataTagName, - final boolean convertNilAttributeToNull, final Map> xsiTypeMap, final Set forceList ) { - this.keepStrings = keepStrings; + final boolean convertNilAttributeToNull, final Map> xsiTypeMap, final Set forceList, + final int maxNestingDepth) { + super(keepStrings, maxNestingDepth); this.cDataTagName = cDataTagName; this.convertNilAttributeToNull = convertNilAttributeToNull; this.xsiTypeMap = Collections.unmodifiableMap(xsiTypeMap); @@ -186,40 +168,30 @@ public class XMLParserConfiguration { this.cDataTagName, this.convertNilAttributeToNull, this.xsiTypeMap, - this.forceList + this.forceList, + this.maxNestingDepth ); } - - /** - * 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) - * - * @return The keepStrings configuration value. - */ - public boolean isKeepStrings() { - return this.keepStrings; - } /** * 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. */ + @Override public XMLParserConfiguration withKeepStrings(final boolean newVal) { - XMLParserConfiguration newConfig = this.clone(); - newConfig.keepStrings = newVal; - return newConfig; + return super.withKeepStrings(newVal); } /** * 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() { @@ -230,10 +202,10 @@ public class XMLParserConfiguration { * 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) { @@ -246,7 +218,7 @@ public class XMLParserConfiguration { * 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() { @@ -257,10 +229,10 @@ public class XMLParserConfiguration { * 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) { @@ -298,7 +270,7 @@ public class XMLParserConfiguration { /** * 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 + * in this configuration {@code Set} to parse the provided tags' values as arrays * @return forceList unmodifiable configuration set. */ public Set getForceList() { @@ -307,8 +279,8 @@ public class XMLParserConfiguration { /** * 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 + * 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) { @@ -317,4 +289,18 @@ public class XMLParserConfiguration { 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. + */ + @Override + public XMLParserConfiguration withMaxNestingDepth(int maxNestingDepth) { + return super.withMaxNestingDepth(maxNestingDepth); + } } diff --git a/src/main/java/org/json/XMLTokener.java b/src/main/java/org/json/XMLTokener.java index 3bbd3824bc3bdc6c993afb09fa2687767baac744..957498ca27874c82480d36578a2b6a4ac3d0e5d1 100644 --- a/src/main/java/org/json/XMLTokener.java +++ b/src/main/java/org/json/XMLTokener.java @@ -1,27 +1,7 @@ package org.json; /* -Copyright (c) 2002 JSON.org - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -The Software shall be used for Good, not Evil. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +Public Domain. */ import java.io.Reader; diff --git a/src/main/java/org/json/XMLXsiTypeConverter.java b/src/main/java/org/json/XMLXsiTypeConverter.java index 0f8a8c33259ee82090b220f0f469ad91d4165e39..0011effae8d5a5860d82a0b6458d901bcc57d4e3 100644 --- a/src/main/java/org/json/XMLXsiTypeConverter.java +++ b/src/main/java/org/json/XMLXsiTypeConverter.java @@ -1,26 +1,6 @@ package org.json; /* -Copyright (c) 2002 JSON.org - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -The Software shall be used for Good, not Evil. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +Public Domain. */ /** diff --git a/src/test/java/org/json/junit/CDLTest.java b/src/test/java/org/json/junit/CDLTest.java index b8bdede395aab105d37eb459fea2a2ee9c314e1b..f3364fbbab9413443582e1a70492fa3c9caf524b 100644 --- a/src/test/java/org/json/junit/CDLTest.java +++ b/src/test/java/org/json/junit/CDLTest.java @@ -1,27 +1,7 @@ package org.json.junit; /* -Copyright (c) 2020 JSON.org - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -The Software shall be used for Good, not Evil. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +Public Domain. */ import static org.junit.Assert.*; diff --git a/src/test/java/org/json/junit/CookieListTest.java b/src/test/java/org/json/junit/CookieListTest.java index c3f647f900ee92d55c9c74cb5ce3c484d9020e90..0af96401b4eaceb9bbc1dadcbbdeba32122304cd 100644 --- a/src/test/java/org/json/junit/CookieListTest.java +++ b/src/test/java/org/json/junit/CookieListTest.java @@ -1,27 +1,7 @@ package org.json.junit; /* -Copyright (c) 2020 JSON.org - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -The Software shall be used for Good, not Evil. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +Public Domain. */ import static org.junit.Assert.*; diff --git a/src/test/java/org/json/junit/CookieTest.java b/src/test/java/org/json/junit/CookieTest.java index 7e7b62b45d109370052407d67463cfcd3335b771..edd8a7eeb01ff4735679cc5e7f4b51ef196d9fb6 100644 --- a/src/test/java/org/json/junit/CookieTest.java +++ b/src/test/java/org/json/junit/CookieTest.java @@ -1,27 +1,7 @@ package org.json.junit; /* -Copyright (c) 2020 JSON.org - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -The Software shall be used for Good, not Evil. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +Public Domain. */ import static org.junit.Assert.*; diff --git a/src/test/java/org/json/junit/EnumTest.java b/src/test/java/org/json/junit/EnumTest.java index 6867123600fab24014e1cff6aad67ead179ab033..1496a636a07484fcece0b329f21b464c951bb018 100644 --- a/src/test/java/org/json/junit/EnumTest.java +++ b/src/test/java/org/json/junit/EnumTest.java @@ -1,27 +1,7 @@ package org.json.junit; /* -Copyright (c) 2020 JSON.org - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -The Software shall be used for Good, not Evil. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +Public Domain. */ import static org.junit.Assert.assertEquals; diff --git a/src/test/java/org/json/junit/HTTPTest.java b/src/test/java/org/json/junit/HTTPTest.java index 8182b60593803a45f1fe3c7d97a47fdaefc390c8..703d5ad2fd615398926e088e04f527a9ed6338a2 100644 --- a/src/test/java/org/json/junit/HTTPTest.java +++ b/src/test/java/org/json/junit/HTTPTest.java @@ -1,27 +1,7 @@ package org.json.junit; /* -Copyright (c) 2020 JSON.org - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -The Software shall be used for Good, not Evil. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +Public Domain. */ import static org.junit.Assert.*; diff --git a/src/test/java/org/json/junit/JSONArrayTest.java b/src/test/java/org/json/junit/JSONArrayTest.java index 987891e1204858d5eda3c85397225796987bf348..aa8657f069e5a5e8e61495e9884d4dec24087432 100644 --- a/src/test/java/org/json/junit/JSONArrayTest.java +++ b/src/test/java/org/json/junit/JSONArrayTest.java @@ -1,27 +1,7 @@ package org.json.junit; /* -Copyright (c) 2020 JSON.org - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -The Software shall be used for Good, not Evil. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +Public Domain. */ import static org.junit.Assert.assertEquals; @@ -49,7 +29,9 @@ import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import org.json.JSONPointerException; +import org.json.JSONString; import org.json.JSONTokener; +import org.json.junit.data.MyJsonString; import org.junit.Test; import com.jayway.jsonpath.Configuration; @@ -237,6 +219,10 @@ public class JSONArrayTest { assertTrue( "The RAW Collection should give me the same as the Typed Collection", expected.similar(jaObj)); + Util.checkJSONArrayMaps(expected); + Util.checkJSONArrayMaps(jaObj); + Util.checkJSONArrayMaps(jaRaw); + Util.checkJSONArrayMaps(jaInt); } /** @@ -275,6 +261,7 @@ public class JSONArrayTest { myList.get(i), jsonArray.getString(myInts.length + i)); } + Util.checkJSONArrayMaps(jsonArray); } /** @@ -308,6 +295,9 @@ public class JSONArrayTest { assertTrue( "The RAW Collection should give me the same as the Typed Collection", expected.similar(jaInt)); + Util.checkJSONArraysMaps(new ArrayList(Arrays.asList( + jaRaw, jaObj, jaInt + ))); } @@ -351,6 +341,9 @@ public class JSONArrayTest { assertTrue( "The RAW Collection should give me the same as the Typed Collection", expected.similar(jaObjObj)); + Util.checkJSONArraysMaps(new ArrayList(Arrays.asList( + expected, jaRaw, jaStrObj, jaStrInt, jaObjObj + ))); } /** @@ -397,6 +390,7 @@ public class JSONArrayTest { new Long(-1).equals(jsonArray.getLong(12))); assertTrue("Array value null", jsonArray.isNull(-1)); + Util.checkJSONArrayMaps(jsonArray); } /** @@ -463,6 +457,7 @@ public class JSONArrayTest { assertEquals("Expected an exception message", "JSONArray[5] is not a String (class java.math.BigDecimal : 0.002345).",e.getMessage()); } + Util.checkJSONArrayMaps(jsonArray); } /** @@ -499,6 +494,7 @@ public class JSONArrayTest { 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"))); + Util.checkJSONArrayMaps(jsonArray); } /** @@ -512,6 +508,9 @@ public class JSONArrayTest { assertTrue("expected JSONArray length 13. instead found "+jsonArray.length(), jsonArray.length() == 13); JSONArray nestedJsonArray = jsonArray.getJSONArray(9); assertTrue("expected JSONArray length 1", nestedJsonArray.length() == 1); + Util.checkJSONArraysMaps(new ArrayList(Arrays.asList( + jsonArray, nestedJsonArray + ))); } /** @@ -587,6 +586,10 @@ public class JSONArrayTest { "hello".equals(jsonArray.optString(4))); assertTrue("Array opt string default implicit", "".equals(jsonArray.optString(-1))); + Util.checkJSONArraysMaps(new ArrayList(Arrays.asList( + jsonArray, nestedJsonArray + ))); + Util.checkJSONObjectMaps(nestedJsonObject); } /** @@ -601,7 +604,9 @@ public class JSONArrayTest { assertTrue("unexpected optLong value",ja.optLong(0,0)==123); assertTrue("unexpected optDouble value",ja.optDouble(0,0.0)==123.0); assertTrue("unexpected optBigInteger value",ja.optBigInteger(0,BigInteger.ZERO).compareTo(new BigInteger("123"))==0); - assertTrue("unexpected optBigDecimal value",ja.optBigDecimal(0,BigDecimal.ZERO).compareTo(new BigDecimal("123"))==0); } + assertTrue("unexpected optBigDecimal value",ja.optBigDecimal(0,BigDecimal.ZERO).compareTo(new BigDecimal("123"))==0); + Util.checkJSONArrayMaps(ja); + } /** * Exercise the JSONArray.put(value) method with various parameters @@ -677,6 +682,8 @@ public class JSONArrayTest { 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"))); + Util.checkJSONArrayMaps(jsonArray); + Util.checkJSONObjectMaps(jsonObject); } /** @@ -756,6 +763,8 @@ public class JSONArrayTest { assertTrue("expected 2", Integer.valueOf(2).equals(jsonArray.query("/9/1"))); assertTrue("expected 1 item in [10]", ((Map)(JsonPath.read(doc, "$[10]"))).size() == 1); assertTrue("expected v1", "v1".equals(jsonArray.query("/10/k1"))); + Util.checkJSONObjectMaps(jsonObject); + Util.checkJSONArrayMaps(jsonArray); } /** @@ -772,6 +781,7 @@ public class JSONArrayTest { jsonArray.remove(0); assertTrue("array should be empty", null == jsonArray.remove(5)); assertTrue("jsonArray should be empty", jsonArray.isEmpty()); + Util.checkJSONArrayMaps(jsonArray); } /** @@ -811,6 +821,12 @@ public class JSONArrayTest { otherJsonArray.put("world"); assertTrue("arrays values differ", !jsonArray.similar(otherJsonArray)); + Util.checkJSONArraysMaps(new ArrayList(Arrays.asList( + jsonArray, otherJsonArray + ))); + Util.checkJSONObjectsMaps(new ArrayList(Arrays.asList( + jsonObject, otherJsonObject + ))); } /** @@ -894,6 +910,7 @@ public class JSONArrayTest { for (String s : jsonArray4Strs) { list.contains(s); } + Util.checkJSONArrayMaps(jsonArray); } /** @@ -905,6 +922,9 @@ public class JSONArrayTest { JSONArray jsonArray = new JSONArray(); assertTrue("toJSONObject should return null", null == jsonArray.toJSONObject(names)); + Util.checkJSONArraysMaps(new ArrayList(Arrays.asList( + names, jsonArray + ))); } /** @@ -926,6 +946,7 @@ public class JSONArrayTest { 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"))); + Util.checkJSONArrayMaps(jsonArray); } /** @@ -968,6 +989,10 @@ public class JSONArrayTest { assertTrue("Array value string long", new Long(-1).equals(Long.parseLong((String) it.next()))); assertTrue("should be at end of array", !it.hasNext()); + Util.checkJSONArraysMaps(new ArrayList(Arrays.asList( + jsonArray, nestedJsonArray + ))); + Util.checkJSONObjectMaps(nestedJsonObject); } @Test(expected = JSONPointerException.class) @@ -1010,6 +1035,7 @@ public class JSONArrayTest { } finally { stringWriter.close(); } + Util.checkJSONArrayMaps(jsonArray); } /** @@ -1069,9 +1095,11 @@ public class JSONArrayTest { && actualStr.contains("\"key2\": false") && actualStr.contains("\"key3\": 3.14") ); + Util.checkJSONArrayMaps(finalArray); } finally { stringWriter.close(); } + Util.checkJSONArrayMaps(jsonArray); } /** @@ -1182,6 +1210,7 @@ public class JSONArrayTest { // assert that the new list is mutable assertTrue("Removing an entry should succeed", list.remove(2) != null); assertTrue("List should have 2 elements", list.size() == 2); + Util.checkJSONArrayMaps(jsonArray); } /** @@ -1190,13 +1219,13 @@ public class JSONArrayTest { */ @Test public void testJSONArrayInt() { - assertNotNull(new JSONArray(0)); - assertNotNull(new JSONArray(5)); - // Check Size -> Even though the capacity of the JSONArray can be specified using a positive - // integer but the length of JSONArray always reflects upon the items added into it. - assertEquals(0l, new JSONArray(10).length()); + assertNotNull(new JSONArray(0)); + assertNotNull(new JSONArray(5)); + // Check Size -> Even though the capacity of the JSONArray can be specified using a positive + // integer but the length of JSONArray always reflects upon the items added into it. + // assertEquals(0l, new JSONArray(10).length()); try { - assertNotNull("Should throw an exception", new JSONArray(-1)); + assertNotNull("Should throw an exception", new JSONArray(-1)); } catch (JSONException e) { assertEquals("Expected an exception message", "JSONArray initial capacity cannot be negative.", @@ -1223,8 +1252,8 @@ public class JSONArrayTest { ((Collection)o).add("test"); ((Collection)o).add(false); try { - a = new JSONArray(o); - assertNull("Should error", a); + JSONArray a0 = new JSONArray(o); + assertNull("Should error", a0); } catch (JSONException ex) { } @@ -1232,10 +1261,11 @@ public class JSONArrayTest { // this is required for backwards compatibility o = a; try { - a = new JSONArray(o); - assertNull("Should error", a); + JSONArray a1 = new JSONArray(o); + assertNull("Should error", a1); } catch (JSONException ex) { } + Util.checkJSONArrayMaps(a); } /** @@ -1252,6 +1282,9 @@ public class JSONArrayTest { for(int i = 0; i < a1.length(); i++) { assertEquals("index " + i + " are equal", a1.get(i), a2.get(i)); } + Util.checkJSONArraysMaps(new ArrayList(Arrays.asList( + a1, a2 + ))); } /** @@ -1269,6 +1302,9 @@ public class JSONArrayTest { for(int i = 0; i < a1.length(); i++) { assertEquals("index " + i + " are equal", a1.get(i), a2.get(i)); } + Util.checkJSONArraysMaps(new ArrayList(Arrays.asList( + a1, a2 + ))); } /** @@ -1284,6 +1320,7 @@ public class JSONArrayTest { 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 + Util.checkJSONArrayMaps(jsonArray); } /** @@ -1297,5 +1334,27 @@ public class JSONArrayTest { JSONArray json_input = new JSONArray(tokener); assertNotNull(json_input); fail("Excepected Exception."); + Util.checkJSONArrayMaps(json_input); + } + + @Test + public void testIssue682SimilarityOfJSONString() { + JSONArray ja1 = new JSONArray() + .put(new MyJsonString()) + .put(2); + JSONArray ja2 = new JSONArray() + .put(new MyJsonString()) + .put(2); + assertTrue(ja1.similar(ja2)); + + JSONArray ja3 = new JSONArray() + .put(new JSONString() { + @Override + public String toJSONString() { + return "\"different value\""; + } + }) + .put(2); + assertFalse(ja1.similar(ja3)); } } diff --git a/src/test/java/org/json/junit/JSONMLTest.java b/src/test/java/org/json/junit/JSONMLTest.java index 390cbd82eb96d1602b9d2d7b580f18d2f6326752..35c0af2c48d292cfcc351b456b4f58383933f8d3 100644 --- a/src/test/java/org/json/junit/JSONMLTest.java +++ b/src/test/java/org/json/junit/JSONMLTest.java @@ -1,27 +1,7 @@ package org.json.junit; /* -Copyright (c) 2020 JSON.org - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -The Software shall be used for Good, not Evil. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +Public Domain. */ import static org.junit.Assert.*; @@ -31,19 +11,19 @@ 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 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. + * 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 { @@ -76,7 +56,7 @@ public class JSONMLTest { /** * Attempts to call JSONML.toString() with a null JSONArray. - * Expects a NullPointerException. + * Expects a NullPointerException. */ @Test(expected=NullPointerException.class) public void nullJSONXMLException() { @@ -89,7 +69,7 @@ public class JSONMLTest { /** * Attempts to call JSONML.toString() with a null JSONArray. - * Expects a JSONException. + * Expects a JSONException. */ @Test public void emptyJSONXMLException() { @@ -145,7 +125,7 @@ public class JSONMLTest { "[\"addresses\","+ "{\"xsi:noNamespaceSchemaLocation\":\"test.xsd\","+ "\"xmlns:xsi\":\"http://www.w3.org/2001/XMLSchema-instance\"},"+ - // this array has no name + // this array has no name "["+ "[\"name\"],"+ "[\"nocontent\"],"+ @@ -200,7 +180,7 @@ public class JSONMLTest { } /** - * Attempts to transform a malformed XML document + * Attempts to transform a malformed XML document * (element tag has a frontslash) to a JSONArray.\ * Expects a JSONException */ @@ -211,7 +191,7 @@ public class JSONMLTest { * In this case, the XML is invalid because the 'name' element * contains an invalid frontslash. */ - String xmlStr = + String xmlStr = "\n"+ "\n"+ @@ -236,7 +216,7 @@ public class JSONMLTest { */ @Test public void invalidBangInTagException() { - String xmlStr = + String xmlStr = "\n"+ "\n"+ @@ -266,7 +246,7 @@ public class JSONMLTest { * In this case, the XML is invalid because an element * starts with '!' and has no closing tag */ - String xmlStr = + String xmlStr = "\n"+ "\n"+ @@ -296,7 +276,7 @@ public class JSONMLTest { * In this case, the XML is invalid because an element * has no closing '>'. */ - String xmlStr = + String xmlStr = "\n"+ "\n"+ @@ -326,7 +306,7 @@ public class JSONMLTest { * In this case, the XML is invalid because an element * has no name after the closing tag '\n"+ "\n"+ @@ -356,7 +336,7 @@ public class JSONMLTest { * In this case, the XML is invalid because an element * has '>' after the closing tag '\n"+ "\n"+ @@ -384,9 +364,9 @@ public class JSONMLTest { /** * 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. + * does not have a complete CDATA string. */ - String xmlStr = + String xmlStr = "\n"+ "\n"+ @@ -408,7 +388,7 @@ public class JSONMLTest { /** * 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 + * a JSONArray. Both JSONArrays are compared against a control to * confirm the contents. */ @Test @@ -425,7 +405,7 @@ public class JSONMLTest { * which is used to create a final JSONArray, which is also compared * against the expected JSONArray. */ - String xmlStr = + String xmlStr = "\n"+ "\n"+ @@ -434,7 +414,7 @@ public class JSONMLTest { ">\n"+ "\n"+ ""; - String expectedStr = + String expectedStr = "[\"addresses\","+ "{\"xsi:noNamespaceSchemaLocation\":\"test.xsd\","+ "\"xmlns:xsi\":\"http://www.w3.org/2001/XMLSchema-instance\"},"+ @@ -454,12 +434,12 @@ public class JSONMLTest { } /** - * Convert an XML document into a JSONObject. Use JSONML.toString() to + * 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 + * 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. @@ -472,23 +452,23 @@ public class JSONMLTest { /** * 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 + * 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 = + String xmlStr = "\n"+ "\n"+ @@ -605,7 +585,7 @@ public class JSONMLTest { "\"tagName\":\"addresses\""+ "}"; - String expectedJSONArrayStr = + String expectedJSONArrayStr = "["+ "\"addresses\","+ "{"+ @@ -665,12 +645,12 @@ public class JSONMLTest { JSONObject finalJsonObject = JSONML.toJSONObject(jsonObjectXmlToStr); Util.compareActualVsExpectedJsonObjects(finalJsonObject, expectedJsonObject); - // create a JSON array from the original string and make sure it + // 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); @@ -688,14 +668,14 @@ public class JSONMLTest { * 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. + * JSONArray to confirm the contents. *

* This test shows how XML comments are handled. */ @Test public void commentsInXML() { - String xmlStr = + String xmlStr = "\n"+ "\n"+ "\n"+ @@ -754,7 +734,7 @@ public class JSONMLTest { 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); } @@ -769,7 +749,7 @@ public class JSONMLTest { final String revertedXml = JSONML.toString(jsonArray); assertEquals(revertedXml, originalXml); } - + /** * JSON string cannot be reverted to original xml. See test result in * comment below. @@ -790,7 +770,7 @@ public class JSONMLTest { // 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. +// This means that can not be reversed reliably. // // /** // * Test texts taken from jsonml.org. Currently our implementation FAILS this conversion but shouldn't. @@ -803,13 +783,13 @@ public class JSONMLTest { // 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. // */ @@ -819,15 +799,15 @@ public class JSONMLTest { // 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 +// // order not happen the same way twice // assertEquals(originalXml, reverseXml); // // assertEquals(expectedJsonString, actualJsonString); // } - + @Test (timeout = 6000) public void testIssue484InfinteLoop1() { try { @@ -839,11 +819,11 @@ public class JSONMLTest { ex.getMessage()); } } - + @Test (timeout = 6000) public void testIssue484InfinteLoop2() { try { - String input = "??*\n" + + String input = "??*\n" + "??|?CglR??`??>?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"); + } + } + } diff --git a/src/test/java/org/json/junit/JSONObjectLocaleTest.java b/src/test/java/org/json/junit/JSONObjectLocaleTest.java index 5112bf56ee24604cf7d52d191f44626715497af8..1cdaf743d872252fc6440d17fff569fa4b79717d 100755 --- a/src/test/java/org/json/junit/JSONObjectLocaleTest.java +++ b/src/test/java/org/json/junit/JSONObjectLocaleTest.java @@ -1,27 +1,7 @@ package org.json.junit; /* -Copyright (c) 2020 JSON.org - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -The Software shall be used for Good, not Evil. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +Public Domain. */ import static org.junit.Assert.*; diff --git a/src/test/java/org/json/junit/JSONObjectNumberTest.java b/src/test/java/org/json/junit/JSONObjectNumberTest.java new file mode 100644 index 0000000000000000000000000000000000000000..f6e13c63d8071802fa40ddf534b191d246ee5408 --- /dev/null +++ b/src/test/java/org/json/junit/JSONObjectNumberTest.java @@ -0,0 +1,126 @@ +package org.json.junit; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import java.math.BigDecimal; +import java.math.BigInteger; +import java.util.Arrays; +import java.util.Collection; + +import org.json.JSONObject; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameters; + +@RunWith(value = Parameterized.class) +public class JSONObjectNumberTest { + private final String objectString; + private Integer value = 50; + + @Parameters(name = "{index}: {0}") + public static Collection data() { + return Arrays.asList(new Object[][]{ + {"{value:50}", 1}, + {"{value:50.0}", 1}, + {"{value:5e1}", 1}, + {"{value:5E1}", 1}, + {"{value:5e1}", 1}, + {"{value:'50'}", 1}, + {"{value:-50}", -1}, + {"{value:-50.0}", -1}, + {"{value:-5e1}", -1}, + {"{value:-5E1}", -1}, + {"{value:-5e1}", -1}, + {"{value:'-50'}", -1} + // JSON does not support octal or hex numbers; + // see https://stackoverflow.com/a/52671839/6323312 + // "{value:062}", // octal 50 + // "{value:0x32}" // hex 50 + }); + } + + public JSONObjectNumberTest(String objectString, int resultIsNegative) { + this.objectString = objectString; + this.value *= resultIsNegative; + } + + private JSONObject object; + + @Before + public void setJsonObject() { + object = new JSONObject(objectString); + } + + @Test + public void testGetNumber() { + assertEquals(value.intValue(), object.getNumber("value").intValue()); + } + + @Test + public void testGetBigDecimal() { + assertTrue(BigDecimal.valueOf(value).compareTo(object.getBigDecimal("value")) == 0); + } + + @Test + public void testGetBigInteger() { + assertEquals(BigInteger.valueOf(value), object.getBigInteger("value")); + } + + @Test + public void testGetFloat() { + assertEquals(value.floatValue(), object.getFloat("value"), 0.0f); + } + + @Test + public void testGetDouble() { + assertEquals(value.doubleValue(), object.getDouble("value"), 0.0d); + } + + @Test + public void testGetInt() { + assertEquals(value.intValue(), object.getInt("value")); + } + + @Test + public void testGetLong() { + assertEquals(value.longValue(), object.getLong("value")); + } + + @Test + public void testOptNumber() { + assertEquals(value.intValue(), object.optNumber("value").intValue()); + } + + @Test + public void testOptBigDecimal() { + assertTrue(BigDecimal.valueOf(value).compareTo(object.optBigDecimal("value", null)) == 0); + } + + @Test + public void testOptBigInteger() { + assertEquals(BigInteger.valueOf(value), object.optBigInteger("value", null)); + } + + @Test + public void testOptFloat() { + assertEquals(value.floatValue(), object.optFloat("value"), 0.0f); + } + + @Test + public void testOptDouble() { + assertEquals(value.doubleValue(), object.optDouble("value"), 0.0d); + } + + @Test + public void testOptInt() { + assertEquals(value.intValue(), object.optInt("value")); + } + + @Test + public void testOptLong() { + assertEquals(value.longValue(), object.optLong("value")); + } +} diff --git a/src/test/java/org/json/junit/JSONObjectTest.java b/src/test/java/org/json/junit/JSONObjectTest.java index 2ba58bf6e1e6b943485e10b8b2fd51ac2d95d8c7..ea0cec39c79044622129e4209f378d0bb24d4335 100644 --- a/src/test/java/org/json/junit/JSONObjectTest.java +++ b/src/test/java/org/json/junit/JSONObjectTest.java @@ -1,27 +1,7 @@ package org.json.junit; /* -Copyright (c) 2020 JSON.org - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -The Software shall be used for Good, not Evil. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +Public Domain. */ import static org.junit.Assert.assertEquals; @@ -41,14 +21,7 @@ import java.io.StringReader; import java.io.StringWriter; import java.math.BigDecimal; import java.math.BigInteger; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Locale; -import java.util.Map; +import java.util.*; import java.util.concurrent.atomic.AtomicInteger; import java.util.regex.Pattern; @@ -57,6 +30,7 @@ import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import org.json.JSONPointerException; +import org.json.JSONString; import org.json.JSONTokener; import org.json.XML; import org.json.junit.data.BrokenToString; @@ -80,6 +54,7 @@ import org.json.junit.data.Singleton; import org.json.junit.data.SingletonEnum; import org.json.junit.data.WeirdList; import org.junit.Test; +import org.json.junit.Util; import com.jayway.jsonpath.Configuration; import com.jayway.jsonpath.JsonPath; @@ -140,8 +115,12 @@ public class JSONObjectTest { JSONObject first = new JSONObject("{\"a\": 1, \"b\": 2, \"c\": 3}"); JSONObject second = new JSONObject("{\"a\": 1, \"b\": 2.0, \"c\": 4}"); assertFalse("first-second should eval to false", first.similar(second)); + List jsonObjects = new ArrayList( + Arrays.asList(obj1, obj2, obj3, obj4, obj5) + ); + Util.checkJSONObjectsMaps(jsonObjects); } - + @Test public void timeNumberParsing() { // test data to use @@ -214,7 +193,9 @@ public class JSONObjectTest { */ @Test(expected=NullPointerException.class) public void jsonObjectByNullBean() { - assertNull("Expected an exception",new JSONObject((MyBean)null)); + JSONObject jsonObject = new JSONObject((MyBean)null); + assertNull("Expected an exception", jsonObject); + Util.checkJSONObjectMaps(jsonObject); } /** @@ -232,6 +213,7 @@ public class JSONObjectTest { assertTrue("expected value1", textStr.contains("\"value1\"")); assertTrue("expected key2", textStr.contains("\"key2\"")); assertTrue("expected 42", textStr.contains("42")); + Util.checkJSONObjectMaps(jsonObject); } @Test @@ -252,6 +234,7 @@ public class JSONObjectTest { final String actualString = json.optString("key"); assert str.equals(actualString) : "Incorrect key value. Got " + actualString + " expected " + str; + Util.checkJSONObjectMaps(json); } /** @@ -261,6 +244,7 @@ public class JSONObjectTest { public void emptyJsonObject() { JSONObject jsonObject = new JSONObject(); assertTrue("jsonObject should be empty", jsonObject.isEmpty()); + Util.checkJSONObjectMaps(jsonObject); } /** @@ -291,6 +275,7 @@ public class JSONObjectTest { 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"))); + Util.checkJSONObjectsMaps(new ArrayList(Arrays.asList(jsonObject, jsonObjectByName))); } /** @@ -304,6 +289,7 @@ public class JSONObjectTest { Map map = null; JSONObject jsonObject = new JSONObject(map); assertTrue("jsonObject should be empty", jsonObject.isEmpty()); + Util.checkJSONObjectMaps(jsonObject); } /** @@ -329,6 +315,7 @@ public class JSONObjectTest { 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"))); + Util.checkJSONObjectMaps(jsonObject); } /** @@ -367,6 +354,9 @@ public class JSONObjectTest { assertTrue( "The RAW Collection should give me the same as the Typed Collection", expected.similar(jaObjObj)); + Util.checkJSONObjectsMaps(new ArrayList( + Arrays.asList(jaRaw, jaStrObj, jaStrInt, jaObjObj)) + ); } /** @@ -384,8 +374,8 @@ public class JSONObjectTest { * The only getter is getNumber (key=number), whose return value is * BigDecimal(42). */ - JSONObject jsonObject = new JSONObject(new MyNumberContainer()); - String actual = jsonObject.toString(); + JSONObject jsonObject0 = new JSONObject(new MyNumberContainer()); + String actual = jsonObject0.toString(); String expected = "{\"myNumber\":{\"number\":42}}"; assertEquals("Equal", expected , actual); @@ -397,9 +387,9 @@ public class JSONObjectTest { * The MyNumber.toString() method is responsible for * returning a reasonable value: the string '42'. */ - jsonObject = new JSONObject(); - jsonObject.put("myNumber", new MyNumber()); - actual = jsonObject.toString(); + JSONObject jsonObject1 = new JSONObject(); + jsonObject1.put("myNumber", new MyNumber()); + actual = jsonObject1.toString(); expected = "{\"myNumber\":42}"; assertEquals("Equal", expected , actual); @@ -411,8 +401,8 @@ public class JSONObjectTest { * wrap() inserts the value as a string. That is why 42 comes back * wrapped in quotes. */ - jsonObject = new JSONObject(Collections.singletonMap("myNumber", new AtomicInteger(42))); - actual = jsonObject.toString(); + JSONObject jsonObject2 = new JSONObject(Collections.singletonMap("myNumber", new AtomicInteger(42))); + actual = jsonObject2.toString(); expected = "{\"myNumber\":\"42\"}"; assertEquals("Equal", expected , actual); @@ -422,9 +412,9 @@ public class JSONObjectTest { * AtomicInteger is recognized as a Number, and converted via * numberToString() into the unquoted string '42'. */ - jsonObject = new JSONObject(); - jsonObject.put("myNumber", new AtomicInteger(42)); - actual = jsonObject.toString(); + JSONObject jsonObject3 = new JSONObject(); + jsonObject3.put("myNumber", new AtomicInteger(42)); + actual = jsonObject3.toString(); expected = "{\"myNumber\":42}"; assertEquals("Equal", expected , actual); @@ -435,11 +425,11 @@ public class JSONObjectTest { * bean and inserted into a contained JSONObject. It has 2 getters, * for numerator and denominator. */ - jsonObject = new JSONObject(Collections.singletonMap("myNumber", new Fraction(4,2))); - assertEquals(1, jsonObject.length()); - assertEquals(2, ((JSONObject)(jsonObject.get("myNumber"))).length()); - assertEquals("Numerator", BigInteger.valueOf(4) , jsonObject.query("/myNumber/numerator")); - assertEquals("Denominator", BigInteger.valueOf(2) , jsonObject.query("/myNumber/denominator")); + 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")); /** * JSONObject.put() inserts the Fraction directly into the @@ -449,11 +439,15 @@ public class JSONObjectTest { * BigDecimal sanity check fails, so writeValue() defaults * to returning a safe JSON quoted string. Pretty slick! */ - jsonObject = new JSONObject(); - jsonObject.put("myNumber", new Fraction(4,2)); - actual = jsonObject.toString(); + JSONObject jsonObject5 = new JSONObject(); + jsonObject5.put("myNumber", new Fraction(4,2)); + actual = jsonObject5.toString(); expected = "{\"myNumber\":\"4/2\"}"; // valid JSON, bug fixed assertEquals("Equal", expected , actual); + + Util.checkJSONObjectsMaps(new ArrayList(Arrays.asList( + jsonObject0, jsonObject1, jsonObject2, jsonObject3, jsonObject4, jsonObject5 + ))); } /** @@ -488,6 +482,10 @@ public class JSONObjectTest { assertTrue( "The RAW Collection should give me the same as the Typed Collection", expected.similar(jaInt)); + + Util.checkJSONObjectsMaps(new ArrayList(Arrays.asList( + jaRaw, jaObj, jaInt + ))); } @@ -531,6 +529,10 @@ public class JSONObjectTest { assertTrue( "The RAW Collection should give me the same as the Typed Collection", expected.similar(jaObjObj)); + + Util.checkJSONObjectsMaps(new ArrayList(Arrays.asList( + jaRaw, jaStrObj, jaStrInt, jaStrObj + ))); } @@ -553,6 +555,7 @@ public class JSONObjectTest { 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"))); + Util.checkJSONObjectMaps(jsonObject); } /** @@ -580,6 +583,7 @@ public class JSONObjectTest { 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"))); + Util.checkJSONObjectMaps(jsonObject); } /** @@ -620,6 +624,7 @@ public class JSONObjectTest { assertTrue("expected 2 callbacks items", ((List)(JsonPath.read(doc, "$.callbacks"))).size() == 2); assertTrue("expected 0 handler items", ((Map)(JsonPath.read(doc, "$.callbacks[0].handler"))).size() == 0); assertTrue("expected 0 callbacks[1] items", ((Map)(JsonPath.read(doc, "$.callbacks[1]"))).size() == 0); + Util.checkJSONObjectMaps(jsonObject); } /** @@ -655,6 +660,7 @@ public class JSONObjectTest { // 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); } /** @@ -705,6 +711,7 @@ public class JSONObjectTest { // 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); } /** @@ -725,6 +732,7 @@ public class JSONObjectTest { 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"))); + Util.checkJSONObjectMaps(jsonObject); } /** @@ -746,6 +754,7 @@ public class JSONObjectTest { 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"))); + Util.checkJSONObjectMaps(jsonObject); } /** @@ -778,6 +787,7 @@ public class JSONObjectTest { 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"))); + Util.checkJSONObjectMaps(jsonObject); } /** @@ -809,6 +819,7 @@ public class JSONObjectTest { 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"))); + Util.checkJSONObjectMaps(jsonObject); } /** @@ -944,6 +955,7 @@ public class JSONObjectTest { JSONObject jsonObjectInner = jsonObject.getJSONObject("objectKey"); assertTrue("objectKey should be JSONObject", jsonObjectInner.get("myKey").equals("myVal")); + Util.checkJSONObjectMaps(jsonObject); } /** @@ -1006,6 +1018,7 @@ public class JSONObjectTest { obj = jsonObject.get( "largeExponent" ); assertTrue("largeExponent should evaluate as a BigDecimal", new BigDecimal("-23.45e2327").equals(obj)); + Util.checkJSONObjectMaps(jsonObject); } /** @@ -1054,6 +1067,7 @@ public class JSONObjectTest { jsonObject.get("floatIdentifier").equals(Double.valueOf(0.1))); assertTrue("doubleIdentifier currently evaluates to double 0.1", jsonObject.get("doubleIdentifier").equals(Double.valueOf(0.1))); + Util.checkJSONObjectMaps(jsonObject); } /** @@ -1205,6 +1219,7 @@ public class JSONObjectTest { "JSONObject[\"stringKey\"] is not a JSONObject (class java.lang.String : hello world!).", e.getMessage()); } + Util.checkJSONObjectMaps(jsonObject); } /** @@ -1232,6 +1247,7 @@ public class JSONObjectTest { assertTrue("3.0 can still be interpreted as a double", deserialized.getDouble(key30) == 3.0); assertTrue("3.1 remains a double", deserialized.getDouble(key31) == 3.1); + Util.checkJSONObjectMaps(jsonObject); } /** @@ -1247,9 +1263,9 @@ public class JSONObjectTest { * value is stored. This should be fixed. */ BigInteger bigInteger = new BigInteger("123456789012345678901234567890"); - JSONObject jsonObject = new JSONObject(bigInteger); - Object obj = jsonObject.get("lowestSetBit"); - assertTrue("JSONObject only has 1 value", jsonObject.length() == 1); + JSONObject jsonObject0 = new JSONObject(bigInteger); + Object obj = jsonObject0.get("lowestSetBit"); + assertTrue("JSONObject only has 1 value", jsonObject0.length() == 1); assertTrue("JSONObject parses BigInteger as the Integer lowestBitSet", obj instanceof Integer); assertTrue("this bigInteger lowestBitSet happens to be 1", @@ -1262,57 +1278,57 @@ public class JSONObjectTest { */ BigDecimal bigDecimal = new BigDecimal( "123456789012345678901234567890.12345678901234567890123456789"); - jsonObject = new JSONObject(bigDecimal); - assertTrue("large bigDecimal is not stored", jsonObject.isEmpty()); + JSONObject jsonObject1 = new JSONObject(bigDecimal); + assertTrue("large bigDecimal is not stored", jsonObject1.isEmpty()); /** * JSONObject put(String, Object) method stores and serializes * bigInt and bigDec correctly. Nothing needs to change. */ - jsonObject = new JSONObject(); - jsonObject.put("bigInt", bigInteger); + JSONObject jsonObject2 = new JSONObject(); + jsonObject2.put("bigInt", bigInteger); assertTrue("jsonObject.put() handles bigInt correctly", - jsonObject.get("bigInt").equals(bigInteger)); + jsonObject2.get("bigInt").equals(bigInteger)); assertTrue("jsonObject.getBigInteger() handles bigInt correctly", - jsonObject.getBigInteger("bigInt").equals(bigInteger)); + jsonObject2.getBigInteger("bigInt").equals(bigInteger)); assertTrue("jsonObject.optBigInteger() handles bigInt correctly", - jsonObject.optBigInteger("bigInt", BigInteger.ONE).equals(bigInteger)); + jsonObject2.optBigInteger("bigInt", BigInteger.ONE).equals(bigInteger)); assertTrue("jsonObject serializes bigInt correctly", - jsonObject.toString().equals("{\"bigInt\":123456789012345678901234567890}")); + jsonObject2.toString().equals("{\"bigInt\":123456789012345678901234567890}")); assertTrue("BigInteger as BigDecimal", - jsonObject.getBigDecimal("bigInt").equals(new BigDecimal(bigInteger))); + jsonObject2.getBigDecimal("bigInt").equals(new BigDecimal(bigInteger))); - jsonObject = new JSONObject(); - jsonObject.put("bigDec", bigDecimal); + JSONObject jsonObject3 = new JSONObject(); + jsonObject3.put("bigDec", bigDecimal); assertTrue("jsonObject.put() handles bigDec correctly", - jsonObject.get("bigDec").equals(bigDecimal)); + jsonObject3.get("bigDec").equals(bigDecimal)); assertTrue("jsonObject.getBigDecimal() handles bigDec correctly", - jsonObject.getBigDecimal("bigDec").equals(bigDecimal)); + jsonObject3.getBigDecimal("bigDec").equals(bigDecimal)); assertTrue("jsonObject.optBigDecimal() handles bigDec correctly", - jsonObject.optBigDecimal("bigDec", BigDecimal.ONE).equals(bigDecimal)); + jsonObject3.optBigDecimal("bigDec", BigDecimal.ONE).equals(bigDecimal)); assertTrue("jsonObject serializes bigDec correctly", - jsonObject.toString().equals( + jsonObject3.toString().equals( "{\"bigDec\":123456789012345678901234567890.12345678901234567890123456789}")); assertTrue("BigDecimal as BigInteger", - jsonObject.getBigInteger("bigDec").equals(bigDecimal.toBigInteger())); + jsonObject3.getBigInteger("bigDec").equals(bigDecimal.toBigInteger())); /** * exercise some exceptions */ try { // bigInt key does not exist - jsonObject.getBigDecimal("bigInt"); + jsonObject3.getBigDecimal("bigInt"); fail("expected an exeption"); } catch (JSONException ignored) {} - obj = jsonObject.optBigDecimal("bigInt", BigDecimal.ONE); + obj = jsonObject3.optBigDecimal("bigInt", BigDecimal.ONE); assertTrue("expected BigDecimal", obj.equals(BigDecimal.ONE)); - jsonObject.put("stringKey", "abc"); + jsonObject3.put("stringKey", "abc"); try { - jsonObject.getBigDecimal("stringKey"); + jsonObject3.getBigDecimal("stringKey"); fail("expected an exeption"); } catch (JSONException ignored) {} - obj = jsonObject.optBigInteger("bigDec", BigInteger.ONE); + obj = jsonObject3.optBigInteger("bigDec", BigInteger.ONE); assertTrue("expected BigInteger", obj instanceof BigInteger); assertEquals(bigDecimal.toBigInteger(), obj); @@ -1345,79 +1361,79 @@ public class JSONObjectTest { // bigInt map ctor Map map = new HashMap(); map.put("bigInt", bigInteger); - jsonObject = new JSONObject(map); - String actualFromMapStr = jsonObject.toString(); + JSONObject jsonObject4 = new JSONObject(map); + String actualFromMapStr = jsonObject4.toString(); assertTrue("bigInt in map (or array or bean) is a string", actualFromMapStr.equals( "{\"bigInt\":123456789012345678901234567890}")); // bigInt put - jsonObject = new JSONObject(); - jsonObject.put("bigInt", bigInteger); - String actualFromPutStr = jsonObject.toString(); + JSONObject jsonObject5 = new JSONObject(); + jsonObject5.put("bigInt", bigInteger); + String actualFromPutStr = jsonObject5.toString(); assertTrue("bigInt from put is a number", actualFromPutStr.equals( "{\"bigInt\":123456789012345678901234567890}")); // bigDec map ctor map = new HashMap(); map.put("bigDec", bigDecimal); - jsonObject = new JSONObject(map); - actualFromMapStr = jsonObject.toString(); + JSONObject jsonObject6 = new JSONObject(map); + actualFromMapStr = jsonObject6.toString(); assertTrue("bigDec in map (or array or bean) is a bigDec", actualFromMapStr.equals( "{\"bigDec\":123456789012345678901234567890.12345678901234567890123456789}")); // bigDec put - jsonObject = new JSONObject(); - jsonObject.put("bigDec", bigDecimal); - actualFromPutStr = jsonObject.toString(); + JSONObject jsonObject7 = new JSONObject(); + jsonObject7.put("bigDec", bigDecimal); + actualFromPutStr = jsonObject7.toString(); assertTrue("bigDec from put is a number", actualFromPutStr.equals( "{\"bigDec\":123456789012345678901234567890.12345678901234567890123456789}")); // bigInt,bigDec put - JSONArray jsonArray = new JSONArray(); - jsonArray.put(bigInteger); - jsonArray.put(bigDecimal); - actualFromPutStr = jsonArray.toString(); + JSONArray jsonArray0 = new JSONArray(); + jsonArray0.put(bigInteger); + jsonArray0.put(bigDecimal); + actualFromPutStr = jsonArray0.toString(); assertTrue("bigInt, bigDec from put is a number", actualFromPutStr.equals( "[123456789012345678901234567890,123456789012345678901234567890.12345678901234567890123456789]")); - assertTrue("getBigInt is bigInt", jsonArray.getBigInteger(0).equals(bigInteger)); - assertTrue("getBigDec is bigDec", jsonArray.getBigDecimal(1).equals(bigDecimal)); - assertTrue("optBigInt is bigInt", jsonArray.optBigInteger(0, BigInteger.ONE).equals(bigInteger)); - assertTrue("optBigDec is bigDec", jsonArray.optBigDecimal(1, BigDecimal.ONE).equals(bigDecimal)); - jsonArray.put(Boolean.TRUE); + assertTrue("getBigInt is bigInt", jsonArray0.getBigInteger(0).equals(bigInteger)); + assertTrue("getBigDec is bigDec", jsonArray0.getBigDecimal(1).equals(bigDecimal)); + assertTrue("optBigInt is bigInt", jsonArray0.optBigInteger(0, BigInteger.ONE).equals(bigInteger)); + assertTrue("optBigDec is bigDec", jsonArray0.optBigDecimal(1, BigDecimal.ONE).equals(bigDecimal)); + jsonArray0.put(Boolean.TRUE); try { - jsonArray.getBigInteger(2); + jsonArray0.getBigInteger(2); fail("should not be able to get big int"); } catch (Exception ignored) {} try { - jsonArray.getBigDecimal(2); + jsonArray0.getBigDecimal(2); fail("should not be able to get big dec"); } catch (Exception ignored) {} - assertTrue("optBigInt is default", jsonArray.optBigInteger(2, BigInteger.ONE).equals(BigInteger.ONE)); - assertTrue("optBigDec is default", jsonArray.optBigDecimal(2, BigDecimal.ONE).equals(BigDecimal.ONE)); + assertTrue("optBigInt is default", jsonArray0.optBigInteger(2, BigInteger.ONE).equals(BigInteger.ONE)); + assertTrue("optBigDec is default", jsonArray0.optBigDecimal(2, BigDecimal.ONE).equals(BigDecimal.ONE)); // bigInt,bigDec list ctor List list = new ArrayList(); list.add(bigInteger); list.add(bigDecimal); - jsonArray = new JSONArray(list); - String actualFromListStr = jsonArray.toString(); + JSONArray jsonArray1 = new JSONArray(list); + String actualFromListStr = jsonArray1.toString(); assertTrue("bigInt, bigDec in list is a bigInt, bigDec", actualFromListStr.equals( "[123456789012345678901234567890,123456789012345678901234567890.12345678901234567890123456789]")); // bigInt bean ctor MyBigNumberBean myBigNumberBean = mock(MyBigNumberBean.class); when(myBigNumberBean.getBigInteger()).thenReturn(new BigInteger("123456789012345678901234567890")); - jsonObject = new JSONObject(myBigNumberBean); - String actualFromBeanStr = jsonObject.toString(); + JSONObject jsonObject8 = new JSONObject(myBigNumberBean); + String actualFromBeanStr = jsonObject8.toString(); // can't do a full string compare because mockery adds an extra key/value assertTrue("bigInt from bean ctor is a bigInt", actualFromBeanStr.contains("123456789012345678901234567890")); // bigDec bean ctor myBigNumberBean = mock(MyBigNumberBean.class); when(myBigNumberBean.getBigDecimal()).thenReturn(new BigDecimal("123456789012345678901234567890.12345678901234567890123456789")); - jsonObject = new JSONObject(myBigNumberBean); - actualFromBeanStr = jsonObject.toString(); + jsonObject8 = new JSONObject(myBigNumberBean); + actualFromBeanStr = jsonObject8.toString(); // can't do a full string compare because mockery adds an extra key/value assertTrue("bigDec from bean ctor is a bigDec", actualFromBeanStr.contains("123456789012345678901234567890.12345678901234567890123456789")); @@ -1426,7 +1442,12 @@ public class JSONObjectTest { assertTrue("wrap() returns big num",obj.equals(bigInteger)); obj = JSONObject.wrap(bigDecimal); assertTrue("wrap() returns string",obj.equals(bigDecimal)); - + Util.checkJSONObjectsMaps(new ArrayList(Arrays.asList( + jsonObject0, jsonObject1, jsonObject2, jsonObject3, jsonObject4, + jsonObject5, jsonObject6, jsonObject7, jsonObject8 + ))); + Util.checkJSONArrayMaps(jsonArray0, jsonObject0.getMapType()); + Util.checkJSONArrayMaps(jsonArray1, jsonObject0.getMapType()); } /** @@ -1438,7 +1459,6 @@ public class JSONObjectTest { */ @Test public void jsonObjectNames() { - JSONObject jsonObject; // getNames() from null JSONObject assertTrue("null names from null Object", @@ -1449,16 +1469,16 @@ public class JSONObjectTest { null == JSONObject.getNames(new MyJsonString())); // getNames from new JSONOjbect - jsonObject = new JSONObject(); - String [] names = JSONObject.getNames(jsonObject); + JSONObject jsonObject0 = new JSONObject(); + String [] names = JSONObject.getNames(jsonObject0); assertTrue("names should be null", names == null); // getNames() from empty JSONObject String emptyStr = "{}"; - jsonObject = new JSONObject(emptyStr); + JSONObject jsonObject1 = new JSONObject(emptyStr); assertTrue("empty JSONObject should have null names", - null == JSONObject.getNames(jsonObject)); + null == JSONObject.getNames(jsonObject1)); // getNames() from JSONObject String str = @@ -1467,13 +1487,13 @@ public class JSONObjectTest { "\"falseKey\":false,"+ "\"stringKey\":\"hello world!\","+ "}"; - jsonObject = new JSONObject(str); - names = JSONObject.getNames(jsonObject); - JSONArray jsonArray = new JSONArray(names); + JSONObject jsonObject2 = new JSONObject(str); + names = JSONObject.getNames(jsonObject2); + JSONArray jsonArray0 = new JSONArray(names); // validate JSON Object doc = Configuration.defaultConfiguration().jsonProvider() - .parse(jsonArray.toString()); + .parse(jsonArray0.toString()); List docList = JsonPath.read(doc, "$"); assertTrue("expected 3 items", docList.size() == 3); assertTrue( @@ -1494,9 +1514,9 @@ public class JSONObjectTest { names = JSONObject.getNames(myEnumField); // validate JSON - jsonArray = new JSONArray(names); + JSONArray jsonArray1 = new JSONArray(names); doc = Configuration.defaultConfiguration().jsonProvider() - .parse(jsonArray.toString()); + .parse(jsonArray1.toString()); docList = JsonPath.read(doc, "$"); assertTrue("expected 3 items", docList.size() == 3); assertTrue( @@ -1518,9 +1538,9 @@ public class JSONObjectTest { names = JSONObject.getNames(myPublicClass); // validate JSON - jsonArray = new JSONArray(names); + JSONArray jsonArray2 = new JSONArray(names); doc = Configuration.defaultConfiguration().jsonProvider() - .parse(jsonArray.toString()); + .parse(jsonArray2.toString()); docList = JsonPath.read(doc, "$"); assertTrue("expected 2 items", docList.size() == 2); assertTrue( @@ -1529,6 +1549,12 @@ public class JSONObjectTest { assertTrue( "expected to find publicInt", ((List) JsonPath.read(doc, "$[?(@=='publicInt')]")).size() == 1); + Util.checkJSONObjectsMaps(new ArrayList(Arrays.asList( + jsonObject0, jsonObject1, jsonObject2 + ))); + Util.checkJSONArrayMaps(jsonArray0, jsonObject0.getMapType()); + Util.checkJSONArrayMaps(jsonArray1, jsonObject0.getMapType()); + Util.checkJSONArrayMaps(jsonArray2, jsonObject0.getMapType()); } /** @@ -1540,6 +1566,8 @@ public class JSONObjectTest { JSONObject jsonObject = new JSONObject(); JSONArray jsonArray = jsonObject.names(); assertTrue("jsonArray should be null", jsonArray == null); + Util.checkJSONObjectMaps(jsonObject); + Util.checkJSONArrayMaps(jsonArray, jsonObject.getMapType()); } /** @@ -1564,6 +1592,8 @@ public class JSONObjectTest { assertTrue("expected to find trueKey", ((List) JsonPath.read(doc, "$[?(@=='trueKey')]")).size() == 1); assertTrue("expected to find falseKey", ((List) JsonPath.read(doc, "$[?(@=='falseKey')]")).size() == 1); assertTrue("expected to find stringKey", ((List) JsonPath.read(doc, "$[?(@=='stringKey')]")).size() == 1); + Util.checkJSONObjectMaps(jsonObject); + Util.checkJSONArrayMaps(jsonArray, jsonObject.getMapType()); } /** @@ -1682,7 +1712,9 @@ public class JSONObjectTest { // this.put(key, new Float((Float) value + 1)); // Probably it would be better to deprecate the method and remove some day, while convenient processing the "payload" is not // really in the scope of a JSON-library (IMHO.) - + Util.checkJSONObjectsMaps(new ArrayList(Arrays.asList( + jsonObject, inc + ))); } /** @@ -1780,6 +1812,12 @@ public class JSONObjectTest { JSONObject bCompareArrayJsonObject = new JSONObject(bCompareArrayStr); assertTrue("different nested JSONArrays should not be similar", !aCompareArrayJsonObject.similar(bCompareArrayJsonObject)); + Util.checkJSONObjectsMaps(new ArrayList(Arrays.asList( + jsonObject, expectedJsonObject, aCompareValueJsonObject, + aCompareArrayJsonObject, aCompareObjectJsonObject, aCompareArrayJsonObject, + bCompareValueJsonObject, bCompareArrayJsonObject, bCompareObjectJsonObject, + bCompareArrayJsonObject + ))); } /** @@ -1815,6 +1853,7 @@ public class JSONObjectTest { 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"))); + Util.checkJSONObjectMaps(jsonObject); } /** @@ -1888,6 +1927,9 @@ public class JSONObjectTest { JSONObject jo = new JSONObject().put("TABLE", new JSONObject().put("yhoo", new JSONObject())); assertEquals("toString(2)","{\"TABLE\": {\"yhoo\": {}}}", jo.toString(2)); + Util.checkJSONObjectsMaps(new ArrayList(Arrays.asList( + jsonObject, jo + ))); } /** @@ -1909,6 +1951,7 @@ public class JSONObjectTest { 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"))); + Util.checkJSONObjectMaps(jsonObject); } /** @@ -1931,6 +1974,7 @@ public class JSONObjectTest { 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"))); + Util.checkJSONObjectMaps(jsonObject); } /** @@ -1978,7 +2022,9 @@ public class JSONObjectTest { jsonArray.toString().equals(JSONObject.valueToString(collection))); Integer[] array = { new Integer(1), new Integer(2), new Integer(3) }; assertTrue("array valueToString() incorrect", - jsonArray.toString().equals(JSONObject.valueToString(array))); + jsonArray.toString().equals(JSONObject.valueToString(array))); + Util.checkJSONObjectMaps(jsonObject); + Util.checkJSONArrayMaps(jsonArray, jsonObject.getMapType()); } /** @@ -2082,6 +2128,11 @@ public class JSONObjectTest { assertTrue("expected val1", "val1".equals(mapJsonObject.query("/key1"))); assertTrue("expected val2", "val2".equals(mapJsonObject.query("/key2"))); assertTrue("expected val3", "val3".equals(mapJsonObject.query("/key3"))); + Util.checkJSONObjectsMaps(new ArrayList(Arrays.asList( + jsonObject, mapJsonObject + ))); + Util.checkJSONArrayMaps(jsonArray, jsonObject.getMapType()); + Util.checkJSONArrayMaps(integerArrayJsonArray, jsonObject.getMapType()); } @@ -2096,6 +2147,7 @@ public class JSONObjectTest { try { 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) { 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' @@ -2395,6 +2447,7 @@ public class JSONObjectTest { assertTrue("jsonObject should be empty", jsonObject.isEmpty()); jsonObject.putOnce(null, ""); assertTrue("jsonObject should be empty", jsonObject.isEmpty()); + Util.checkJSONObjectMaps(jsonObject); } /** @@ -2430,6 +2483,7 @@ public class JSONObjectTest { 42l == jsonObject.optNumber("myKey", Long.valueOf(42)).longValue()); assertTrue("optString() should return default string", "hi".equals(jsonObject.optString("hiKey", "hi"))); + Util.checkJSONObjectMaps(jsonObject); } /** @@ -2466,6 +2520,7 @@ public class JSONObjectTest { 42l == jsonObject.optNumber("myKey", Long.valueOf(42)).longValue()); assertTrue("optString() should return default string", "hi".equals(jsonObject.optString("hiKey", "hi"))); + Util.checkJSONObjectMaps(jsonObject); } /** @@ -2484,6 +2539,7 @@ public class JSONObjectTest { assertTrue("unexpected optBigDecimal value",jo.optBigDecimal("int",BigDecimal.ZERO).compareTo(new BigDecimal("123"))==0); assertTrue("unexpected optBigDecimal value",jo.optBigDecimal("int",BigDecimal.ZERO).compareTo(new BigDecimal("123"))==0); assertTrue("unexpected optNumber value",jo.optNumber("int",BigInteger.ZERO).longValue()==123l); + Util.checkJSONObjectMaps(jo); } /** @@ -2518,6 +2574,7 @@ public class JSONObjectTest { assertNotEquals((int)Double.parseDouble("19007199254740993.35481234487103587486413587843213584"), jo.optInt("largeNumberStr")); assertEquals(19007199254740992l, (long)Double.parseDouble("19007199254740993.35481234487103587486413587843213584")); assertEquals(2147483647, (int)Double.parseDouble("19007199254740993.35481234487103587486413587843213584")); + Util.checkJSONObjectMaps(jo); } /** @@ -2540,6 +2597,7 @@ public class JSONObjectTest { assertNull(jo.optBigDecimal("nullVal", null)); assertEquals(jo.optBigDecimal("float", null),jo.getBigDecimal("float")); assertEquals(jo.optBigDecimal("double", null),jo.getBigDecimal("double")); + Util.checkJSONObjectMaps(jo); } /** @@ -2560,6 +2618,7 @@ public class JSONObjectTest { assertEquals(new BigInteger("1234"),jo.optBigInteger("bigInteger", null)); assertEquals(new BigInteger("1234"),jo.optBigInteger("bigDecimal", null)); assertNull(jo.optBigDecimal("nullVal", null)); + Util.checkJSONObjectMaps(jo); } /** @@ -2577,8 +2636,9 @@ public class JSONObjectTest { JSONObject jsonObjectPutNull = new JSONObject(str); jsonObjectPutNull.put("myKey", (Object) null); assertTrue("jsonObject should be empty", jsonObjectPutNull.isEmpty()); - - + Util.checkJSONObjectsMaps(new ArrayList(Arrays.asList( + jsonObjectRemove, jsonObjectPutNull + ))); } /** @@ -2663,6 +2723,7 @@ public class JSONObjectTest { } finally { stringWriter.close(); } + Util.checkJSONObjectMaps(jsonObject); } /** @@ -2745,7 +2806,7 @@ public class JSONObjectTest { writer.close(); } catch (Exception e) {} } - + Util.checkJSONObjectMaps(jsonObject); } @@ -2813,6 +2874,7 @@ public class JSONObjectTest { stringWriter.close(); } catch (Exception e) {} } + Util.checkJSONObjectMaps(jsonObject); } /** @@ -2855,6 +2917,7 @@ public class JSONObjectTest { JSONObject aJsonObject = new JSONObject(str); assertTrue("Same JSONObject should be equal to itself", aJsonObject.equals(aJsonObject)); + Util.checkJSONObjectMaps(aJsonObject); } /** @@ -2940,6 +3003,9 @@ public class JSONObjectTest { "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) @@ -3037,6 +3103,7 @@ public class JSONObjectTest { // assert that the new map is mutable assertTrue("Removing a key should succeed", map.remove("key3") != null); assertTrue("Map should have 2 elements", map.size() == 2); + Util.checkJSONObjectMaps(jsonObject); } /** @@ -3061,6 +3128,9 @@ public class JSONObjectTest { // ensure our original jo hasn't changed. assertEquals(0, jo.get("someInt")); assertEquals(null, jo.opt("someString")); + Util.checkJSONObjectsMaps(new ArrayList(Arrays.asList( + jo, jo2 + ))); } /** @@ -3085,6 +3155,9 @@ public class JSONObjectTest { // ensure our original jo hasn't changed. assertEquals(0, jo.get("someInt")); assertEquals(null, jo.opt("someString")); + Util.checkJSONObjectsMaps(new ArrayList(Arrays.asList( + jo, jo2 + ))); } /** @@ -3100,6 +3173,7 @@ public class JSONObjectTest { assertEquals("Expected the getter to only be called once", 1, bean.genericGetCounter); assertEquals(0, bean.genericSetCounter); + Util.checkJSONObjectMaps(jo); } /** @@ -3115,6 +3189,7 @@ public class JSONObjectTest { assertEquals("Expected the getter to only be called once", 1, bean.genericGetCounter); assertEquals(0, bean.genericSetCounter); + Util.checkJSONObjectMaps(jo); } /** @@ -3133,6 +3208,7 @@ public class JSONObjectTest { assertEquals("Expected 1 key to be mapped. Instead found: "+jo.keySet().toString(), 1, jo.length()); assertNotNull(jo.get("ALL")); + Util.checkJSONObjectMaps(jo); } /** @@ -3150,6 +3226,8 @@ public class JSONObjectTest { BigDecimal wantedValue = BigDecimal.valueOf(value); assertEquals(current, wantedValue); + Util.checkJSONObjectMaps(jsonObject); + Util.checkJSONArrayMaps(array, jsonObject.getMapType()); } /** @@ -3163,6 +3241,7 @@ public class JSONObjectTest { 1, jo.length()); assertTrue(jo.get("closeable") instanceof JSONObject); assertTrue(jo.getJSONObject("closeable").has("string")); + Util.checkJSONObjectMaps(jo); } @Test(expected=NullPointerException.class) @@ -3289,9 +3368,12 @@ public class JSONObjectTest { ObjC.setRef(ObjA); ObjB.setRef(ObjA); ObjB.setRef2(ObjA); - new JSONObject(ObjC); - new JSONObject(ObjB); - new JSONObject(ObjA); + JSONObject j0 = new JSONObject(ObjC); + JSONObject j1 = new JSONObject(ObjB); + JSONObject j2 = new JSONObject(ObjA); + Util.checkJSONObjectsMaps(new ArrayList(Arrays.asList( + j0, j1, j2 + ))); } @Test public void testLongRepeatObjectNotRecursive() { @@ -3307,17 +3389,21 @@ public class JSONObjectTest { ObjB.setRef2(ObjD); ObjA.setRef(ObjD); ObjD.setRef(ObjE); - new JSONObject(ObjC); - new JSONObject(ObjB); - new JSONObject(ObjA); - new JSONObject(ObjD); - new JSONObject(ObjE); + JSONObject j0 = new JSONObject(ObjC); + JSONObject j1 = new JSONObject(ObjB); + JSONObject j2 = new JSONObject(ObjA); + JSONObject j3 = new JSONObject(ObjD); + JSONObject j4 = new JSONObject(ObjE); + Util.checkJSONObjectsMaps(new ArrayList(Arrays.asList( + j0, j1, j2, j3, j4 + ))); } @Test(expected=JSONException.class) public void testRecursiveEquals() { RecursiveBeanEquals a = new RecursiveBeanEquals("same"); a.setRef(a); - new JSONObject(a); + JSONObject j0 = new JSONObject(a); + Util.checkJSONObjectMaps(j0); } @Test public void testNotRecursiveEquals() { @@ -3326,7 +3412,8 @@ public class JSONObjectTest { RecursiveBeanEquals c = new RecursiveBeanEquals("same"); a.setRef(b); b.setRef(c); - new JSONObject(a); + JSONObject j0 = new JSONObject(a); + Util.checkJSONObjectMaps(j0); } @@ -3336,6 +3423,7 @@ public class JSONObjectTest { assertTrue("missing expected key 'empty_json_array'", jsonObject.has("empty_json_array")); assertNotNull("'empty_json_array' should be an array", jsonObject.getJSONArray("empty_json_array")); assertEquals("'empty_json_array' should have a length of 0", 0, jsonObject.getJSONArray("empty_json_array").length()); + Util.checkJSONObjectMaps(jsonObject); } /** @@ -3351,6 +3439,7 @@ public class JSONObjectTest { 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 + Util.checkJSONObjectMaps(jsonObject); } /** @@ -3364,6 +3453,7 @@ public class JSONObjectTest { JSONObject json_input = new JSONObject(input); assertNotNull(json_input); fail("Excepected Exception."); + Util.checkJSONObjectMaps(json_input); } /** @@ -3373,7 +3463,7 @@ public class JSONObjectTest { public void issue654IncorrectNestingNoKey1() { JSONObject json_input = new JSONObject("{{\"a\":0}}"); assertNotNull(json_input); - fail("Excepected Exception."); + fail("Expected Exception."); } /** @@ -3398,4 +3488,25 @@ public class JSONObjectTest { assertNotNull(json_input); fail("Excepected Exception."); } + + @Test + public void testIssue682SimilarityOfJSONString() { + JSONObject jo1 = new JSONObject() + .put("a", new MyJsonString()) + .put("b", 2); + JSONObject jo2 = new JSONObject() + .put("a", new MyJsonString()) + .put("b", 2); + assertTrue(jo1.similar(jo2)); + + JSONObject jo3 = new JSONObject() + .put("a", new JSONString() { + @Override + public String toJSONString() { + return "\"different value\""; + } + }) + .put("b", 2); + assertFalse(jo1.similar(jo3)); + } } diff --git a/src/test/java/org/json/junit/JSONPointerTest.java b/src/test/java/org/json/junit/JSONPointerTest.java index 4ea7434543165740bbc1e72c2e7c83709cc6f984..45c7dbd3dc872577c108c7fad0e573668548aa37 100644 --- a/src/test/java/org/json/junit/JSONPointerTest.java +++ b/src/test/java/org/json/junit/JSONPointerTest.java @@ -1,27 +1,7 @@ package org.json.junit; /* -Copyright (c) 2020 JSON.org - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -The Software shall be used for Good, not Evil. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +Public Domain. */ import static org.junit.Assert.assertEquals; @@ -92,8 +72,10 @@ public class JSONPointerTest { @Test public void queryByEmptyKeySubObject() { - assertEquals( "{\"\":\"empty key of an object with an empty key\",\"subKey\":\"Some" + - " other value\"}", query("/obj/").toString()); + 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 diff --git a/src/test/java/org/json/junit/JSONStringTest.java b/src/test/java/org/json/junit/JSONStringTest.java index a19961103a157342474dd8b68c7dc5c815f6bf3a..b4fee3eb739fbd1b8f57f15668311a3345cb0f8f 100644 --- a/src/test/java/org/json/junit/JSONStringTest.java +++ b/src/test/java/org/json/junit/JSONStringTest.java @@ -1,27 +1,7 @@ package org.json.junit; /* -Copyright (c) 2020 JSON.org - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -The Software shall be used for Good, not Evil. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +Public Domain. */ import static org.junit.Assert.*; diff --git a/src/test/java/org/json/junit/JSONStringerTest.java b/src/test/java/org/json/junit/JSONStringerTest.java index a99db3b8ce1008815cac96bb1f5636d13cbf4cea..0ecb9d662b542e0fc37e8e600f01ea85d72432c7 100644 --- a/src/test/java/org/json/junit/JSONStringerTest.java +++ b/src/test/java/org/json/junit/JSONStringerTest.java @@ -1,27 +1,7 @@ package org.json.junit; /* -Copyright (c) 2020 JSON.org - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -The Software shall be used for Good, not Evil. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +Public Domain. */ import static org.junit.Assert.*; diff --git a/src/test/java/org/json/junit/JSONTokenerTest.java b/src/test/java/org/json/junit/JSONTokenerTest.java index e8e0f98a947ceab05357d0a61aa29b7cc0ed9e77..59ca6d8f62c1718fad2f5a3a52634597707e4e69 100644 --- a/src/test/java/org/json/junit/JSONTokenerTest.java +++ b/src/test/java/org/json/junit/JSONTokenerTest.java @@ -1,27 +1,7 @@ package org.json.junit; /* -Copyright (c) 2020 JSON.org - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -The Software shall be used for Good, not Evil. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +Public Domain. */ import static org.junit.Assert.assertEquals; @@ -333,4 +313,16 @@ public class JSONTokenerTest { assertEquals(0, t2.next()); assertFalse(t2.more()); } + + @Test + public void testAutoClose(){ + Reader reader = new StringReader("some test string"); + try { + JSONTokener tokener = new JSONTokener(reader); + tokener.close(); + tokener.next(); + } catch (Exception exception){ + assertEquals("Stream closed", exception.getMessage()); + } + } } diff --git a/src/test/java/org/json/junit/PropertyTest.java b/src/test/java/org/json/junit/PropertyTest.java index e1a9b8dcfede250220ffe50bb507d71dd4d1bc23..eee482fbf530230fbc8a3e9a8dcc27e42346afb1 100644 --- a/src/test/java/org/json/junit/PropertyTest.java +++ b/src/test/java/org/json/junit/PropertyTest.java @@ -1,27 +1,7 @@ package org.json.junit; /* -Copyright (c) 2020 JSON.org - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -The Software shall be used for Good, not Evil. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +Public Domain. */ import java.util.*; diff --git a/src/test/java/org/json/junit/Util.java b/src/test/java/org/json/junit/Util.java index 8dc27ddfa8fda38b72c4db97cc8814391b3662ac..b676045b89aea5b3e3c022f64a97b18f10e61494 100644 --- a/src/test/java/org/json/junit/Util.java +++ b/src/test/java/org/json/junit/Util.java @@ -1,27 +1,7 @@ package org.json.junit; /* -Copyright (c) 2020 JSON.org - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -The Software shall be used for Good, not Evil. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +Public Domain. */ import static org.junit.Assert.*; @@ -78,7 +58,6 @@ public class Util { * or something else. * @param value created by the code to be tested * @param expectedValue created specifically for comparing - * @param key key to the jsonObject entry to be compared */ private static void compareActualVsExpectedObjects(Object value, Object expectedValue) { @@ -117,4 +96,106 @@ public class Util { ); } } + + /** + * Asserts that all JSONObject maps are the same as the default ctor + * @param jsonObjects list of objects to be tested + */ + public static void checkJSONObjectsMaps(List jsonObjects) { + if (jsonObjects == null || jsonObjects.size() == 0) { + return; + } + Class mapType = new JSONObject().getMapType(); + for (JSONObject jsonObject : jsonObjects) { + if (jsonObject != null) { + assertTrue(mapType == jsonObject.getMapType()); + checkJSONObjectMaps(jsonObject, mapType); + } + } + } + + /** + * Asserts that all JSONObject maps are the same as the default ctor + * @param jsonObject the object to be tested + */ + public static void checkJSONObjectMaps(JSONObject jsonObject) { + if (jsonObject != null) { + checkJSONObjectMaps(jsonObject, jsonObject.getMapType()); + } + } + + /** + * Asserts that all JSONObject maps are the same as mapType + * @param jsonObject object to be tested + * @param mapType mapType to test against + */ + public static void checkJSONObjectMaps(JSONObject jsonObject, Class mapType) { + if (mapType == null) { + mapType = new JSONObject().getMapType(); + } + Set keys = jsonObject.keySet(); + for (String key : keys) { + Object val = jsonObject.get(key); + if (val instanceof JSONObject) { + JSONObject jsonObjectVal = (JSONObject) val; + assertTrue(mapType == ((JSONObject) val).getMapType()); + checkJSONObjectMaps(jsonObjectVal, mapType); + } else if (val instanceof JSONArray) { + JSONArray jsonArrayVal = (JSONArray)val; + checkJSONArrayMaps(jsonArrayVal, mapType); + } + } + } + + /** + * Asserts that all JSONObject maps in the JSONArray object match the default map + * @param jsonArrays list of JSONArray objects to be tested + */ + public static void checkJSONArraysMaps(List jsonArrays) { + if (jsonArrays == null || jsonArrays.size() == 0) { + return; + } + Class mapType = new JSONObject().getMapType(); + for (JSONArray jsonArray : jsonArrays) { + if (jsonArray != null) { + checkJSONArrayMaps(jsonArray, mapType); + } + } + } + + /** + * Asserts that all JSONObject maps in the JSONArray object match mapType + * @param jsonArray object to be tested + * @param mapType map type to be tested against + */ + public static void checkJSONArrayMaps(JSONArray jsonArray, Class mapType) { + if (jsonArray == null) { + return; + } + if (mapType == null) { + mapType = new JSONObject().getMapType(); + } + Iterator it = jsonArray.iterator(); + while (it.hasNext()) { + Object val = it.next(); + if (val instanceof JSONObject) { + JSONObject jsonObjectVal = (JSONObject)val; + checkJSONObjectMaps(jsonObjectVal, mapType); + } else if (val instanceof JSONArray) { + JSONArray jsonArrayVal = (JSONArray)val; + checkJSONArrayMaps(jsonArrayVal, mapType); + } + } + } + + /** + * Asserts that all JSONObject maps nested in the JSONArray match + * the default mapType + * @param jsonArray the object to be tested + */ + public static void checkJSONArrayMaps(JSONArray jsonArray) { + if (jsonArray != null) { + checkJSONArrayMaps(jsonArray, null); + } + } } diff --git a/src/test/java/org/json/junit/XMLConfigurationTest.java b/src/test/java/org/json/junit/XMLConfigurationTest.java index 2ab06be05aed38f697295118f103ab4d002e7dce..21a2b595ec932fe093d358bf0287060e5b143705 100755 --- a/src/test/java/org/json/junit/XMLConfigurationTest.java +++ b/src/test/java/org/json/junit/XMLConfigurationTest.java @@ -1,27 +1,7 @@ package org.json.junit; /* -Copyright (c) 2020 JSON.org - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -The Software shall be used for Good, not Evil. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +Public Domain. */ import static org.junit.Assert.assertEquals; @@ -1071,6 +1051,29 @@ public class XMLConfigurationTest { Util.compareActualVsExpectedJsonObjects(jsonObject, expetedJsonObject); } + + @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, diff --git a/src/test/java/org/json/junit/XMLTest.java b/src/test/java/org/json/junit/XMLTest.java index 015547220b93c046093386aa753b8f1c9890cbd8..aefaa49da0707f35d309890c915f85bc8bbea8ad 100644 --- a/src/test/java/org/json/junit/XMLTest.java +++ b/src/test/java/org/json/junit/XMLTest.java @@ -1,27 +1,7 @@ package org.json.junit; /* -Copyright (c) 2020 JSON.org - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -The Software shall be used for Good, not Evil. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +Public Domain. */ import static org.junit.Assert.assertEquals; @@ -41,13 +21,7 @@ import java.io.StringReader; import java.util.HashMap; import java.util.Map; -import org.json.JSONArray; -import org.json.JSONException; -import org.json.JSONObject; -import org.json.JSONTokener; -import org.json.XML; -import org.json.XMLParserConfiguration; -import org.json.XMLXsiTypeConverter; +import org.json.*; import org.junit.Rule; import org.junit.Test; import org.junit.rules.TemporaryFolder; @@ -1069,4 +1043,276 @@ public class XMLTest { 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 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 = null; + try { + 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); + InputStream xmlStream = null; + try { + 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); + } + assertEquals(expected.toString(), actualString.replaceAll("\\n|\\r\\n", System.getProperty("line.separator"))); + } finally { + if (xmlStream != null) { + xmlStream.close(); + } + } + } finally { + if (jsonStream != null) { + jsonStream.close(); + } + } + } 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"); + } + } } + + + diff --git a/src/test/resources/Issue593.json b/src/test/resources/Issue593.json new file mode 100644 index 0000000000000000000000000000000000000000..213625af23438cef7e8883b16403cb8e75c9ef1c --- /dev/null +++ b/src/test/resources/Issue593.json @@ -0,0 +1,704 @@ +{ + "success": true, + "error": null, + "response": [ + { + "loc": { + "long": 31.25, + "lat": 30.063 + }, + "interval": "day", + "place": { + "name": "cairo", + "state": "qh", + "country": "eg" + }, + "periods": [ + { + "timestamp": 1665032400, + "validTime": "2022-10-06T07:00:00+02:00", + "dateTimeISO": "2022-10-06T07:00:00+02:00", + "maxTempC": 32, + "maxTempF": 90, + "minTempC": 19, + "minTempF": 66, + "avgTempC": 25, + "avgTempF": 78, + "tempC": null, + "tempF": null, + "maxFeelslikeC": 32, + "maxFeelslikeF": 89, + "minFeelslikeC": 21, + "minFeelslikeF": 70, + "avgFeelslikeC": 26, + "avgFeelslikeF": 80, + "feelslikeC": 21, + "feelslikeF": 70, + "maxDewpointC": 17, + "maxDewpointF": 63, + "minDewpointC": 11, + "minDewpointF": 52, + "avgDewpointC": 14, + "avgDewpointF": 58, + "dewpointC": 17, + "dewpointF": 63, + "maxHumidity": 77, + "minHumidity": 29, + "humidity": 77, + "pop": 0, + "precipMM": 0, + "precipIN": 0, + "iceaccum": null, + "iceaccumMM": null, + "iceaccumIN": null, + "snowCM": 0, + "snowIN": 0, + "pressureMB": 1015, + "pressureIN": 29.97, + "windDir": "N", + "windDirDEG": 353, + "windSpeedKTS": 5, + "windSpeedKPH": 9, + "windSpeedMPH": 6, + "windGustKTS": 21, + "windGustKPH": 40, + "windGustMPH": 25, + "windDirMax": "NNW", + "windDirMaxDEG": 342, + "windSpeedMaxKTS": 9, + "windSpeedMaxKPH": 16, + "windSpeedMaxMPH": 10, + "windDirMin": "N", + "windDirMinDEG": 353, + "windSpeedMinKTS": 1, + "windSpeedMinKPH": 2, + "windSpeedMinMPH": 1, + "windDir80m": "N", + "windDir80mDEG": 11, + "windSpeed80mKTS": 12, + "windSpeed80mKPH": 22, + "windSpeed80mMPH": 13, + "windGust80mKTS": 22, + "windGust80mKPH": 41, + "windGust80mMPH": 25, + "windDirMax80m": "NNW", + "windDirMax80mDEG": 343, + "windSpeedMax80mKTS": 22, + "windSpeedMax80mKPH": 41, + "windSpeedMax80mMPH": 25, + "windDirMin80m": "E", + "windDirMin80mDEG": 95, + "windSpeedMin80mKTS": 8, + "windSpeedMin80mKPH": 15, + "windSpeedMin80mMPH": 10, + "sky": 22, + "cloudsCoded": "FW", + "weather": "Mostly Sunny", + "weatherCoded": [], + "weatherPrimary": "Mostly Sunny", + "weatherPrimaryCoded": "::FW", + "icon": "fair.png", + "visibilityKM": 24.135, + "visibilityMI": 15, + "uvi": 6, + "solradWM2": 5608, + "solradMinWM2": 0, + "solradMaxWM2": 778, + "isDay": true, + "maxCoverage": "", + "sunrise": 1665028274, + "sunset": 1665070502, + "sunriseISO": "2022-10-06T05:51:14+02:00", + "sunsetISO": "2022-10-06T17:35:02+02:00" + }, + { + "timestamp": 1665118800, + "validTime": "2022-10-07T07:00:00+02:00", + "dateTimeISO": "2022-10-07T07:00:00+02:00", + "maxTempC": 30, + "maxTempF": 86, + "minTempC": 19, + "minTempF": 66, + "avgTempC": 24, + "avgTempF": 76, + "tempC": null, + "tempF": null, + "maxFeelslikeC": 29, + "maxFeelslikeF": 85, + "minFeelslikeC": 19, + "minFeelslikeF": 67, + "avgFeelslikeC": 24, + "avgFeelslikeF": 76, + "feelslikeC": 19, + "feelslikeF": 67, + "maxDewpointC": 15, + "maxDewpointF": 60, + "minDewpointC": 10, + "minDewpointF": 50, + "avgDewpointC": 12, + "avgDewpointF": 54, + "dewpointC": 15, + "dewpointF": 60, + "maxHumidity": 77, + "minHumidity": 30, + "humidity": 77, + "pop": 0, + "precipMM": 0, + "precipIN": 0, + "iceaccum": null, + "iceaccumMM": null, + "iceaccumIN": null, + "snowCM": 0, + "snowIN": 0, + "pressureMB": 1014, + "pressureIN": 29.95, + "windDir": "NW", + "windDirDEG": 325, + "windSpeedKTS": 1, + "windSpeedKPH": 2, + "windSpeedMPH": 1, + "windGustKTS": 16, + "windGustKPH": 29, + "windGustMPH": 18, + "windDirMax": "WNW", + "windDirMaxDEG": 298, + "windSpeedMaxKTS": 7, + "windSpeedMaxKPH": 13, + "windSpeedMaxMPH": 8, + "windDirMin": "NW", + "windDirMinDEG": 325, + "windSpeedMinKTS": 1, + "windSpeedMinKPH": 2, + "windSpeedMinMPH": 1, + "windDir80m": "NNW", + "windDir80mDEG": 347, + "windSpeed80mKTS": 6, + "windSpeed80mKPH": 10, + "windSpeed80mMPH": 6, + "windGust80mKTS": 20, + "windGust80mKPH": 37, + "windGust80mMPH": 23, + "windDirMax80m": "NW", + "windDirMax80mDEG": 316, + "windSpeedMax80mKTS": 20, + "windSpeedMax80mKPH": 37, + "windSpeedMax80mMPH": 23, + "windDirMin80m": "NNW", + "windDirMin80mDEG": 347, + "windSpeedMin80mKTS": 6, + "windSpeedMin80mKPH": 10, + "windSpeedMin80mMPH": 6, + "sky": 30, + "cloudsCoded": "FW", + "weather": "Mostly Sunny", + "weatherCoded": [], + "weatherPrimary": "Mostly Sunny", + "weatherPrimaryCoded": "::FW", + "icon": "fair.png", + "visibilityKM": 24.135, + "visibilityMI": 15, + "uvi": 6, + "solradWM2": 5486, + "solradMinWM2": 0, + "solradMaxWM2": 742, + "isDay": true, + "maxCoverage": "", + "sunrise": 1665114710, + "sunset": 1665156831, + "sunriseISO": "2022-10-07T05:51:50+02:00", + "sunsetISO": "2022-10-07T17:33:51+02:00" + }, + { + "timestamp": 1665205200, + "validTime": "2022-10-08T07:00:00+02:00", + "dateTimeISO": "2022-10-08T07:00:00+02:00", + "maxTempC": 30, + "maxTempF": 87, + "minTempC": 19, + "minTempF": 66, + "avgTempC": 25, + "avgTempF": 76, + "tempC": null, + "tempF": null, + "maxFeelslikeC": 30, + "maxFeelslikeF": 86, + "minFeelslikeC": 19, + "minFeelslikeF": 67, + "avgFeelslikeC": 25, + "avgFeelslikeF": 76, + "feelslikeC": 19, + "feelslikeF": 67, + "maxDewpointC": 15, + "maxDewpointF": 59, + "minDewpointC": 11, + "minDewpointF": 52, + "avgDewpointC": 13, + "avgDewpointF": 56, + "dewpointC": 15, + "dewpointF": 59, + "maxHumidity": 76, + "minHumidity": 32, + "humidity": 76, + "pop": 0, + "precipMM": 0, + "precipIN": 0, + "iceaccum": null, + "iceaccumMM": null, + "iceaccumIN": null, + "snowCM": 0, + "snowIN": 0, + "pressureMB": 1014, + "pressureIN": 29.94, + "windDir": "NNE", + "windDirDEG": 21, + "windSpeedKTS": 1, + "windSpeedKPH": 2, + "windSpeedMPH": 1, + "windGustKTS": 17, + "windGustKPH": 32, + "windGustMPH": 20, + "windDirMax": "WNW", + "windDirMaxDEG": 301, + "windSpeedMaxKTS": 7, + "windSpeedMaxKPH": 13, + "windSpeedMaxMPH": 8, + "windDirMin": "NNE", + "windDirMinDEG": 21, + "windSpeedMinKTS": 1, + "windSpeedMinKPH": 2, + "windSpeedMinMPH": 1, + "windDir80m": "NW", + "windDir80mDEG": 309, + "windSpeed80mKTS": 5, + "windSpeed80mKPH": 9, + "windSpeed80mMPH": 5, + "windGust80mKTS": 17, + "windGust80mKPH": 31, + "windGust80mMPH": 19, + "windDirMax80m": "NW", + "windDirMax80mDEG": 322, + "windSpeedMax80mKTS": 17, + "windSpeedMax80mKPH": 31, + "windSpeedMax80mMPH": 19, + "windDirMin80m": "NW", + "windDirMin80mDEG": 309, + "windSpeedMin80mKTS": 5, + "windSpeedMin80mKPH": 9, + "windSpeedMin80mMPH": 5, + "sky": 47, + "cloudsCoded": "SC", + "weather": "Partly Cloudy", + "weatherCoded": [], + "weatherPrimary": "Partly Cloudy", + "weatherPrimaryCoded": "::SC", + "icon": "pcloudy.png", + "visibilityKM": 24.135, + "visibilityMI": 15, + "uvi": 7, + "solradWM2": 4785, + "solradMinWM2": 0, + "solradMaxWM2": 682, + "isDay": true, + "maxCoverage": "", + "sunrise": 1665201146, + "sunset": 1665243161, + "sunriseISO": "2022-10-08T05:52:26+02:00", + "sunsetISO": "2022-10-08T17:32:41+02:00" + }, + { + "timestamp": 1665291600, + "validTime": "2022-10-09T07:00:00+02:00", + "dateTimeISO": "2022-10-09T07:00:00+02:00", + "maxTempC": 31, + "maxTempF": 87, + "minTempC": 19, + "minTempF": 67, + "avgTempC": 25, + "avgTempF": 77, + "tempC": null, + "tempF": null, + "maxFeelslikeC": 30, + "maxFeelslikeF": 86, + "minFeelslikeC": 20, + "minFeelslikeF": 67, + "avgFeelslikeC": 25, + "avgFeelslikeF": 77, + "feelslikeC": 20, + "feelslikeF": 67, + "maxDewpointC": 17, + "maxDewpointF": 63, + "minDewpointC": 11, + "minDewpointF": 52, + "avgDewpointC": 14, + "avgDewpointF": 57, + "dewpointC": 17, + "dewpointF": 63, + "maxHumidity": 86, + "minHumidity": 31, + "humidity": 86, + "pop": 0, + "precipMM": 0, + "precipIN": 0, + "iceaccum": null, + "iceaccumMM": null, + "iceaccumIN": null, + "snowCM": 0, + "snowIN": 0, + "pressureMB": 1016, + "pressureIN": 29.99, + "windDir": "N", + "windDirDEG": 356, + "windSpeedKTS": 2, + "windSpeedKPH": 4, + "windSpeedMPH": 2, + "windGustKTS": 19, + "windGustKPH": 36, + "windGustMPH": 22, + "windDirMax": "NNW", + "windDirMaxDEG": 343, + "windSpeedMaxKTS": 8, + "windSpeedMaxKPH": 14, + "windSpeedMaxMPH": 9, + "windDirMin": "N", + "windDirMinDEG": 356, + "windSpeedMinKTS": 2, + "windSpeedMinKPH": 4, + "windSpeedMinMPH": 2, + "windDir80m": "NW", + "windDir80mDEG": 316, + "windSpeed80mKTS": 5, + "windSpeed80mKPH": 9, + "windSpeed80mMPH": 6, + "windGust80mKTS": 20, + "windGust80mKPH": 36, + "windGust80mMPH": 23, + "windDirMax80m": "N", + "windDirMax80mDEG": 354, + "windSpeedMax80mKTS": 20, + "windSpeedMax80mKPH": 36, + "windSpeedMax80mMPH": 23, + "windDirMin80m": "NW", + "windDirMin80mDEG": 316, + "windSpeedMin80mKTS": 5, + "windSpeedMin80mKPH": 9, + "windSpeedMin80mMPH": 6, + "sky": 47, + "cloudsCoded": "SC", + "weather": "Partly Cloudy", + "weatherCoded": [], + "weatherPrimary": "Partly Cloudy", + "weatherPrimaryCoded": "::SC", + "icon": "pcloudy.png", + "visibilityKM": 24.135, + "visibilityMI": 15, + "uvi": 7, + "solradWM2": 4768, + "solradMinWM2": 0, + "solradMaxWM2": 726, + "isDay": true, + "maxCoverage": "", + "sunrise": 1665287583, + "sunset": 1665329491, + "sunriseISO": "2022-10-09T05:53:03+02:00", + "sunsetISO": "2022-10-09T17:31:31+02:00" + }, + { + "timestamp": 1665378000, + "validTime": "2022-10-10T07:00:00+02:00", + "dateTimeISO": "2022-10-10T07:00:00+02:00", + "maxTempC": 31, + "maxTempF": 87, + "minTempC": 21, + "minTempF": 70, + "avgTempC": 26, + "avgTempF": 78, + "tempC": null, + "tempF": null, + "maxFeelslikeC": 30, + "maxFeelslikeF": 86, + "minFeelslikeC": 21, + "minFeelslikeF": 69, + "avgFeelslikeC": 25, + "avgFeelslikeF": 78, + "feelslikeC": 21, + "feelslikeF": 69, + "maxDewpointC": 16, + "maxDewpointF": 61, + "minDewpointC": 13, + "minDewpointF": 55, + "avgDewpointC": 14, + "avgDewpointF": 58, + "dewpointC": 16, + "dewpointF": 61, + "maxHumidity": 75, + "minHumidity": 35, + "humidity": 75, + "pop": 0, + "precipMM": 0, + "precipIN": 0, + "iceaccum": null, + "iceaccumMM": null, + "iceaccumIN": null, + "snowCM": 0, + "snowIN": 0, + "pressureMB": 1017, + "pressureIN": 30.03, + "windDir": "N", + "windDirDEG": 358, + "windSpeedKTS": 2, + "windSpeedKPH": 4, + "windSpeedMPH": 2, + "windGustKTS": 16, + "windGustKPH": 30, + "windGustMPH": 19, + "windDirMax": "N", + "windDirMaxDEG": 10, + "windSpeedMaxKTS": 8, + "windSpeedMaxKPH": 15, + "windSpeedMaxMPH": 9, + "windDirMin": "N", + "windDirMinDEG": 358, + "windSpeedMinKTS": 2, + "windSpeedMinKPH": 4, + "windSpeedMinMPH": 2, + "windDir80m": "N", + "windDir80mDEG": 8, + "windSpeed80mKTS": 7, + "windSpeed80mKPH": 13, + "windSpeed80mMPH": 8, + "windGust80mKTS": 19, + "windGust80mKPH": 36, + "windGust80mMPH": 22, + "windDirMax80m": "N", + "windDirMax80mDEG": 10, + "windSpeedMax80mKTS": 19, + "windSpeedMax80mKPH": 36, + "windSpeedMax80mMPH": 22, + "windDirMin80m": "E", + "windDirMin80mDEG": 91, + "windSpeedMin80mKTS": 7, + "windSpeedMin80mKPH": 13, + "windSpeedMin80mMPH": 8, + "sky": 64, + "cloudsCoded": "SC", + "weather": "Partly Cloudy", + "weatherCoded": [], + "weatherPrimary": "Partly Cloudy", + "weatherPrimaryCoded": "::SC", + "icon": "pcloudy.png", + "visibilityKM": 24.135, + "visibilityMI": 15, + "uvi": 6, + "solradWM2": 4494, + "solradMinWM2": 0, + "solradMaxWM2": 597, + "isDay": true, + "maxCoverage": "", + "sunrise": 1665374020, + "sunset": 1665415821, + "sunriseISO": "2022-10-10T05:53:40+02:00", + "sunsetISO": "2022-10-10T17:30:21+02:00" + }, + { + "timestamp": 1665464400, + "validTime": "2022-10-11T07:00:00+02:00", + "dateTimeISO": "2022-10-11T07:00:00+02:00", + "maxTempC": 31, + "maxTempF": 87, + "minTempC": 21, + "minTempF": 70, + "avgTempC": 26, + "avgTempF": 78, + "tempC": null, + "tempF": null, + "maxFeelslikeC": 31, + "maxFeelslikeF": 87, + "minFeelslikeC": 22, + "minFeelslikeF": 72, + "avgFeelslikeC": 26, + "avgFeelslikeF": 79, + "feelslikeC": 22, + "feelslikeF": 72, + "maxDewpointC": 17, + "maxDewpointF": 62, + "minDewpointC": 11, + "minDewpointF": 51, + "avgDewpointC": 13, + "avgDewpointF": 55, + "dewpointC": 17, + "dewpointF": 62, + "maxHumidity": 71, + "minHumidity": 30, + "humidity": 71, + "pop": 0, + "precipMM": 0, + "precipIN": 0, + "iceaccum": null, + "iceaccumMM": null, + "iceaccumIN": null, + "snowCM": 0, + "snowIN": 0, + "pressureMB": 1015, + "pressureIN": 29.98, + "windDir": "NNE", + "windDirDEG": 13, + "windSpeedKTS": 8, + "windSpeedKPH": 15, + "windSpeedMPH": 9, + "windGustKTS": 15, + "windGustKPH": 28, + "windGustMPH": 17, + "windDirMax": "NNE", + "windDirMaxDEG": 28, + "windSpeedMaxKTS": 15, + "windSpeedMaxKPH": 28, + "windSpeedMaxMPH": 18, + "windDirMin": "NNE", + "windDirMinDEG": 14, + "windSpeedMinKTS": 7, + "windSpeedMinKPH": 14, + "windSpeedMinMPH": 8, + "windDir80m": "NNE", + "windDir80mDEG": 16, + "windSpeed80mKTS": 10, + "windSpeed80mKPH": 19, + "windSpeed80mMPH": 12, + "windGust80mKTS": 17, + "windGust80mKPH": 31, + "windGust80mMPH": 19, + "windDirMax80m": "NNE", + "windDirMax80mDEG": 28, + "windSpeedMax80mKTS": 17, + "windSpeedMax80mKPH": 31, + "windSpeedMax80mMPH": 19, + "windDirMin80m": "NNE", + "windDirMin80mDEG": 13, + "windSpeedMin80mKTS": 9, + "windSpeedMin80mKPH": 18, + "windSpeedMin80mMPH": 11, + "sky": 0, + "cloudsCoded": "CL", + "weather": "Sunny", + "weatherCoded": [], + "weatherPrimary": "Sunny", + "weatherPrimaryCoded": "::CL", + "icon": "sunny.png", + "visibilityKM": 24.135, + "visibilityMI": 15, + "uvi": null, + "solradWM2": 5450, + "solradMinWM2": 0, + "solradMaxWM2": 758, + "isDay": true, + "maxCoverage": "", + "sunrise": 1665460458, + "sunset": 1665502153, + "sunriseISO": "2022-10-11T05:54:18+02:00", + "sunsetISO": "2022-10-11T17:29:13+02:00" + }, + { + "timestamp": 1665550800, + "validTime": "2022-10-12T07:00:00+02:00", + "dateTimeISO": "2022-10-12T07:00:00+02:00", + "maxTempC": 31, + "maxTempF": 88, + "minTempC": 21, + "minTempF": 69, + "avgTempC": 26, + "avgTempF": 79, + "tempC": null, + "tempF": null, + "maxFeelslikeC": 31, + "maxFeelslikeF": 88, + "minFeelslikeC": 22, + "minFeelslikeF": 72, + "avgFeelslikeC": 26, + "avgFeelslikeF": 80, + "feelslikeC": 22, + "feelslikeF": 72, + "maxDewpointC": 16, + "maxDewpointF": 60, + "minDewpointC": 11, + "minDewpointF": 51, + "avgDewpointC": 13, + "avgDewpointF": 55, + "dewpointC": 16, + "dewpointF": 60, + "maxHumidity": 68, + "minHumidity": 29, + "humidity": 68, + "pop": 0, + "precipMM": 0, + "precipIN": 0, + "iceaccum": null, + "iceaccumMM": null, + "iceaccumIN": null, + "snowCM": 0, + "snowIN": 0, + "pressureMB": 1014, + "pressureIN": 29.95, + "windDir": "NNE", + "windDirDEG": 12, + "windSpeedKTS": 8, + "windSpeedKPH": 15, + "windSpeedMPH": 9, + "windGustKTS": 15, + "windGustKPH": 28, + "windGustMPH": 17, + "windDirMax": "E", + "windDirMaxDEG": 96, + "windSpeedMaxKTS": 14, + "windSpeedMaxKPH": 26, + "windSpeedMaxMPH": 16, + "windDirMin": "NNE", + "windDirMinDEG": 12, + "windSpeedMinKTS": 7, + "windSpeedMinKPH": 13, + "windSpeedMinMPH": 8, + "windDir80m": "NNE", + "windDir80mDEG": 15, + "windSpeed80mKTS": 10, + "windSpeed80mKPH": 19, + "windSpeed80mMPH": 12, + "windGust80mKTS": 18, + "windGust80mKPH": 33, + "windGust80mMPH": 21, + "windDirMax80m": "E", + "windDirMax80mDEG": 96, + "windSpeedMax80mKTS": 18, + "windSpeedMax80mKPH": 33, + "windSpeedMax80mMPH": 21, + "windDirMin80m": "NNE", + "windDirMin80mDEG": 15, + "windSpeedMin80mKTS": 10, + "windSpeedMin80mKPH": 18, + "windSpeedMin80mMPH": 11, + "sky": 27, + "cloudsCoded": "FW", + "weather": "Mostly Sunny", + "weatherCoded": [], + "weatherPrimary": "Mostly Sunny", + "weatherPrimaryCoded": "::FW", + "icon": "fair.png", + "visibilityKM": 24.135, + "visibilityMI": 15, + "uvi": null, + "solradWM2": 4740, + "solradMinWM2": 0, + "solradMaxWM2": 743, + "isDay": true, + "maxCoverage": "", + "sunrise": 1665546895, + "sunset": 1665588484, + "sunriseISO": "2022-10-12T05:54:55+02:00", + "sunsetISO": "2022-10-12T17:28:04+02:00" + } + ], + "profile": { + "tz": "Africa/Cairo", + "elevM": 23, + "elevFT": 75 + } + } + ] +} \ No newline at end of file diff --git a/src/test/resources/Issue593.xml b/src/test/resources/Issue593.xml new file mode 100644 index 0000000000000000000000000000000000000000..0c6c038b69c70dec24e92af73727ec57a4734f31 --- /dev/null +++ b/src/test/resources/Issue593.xml @@ -0,0 +1,691 @@ +true + + + 31.25 + 30.063 + + + 23 + Africa/Cairo + 75 + + + 2022-10-06T07:00:00+02:00 + E + 95 + 21 + 15 + 10 + 353 + N + 2022-10-06T05:51:14+02:00 + null + 9 + null + 66 + 0 + Mostly Sunny + 2022-10-06T17:35:02+02:00 + 32 + 77 + N + 89 + 0 + 22 + 25 + 25 + Mostly Sunny + 41 + 58 + 41 + 22 + 14 + 0 + 22 + 353 + 16 + 8 + 70 + 2022-10-06T07:00:00+02:00 + 10 + 778 + 25 + 15 + ::FW + 1665028274 + 78 + N + + fair.png + 21 + 17 + FW + 70 + 29 + 63 + 12 + 0 + 0 + NNW + 13 + 22 + 11 + 32 + 1015 + 24.135 + 1665032400 + 90 + null + 11 + 0 + 1 + 343 + 21 + 2 + 63 + 1 + 26 + 6 + NNW + 17 + 29.97 + 80 + null + true + 19 + 52 + 5 + 1665070502 + 5608 + 9 + 25 + 77 + 6 + 40 + 342 + null + + + 2022-10-07T07:00:00+02:00 + NNW + 347 + 19 + 15 + 8 + 325 + NW + 2022-10-07T05:51:50+02:00 + null + 7 + null + 66 + 0 + Mostly Sunny + 2022-10-07T17:33:51+02:00 + 29 + 77 + NNW + 85 + 0 + 30 + 23 + 23 + Mostly Sunny + 37 + 54 + 37 + 20 + 12 + 0 + 20 + 325 + 13 + 6 + 67 + 2022-10-07T07:00:00+02:00 + 6 + 742 + 24 + 10 + ::FW + 1665114710 + 76 + NW + + fair.png + 19 + 15 + FW + 67 + 30 + 60 + 6 + 0 + 0 + WNW + 6 + 10 + 347 + 30 + 1014 + 24.135 + 1665118800 + 86 + null + 10 + 0 + 1 + 316 + 16 + 2 + 60 + 1 + 24 + 6 + NW + 15 + 29.95 + 76 + null + true + 19 + 50 + 1 + 1665156831 + 5486 + 2 + 18 + 77 + 1 + 29 + 298 + null + + + 2022-10-08T07:00:00+02:00 + NW + 309 + 19 + 15 + 8 + 21 + NNE + 2022-10-08T05:52:26+02:00 + null + 7 + null + 66 + 0 + Partly Cloudy + 2022-10-08T17:32:41+02:00 + 30 + 76 + NW + 86 + 0 + 47 + 19 + 19 + Partly Cloudy + 31 + 56 + 31 + 17 + 13 + 0 + 17 + 21 + 13 + 5 + 67 + 2022-10-08T07:00:00+02:00 + 5 + 682 + 25 + 9 + ::SC + 1665201146 + 76 + NNE + + pcloudy.png + 19 + 15 + SC + 67 + 32 + 59 + 5 + 0 + 0 + WNW + 5 + 9 + 309 + 30 + 1014 + 24.135 + 1665205200 + 87 + null + 11 + 0 + 1 + 322 + 17 + 2 + 59 + 1 + 25 + 7 + NW + 15 + 29.94 + 76 + null + true + 19 + 52 + 1 + 1665243161 + 4785 + 2 + 20 + 76 + 1 + 32 + 301 + null + + + 2022-10-09T07:00:00+02:00 + NW + 316 + 20 + 15 + 9 + 356 + N + 2022-10-09T05:53:03+02:00 + null + 8 + null + 67 + 0 + Partly Cloudy + 2022-10-09T17:31:31+02:00 + 30 + 86 + NW + 86 + 0 + 47 + 23 + 23 + Partly Cloudy + 36 + 57 + 36 + 20 + 14 + 0 + 20 + 356 + 14 + 5 + 67 + 2022-10-09T07:00:00+02:00 + 6 + 726 + 25 + 9 + ::SC + 1665287583 + 77 + N + + pcloudy.png + 20 + 17 + SC + 67 + 31 + 63 + 5 + 0 + 0 + NNW + 6 + 9 + 316 + 31 + 1016 + 24.135 + 1665291600 + 87 + null + 11 + 0 + 2 + 354 + 19 + 4 + 63 + 2 + 25 + 7 + N + 17 + 29.99 + 77 + null + true + 19 + 52 + 2 + 1665329491 + 4768 + 4 + 22 + 86 + 2 + 36 + 343 + null + + + 2022-10-10T07:00:00+02:00 + E + 91 + 21 + 15 + 9 + 358 + N + 2022-10-10T05:53:40+02:00 + null + 8 + null + 70 + 0 + Partly Cloudy + 2022-10-10T17:30:21+02:00 + 30 + 75 + N + 86 + 0 + 64 + 22 + 22 + Partly Cloudy + 36 + 58 + 36 + 19 + 14 + 0 + 19 + 358 + 15 + 7 + 69 + 2022-10-10T07:00:00+02:00 + 8 + 597 + 26 + 13 + ::SC + 1665374020 + 78 + N + + pcloudy.png + 21 + 16 + SC + 69 + 35 + 61 + 7 + 0 + 0 + N + 8 + 13 + 8 + 31 + 1017 + 24.135 + 1665378000 + 87 + null + 13 + 0 + 2 + 10 + 16 + 4 + 61 + 2 + 25 + 6 + N + 16 + 30.03 + 78 + null + true + 21 + 55 + 2 + 1665415821 + 4494 + 4 + 19 + 75 + 2 + 30 + 10 + null + + + 2022-10-11T07:00:00+02:00 + NNE + 13 + 22 + 15 + 18 + 13 + NNE + 2022-10-11T05:54:18+02:00 + null + 15 + null + 70 + 0 + Sunny + 2022-10-11T17:29:13+02:00 + 31 + 71 + NNE + 87 + 0 + 0 + 19 + 19 + Sunny + 31 + 55 + 31 + 17 + 13 + 0 + 17 + 14 + 28 + 9 + 72 + 2022-10-11T07:00:00+02:00 + 11 + 758 + 26 + 18 + ::CL + 1665460458 + 78 + NNE + + sunny.png + 22 + 17 + CL + 72 + 30 + 62 + 10 + 0 + 0 + NNE + 12 + 19 + 16 + 31 + 1015 + 24.135 + 1665464400 + 87 + null + 11 + 0 + 7 + 28 + 15 + 14 + 62 + 8 + 26 + null + NNE + 17 + 29.98 + 79 + null + true + 21 + 51 + 8 + 1665502153 + 5450 + 15 + 17 + 71 + 9 + 28 + 28 + null + + + 2022-10-12T07:00:00+02:00 + NNE + 15 + 22 + 15 + 16 + 12 + NNE + 2022-10-12T05:54:55+02:00 + null + 14 + null + 69 + 0 + Mostly Sunny + 2022-10-12T17:28:04+02:00 + 31 + 68 + NNE + 88 + 0 + 27 + 21 + 21 + Mostly Sunny + 33 + 55 + 33 + 18 + 13 + 0 + 18 + 12 + 26 + 10 + 72 + 2022-10-12T07:00:00+02:00 + 11 + 743 + 26 + 18 + ::FW + 1665546895 + 79 + NNE + + fair.png + 22 + 16 + FW + 72 + 29 + 60 + 10 + 0 + 0 + E + 12 + 19 + 15 + 31 + 1014 + 24.135 + 1665550800 + 88 + null + 11 + 0 + 7 + 96 + 15 + 13 + 60 + 8 + 26 + null + E + 16 + 29.95 + 80 + null + true + 21 + 51 + 8 + 1665588484 + 4740 + 15 + 17 + 68 + 9 + 28 + 96 + null + + day + + eg + cairo + qh + + +null