diff --git a/.gitignore b/.gitignore
index 50b216e..7794c4c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,3 +4,13 @@
# ignore Intellij Idea project files
.idea
*.iml
+/target/
+
+/bin/
+build
+.settings/
+/.gradle/
+/gradle/
+/gradlew
+/gradlew.bat
+.gitmodules
diff --git a/LICENSE b/LICENSE
index 02ee0ef..c8cc5e6 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,4 +1,4 @@
-============================================================================
+===== License for the code in /src/main:
Copyright (c) 2002 JSON.org
@@ -21,3 +21,182 @@ 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.
+
+===== License for the code in /src/test:
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
\ No newline at end of file
diff --git a/README.md b/README.md
index 80930f8..2040e7d 100644
--- a/README.md
+++ b/README.md
@@ -148,3 +148,63 @@ as of 29 July, 2015.
JSON-java releases can be found by searching the Maven repository for groupId "org.json"
and artifactId "json". For example:
https://search.maven.org/search?q=g:org.json%20AND%20a:json&core=gav
+
+# Unit tests
+The test suite can be run by calling
+```
+mvn test
+```
+
+
+
+## Conventions
+Test filenames should consist of the name of the module being tested, with the suffix "Test".
+For example, Cookie.java is tested by CookieTest.java.
+
+The fundamental issues with JSON-Java testing are:
+* JSONObjects are unordered, making simple string comparison ineffective.
+* Comparisons via **equals()** is not currently supported. Neither JSONArray nor JSONObject override hashCode() or equals(), so comparison defaults to the Object equals(), which is not useful.
+* Access to the JSONArray and JSONObject internal containers for comparison is not currently available.
+
+General issues with unit testing are:
+* Just writing tests to make coverage goals tends to result in poor tests.
+* Unit tests are a form of documentation - how a given method actually works is demonstrated by the test. So for a code reviewer or future developer looking at code a good test helps explain how a function is supposed to work according to the original author. This can be difficult if you are not the original developer.
+* It is difficult to evaluate unit tests in a vacuum. You also need to see the code being tested to understand if a test is good.
+* Without unit tests it is hard to feel confident about the quality of the code, especially when fixing bugs or refactoring. Good tests prevents regressions and keeps the intent of the code correct.
+* If you have unit test results along with pull requests, the reviewer has an easier time understanding your code and determining if the it works as intended.
+
+When you start working on a test, add the empty file to the repository and update the readme, so that others will know that test is taken.
+
+**Caveats:**
+JSON-Java is Java 1.6-compatible, but JSON-Java-unit-tests requires Java 1.8. If you see this error when building JSON-Java-unit-test, make sure you have 1.8 installed, on your path, and set in JAVA_HOME:
+```
+Execution failed for task ':compileJava'.
+> invalid flag: -parameters
+```
+
+
+| Resource files used in test |
+| ------------- |
+| EnumTest.java |
+| MyBean.java |
+| MyBigNumberBean.java |
+| MyEnum.java |
+| MyEnumClass.java |
+| MyEnumField.java |
+| MyJsonString.java |
+| MyPublicClass.java |
+| PropertyTest.java |
+| JunitTestSuite.java |
+| StringsResourceBundle.java |
+| TestRunner.java |
+| Util.java |
+
+## How to release
+- Adapt the version number in the pom file
+- Run
+```
+mvn clean deploy
+```
+
+You will need permissions for the org.json library given by the sonatype maven central team.
+
diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000..1dde059
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,193 @@
+
+ 4.0.0
+
+ org.json
+ json
+ v20200429-SNAPSHOT
+ bundle
+
+ JSON in Java
+
+ JSON is a light-weight, language independent, data interchange format.
+ See http://www.JSON.org/
+
+ The files in this package implement JSON encoders/decoders in Java.
+ It also includes the capability to convert between JSON and XML, HTTP
+ headers, Cookies, and CDL.
+
+ 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
+
+
+ org.sonatype.oss
+ oss-parent
+ 9
+
+
+
+ https://github.com/douglascrockford/JSON-java.git
+ scm:git:git://github.com/douglascrockford/JSON-java.git
+ scm:git:git@github.com:douglascrockford/JSON-java.git
+
+
+
+
+ The JSON License
+ http://json.org/license.html
+ 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.
+
+
+
+
+
+
+ Douglas Crockford
+ douglas@crockford.com
+
+
+
+
+ UTF-8
+
+
+
+
+
+ junit
+ junit
+ 4.12
+ test
+
+
+ com.jayway.jsonpath
+ json-path
+ 2.1.0
+ test
+
+
+ org.mockito
+ mockito-core
+ 1.9.5
+ test
+
+
+
+
+
+
+ org.apache.felix
+ maven-bundle-plugin
+ 3.0.1
+ true
+
+
+
+ org.json
+
+ ${project.artifactId}
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+ 2.3.2
+
+ 1.7
+ 1.7
+
+
+
+ org.apache.maven.plugins
+ maven-source-plugin
+ 2.1.2
+
+
+ attach-sources
+
+ jar-no-fork
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-javadoc-plugin
+ 2.7
+
+
+ attach-javadocs
+
+ jar
+
+
+ -Xdoclint:none
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-gpg-plugin
+ 1.5
+
+
+ sign-artifacts
+ verify
+
+ sign
+
+
+
+
+
+ org.sonatype.plugins
+ nexus-staging-maven-plugin
+ 1.6.3
+ true
+
+ ossrh
+ https://oss.sonatype.org/
+ false
+
+
+
+ org.apache.maven.plugins
+ maven-jar-plugin
+ 3.2.0
+
+
+
+ org.json
+
+
+
+
+
+
+
diff --git a/CDL.java b/src/main/java/org/json/CDL.java
similarity index 100%
rename from CDL.java
rename to src/main/java/org/json/CDL.java
diff --git a/Cookie.java b/src/main/java/org/json/Cookie.java
similarity index 100%
rename from Cookie.java
rename to src/main/java/org/json/Cookie.java
diff --git a/CookieList.java b/src/main/java/org/json/CookieList.java
similarity index 100%
rename from CookieList.java
rename to src/main/java/org/json/CookieList.java
diff --git a/HTTP.java b/src/main/java/org/json/HTTP.java
similarity index 97%
rename from HTTP.java
rename to src/main/java/org/json/HTTP.java
index 70b88ee..84ed53b 100644
--- a/HTTP.java
+++ b/src/main/java/org/json/HTTP.java
@@ -1,162 +1,162 @@
-package org.json;
-
-/*
-Copyright (c) 2002 JSON.org
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-The Software shall be used for Good, not Evil.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
-*/
-
-import java.util.Locale;
-
-/**
- * Convert an HTTP header to a JSONObject and back.
- * @author JSON.org
- * @version 2015-12-09
- */
-public class HTTP {
-
- /** Carriage return/line feed. */
- public static final String CRLF = "\r\n";
-
- /**
- * Convert an HTTP header string into a JSONObject. It can be a request
- * header or a response header. A request header will contain
- *
- * It does no further checking or conversion. It does not parse dates.
- * It does not do '%' transforms on URLs.
- * @param string An HTTP header string.
- * @return A JSONObject containing the elements and attributes
- * of the XML string.
- * @throws JSONException
- */
- public static JSONObject toJSONObject(String string) throws JSONException {
- JSONObject jo = new JSONObject();
- HTTPTokener x = new HTTPTokener(string);
- String token;
-
- token = x.nextToken();
- if (token.toUpperCase(Locale.ROOT).startsWith("HTTP")) {
-
-// Response
-
- jo.put("HTTP-Version", token);
- jo.put("Status-Code", x.nextToken());
- jo.put("Reason-Phrase", x.nextTo('\0'));
- x.next();
-
- } else {
-
-// Request
-
- jo.put("Method", token);
- jo.put("Request-URI", x.nextToken());
- jo.put("HTTP-Version", x.nextToken());
- }
-
-// Fields
-
- while (x.more()) {
- String name = x.nextTo(':');
- x.next(':');
- jo.put(name, x.nextTo('\0'));
- x.next();
- }
- return jo;
- }
-
-
- /**
- * Convert a JSONObject into an HTTP header. A request header must contain
- *
- * Any other members of the JSONObject will be output as HTTP fields.
- * The result will end with two CRLF pairs.
- * @param jo A JSONObject
- * @return An HTTP header string.
- * @throws JSONException if the object does not contain enough
- * information.
- */
- public static String toString(JSONObject jo) throws JSONException {
- StringBuilder sb = new StringBuilder();
- if (jo.has("Status-Code") && jo.has("Reason-Phrase")) {
- sb.append(jo.getString("HTTP-Version"));
- sb.append(' ');
- sb.append(jo.getString("Status-Code"));
- sb.append(' ');
- sb.append(jo.getString("Reason-Phrase"));
- } else if (jo.has("Method") && jo.has("Request-URI")) {
- sb.append(jo.getString("Method"));
- sb.append(' ');
- sb.append('"');
- sb.append(jo.getString("Request-URI"));
- sb.append('"');
- sb.append(' ');
- sb.append(jo.getString("HTTP-Version"));
- } else {
- throw new JSONException("Not enough material for an HTTP header.");
- }
- sb.append(CRLF);
- // Don't use the new entrySet API to maintain Android support
- for (final String key : jo.keySet()) {
- String value = jo.optString(key);
- if (!"HTTP-Version".equals(key) && !"Status-Code".equals(key) &&
- !"Reason-Phrase".equals(key) && !"Method".equals(key) &&
- !"Request-URI".equals(key) && !JSONObject.NULL.equals(value)) {
- sb.append(key);
- sb.append(": ");
- sb.append(jo.optString(key));
- sb.append(CRLF);
- }
- }
- sb.append(CRLF);
- return sb.toString();
- }
-}
+package org.json;
+
+/*
+Copyright (c) 2002 JSON.org
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+The Software shall be used for Good, not Evil.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+*/
+
+import java.util.Locale;
+
+/**
+ * Convert an HTTP header to a JSONObject and back.
+ * @author JSON.org
+ * @version 2015-12-09
+ */
+public class HTTP {
+
+ /** Carriage return/line feed. */
+ public static final String CRLF = "\r\n";
+
+ /**
+ * Convert an HTTP header string into a JSONObject. It can be a request
+ * header or a response header. A request header will contain
+ *
+ * It does no further checking or conversion. It does not parse dates.
+ * It does not do '%' transforms on URLs.
+ * @param string An HTTP header string.
+ * @return A JSONObject containing the elements and attributes
+ * of the XML string.
+ * @throws JSONException
+ */
+ public static JSONObject toJSONObject(String string) throws JSONException {
+ JSONObject jo = new JSONObject();
+ HTTPTokener x = new HTTPTokener(string);
+ String token;
+
+ token = x.nextToken();
+ if (token.toUpperCase(Locale.ROOT).startsWith("HTTP")) {
+
+// Response
+
+ jo.put("HTTP-Version", token);
+ jo.put("Status-Code", x.nextToken());
+ jo.put("Reason-Phrase", x.nextTo('\0'));
+ x.next();
+
+ } else {
+
+// Request
+
+ jo.put("Method", token);
+ jo.put("Request-URI", x.nextToken());
+ jo.put("HTTP-Version", x.nextToken());
+ }
+
+// Fields
+
+ while (x.more()) {
+ String name = x.nextTo(':');
+ x.next(':');
+ jo.put(name, x.nextTo('\0'));
+ x.next();
+ }
+ return jo;
+ }
+
+
+ /**
+ * Convert a JSONObject into an HTTP header. A request header must contain
+ *
+ * Any other members of the JSONObject will be output as HTTP fields.
+ * The result will end with two CRLF pairs.
+ * @param jo A JSONObject
+ * @return An HTTP header string.
+ * @throws JSONException if the object does not contain enough
+ * information.
+ */
+ public static String toString(JSONObject jo) throws JSONException {
+ StringBuilder sb = new StringBuilder();
+ if (jo.has("Status-Code") && jo.has("Reason-Phrase")) {
+ sb.append(jo.getString("HTTP-Version"));
+ sb.append(' ');
+ sb.append(jo.getString("Status-Code"));
+ sb.append(' ');
+ sb.append(jo.getString("Reason-Phrase"));
+ } else if (jo.has("Method") && jo.has("Request-URI")) {
+ sb.append(jo.getString("Method"));
+ sb.append(' ');
+ sb.append('"');
+ sb.append(jo.getString("Request-URI"));
+ sb.append('"');
+ sb.append(' ');
+ sb.append(jo.getString("HTTP-Version"));
+ } else {
+ throw new JSONException("Not enough material for an HTTP header.");
+ }
+ sb.append(CRLF);
+ // Don't use the new entrySet API to maintain Android support
+ for (final String key : jo.keySet()) {
+ String value = jo.optString(key);
+ if (!"HTTP-Version".equals(key) && !"Status-Code".equals(key) &&
+ !"Reason-Phrase".equals(key) && !"Method".equals(key) &&
+ !"Request-URI".equals(key) && !JSONObject.NULL.equals(value)) {
+ sb.append(key);
+ sb.append(": ");
+ sb.append(jo.optString(key));
+ sb.append(CRLF);
+ }
+ }
+ sb.append(CRLF);
+ return sb.toString();
+ }
+}
diff --git a/HTTPTokener.java b/src/main/java/org/json/HTTPTokener.java
similarity index 100%
rename from HTTPTokener.java
rename to src/main/java/org/json/HTTPTokener.java
diff --git a/JSONArray.java b/src/main/java/org/json/JSONArray.java
similarity index 100%
rename from JSONArray.java
rename to src/main/java/org/json/JSONArray.java
diff --git a/JSONException.java b/src/main/java/org/json/JSONException.java
similarity index 100%
rename from JSONException.java
rename to src/main/java/org/json/JSONException.java
diff --git a/JSONML.java b/src/main/java/org/json/JSONML.java
similarity index 100%
rename from JSONML.java
rename to src/main/java/org/json/JSONML.java
diff --git a/JSONObject.java b/src/main/java/org/json/JSONObject.java
similarity index 100%
rename from JSONObject.java
rename to src/main/java/org/json/JSONObject.java
diff --git a/JSONPointer.java b/src/main/java/org/json/JSONPointer.java
similarity index 100%
rename from JSONPointer.java
rename to src/main/java/org/json/JSONPointer.java
diff --git a/JSONPointerException.java b/src/main/java/org/json/JSONPointerException.java
similarity index 100%
rename from JSONPointerException.java
rename to src/main/java/org/json/JSONPointerException.java
diff --git a/JSONPropertyIgnore.java b/src/main/java/org/json/JSONPropertyIgnore.java
similarity index 100%
rename from JSONPropertyIgnore.java
rename to src/main/java/org/json/JSONPropertyIgnore.java
diff --git a/JSONPropertyName.java b/src/main/java/org/json/JSONPropertyName.java
similarity index 100%
rename from JSONPropertyName.java
rename to src/main/java/org/json/JSONPropertyName.java
diff --git a/JSONString.java b/src/main/java/org/json/JSONString.java
similarity index 100%
rename from JSONString.java
rename to src/main/java/org/json/JSONString.java
diff --git a/JSONStringer.java b/src/main/java/org/json/JSONStringer.java
similarity index 97%
rename from JSONStringer.java
rename to src/main/java/org/json/JSONStringer.java
index 6e05d22..bb9e7a4 100644
--- a/JSONStringer.java
+++ b/src/main/java/org/json/JSONStringer.java
@@ -1,79 +1,79 @@
-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.
-*/
-
-import java.io.StringWriter;
-
-/**
- * JSONStringer provides a quick and convenient way of producing JSON text.
- * The texts produced strictly conform to JSON syntax rules. No whitespace is
- * added, so the results are ready for transmission or storage. Each instance of
- * JSONStringer can produce one JSON text.
- *
- * A JSONStringer instance provides a value method for appending
- * values to the
- * text, and a key
- * method for adding keys before values in objects. There are array
- * and endArray methods that make and bound array values, and
- * object and endObject methods which make and bound
- * object values. All of these methods return the JSONWriter instance,
- * permitting cascade style. For example,
- * The first method called must be array or object.
- * There are no methods for adding commas or colons. JSONStringer adds them for
- * you. Objects and arrays can be nested up to 20 levels deep.
- *
- * This can sometimes be easier than using a JSONObject to build a string.
- * @author JSON.org
- * @version 2015-12-09
- */
-public class JSONStringer extends JSONWriter {
- /**
- * Make a fresh JSONStringer. It can be used to build one JSON text.
- */
- public JSONStringer() {
- super(new StringWriter());
- }
-
- /**
- * Return the JSON text. This method is used to obtain the product of the
- * JSONStringer instance. It will return null if there was a
- * problem in the construction of the JSON text (such as the calls to
- * array were not properly balanced with calls to
- * endArray).
- * @return The JSON text.
- */
- @Override
- public String toString() {
- return this.mode == 'd' ? this.writer.toString() : null;
- }
-}
+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.
+*/
+
+import java.io.StringWriter;
+
+/**
+ * JSONStringer provides a quick and convenient way of producing JSON text.
+ * The texts produced strictly conform to JSON syntax rules. No whitespace is
+ * added, so the results are ready for transmission or storage. Each instance of
+ * JSONStringer can produce one JSON text.
+ *
+ * A JSONStringer instance provides a value method for appending
+ * values to the
+ * text, and a key
+ * method for adding keys before values in objects. There are array
+ * and endArray methods that make and bound array values, and
+ * object and endObject methods which make and bound
+ * object values. All of these methods return the JSONWriter instance,
+ * permitting cascade style. For example,
+ * The first method called must be array or object.
+ * There are no methods for adding commas or colons. JSONStringer adds them for
+ * you. Objects and arrays can be nested up to 20 levels deep.
+ *
+ * This can sometimes be easier than using a JSONObject to build a string.
+ * @author JSON.org
+ * @version 2015-12-09
+ */
+public class JSONStringer extends JSONWriter {
+ /**
+ * Make a fresh JSONStringer. It can be used to build one JSON text.
+ */
+ public JSONStringer() {
+ super(new StringWriter());
+ }
+
+ /**
+ * Return the JSON text. This method is used to obtain the product of the
+ * JSONStringer instance. It will return null if there was a
+ * problem in the construction of the JSON text (such as the calls to
+ * array were not properly balanced with calls to
+ * endArray).
+ * @return The JSON text.
+ */
+ @Override
+ public String toString() {
+ return this.mode == 'd' ? this.writer.toString() : null;
+ }
+}
diff --git a/JSONTokener.java b/src/main/java/org/json/JSONTokener.java
similarity index 100%
rename from JSONTokener.java
rename to src/main/java/org/json/JSONTokener.java
diff --git a/JSONWriter.java b/src/main/java/org/json/JSONWriter.java
similarity index 97%
rename from JSONWriter.java
rename to src/main/java/org/json/JSONWriter.java
index 19f2dc8..b61a6f1 100644
--- a/JSONWriter.java
+++ b/src/main/java/org/json/JSONWriter.java
@@ -1,413 +1,413 @@
-package org.json;
-
-import java.io.IOException;
-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.
-*/
-
-/**
- * JSONWriter provides a quick and convenient way of producing JSON text.
- * The texts produced strictly conform to JSON syntax rules. No whitespace is
- * added, so the results are ready for transmission or storage. Each instance of
- * JSONWriter can produce one JSON text.
- *
- * A JSONWriter instance provides a value method for appending
- * values to the
- * text, and a key
- * method for adding keys before values in objects. There are array
- * and endArray methods that make and bound array values, and
- * object and endObject methods which make and bound
- * object values. All of these methods return the JSONWriter instance,
- * permitting a cascade style. For example,
- * The first method called must be array or object.
- * There are no methods for adding commas or colons. JSONWriter adds them for
- * you. Objects and arrays can be nested up to 200 levels deep.
- *
- * This can sometimes be easier than using a JSONObject to build a string.
- * @author JSON.org
- * @version 2016-08-08
- */
-public class JSONWriter {
- private static final int maxdepth = 200;
-
- /**
- * The comma flag determines if a comma should be output before the next
- * value.
- */
- private boolean comma;
-
- /**
- * The current mode. Values:
- * 'a' (array),
- * 'd' (done),
- * 'i' (initial),
- * 'k' (key),
- * 'o' (object).
- */
- protected char mode;
-
- /**
- * The object/array stack.
- */
- private final JSONObject stack[];
-
- /**
- * The stack top index. A value of 0 indicates that the stack is empty.
- */
- private int top;
-
- /**
- * The writer that will receive the output.
- */
- protected Appendable writer;
-
- /**
- * Make a fresh JSONWriter. It can be used to build one JSON text.
- */
- public JSONWriter(Appendable w) {
- this.comma = false;
- this.mode = 'i';
- this.stack = new JSONObject[maxdepth];
- this.top = 0;
- this.writer = w;
- }
-
- /**
- * Append a value.
- * @param string A string value.
- * @return this
- * @throws JSONException If the value is out of sequence.
- */
- private JSONWriter append(String string) throws JSONException {
- if (string == null) {
- throw new JSONException("Null pointer");
- }
- if (this.mode == 'o' || this.mode == 'a') {
- try {
- if (this.comma && this.mode == 'a') {
- this.writer.append(',');
- }
- this.writer.append(string);
- } catch (IOException e) {
- // Android as of API 25 does not support this exception constructor
- // however we won't worry about it. If an exception is happening here
- // it will just throw a "Method not found" exception instead.
- throw new JSONException(e);
- }
- if (this.mode == 'o') {
- this.mode = 'k';
- }
- this.comma = true;
- return this;
- }
- throw new JSONException("Value out of sequence.");
- }
-
- /**
- * Begin appending a new array. All values until the balancing
- * endArray will be appended to this array. The
- * endArray method must be called to mark the array's end.
- * @return this
- * @throws JSONException If the nesting is too deep, or if the object is
- * started in the wrong place (for example as a key or after the end of the
- * outermost array or object).
- */
- public JSONWriter array() throws JSONException {
- if (this.mode == 'i' || this.mode == 'o' || this.mode == 'a') {
- this.push(null);
- this.append("[");
- this.comma = false;
- return this;
- }
- throw new JSONException("Misplaced array.");
- }
-
- /**
- * End something.
- * @param m Mode
- * @param c Closing character
- * @return this
- * @throws JSONException If unbalanced.
- */
- private JSONWriter end(char m, char c) throws JSONException {
- if (this.mode != m) {
- throw new JSONException(m == 'a'
- ? "Misplaced endArray."
- : "Misplaced endObject.");
- }
- this.pop(m);
- try {
- this.writer.append(c);
- } catch (IOException e) {
- // Android as of API 25 does not support this exception constructor
- // however we won't worry about it. If an exception is happening here
- // it will just throw a "Method not found" exception instead.
- throw new JSONException(e);
- }
- this.comma = true;
- return this;
- }
-
- /**
- * End an array. This method most be called to balance calls to
- * array.
- * @return this
- * @throws JSONException If incorrectly nested.
- */
- public JSONWriter endArray() throws JSONException {
- return this.end('a', ']');
- }
-
- /**
- * End an object. This method most be called to balance calls to
- * object.
- * @return this
- * @throws JSONException If incorrectly nested.
- */
- public JSONWriter endObject() throws JSONException {
- return this.end('k', '}');
- }
-
- /**
- * Append a key. The key will be associated with the next value. In an
- * object, every value must be preceded by a key.
- * @param string A key string.
- * @return this
- * @throws JSONException If the key is out of place. For example, keys
- * do not belong in arrays or if the key is null.
- */
- public JSONWriter key(String string) throws JSONException {
- if (string == null) {
- throw new JSONException("Null key.");
- }
- if (this.mode == 'k') {
- try {
- JSONObject topObject = this.stack[this.top - 1];
- // don't use the built in putOnce method to maintain Android support
- if(topObject.has(string)) {
- throw new JSONException("Duplicate key \"" + string + "\"");
- }
- topObject.put(string, true);
- if (this.comma) {
- this.writer.append(',');
- }
- this.writer.append(JSONObject.quote(string));
- this.writer.append(':');
- this.comma = false;
- this.mode = 'o';
- return this;
- } catch (IOException e) {
- // Android as of API 25 does not support this exception constructor
- // however we won't worry about it. If an exception is happening here
- // it will just throw a "Method not found" exception instead.
- throw new JSONException(e);
- }
- }
- throw new JSONException("Misplaced key.");
- }
-
-
- /**
- * Begin appending a new object. All keys and values until the balancing
- * endObject will be appended to this object. The
- * endObject method must be called to mark the object's end.
- * @return this
- * @throws JSONException If the nesting is too deep, or if the object is
- * started in the wrong place (for example as a key or after the end of the
- * outermost array or object).
- */
- public JSONWriter object() throws JSONException {
- if (this.mode == 'i') {
- this.mode = 'o';
- }
- if (this.mode == 'o' || this.mode == 'a') {
- this.append("{");
- this.push(new JSONObject());
- this.comma = false;
- return this;
- }
- throw new JSONException("Misplaced object.");
-
- }
-
-
- /**
- * Pop an array or object scope.
- * @param c The scope to close.
- * @throws JSONException If nesting is wrong.
- */
- private void pop(char c) throws JSONException {
- if (this.top <= 0) {
- throw new JSONException("Nesting error.");
- }
- char m = this.stack[this.top - 1] == null ? 'a' : 'k';
- if (m != c) {
- throw new JSONException("Nesting error.");
- }
- this.top -= 1;
- this.mode = this.top == 0
- ? 'd'
- : this.stack[this.top - 1] == null
- ? 'a'
- : 'k';
- }
-
- /**
- * Push an array or object scope.
- * @param jo The scope to open.
- * @throws JSONException If nesting is too deep.
- */
- private void push(JSONObject jo) throws JSONException {
- if (this.top >= maxdepth) {
- throw new JSONException("Nesting too deep.");
- }
- this.stack[this.top] = jo;
- this.mode = jo == null ? 'a' : 'k';
- this.top += 1;
- }
-
- /**
- * Make a JSON text of an Object value. If the object has an
- * value.toJSONString() method, then that method will be used to produce the
- * JSON text. The method is required to produce a strictly conforming text.
- * If the object does not contain a toJSONString method (which is the most
- * common case), then a text will be produced by other means. If the value
- * is an array or Collection, then a JSONArray will be made from it and its
- * toJSONString method will be called. If the value is a MAP, then a
- * JSONObject will be made from it and its toJSONString method will be
- * called. Otherwise, the value's toString method will be called, and the
- * result will be quoted.
- *
- *
- * Warning: This method assumes that the data structure is acyclical.
- *
- * @param value
- * The value to be serialized.
- * @return a printable, displayable, transmittable representation of the
- * object, beginning with { (left
- * brace) and ending with } (right
- * brace).
- * @throws JSONException
- * If the value is or contains an invalid number.
- */
- public static String valueToString(Object value) throws JSONException {
- if (value == null || value.equals(null)) {
- return "null";
- }
- if (value instanceof JSONString) {
- String object;
- try {
- object = ((JSONString) value).toJSONString();
- } catch (Exception e) {
- throw new JSONException(e);
- }
- if (object != null) {
- return object;
- }
- throw new JSONException("Bad value from toJSONString: " + object);
- }
- if (value instanceof Number) {
- // not all Numbers may match actual JSON Numbers. i.e. Fractions or Complex
- final String numberAsString = JSONObject.numberToString((Number) value);
- if(JSONObject.NUMBER_PATTERN.matcher(numberAsString).matches()) {
- // Close enough to a JSON number that we will return it unquoted
- return numberAsString;
- }
- // The Number value is not a valid JSON number.
- // Instead we will quote it as a string
- return JSONObject.quote(numberAsString);
- }
- if (value instanceof Boolean || value instanceof JSONObject
- || value instanceof JSONArray) {
- return value.toString();
- }
- if (value instanceof Map) {
- Map, ?> map = (Map, ?>) value;
- return new JSONObject(map).toString();
- }
- if (value instanceof Collection) {
- Collection> coll = (Collection>) value;
- return new JSONArray(coll).toString();
- }
- if (value.getClass().isArray()) {
- return new JSONArray(value).toString();
- }
- if(value instanceof Enum>){
- return JSONObject.quote(((Enum>)value).name());
- }
- return JSONObject.quote(value.toString());
- }
-
- /**
- * Append either the value true or the value
- * false.
- * @param b A boolean.
- * @return this
- * @throws JSONException
- */
- public JSONWriter value(boolean b) throws JSONException {
- return this.append(b ? "true" : "false");
- }
-
- /**
- * Append a double value.
- * @param d A double.
- * @return this
- * @throws JSONException If the number is not finite.
- */
- public JSONWriter value(double d) throws JSONException {
- return this.value(Double.valueOf(d));
- }
-
- /**
- * Append a long value.
- * @param l A long.
- * @return this
- * @throws JSONException
- */
- public JSONWriter value(long l) throws JSONException {
- return this.append(Long.toString(l));
- }
-
-
- /**
- * Append an object value.
- * @param object The object to append. It can be null, or a Boolean, Number,
- * String, JSONObject, or JSONArray, or an object that implements JSONString.
- * @return this
- * @throws JSONException If the value is out of sequence.
- */
- public JSONWriter value(Object object) throws JSONException {
- return this.append(valueToString(object));
- }
-}
+package org.json;
+
+import java.io.IOException;
+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.
+*/
+
+/**
+ * JSONWriter provides a quick and convenient way of producing JSON text.
+ * The texts produced strictly conform to JSON syntax rules. No whitespace is
+ * added, so the results are ready for transmission or storage. Each instance of
+ * JSONWriter can produce one JSON text.
+ *
+ * A JSONWriter instance provides a value method for appending
+ * values to the
+ * text, and a key
+ * method for adding keys before values in objects. There are array
+ * and endArray methods that make and bound array values, and
+ * object and endObject methods which make and bound
+ * object values. All of these methods return the JSONWriter instance,
+ * permitting a cascade style. For example,
+ * The first method called must be array or object.
+ * There are no methods for adding commas or colons. JSONWriter adds them for
+ * you. Objects and arrays can be nested up to 200 levels deep.
+ *
+ * This can sometimes be easier than using a JSONObject to build a string.
+ * @author JSON.org
+ * @version 2016-08-08
+ */
+public class JSONWriter {
+ private static final int maxdepth = 200;
+
+ /**
+ * The comma flag determines if a comma should be output before the next
+ * value.
+ */
+ private boolean comma;
+
+ /**
+ * The current mode. Values:
+ * 'a' (array),
+ * 'd' (done),
+ * 'i' (initial),
+ * 'k' (key),
+ * 'o' (object).
+ */
+ protected char mode;
+
+ /**
+ * The object/array stack.
+ */
+ private final JSONObject stack[];
+
+ /**
+ * The stack top index. A value of 0 indicates that the stack is empty.
+ */
+ private int top;
+
+ /**
+ * The writer that will receive the output.
+ */
+ protected Appendable writer;
+
+ /**
+ * Make a fresh JSONWriter. It can be used to build one JSON text.
+ */
+ public JSONWriter(Appendable w) {
+ this.comma = false;
+ this.mode = 'i';
+ this.stack = new JSONObject[maxdepth];
+ this.top = 0;
+ this.writer = w;
+ }
+
+ /**
+ * Append a value.
+ * @param string A string value.
+ * @return this
+ * @throws JSONException If the value is out of sequence.
+ */
+ private JSONWriter append(String string) throws JSONException {
+ if (string == null) {
+ throw new JSONException("Null pointer");
+ }
+ if (this.mode == 'o' || this.mode == 'a') {
+ try {
+ if (this.comma && this.mode == 'a') {
+ this.writer.append(',');
+ }
+ this.writer.append(string);
+ } catch (IOException e) {
+ // Android as of API 25 does not support this exception constructor
+ // however we won't worry about it. If an exception is happening here
+ // it will just throw a "Method not found" exception instead.
+ throw new JSONException(e);
+ }
+ if (this.mode == 'o') {
+ this.mode = 'k';
+ }
+ this.comma = true;
+ return this;
+ }
+ throw new JSONException("Value out of sequence.");
+ }
+
+ /**
+ * Begin appending a new array. All values until the balancing
+ * endArray will be appended to this array. The
+ * endArray method must be called to mark the array's end.
+ * @return this
+ * @throws JSONException If the nesting is too deep, or if the object is
+ * started in the wrong place (for example as a key or after the end of the
+ * outermost array or object).
+ */
+ public JSONWriter array() throws JSONException {
+ if (this.mode == 'i' || this.mode == 'o' || this.mode == 'a') {
+ this.push(null);
+ this.append("[");
+ this.comma = false;
+ return this;
+ }
+ throw new JSONException("Misplaced array.");
+ }
+
+ /**
+ * End something.
+ * @param m Mode
+ * @param c Closing character
+ * @return this
+ * @throws JSONException If unbalanced.
+ */
+ private JSONWriter end(char m, char c) throws JSONException {
+ if (this.mode != m) {
+ throw new JSONException(m == 'a'
+ ? "Misplaced endArray."
+ : "Misplaced endObject.");
+ }
+ this.pop(m);
+ try {
+ this.writer.append(c);
+ } catch (IOException e) {
+ // Android as of API 25 does not support this exception constructor
+ // however we won't worry about it. If an exception is happening here
+ // it will just throw a "Method not found" exception instead.
+ throw new JSONException(e);
+ }
+ this.comma = true;
+ return this;
+ }
+
+ /**
+ * End an array. This method most be called to balance calls to
+ * array.
+ * @return this
+ * @throws JSONException If incorrectly nested.
+ */
+ public JSONWriter endArray() throws JSONException {
+ return this.end('a', ']');
+ }
+
+ /**
+ * End an object. This method most be called to balance calls to
+ * object.
+ * @return this
+ * @throws JSONException If incorrectly nested.
+ */
+ public JSONWriter endObject() throws JSONException {
+ return this.end('k', '}');
+ }
+
+ /**
+ * Append a key. The key will be associated with the next value. In an
+ * object, every value must be preceded by a key.
+ * @param string A key string.
+ * @return this
+ * @throws JSONException If the key is out of place. For example, keys
+ * do not belong in arrays or if the key is null.
+ */
+ public JSONWriter key(String string) throws JSONException {
+ if (string == null) {
+ throw new JSONException("Null key.");
+ }
+ if (this.mode == 'k') {
+ try {
+ JSONObject topObject = this.stack[this.top - 1];
+ // don't use the built in putOnce method to maintain Android support
+ if(topObject.has(string)) {
+ throw new JSONException("Duplicate key \"" + string + "\"");
+ }
+ topObject.put(string, true);
+ if (this.comma) {
+ this.writer.append(',');
+ }
+ this.writer.append(JSONObject.quote(string));
+ this.writer.append(':');
+ this.comma = false;
+ this.mode = 'o';
+ return this;
+ } catch (IOException e) {
+ // Android as of API 25 does not support this exception constructor
+ // however we won't worry about it. If an exception is happening here
+ // it will just throw a "Method not found" exception instead.
+ throw new JSONException(e);
+ }
+ }
+ throw new JSONException("Misplaced key.");
+ }
+
+
+ /**
+ * Begin appending a new object. All keys and values until the balancing
+ * endObject will be appended to this object. The
+ * endObject method must be called to mark the object's end.
+ * @return this
+ * @throws JSONException If the nesting is too deep, or if the object is
+ * started in the wrong place (for example as a key or after the end of the
+ * outermost array or object).
+ */
+ public JSONWriter object() throws JSONException {
+ if (this.mode == 'i') {
+ this.mode = 'o';
+ }
+ if (this.mode == 'o' || this.mode == 'a') {
+ this.append("{");
+ this.push(new JSONObject());
+ this.comma = false;
+ return this;
+ }
+ throw new JSONException("Misplaced object.");
+
+ }
+
+
+ /**
+ * Pop an array or object scope.
+ * @param c The scope to close.
+ * @throws JSONException If nesting is wrong.
+ */
+ private void pop(char c) throws JSONException {
+ if (this.top <= 0) {
+ throw new JSONException("Nesting error.");
+ }
+ char m = this.stack[this.top - 1] == null ? 'a' : 'k';
+ if (m != c) {
+ throw new JSONException("Nesting error.");
+ }
+ this.top -= 1;
+ this.mode = this.top == 0
+ ? 'd'
+ : this.stack[this.top - 1] == null
+ ? 'a'
+ : 'k';
+ }
+
+ /**
+ * Push an array or object scope.
+ * @param jo The scope to open.
+ * @throws JSONException If nesting is too deep.
+ */
+ private void push(JSONObject jo) throws JSONException {
+ if (this.top >= maxdepth) {
+ throw new JSONException("Nesting too deep.");
+ }
+ this.stack[this.top] = jo;
+ this.mode = jo == null ? 'a' : 'k';
+ this.top += 1;
+ }
+
+ /**
+ * Make a JSON text of an Object value. If the object has an
+ * value.toJSONString() method, then that method will be used to produce the
+ * JSON text. The method is required to produce a strictly conforming text.
+ * If the object does not contain a toJSONString method (which is the most
+ * common case), then a text will be produced by other means. If the value
+ * is an array or Collection, then a JSONArray will be made from it and its
+ * toJSONString method will be called. If the value is a MAP, then a
+ * JSONObject will be made from it and its toJSONString method will be
+ * called. Otherwise, the value's toString method will be called, and the
+ * result will be quoted.
+ *
+ *
+ * Warning: This method assumes that the data structure is acyclical.
+ *
+ * @param value
+ * The value to be serialized.
+ * @return a printable, displayable, transmittable representation of the
+ * object, beginning with { (left
+ * brace) and ending with } (right
+ * brace).
+ * @throws JSONException
+ * If the value is or contains an invalid number.
+ */
+ public static String valueToString(Object value) throws JSONException {
+ if (value == null || value.equals(null)) {
+ return "null";
+ }
+ if (value instanceof JSONString) {
+ String object;
+ try {
+ object = ((JSONString) value).toJSONString();
+ } catch (Exception e) {
+ throw new JSONException(e);
+ }
+ if (object != null) {
+ return object;
+ }
+ throw new JSONException("Bad value from toJSONString: " + object);
+ }
+ if (value instanceof Number) {
+ // not all Numbers may match actual JSON Numbers. i.e. Fractions or Complex
+ final String numberAsString = JSONObject.numberToString((Number) value);
+ if(JSONObject.NUMBER_PATTERN.matcher(numberAsString).matches()) {
+ // Close enough to a JSON number that we will return it unquoted
+ return numberAsString;
+ }
+ // The Number value is not a valid JSON number.
+ // Instead we will quote it as a string
+ return JSONObject.quote(numberAsString);
+ }
+ if (value instanceof Boolean || value instanceof JSONObject
+ || value instanceof JSONArray) {
+ return value.toString();
+ }
+ if (value instanceof Map) {
+ Map, ?> map = (Map, ?>) value;
+ return new JSONObject(map).toString();
+ }
+ if (value instanceof Collection) {
+ Collection> coll = (Collection>) value;
+ return new JSONArray(coll).toString();
+ }
+ if (value.getClass().isArray()) {
+ return new JSONArray(value).toString();
+ }
+ if(value instanceof Enum>){
+ return JSONObject.quote(((Enum>)value).name());
+ }
+ return JSONObject.quote(value.toString());
+ }
+
+ /**
+ * Append either the value true or the value
+ * false.
+ * @param b A boolean.
+ * @return this
+ * @throws JSONException
+ */
+ public JSONWriter value(boolean b) throws JSONException {
+ return this.append(b ? "true" : "false");
+ }
+
+ /**
+ * Append a double value.
+ * @param d A double.
+ * @return this
+ * @throws JSONException If the number is not finite.
+ */
+ public JSONWriter value(double d) throws JSONException {
+ return this.value(Double.valueOf(d));
+ }
+
+ /**
+ * Append a long value.
+ * @param l A long.
+ * @return this
+ * @throws JSONException
+ */
+ public JSONWriter value(long l) throws JSONException {
+ return this.append(Long.toString(l));
+ }
+
+
+ /**
+ * Append an object value.
+ * @param object The object to append. It can be null, or a Boolean, Number,
+ * String, JSONObject, or JSONArray, or an object that implements JSONString.
+ * @return this
+ * @throws JSONException If the value is out of sequence.
+ */
+ public JSONWriter value(Object object) throws JSONException {
+ return this.append(valueToString(object));
+ }
+}
diff --git a/Property.java b/src/main/java/org/json/Property.java
similarity index 100%
rename from Property.java
rename to src/main/java/org/json/Property.java
diff --git a/XML.java b/src/main/java/org/json/XML.java
similarity index 100%
rename from XML.java
rename to src/main/java/org/json/XML.java
diff --git a/XMLParserConfiguration.java b/src/main/java/org/json/XMLParserConfiguration.java
similarity index 100%
rename from XMLParserConfiguration.java
rename to src/main/java/org/json/XMLParserConfiguration.java
diff --git a/XMLTokener.java b/src/main/java/org/json/XMLTokener.java
similarity index 100%
rename from XMLTokener.java
rename to src/main/java/org/json/XMLTokener.java
diff --git a/src/test/java/org/json/junit/CDLTest.java b/src/test/java/org/json/junit/CDLTest.java
new file mode 100644
index 0000000..721fd3c
--- /dev/null
+++ b/src/test/java/org/json/junit/CDLTest.java
@@ -0,0 +1,300 @@
+package org.json.junit;
+
+import static org.junit.Assert.*;
+import org.junit.Test;
+
+import org.json.JSONException;
+import org.json.JSONObject;
+import org.json.JSONArray;
+import org.json.CDL;
+
+/**
+ * Tests for CDL.java.
+ * CDL provides an application level API, but it is not used by the
+ * reference app. To test it, strings will be converted to JSON-Java classes
+ * and then converted back.
+ */
+public class CDLTest {
+
+ /**
+ * String of lines where the column names are in the first row,
+ * and all subsequent rows are values. All keys and values should be legal.
+ */
+ String lines = new String(
+ "Col 1, Col 2, \tCol 3, Col 4, Col 5, Col 6, Col 7\n" +
+ "val1, val2, val3, val4, val5, val6, val7\n" +
+ "1, 2, 3, 4\t, 5, 6, 7\n" +
+ "true, false, true, true, false, false, false\n" +
+ "0.23, 57.42, 5e27, -234.879, 2.34e5, 0.0, 9e-3\n" +
+ "\"va\tl1\", \"v\bal2\", \"val3\", \"val\f4\", \"val5\", va\'l6, val7\n"
+ );
+
+ /**
+ * CDL.toJSONArray() adds all values as strings, with no filtering or
+ * conversions. For testing, this means that the expected JSONObject
+ * values all must be quoted in the cases where the JSONObject parsing
+ * might normally convert the value into a non-string.
+ */
+ String expectedLines = new String(
+ "[{Col 1:val1, Col 2:val2, Col 3:val3, Col 4:val4, Col 5:val5, Col 6:val6, Col 7:val7}, "+
+ "{Col 1:\"1\", Col 2:\"2\", Col 3:\"3\", Col 4:\"4\", Col 5:\"5\", Col 6:\"6\", Col 7:\"7\"}, "+
+ "{Col 1:\"true\", Col 2:\"false\", Col 3:\"true\", Col 4:\"true\", Col 5:\"false\", Col 6:\"false\", Col 7:\"false\"}, "+
+ "{Col 1:\"0.23\", Col 2:\"57.42\", Col 3:\"5e27\", Col 4:\"-234.879\", Col 5:\"2.34e5\", Col 6:\"0.0\", Col 7:\"9e-3\"}, "+
+ "{Col 1:\"va\tl1\", Col 2:\"v\bal2\", Col 3:val3, Col 4:\"val\f4\", Col 5:val5, Col 6:va\'l6, Col 7:val7}]");
+
+ /**
+ * Attempts to create a JSONArray from a null string.
+ * Expect a NullPointerException.
+ */
+ @Test(expected=NullPointerException.class)
+ public void exceptionOnNullString() {
+ String nullStr = null;
+ CDL.toJSONArray(nullStr);
+ }
+
+ /**
+ * Attempts to create a JSONArray from a string with unbalanced quotes
+ * in column title line. Expects a JSONException.
+ */
+ @Test
+ public void unbalancedQuoteInName() {
+ String badLine = "Col1, \"Col2\nVal1, Val2";
+ try {
+ CDL.toJSONArray(badLine);
+ fail("Expecting an exception");
+ } catch (JSONException e) {
+ assertEquals("Expecting an exception message",
+ "Missing close quote '\"'. at 12 [character 0 line 2]",
+ e.getMessage());
+ }
+ }
+
+ /**
+ * Attempts to create a JSONArray from a string with unbalanced quotes
+ * in value line. Expects a JSONException.
+ */
+ @Test
+ public void unbalancedQuoteInValue() {
+ String badLine = "Col1, Col2\n\"Val1, Val2";
+ try {
+ CDL.toJSONArray(badLine);
+ fail("Expecting an exception");
+ } catch (JSONException e) {
+ assertEquals("Expecting an exception message",
+ "Missing close quote '\"'. at 22 [character 11 line 2]",
+ e.getMessage());
+
+ }
+ }
+
+ /**
+ * Attempts to create a JSONArray from a string with null char
+ * in column title line. Expects a JSONException.
+ */
+ @Test
+ public void nullInName() {
+ String badLine = "C\0ol1, Col2\nVal1, Val2";
+ try {
+ CDL.toJSONArray(badLine);
+ fail("Expecting an exception");
+ } catch (JSONException e) {
+ assertEquals("Expecting an exception message",
+ "Bad character 'o' (111). at 2 [character 3 line 1]",
+ e.getMessage());
+
+ }
+ }
+
+ /**
+ * Attempt to create a JSONArray with unbalanced quotes and a properly escaped doubled quote.
+ * Expects a JSONException.
+ */
+ @Test
+ public void unbalancedEscapedQuote(){
+ String badLine = "Col1, Col2\n\"Val1, \"\"Val2\"\"";
+ try {
+ CDL.toJSONArray(badLine);
+ fail("Expecting an exception");
+ } catch (JSONException e) {
+ assertEquals("Expecting an exception message",
+ "Missing close quote '\"'. at 26 [character 15 line 2]",
+ e.getMessage());
+
+ }
+ }
+
+ /**
+ * Assert that there is no error for a single escaped quote within a properly embedded quote.
+ */
+ @Test
+ public void singleEscapedQuote(){
+ String singleEscape = "Col1, Col2\nVal1, \"\"\"Val2\"";
+ JSONArray jsonArray = CDL.toJSONArray(singleEscape);
+
+ String cdlStr = CDL.toString(jsonArray);
+ assertTrue(cdlStr.contains("Col1"));
+ assertTrue(cdlStr.contains("Col2"));
+ assertTrue(cdlStr.contains("Val1"));
+ assertTrue(cdlStr.contains("\"Val2"));
+ }
+
+ /**
+ * Assert that there is no error for a single escaped quote within a properly
+ * embedded quote when not the last value.
+ */
+ @Test
+ public void singleEscapedQuoteMiddleString(){
+ String singleEscape = "Col1, Col2\nVal1, \"\"\"Val2\"\nVal 3,Val 4";
+ JSONArray jsonArray = CDL.toJSONArray(singleEscape);
+
+ String cdlStr = CDL.toString(jsonArray);
+ assertTrue(cdlStr.contains("Col1"));
+ assertTrue(cdlStr.contains("Col2"));
+ assertTrue(cdlStr.contains("Val1"));
+ assertTrue(cdlStr.contains("\"Val2"));
+ }
+
+ /**
+ * Attempt to create a JSONArray with an escape quote and no enclosing quotes.
+ * Expects a JSONException.
+ */
+ @Test
+ public void badEscapedQuote(){
+ String badLine = "Col1, Col2\nVal1, \"\"Val2";
+
+ try {
+ CDL.toJSONArray(badLine);
+ fail("Expecting an exception");
+ } catch (JSONException e) {
+ System.out.println("Message" + e.getMessage());
+ assertEquals("Expecting an exception message",
+ "Bad character 'V' (86). at 20 [character 9 line 2]",
+ e.getMessage());
+
+ }
+
+ }
+
+ /**
+ * call toString with a null array
+ */
+ @Test(expected=NullPointerException.class)
+ public void nullJSONArrayToString() {
+ CDL.toString((JSONArray)null);
+ }
+
+ /**
+ * Create a JSONArray from an empty string
+ */
+ @Test
+ public void emptyString() {
+ String emptyStr = "";
+ JSONArray jsonArray = CDL.toJSONArray(emptyStr);
+ assertTrue("CDL should return null when the input string is empty",
+ jsonArray == null);
+ }
+
+ /**
+ * Create a JSONArray with only 1 row
+ */
+ @Test
+ public void onlyColumnNames() {
+ String columnNameStr = "col1, col2, col3";
+ JSONArray jsonArray = CDL.toJSONArray(columnNameStr);
+ assertNull("CDL should return null when only 1 row is given",
+ jsonArray);
+ }
+
+ /**
+ * Create a JSONArray from string containing only whitespace and commas
+ */
+ @Test
+ public void emptyLinesToJSONArray() {
+ String str = " , , , \n , , , ";
+ JSONArray jsonArray = CDL.toJSONArray(str);
+ assertNull("JSONArray should be null for no content",
+ jsonArray);
+ }
+
+ /**
+ * call toString with a null array
+ */
+ @Test
+ public void emptyJSONArrayToString() {
+ JSONArray jsonArray = new JSONArray();
+ String str = CDL.toString(jsonArray);
+ assertNull("CDL should return null for toString(null)",
+ str);
+ }
+
+ /**
+ * call toString with a null arrays for names and values
+ */
+ @Test
+ public void nullJSONArraysToString() {
+ String str = CDL.toString(null, null);
+ assertNull("CDL should return null for toString(null)",
+ str);
+ }
+
+ /**
+ * Given a JSONArray that was not built by CDL, some chars may be
+ * found that would otherwise be filtered out by CDL.
+ */
+ @Test
+ public void checkSpecialChars() {
+ JSONArray jsonArray = new JSONArray();
+ JSONObject jsonObject = new JSONObject();
+ jsonArray.put(jsonObject);
+ // \r will be filtered from name
+ jsonObject.put("Col \r1", "V1");
+ // \r will be filtered from value
+ jsonObject.put("Col 2", "V2\r");
+ assertTrue("expected length should be 1",jsonArray.length() == 1);
+ String cdlStr = CDL.toString(jsonArray);
+ jsonObject = jsonArray.getJSONObject(0);
+ assertTrue(cdlStr.contains("\"Col 1\""));
+ assertTrue(cdlStr.contains("Col 2"));
+ assertTrue(cdlStr.contains("V1"));
+ assertTrue(cdlStr.contains("\"V2\""));
+ }
+
+ /**
+ * Create a JSONArray from a string of lines
+ */
+ @Test
+ public void textToJSONArray() {
+ JSONArray jsonArray = CDL.toJSONArray(this.lines);
+ JSONArray expectedJsonArray = new JSONArray(this.expectedLines);
+ Util.compareActualVsExpectedJsonArrays(jsonArray, expectedJsonArray);
+ }
+
+ /**
+ * Create a JSONArray from a JSONArray of titles and a
+ * string of value lines
+ */
+ @Test
+ public void jsonArrayToJSONArray() {
+ String nameArrayStr = "[Col1, Col2]";
+ String values = "V1, V2";
+ JSONArray nameJSONArray = new JSONArray(nameArrayStr);
+ JSONArray jsonArray = CDL.toJSONArray(nameJSONArray, values);
+ JSONArray expectedJsonArray = new JSONArray("[{Col1:V1,Col2:V2}]");
+ Util.compareActualVsExpectedJsonArrays(jsonArray, expectedJsonArray);
+ }
+
+ /**
+ * Create a JSONArray from a string of lines,
+ * then convert to string and then back to JSONArray
+ */
+ @Test
+ public void textToJSONArrayAndBackToString() {
+ JSONArray jsonArray = CDL.toJSONArray(this.lines);
+ String jsonStr = CDL.toString(jsonArray);
+ JSONArray finalJsonArray = CDL.toJSONArray(jsonStr);
+ JSONArray expectedJsonArray = new JSONArray(this.expectedLines);
+ Util.compareActualVsExpectedJsonArrays(finalJsonArray, expectedJsonArray);
+ }
+
+
+}
\ No newline at end of file
diff --git a/src/test/java/org/json/junit/CookieListTest.java b/src/test/java/org/json/junit/CookieListTest.java
new file mode 100644
index 0000000..7149644
--- /dev/null
+++ b/src/test/java/org/json/junit/CookieListTest.java
@@ -0,0 +1,186 @@
+package org.json.junit;
+
+import static org.junit.Assert.*;
+
+import java.util.*;
+
+import org.json.*;
+import org.junit.Test;
+
+import com.jayway.jsonpath.*;
+
+/**
+ * HTTP cookie specification RFC6265: http://tools.ietf.org/html/rfc6265
+ *
+ * A cookie list is a JSONObject whose members are presumed to be cookie
+ * name/value pairs. Entries are unescaped while being added, and escaped in
+ * the toString() output.
+ * Unescaping means to convert %hh hex strings to the ascii equivalent
+ * and converting '+' to ' '.
+ * Escaping converts '+', '%', '=', ';' and ascii control chars to %hh hex strings.
+ *
+ * CookieList should not be considered as just a list of Cookie objects:
+ * - CookieList stores a cookie name/value pair as a single entry; Cookie stores
+ * it as 2 entries (key="name" and key="value").
+ * - CookieList requires multiple name/value pairs as input; Cookie allows the
+ * 'secure' name with no associated value
+ * - CookieList has no special handling for attribute name/value pairs.
+ */
+public class CookieListTest {
+
+ /**
+ * Attempts to create a CookieList from a null string.
+ * Expects a NullPointerException.
+ */
+ @Test(expected=NullPointerException.class)
+ public void nullCookieListException() {
+ String cookieStr = null;
+ CookieList.toJSONObject(cookieStr);
+ }
+
+ /**
+ * Attempts to create a CookieList from a malformed string.
+ * Expects a JSONException.
+ */
+ @Test
+ public void malFormedCookieListException() {
+ String cookieStr = "thisCookieHasNoEqualsChar";
+ try {
+ CookieList.toJSONObject(cookieStr);
+ fail("should throw an exception");
+ } catch (JSONException e) {
+ /**
+ * Not sure of the missing char, but full string compare fails
+ */
+ assertEquals("Expecting an exception message",
+ "Expected '=' and instead saw '' at 25 [character 26 line 1]",
+ e.getMessage());
+ }
+ }
+
+ /**
+ * Creates a CookieList from an empty string.
+ */
+ @Test
+ public void emptyStringCookieList() {
+ String cookieStr = "";
+ JSONObject jsonObject = CookieList.toJSONObject(cookieStr);
+ assertTrue(jsonObject.isEmpty());
+ }
+
+ /**
+ * CookieList with the simplest cookie - a name/value pair with no delimiter.
+ */
+ @Test
+ public void simpleCookieList() {
+ String cookieStr = "SID=31d4d96e407aad42";
+ JSONObject jsonObject = CookieList.toJSONObject(cookieStr);
+ // validate JSON content
+ Object doc = Configuration.defaultConfiguration().jsonProvider().parse(jsonObject.toString());
+ assertTrue("Expected 1 top level item", ((Map,?>)(JsonPath.read(doc, "$"))).size() == 1);
+ assertTrue("expected 31d4d96e407aad42", "31d4d96e407aad42".equals(jsonObject.query("/SID")));
+ }
+
+ /**
+ * CookieList with a single a cookie which has a name/value pair and delimiter.
+ */
+ @Test
+ public void simpleCookieListWithDelimiter() {
+ String cookieStr = "SID=31d4d96e407aad42;";
+ JSONObject jsonObject = CookieList.toJSONObject(cookieStr);
+ // validate JSON content
+ Object doc = Configuration.defaultConfiguration().jsonProvider().parse(jsonObject.toString());
+ assertTrue("Expected 1 top level item", ((Map,?>)(JsonPath.read(doc, "$"))).size() == 1);
+ assertTrue("expected 31d4d96e407aad42", "31d4d96e407aad42".equals(jsonObject.query("/SID")));
+ }
+
+ /**
+ * CookieList with multiple cookies consisting of name/value pairs
+ * with delimiters.
+ */
+ @Test
+ public void multiPartCookieList() {
+ String cookieStr =
+ "name1=myCookieValue1; "+
+ " name2=myCookieValue2;"+
+ "name3=myCookieValue3;"+
+ " name4=myCookieValue4; "+
+ "name5=myCookieValue5;"+
+ " name6=myCookieValue6;";
+ JSONObject jsonObject = CookieList.toJSONObject(cookieStr);
+ // validate JSON content
+ Object doc = Configuration.defaultConfiguration().jsonProvider().parse(jsonObject.toString());
+ assertTrue("Expected 6 top level items", ((Map,?>)(JsonPath.read(doc, "$"))).size() == 6);
+ assertTrue("expected myCookieValue1", "myCookieValue1".equals(jsonObject.query("/name1")));
+ assertTrue("expected myCookieValue2", "myCookieValue2".equals(jsonObject.query("/name2")));
+ assertTrue("expected myCookieValue3", "myCookieValue3".equals(jsonObject.query("/name3")));
+ assertTrue("expected myCookieValue4", "myCookieValue4".equals(jsonObject.query("/name4")));
+ assertTrue("expected myCookieValue5", "myCookieValue5".equals(jsonObject.query("/name5")));
+ assertTrue("expected myCookieValue6", "myCookieValue6".equals(jsonObject.query("/name6")));
+ }
+
+ /**
+ * CookieList from a JSONObject with valid key and null value
+ */
+ @Test
+ public void convertCookieListWithNullValueToString() {
+ JSONObject jsonObject = new JSONObject();
+ jsonObject.put("key", JSONObject.NULL);
+ String cookieToStr = CookieList.toString(jsonObject);
+ assertTrue("toString() should be empty", "".equals(cookieToStr));
+ }
+
+ /**
+ * CookieList with multiple entries converted to a JSON document.
+ */
+ @Test
+ public void convertCookieListToString() {
+ String cookieStr =
+ "name1=myCookieValue1; "+
+ " name2=myCookieValue2;"+
+ "name3=myCookieValue3;"+
+ " name4=myCookieValue4; "+
+ "name5=myCookieValue5;"+
+ " name6=myCookieValue6;";
+ JSONObject jsonObject = CookieList.toJSONObject(cookieStr);
+ // exercise CookieList.toString()
+ String cookieListString = CookieList.toString(jsonObject);
+ // have to convert it back for validation
+ jsonObject = CookieList.toJSONObject(cookieListString);
+
+ // validate JSON content
+ Object doc = Configuration.defaultConfiguration().jsonProvider().parse(jsonObject.toString());
+ assertTrue("Expected 6 top level items", ((Map,?>)(JsonPath.read(doc, "$"))).size() == 6);
+ assertTrue("expected myCookieValue1", "myCookieValue1".equals(jsonObject.query("/name1")));
+ assertTrue("expected myCookieValue2", "myCookieValue2".equals(jsonObject.query("/name2")));
+ assertTrue("expected myCookieValue3", "myCookieValue3".equals(jsonObject.query("/name3")));
+ assertTrue("expected myCookieValue4", "myCookieValue4".equals(jsonObject.query("/name4")));
+ assertTrue("expected myCookieValue5", "myCookieValue5".equals(jsonObject.query("/name5")));
+ assertTrue("expected myCookieValue6", "myCookieValue6".equals(jsonObject.query("/name6")));
+ }
+
+ /**
+ * CookieList with multiple entries and some '+' chars and URL-encoded
+ * values converted to a JSON document.
+ */
+ @Test
+ public void convertEncodedCookieListToString() {
+ String cookieStr =
+ "name1=myCookieValue1; "+
+ " name2=my+Cookie+Value+2;"+
+ "name3=my%2BCookie%26Value%3B3%3D;"+
+ " name4=my%25CookieValue4; "+
+ "name5=myCookieValue5;"+
+ " name6=myCookieValue6;";
+ JSONObject jsonObject = CookieList.toJSONObject(cookieStr);
+ // validate JSON content
+ Object doc = Configuration.defaultConfiguration().jsonProvider().parse(jsonObject.toString());
+ assertTrue("Expected 6 top level items", ((Map,?>)(JsonPath.read(doc, "$"))).size() == 6);
+ assertTrue("expected myCookieValue1", "myCookieValue1".equals(jsonObject.query("/name1")));
+ assertTrue("expected my Cookie Value 2", "my Cookie Value 2".equals(jsonObject.query("/name2")));
+ assertTrue("expected my+Cookie&Value;3=", "my+Cookie&Value;3=".equals(jsonObject.query("/name3")));
+ assertTrue("expected my%CookieValue4", "my%CookieValue4".equals(jsonObject.query("/name4")));
+ assertTrue("expected my%CookieValue5", "myCookieValue5".equals(jsonObject.query("/name5")));
+ assertTrue("expected myCookieValue6", "myCookieValue6".equals(jsonObject.query("/name6")));
+ }
+}
diff --git a/src/test/java/org/json/junit/CookieTest.java b/src/test/java/org/json/junit/CookieTest.java
new file mode 100644
index 0000000..4b7ca44
--- /dev/null
+++ b/src/test/java/org/json/junit/CookieTest.java
@@ -0,0 +1,226 @@
+package org.json.junit;
+
+
+
+import static org.junit.Assert.*;
+
+import org.json.*;
+import org.junit.Test;
+
+
+/**
+ * HTTP cookie specification: RFC6265
+ *
+ * At its most basic, a cookie is a name=value pair. The value may be subdivided
+ * into other cookies, but that is not tested here. The cookie may also include
+ * certain named attributes, delimited by semicolons.
+ *
+ * The Cookie.toString() method emits certain attributes if present: expires,
+ * domain, path, secure. All but secure are name-value pairs. Other attributes
+ * are not included in the toString() output.
+ *
+ * A JSON-Java encoded cookie escapes '+', '%', '=', ';' with %hh values.
+ */
+public class CookieTest {
+
+ /**
+ * Attempts to create a JSONObject from a null string.
+ * Expects a NullPointerException.
+ */
+ @Test(expected=NullPointerException.class)
+ public void nullCookieException() {
+ String cookieStr = null;
+ Cookie.toJSONObject(cookieStr);
+ }
+
+ /**
+ * Attempts to create a JSONObject from a cookie string with
+ * no '=' char.
+ * Expects a JSONException.
+ */
+ @Test
+ public void malFormedNameValueException() {
+ String cookieStr = "thisCookieHasNoEqualsChar";
+ try {
+ Cookie.toJSONObject(cookieStr);
+ fail("Expecting an exception");
+ } catch (JSONException e) {
+ assertEquals("Expecting an exception message",
+ "Expected '=' and instead saw '' at 25 [character 26 line 1]",
+ e.getMessage());
+ }
+ }
+
+ /**
+ * Attempts to create a JSONObject from a cookie string
+ * with embedded ';' char.
+ * Expects a JSONException.
+ */
+ @Test
+ public void malFormedAttributeException() {
+ String cookieStr = "this=Cookie;myAttribute";
+ try {
+ Cookie.toJSONObject(cookieStr);
+ fail("Expecting an exception");
+ } catch (JSONException e) {
+ assertEquals("Expecting an exception message",
+ "Missing '=' in cookie parameter. at 23 [character 24 line 1]",
+ e.getMessage());
+ }
+ }
+
+ /**
+ * Attempts to create a JSONObject from an empty cookie string.
+ * Note: Cookie throws an exception, but CookieList does not.
+ * Expects a JSONException
+ */
+ @Test
+ public void emptyStringCookieException() {
+ String cookieStr = "";
+ try {
+ Cookie.toJSONObject(cookieStr);
+ fail("Expecting an exception");
+ } catch (JSONException e) {
+ assertEquals("Expecting an exception message",
+ "Expected '=' and instead saw '' at 0 [character 1 line 1]",
+ e.getMessage());
+ }
+ }
+
+ /**
+ * Cookie from a simple name/value pair with no delimiter
+ */
+ @Test
+ public void simpleCookie() {
+ String cookieStr = "SID=31d4d96e407aad42";
+ String expectedCookieStr = "{\"name\":\"SID\",\"value\":\"31d4d96e407aad42\"}";
+ JSONObject jsonObject = Cookie.toJSONObject(cookieStr);
+ JSONObject expectedJsonObject = new JSONObject(expectedCookieStr);
+ Util.compareActualVsExpectedJsonObjects(jsonObject,expectedJsonObject);
+ }
+
+ /**
+ * Store a cookie with all of the supported attributes in a
+ * JSONObject. The secure attribute, which has no value, is treated
+ * as a boolean.
+ */
+ @Test
+ public void multiPartCookie() {
+ String cookieStr =
+ "PH=deleted; "+
+ " expires=Wed, 19-Mar-2014 17:53:53 GMT;"+
+ "path=/; "+
+ " domain=.yahoo.com;"+
+ "secure";
+ String expectedCookieStr =
+ "{"+
+ "\"name\":\"PH\","+
+ "\"value\":\"deleted\","+
+ "\"path\":\"/\","+
+ "\"expires\":\"Wed, 19-Mar-2014 17:53:53 GMT\","+
+ "\"domain\":\".yahoo.com\","+
+ "\"secure\":true"+
+ "}";
+ JSONObject jsonObject = Cookie.toJSONObject(cookieStr);
+ JSONObject expectedJsonObject = new JSONObject(expectedCookieStr);
+ Util.compareActualVsExpectedJsonObjects(jsonObject,expectedJsonObject);
+ }
+
+ /**
+ * Cookie.toString() will omit the non-standard "thiswont=beIncluded"
+ * attribute, but the attribute is still stored in the JSONObject.
+ * This test confirms both behaviors.
+ */
+ @Test
+ public void convertCookieToString() {
+ String cookieStr =
+ "PH=deleted; "+
+ " expires=Wed, 19-Mar-2014 17:53:53 GMT;"+
+ "path=/; "+
+ " domain=.yahoo.com;"+
+ "thisWont=beIncluded;"+
+ "secure";
+ String expectedCookieStr =
+ "{\"path\":\"/\","+
+ "\"expires\":\"Wed, 19-Mar-2014 17:53:53 GMT\","+
+ "\"domain\":\".yahoo.com\","+
+ "\"name\":\"PH\","+
+ "\"secure\":true,"+
+ "\"value\":\"deleted\"}";
+ // Add the nonstandard attribute to the expected cookie string
+ String expectedDirectCompareCookieStr =
+ expectedCookieStr.replaceAll("\\{", "\\{\"thisWont\":\"beIncluded\",");
+ // convert all strings into JSONObjects
+ JSONObject jsonObject = Cookie.toJSONObject(cookieStr);
+ JSONObject expectedJsonObject = new JSONObject(expectedCookieStr);
+ JSONObject expectedDirectCompareJsonObject =
+ new JSONObject(expectedDirectCompareCookieStr);
+ // emit the string
+ String cookieToStr = Cookie.toString(jsonObject);
+ // create a final JSONObject from the string
+ JSONObject finalJsonObject = Cookie.toJSONObject(cookieToStr);
+ // JSONObject should contain the nonstandard string
+ Util.compareActualVsExpectedJsonObjects(jsonObject,expectedDirectCompareJsonObject);
+ // JSONObject -> string -> JSONObject should not contain the nonstandard string
+ Util.compareActualVsExpectedJsonObjects(finalJsonObject,expectedJsonObject);
+ }
+
+ /**
+ * A string may be URL-encoded when converting to JSONObject.
+ * If found, '+' is converted to ' ', and %hh hex strings are converted
+ * to their ascii char equivalents. This test confirms the decoding
+ * behavior.
+ */
+ @Test
+ public void convertEncodedCookieToString() {
+ String cookieStr =
+ "PH=deleted; "+
+ " expires=Wed,+19-Mar-2014+17:53:53+GMT;"+
+ "path=/%2Bthis/is%26/a/spec%3Bsegment%3D; "+
+ " domain=.yahoo.com;"+
+ "secure";
+ String expectedCookieStr =
+ "{\"path\":\"/+this/is&/a/spec;segment=\","+
+ "\"expires\":\"Wed, 19-Mar-2014 17:53:53 GMT\","+
+ "\"domain\":\".yahoo.com\","+
+ "\"name\":\"PH\","+
+ "\"secure\":true,"+
+ "\"value\":\"deleted\"}";
+ JSONObject jsonObject = Cookie.toJSONObject(cookieStr);
+ JSONObject expectedJsonObject = new JSONObject(expectedCookieStr);
+ String cookieToStr = Cookie.toString(jsonObject);
+ JSONObject finalJsonObject = Cookie.toJSONObject(cookieToStr);
+ Util.compareActualVsExpectedJsonObjects(jsonObject,expectedJsonObject);
+ Util.compareActualVsExpectedJsonObjects(finalJsonObject,expectedJsonObject);
+ }
+
+ /**
+ * A public API method performs a URL encoding for selected chars
+ * in a string. Control chars, '+', '%', '=', ';' are all encoded
+ * as %hh hex strings. The string is also trimmed.
+ * This test confirms that behavior.
+ */
+ @Test
+ public void escapeString() {
+ String str = " +%\r\n\t\b%=;;; ";
+ String expectedStr = "%2b%25%0d%0a%09%08%25%3d%3b%3b%3b";
+ String actualStr = Cookie.escape(str);
+ assertTrue("expect escape() to encode correctly. Actual: " +actualStr+
+ " expected: " +expectedStr, expectedStr.equals(actualStr));
+ }
+
+ /**
+ * A public API method performs URL decoding for strings.
+ * '+' is converted to space and %hh hex strings are converted to
+ * their ascii equivalent values. The string is not trimmed.
+ * This test confirms that behavior.
+ */
+ @Test
+ public void unescapeString() {
+ String str = " +%2b%25%0d%0a%09%08%25%3d%3b%3b%3b+ ";
+ String expectedStr = " +%\r\n\t\b%=;;; ";
+ String actualStr = Cookie.unescape(str);
+ assertTrue("expect unescape() to decode correctly. Actual: " +actualStr+
+ " expected: " +expectedStr, expectedStr.equals(actualStr));
+ }
+}
diff --git a/src/test/java/org/json/junit/EnumTest.java b/src/test/java/org/json/junit/EnumTest.java
new file mode 100644
index 0000000..366643e
--- /dev/null
+++ b/src/test/java/org/json/junit/EnumTest.java
@@ -0,0 +1,429 @@
+package org.json.junit;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import java.util.EnumSet;
+import java.util.List;
+import java.util.Map;
+
+import org.json.JSONArray;
+import org.json.JSONObject;
+import org.json.junit.data.MyEnum;
+import org.json.junit.data.MyEnumClass;
+import org.json.junit.data.MyEnumField;
+import org.junit.Test;
+
+import com.jayway.jsonpath.Configuration;
+import com.jayway.jsonpath.JsonPath;
+
+/**
+ * Enums are not explicitly supported in JSON-Java. But because enums act like
+ * classes, all required behavior is already be present in some form.
+ * These tests explore how enum serialization works with JSON-Java.
+ */
+public class EnumTest {
+
+ /**
+ * To serialize an enum by its getters, use the JSONObject Object constructor.
+ * The JSONObject ctor handles enum like any other bean. A JSONobject
+ * is created whose entries are the getter name/value pairs.
+ */
+ @Test
+ public void jsonObjectFromEnum() {
+ // If there are no getters then the object is empty.
+ MyEnum myEnum = MyEnum.VAL2;
+ JSONObject jsonObject = new JSONObject(myEnum);
+ assertTrue("simple enum has no getters", jsonObject.isEmpty());
+
+ // enum with a getters should create a non-empty object
+ MyEnumField myEnumField = MyEnumField.VAL2;
+ jsonObject = new JSONObject(myEnumField);
+
+ // validate JSON content
+ Object doc = Configuration.defaultConfiguration().jsonProvider()
+ .parse(jsonObject.toString());
+ assertTrue("expecting 2 items in top level object", ((Map,?>)(JsonPath.read(doc, "$"))).size() == 2);
+ assertTrue("expecting val 2", "val 2".equals(jsonObject.query("/value")));
+ assertTrue("expecting 2", Integer.valueOf(2).equals(jsonObject.query("/intVal")));
+
+ /**
+ * class which contains enum instances. Each enum should be stored
+ * in its own JSONObject
+ */
+ MyEnumClass myEnumClass = new MyEnumClass();
+ myEnumClass.setMyEnum(MyEnum.VAL1);
+ myEnumClass.setMyEnumField(MyEnumField.VAL3);
+ jsonObject = new JSONObject(myEnumClass);
+
+ // validate JSON content
+ doc = Configuration.defaultConfiguration().jsonProvider().parse(jsonObject.toString());
+ assertTrue("expected 2 top level items", ((Map,?>)(JsonPath.read(doc, "$"))).size() == 2);
+ assertTrue("expected 2 myEnumField items", "VAL3".equals((JsonPath.read(doc, "$.myEnumField"))));
+ assertTrue("expected 0 myEnum items", "VAL1".equals((JsonPath.read(doc, "$.myEnum"))));
+
+ assertTrue("expecting MyEnumField.VAL3", MyEnumField.VAL3.equals(jsonObject.query("/myEnumField")));
+ assertTrue("expecting MyEnum.VAL1", MyEnum.VAL1.equals(jsonObject.query("/myEnum")));
+ }
+
+ /**
+ * To serialize an enum by its set of allowed values, use getNames()
+ * and the the JSONObject Object with names constructor.
+ */
+ @Test
+ public void jsonObjectFromEnumWithNames() {
+ String [] names;
+ JSONObject jsonObject;
+
+ MyEnum myEnum = MyEnum.VAL1;
+ names = JSONObject.getNames(myEnum);
+ // The values will be MyEnum fields
+ jsonObject = new JSONObject(myEnum, names);
+
+ // validate JSON object
+ Object doc = Configuration.defaultConfiguration().jsonProvider().parse(jsonObject.toString());
+ assertTrue("expected 3 top level items", ((Map,?>)(JsonPath.read(doc, "$"))).size() == 3);
+ assertTrue("expected VAL1", MyEnum.VAL1.equals(jsonObject.query("/VAL1")));
+ assertTrue("expected VAL2", MyEnum.VAL2.equals(jsonObject.query("/VAL2")));
+ assertTrue("expected VAL3", MyEnum.VAL3.equals(jsonObject.query("/VAL3")));
+
+ MyEnumField myEnumField = MyEnumField.VAL3;
+ names = JSONObject.getNames(myEnumField);
+ // The values will be MyEnmField fields
+ jsonObject = new JSONObject(myEnumField, names);
+ doc = Configuration.defaultConfiguration().jsonProvider().parse(jsonObject.toString());
+ assertTrue("expected 3 top level items", ((Map,?>)(JsonPath.read(doc, "$"))).size() == 3);
+ assertTrue("expected VAL1", MyEnumField.VAL1.equals(jsonObject.query("/VAL1")));
+ assertTrue("expected VAL2", MyEnumField.VAL2.equals(jsonObject.query("/VAL2")));
+ assertTrue("expected VAL3", MyEnumField.VAL3.equals(jsonObject.query("/VAL3")));
+ }
+
+ /**
+ * Verify that enums are handled consistently between JSONArray and JSONObject
+ */
+ @Test
+ public void verifyEnumConsistency(){
+ JSONObject jo = new JSONObject();
+
+ jo.put("value", MyEnumField.VAL2);
+ String expected="{\"value\":\"VAL2\"}";
+ String actual = jo.toString();
+ assertTrue("Expected "+expected+" but actual was "+actual, expected.equals(actual));
+
+ jo.accumulate("value", MyEnumField.VAL1);
+ expected="{\"value\":[\"VAL2\",\"VAL1\"]}";
+ actual = jo.toString();
+ assertTrue("Expected "+expected+" but actual was "+actual, expected.equals(actual));
+
+ jo.remove("value");
+ jo.append("value", MyEnumField.VAL1);
+ expected="{\"value\":[\"VAL1\"]}";
+ actual = jo.toString();
+ assertTrue("Expected "+expected+" but actual was "+actual, expected.equals(actual));
+
+ jo.put("value", EnumSet.of(MyEnumField.VAL2));
+ expected="{\"value\":[\"VAL2\"]}";
+ actual = jo.toString();
+ assertTrue("Expected "+expected+" but actual was "+actual, expected.equals(actual));
+
+ JSONArray ja = new JSONArray();
+ ja.put(MyEnumField.VAL2);
+ jo.put("value", ja);
+ actual = jo.toString();
+ assertTrue("Expected "+expected+" but actual was "+actual, expected.equals(actual));
+
+ jo.put("value", new MyEnumField[]{MyEnumField.VAL2});
+ actual = jo.toString();
+ assertTrue("Expected "+expected+" but actual was "+actual, expected.equals(actual));
+
+ }
+
+ /**
+ * To serialize by assigned value, use the put() methods. The value
+ * will be stored as a enum type.
+ */
+ @Test
+ public void enumPut() {
+ JSONObject jsonObject = new JSONObject();
+ MyEnum myEnum = MyEnum.VAL2;
+ jsonObject.put("myEnum", myEnum);
+ MyEnumField myEnumField = MyEnumField.VAL1;
+ jsonObject.putOnce("myEnumField", myEnumField);
+
+ // validate JSON content
+ Object doc = Configuration.defaultConfiguration().jsonProvider().parse(jsonObject.toString());
+ assertTrue("expected 2 top level objects", ((Map,?>)(JsonPath.read(doc, "$"))).size() == 2);
+ assertTrue("expected VAL2", MyEnum.VAL2.equals(jsonObject.query("/myEnum")));
+ assertTrue("expected VAL1", MyEnumField.VAL1.equals(jsonObject.query("/myEnumField")));
+
+ JSONArray jsonArray = new JSONArray();
+ jsonArray.put(myEnum);
+ jsonArray.put(1, myEnumField);
+
+ // validate JSON content
+ doc = Configuration.defaultConfiguration().jsonProvider().parse(jsonArray.toString());
+ assertTrue("expected 2 top level objects", ((List>)(JsonPath.read(doc, "$"))).size() == 2);
+ assertTrue("expected VAL2", MyEnum.VAL2.equals(jsonArray.query("/0")));
+ assertTrue("expected VAL1", MyEnumField.VAL1.equals(jsonArray.query("/1")));
+
+ /**
+ * Leaving these tests because they exercise get, opt, and remove
+ */
+ assertTrue("expecting myEnum value", MyEnum.VAL2.equals(jsonArray.get(0)));
+ assertTrue("expecting myEnumField value", MyEnumField.VAL1.equals(jsonArray.opt(1)));
+ assertTrue("expecting myEnumField value", MyEnumField.VAL1.equals(jsonArray.remove(1)));
+ }
+
+ /**
+ * The default action of valueToString() is to call object.toString().
+ * For enums, this means the assigned value will be returned as a string.
+ */
+ @Test
+ public void enumValueToString() {
+ String expectedStr1 = "\"VAL1\"";
+ String expectedStr2 = "\"VAL1\"";
+ MyEnum myEnum = MyEnum.VAL1;
+ MyEnumField myEnumField = MyEnumField.VAL1;
+ MyEnumClass myEnumClass = new MyEnumClass();
+
+ String str1 = JSONObject.valueToString(myEnum);
+ assertTrue("actual myEnum: "+str1+" expected: "+expectedStr1,
+ str1.equals(expectedStr1));
+ String str2 = JSONObject.valueToString(myEnumField);
+ assertTrue("actual myEnumField: "+str2+" expected: "+expectedStr2,
+ str2.equals(expectedStr2));
+
+ /**
+ * However, an enum within another class will not be rendered
+ * unless that class overrides default toString()
+ */
+ String expectedStr3 = "\"org.json.junit.data.MyEnumClass@";
+ myEnumClass.setMyEnum(MyEnum.VAL1);
+ myEnumClass.setMyEnumField(MyEnumField.VAL1);
+ String str3 = JSONObject.valueToString(myEnumClass);
+ assertTrue("actual myEnumClass: "+str3+" expected: "+expectedStr3,
+ str3.startsWith(expectedStr3));
+ }
+
+ /**
+ * In whatever form the enum was added to the JSONObject or JSONArray,
+ * json[Object|Array].toString should serialize it in a reasonable way.
+ */
+ @Test
+ public void enumToString() {
+ MyEnum myEnum = MyEnum.VAL2;
+ JSONObject jsonObject = new JSONObject(myEnum);
+ String expectedStr = "{}";
+ assertTrue("myEnum toString() should be empty", expectedStr.equals(jsonObject.toString()));
+
+ MyEnumField myEnumField = MyEnumField.VAL2;
+ jsonObject = new JSONObject(myEnumField);
+
+ // validate JSON content
+ Object doc = Configuration.defaultConfiguration().jsonProvider().parse(jsonObject.toString());
+ assertTrue("expected 2 top level items", ((Map,?>)(JsonPath.read(doc, "$"))).size() == 2);
+ assertTrue("expected val 2", "val 2".equals(jsonObject.query("/value")));
+ assertTrue("expected 2", Integer.valueOf(2).equals(jsonObject.query("/intVal")));
+
+ MyEnumClass myEnumClass = new MyEnumClass();
+ myEnumClass.setMyEnum(MyEnum.VAL1);
+ myEnumClass.setMyEnumField(MyEnumField.VAL3);
+ jsonObject = new JSONObject(myEnumClass);
+
+ // validate JSON content
+ doc = Configuration.defaultConfiguration().jsonProvider().parse(jsonObject.toString());
+ assertTrue("expected 2 top level items", ((Map,?>)(JsonPath.read(doc, "$"))).size() == 2);
+ assertTrue("expected VAL3", "VAL3".equals((JsonPath.read(doc, "$.myEnumField"))));
+ assertTrue("expected VAL1", "VAL1".equals((JsonPath.read(doc, "$.myEnum"))));
+
+ String [] names = JSONObject.getNames(myEnum);
+ jsonObject = new JSONObject(myEnum, names);
+
+ // validate JSON content
+ doc = Configuration.defaultConfiguration().jsonProvider().parse(jsonObject.toString());
+ assertTrue("expected 3 top level items", ((Map,?>)(JsonPath.read(doc, "$"))).size() == 3);
+ assertTrue("expected VAL1", MyEnum.VAL1.equals(jsonObject.query("/VAL1")));
+ assertTrue("expected VAL2", MyEnum.VAL2.equals(jsonObject.query("/VAL2")));
+ assertTrue("expected VAL3", MyEnum.VAL3.equals(jsonObject.query("/VAL3")));
+
+ names = JSONObject.getNames(myEnumField);
+ jsonObject = new JSONObject(myEnumField, names);
+
+ // validate JSON content
+ doc = Configuration.defaultConfiguration().jsonProvider().parse(jsonObject.toString());
+ assertTrue("expected 3 top level items", ((Map,?>)(JsonPath.read(doc, "$"))).size() == 3);
+ assertTrue("expected VAL1", MyEnumField.VAL1.equals(jsonObject.query("/VAL1")));
+ assertTrue("expected VAL2", MyEnumField.VAL2.equals(jsonObject.query("/VAL2")));
+ assertTrue("expected VAL3", MyEnumField.VAL3.equals(jsonObject.query("/VAL3")));
+
+ expectedStr = "{\"myEnum\":\"VAL2\", \"myEnumField\":\"VAL2\"}";
+ jsonObject = new JSONObject();
+ jsonObject.putOpt("myEnum", myEnum);
+ jsonObject.putOnce("myEnumField", myEnumField);
+
+ // validate JSON content
+ doc = Configuration.defaultConfiguration().jsonProvider().parse(jsonObject.toString());
+ assertTrue("expected 2 top level items", ((Map,?>)(JsonPath.read(doc, "$"))).size() == 2);
+ assertTrue("expected VAL2", MyEnum.VAL2.equals(jsonObject.query("/myEnum")));
+ assertTrue("expected VAL2", MyEnumField.VAL2.equals(jsonObject.query("/myEnumField")));
+
+ JSONArray jsonArray = new JSONArray();
+ jsonArray.put(myEnum);
+ jsonArray.put(1, myEnumField);
+
+ // validate JSON content
+ doc = Configuration.defaultConfiguration().jsonProvider().parse(jsonArray.toString());
+ assertTrue("expected 2 top level items", ((List>)(JsonPath.read(doc, "$"))).size() == 2);
+ assertTrue("expected VAL2", MyEnum.VAL2.equals(jsonArray.query("/0")));
+ assertTrue("expected VAL2", MyEnumField.VAL2.equals(jsonArray.query("/1")));
+ }
+
+ /**
+ * Wrap should handle enums exactly as a value type like Integer, Boolean, or String.
+ */
+ @Test
+ public void wrap() {
+ assertTrue("simple enum has no getters", JSONObject.wrap(MyEnum.VAL2) instanceof MyEnum);
+
+ MyEnumField myEnumField = MyEnumField.VAL2;
+ JSONObject jsonObject = new JSONObject();
+ jsonObject.put("enum",myEnumField);
+
+ // validate JSON content
+ Object doc = Configuration.defaultConfiguration().jsonProvider().parse(jsonObject.toString());
+ assertTrue("expected 1 top level items", ((Map,?>)(JsonPath.read(doc, "$"))).size() == 1);
+ assertTrue("expected VAL2", MyEnumField.VAL2.equals(jsonObject.query("/enum")));
+
+ MyEnumClass myEnumClass = new MyEnumClass();
+ myEnumClass.setMyEnum(MyEnum.VAL1);
+ myEnumClass.setMyEnumField(MyEnumField.VAL3);
+ jsonObject = (JSONObject)JSONObject.wrap(myEnumClass);
+
+ // validate JSON content
+ doc = Configuration.defaultConfiguration().jsonProvider().parse(jsonObject.toString());
+ assertTrue("expected 2 top level items", ((Map,?>)(JsonPath.read(doc, "$"))).size() == 2);
+ assertTrue("expected VAL3", "VAL3".equals((JsonPath.read(doc, "$.myEnumField"))));
+ assertTrue("expected VAL1", "VAL1".equals((JsonPath.read(doc, "$.myEnum"))));
+
+ assertTrue("expecting MyEnumField.VAL3", MyEnumField.VAL3.equals(jsonObject.query("/myEnumField")));
+ assertTrue("expecting MyEnum.VAL1", MyEnum.VAL1.equals(jsonObject.query("/myEnum")));
+ }
+
+ /**
+ * It was determined that some API methods should be added to
+ * support enums:
+ * JSONObject.getEnum(class, key)
+ * JSONObject.optEnum(class, key)
+ * JSONObject.optEnum(class, key, default)
+ * JSONArray.getEnum(class, index)
+ * JSONArray.optEnum(class, index)
+ * JSONArray.optEnum(class, index, default)
+ *
+ * Exercise these enum API methods on JSONObject and JSONArray
+ */
+ @Test
+ public void enumAPI() {
+ MyEnumClass myEnumClass = new MyEnumClass();
+ myEnumClass.setMyEnum(MyEnum.VAL1);
+ MyEnumField myEnumField = MyEnumField.VAL2;
+
+ JSONObject jsonObject = new JSONObject();
+ jsonObject.put("strKey", "value");
+ jsonObject.put("strKey2", "VAL1");
+ jsonObject.put("enumKey", myEnumField);
+ jsonObject.put("enumClassKey", myEnumClass);
+
+ // get a plain old enum
+ MyEnumField actualEnum = jsonObject.getEnum(MyEnumField.class, "enumKey");
+ assertTrue("get myEnumField", actualEnum == MyEnumField.VAL2);
+
+ // try to get the wrong value
+ try {
+ actualEnum = jsonObject.getEnum(MyEnumField.class, "strKey");
+ assertTrue("should throw an exception for wrong key", false);
+ } catch (Exception ignored) {}
+
+ // get a class that contains an enum
+ MyEnumClass actualEnumClass = (MyEnumClass)jsonObject.get("enumClassKey");
+ assertTrue("get enum", actualEnumClass.getMyEnum() == MyEnum.VAL1);
+
+ // opt a plain old enum
+ actualEnum = jsonObject.optEnum(MyEnumField.class, "enumKey");
+ assertTrue("opt myEnumField", actualEnum == MyEnumField.VAL2);
+
+ // opt the wrong value
+ actualEnum = jsonObject.optEnum(MyEnumField.class, "strKey");
+ assertTrue("opt null", actualEnum == null);
+
+ // opt a class that contains an enum
+ actualEnumClass = (MyEnumClass)jsonObject.opt("enumClassKey");
+ assertTrue("get enum", actualEnumClass.getMyEnum() == MyEnum.VAL1);
+
+ // opt with default a plain old enum
+ actualEnum = jsonObject.optEnum(MyEnumField.class, "enumKey", null);
+ assertTrue("opt myEnumField", actualEnum == MyEnumField.VAL2);
+
+ // opt with default the wrong value
+ actualEnum = jsonObject.optEnum(MyEnumField.class, "strKey", null);
+ assertNull("opt null", actualEnum);
+
+ // opt with default the string value
+ actualEnum = jsonObject.optEnum(MyEnumField.class, "strKey2", null);
+ assertEquals(MyEnumField.VAL1, actualEnum);
+
+ // opt with default an index that does not exist
+ actualEnum = jsonObject.optEnum(MyEnumField.class, "noKey", null);
+ assertNull("opt null", actualEnum);
+
+ assertNull("Expected Null when the enum class is null",
+ jsonObject.optEnum(null, "enumKey"));
+
+ /**
+ * Exercise the proposed enum API methods on JSONArray
+ */
+ JSONArray jsonArray = new JSONArray();
+ jsonArray.put("value");
+ jsonArray.put(myEnumField);
+ jsonArray.put(myEnumClass);
+
+ // get a plain old enum
+ actualEnum = jsonArray.getEnum(MyEnumField.class, 1);
+ assertTrue("get myEnumField", actualEnum == MyEnumField.VAL2);
+
+ // try to get the wrong value
+ try {
+ actualEnum = jsonArray.getEnum(MyEnumField.class, 0);
+ assertTrue("should throw an exception for wrong index", false);
+ } catch (Exception ignored) {}
+
+ // get a class that contains an enum
+ actualEnumClass = (MyEnumClass)jsonArray.get(2);
+ assertTrue("get enum", actualEnumClass.getMyEnum() == MyEnum.VAL1);
+
+ // opt a plain old enum
+ actualEnum = jsonArray.optEnum(MyEnumField.class, 1);
+ assertTrue("opt myEnumField", actualEnum == MyEnumField.VAL2);
+
+ // opt the wrong value
+ actualEnum = jsonArray.optEnum(MyEnumField.class, 0);
+ assertTrue("opt null", actualEnum == null);
+
+ // opt a class that contains an enum
+ actualEnumClass = (MyEnumClass)jsonArray.opt(2);
+ assertTrue("get enum", actualEnumClass.getMyEnum() == MyEnum.VAL1);
+
+ // opt with default a plain old enum
+ actualEnum = jsonArray.optEnum(MyEnumField.class, 1, null);
+ assertTrue("opt myEnumField", actualEnum == MyEnumField.VAL2);
+
+ // opt with default the wrong value
+ actualEnum = jsonArray.optEnum(MyEnumField.class, 0, null);
+ assertTrue("opt null", actualEnum == null);
+
+ // opt with default an index that does not exist
+ actualEnum = jsonArray.optEnum(MyEnumField.class, 3, null);
+ assertTrue("opt null", actualEnum == null);
+
+ }
+}
diff --git a/src/test/java/org/json/junit/HTTPTest.java b/src/test/java/org/json/junit/HTTPTest.java
new file mode 100644
index 0000000..2716c3c
--- /dev/null
+++ b/src/test/java/org/json/junit/HTTPTest.java
@@ -0,0 +1,196 @@
+package org.json.junit;
+
+import static org.junit.Assert.*;
+
+import org.json.*;
+import org.junit.Test;
+
+
+/**
+ * Unit tests for JSON-Java HTTP.java. See RFC7230.
+ */
+public class HTTPTest {
+
+ /**
+ * Attempt to call HTTP.toJSONObject() with a null string
+ * Expects a NUllPointerException.
+ */
+ @Test(expected=NullPointerException.class)
+ public void nullHTTPException() {
+ String httpStr = null;
+ HTTP.toJSONObject(httpStr);
+ }
+
+ /**
+ * Attempt to call HTTP.toJSONObject() with a string containing
+ * an empty object. Expects a JSONException.
+ */
+ @Test
+ public void notEnoughHTTPException() {
+ String httpStr = "{}";
+ JSONObject jsonObject = new JSONObject(httpStr);
+ try {
+ HTTP.toString(jsonObject);
+ assertTrue("Expected to throw exception", false);
+ } catch (JSONException e) {
+ assertTrue("Expecting an exception message",
+ "Not enough material for an HTTP header.".equals(e.getMessage()));
+ }
+ }
+
+ /**
+ * Calling HTTP.toJSONObject() with an empty string will result in a
+ * populated JSONObject with keys but no values for Request-URI, Method,
+ * and HTTP-Version.
+ */
+ @Test
+ public void emptyStringHTTPRequest() {
+ String httpStr = "";
+ String expectedHTTPStr = "{\"Request-URI\":\"\",\"Method\":\"\",\"HTTP-Version\":\"\"}";
+ JSONObject jsonObject = HTTP.toJSONObject(httpStr);
+ JSONObject expectedJsonObject = new JSONObject(expectedHTTPStr);
+ Util.compareActualVsExpectedJsonObjects(jsonObject,expectedJsonObject);
+ }
+
+ /**
+ * Call HTTP.toJSONObject() with a Request-URI, Method,
+ * and HTTP-Version.
+ */
+ @Test
+ public void simpleHTTPRequest() {
+ String httpStr = "GET /hello.txt HTTP/1.1";
+ String expectedHTTPStr =
+ "{\"Request-URI\":\"/hello.txt\",\"Method\":\"GET\",\"HTTP-Version\":\"HTTP/1.1\"}";
+ JSONObject jsonObject = HTTP.toJSONObject(httpStr);
+ JSONObject expectedJsonObject = new JSONObject(expectedHTTPStr);
+ Util.compareActualVsExpectedJsonObjects(jsonObject,expectedJsonObject);
+ }
+
+ /**
+ * Call HTTP.toJSONObject() with a response string containing a
+ * HTTP-Version, Status-Code, and Reason.
+ */
+ @Test
+ public void simpleHTTPResponse() {
+ String httpStr = "HTTP/1.1 200 OK";
+ String expectedHTTPStr =
+ "{\"HTTP-Version\":\"HTTP/1.1\",\"Status-Code\":\"200\",\"Reason-Phrase\":\"OK\"}";
+ JSONObject jsonObject = HTTP.toJSONObject(httpStr);
+ JSONObject expectedJsonObject = new JSONObject(expectedHTTPStr);
+ Util.compareActualVsExpectedJsonObjects(jsonObject,expectedJsonObject);
+ }
+
+ /**
+ * Call HTTP.toJSONObject() with a full request string including
+ * request headers.
+ */
+ @Test
+ public void extendedHTTPRequest() {
+ String httpStr =
+ "POST /enlighten/calais.asmx HTTP/1.1\n"+
+ "Host: api.opencalais.com\n"+
+ "Content-Type: text/xml; charset=utf-8\n"+
+ "Content-Length: 100\n"+
+ "SOAPAction: \"http://clearforest.com/Enlighten\"";
+ String expectedHTTPStr =
+ "{"+
+ "\"Request-URI\":\"/enlighten/calais.asmx\","+
+ "\"Host\":\"api.opencalais.com\","+
+ "\"Method\":\"POST\","+
+ "\"HTTP-Version\":\"HTTP/1.1\","+
+ "\"Content-Length\":\"100\","+
+ "\"Content-Type\":\"text/xml; charset=utf-8\"}";
+ JSONObject jsonObject = HTTP.toJSONObject(httpStr);
+ JSONObject expectedJsonObject = new JSONObject(expectedHTTPStr);
+ /**
+ * Not too easy for JSONObject to parse a string with embedded quotes.
+ * For the sake of the test, add it here.
+ */
+ expectedJsonObject.put("SOAPAction","\"http://clearforest.com/Enlighten\"");
+ Util.compareActualVsExpectedJsonObjects(jsonObject,expectedJsonObject);
+ }
+
+ /**
+ * Call HTTP.toJSONObject() with a full response string including
+ * response headers.
+ */
+ @Test
+ public void extendedHTTPResponse() {
+ String httpStr =
+ "HTTP/1.1 200 OK\n"+
+ "Content-Type: text/xml; charset=utf-8\n"+
+ "Content-Length: 100\n";
+ String expectedHTTPStr =
+ "{\"HTTP-Version\":\"HTTP/1.1\","+
+ "\"Status-Code\":\"200\","+
+ "\"Content-Length\":\"100\","+
+ "\"Reason-Phrase\":\"OK\","+
+ "\"Content-Type\":\"text/xml; charset=utf-8\"}";
+ JSONObject jsonObject = HTTP.toJSONObject(httpStr);
+ JSONObject expectedJsonObject = new JSONObject(expectedHTTPStr);
+ Util.compareActualVsExpectedJsonObjects(jsonObject,expectedJsonObject);
+ }
+
+ /**
+ * Call HTTP.toJSONObject() with a full POST request string including
+ * response headers, then convert it back into an HTTP string.
+ */
+ @Test
+ public void convertHTTPRequestToString() {
+ String httpStr =
+ "POST /enlighten/calais.asmx HTTP/1.1\n"+
+ "Host: api.opencalais.com\n"+
+ "Content-Type: text/xml; charset=utf-8\n"+
+ "Content-Length: 100";
+ String expectedHTTPStr =
+ "{"+
+ "\"Request-URI\":\"/enlighten/calais.asmx\","+
+ "\"Host\":\"api.opencalais.com\","+
+ "\"Method\":\"POST\","+
+ "\"HTTP-Version\":\"HTTP/1.1\","+
+ "\"Content-Length\":\"100\","+
+ "\"Content-Type\":\"text/xml; charset=utf-8\"}";
+ JSONObject jsonObject = HTTP.toJSONObject(httpStr);
+ JSONObject expectedJsonObject = new JSONObject(expectedHTTPStr);
+ String httpToStr = HTTP.toString(jsonObject);
+ /**
+ * JSONObject objects to crlfs and any trailing chars.
+ * For the sake of the test, simplify the resulting string
+ */
+ httpToStr = httpToStr.replaceAll("("+HTTP.CRLF+HTTP.CRLF+")", "");
+ httpToStr = httpToStr.replaceAll(HTTP.CRLF, "\n");
+ JSONObject finalJsonObject = HTTP.toJSONObject(httpToStr);
+ Util.compareActualVsExpectedJsonObjects(jsonObject,expectedJsonObject);
+ Util.compareActualVsExpectedJsonObjects(finalJsonObject,expectedJsonObject);
+ }
+
+ /**
+ * Call HTTP.toJSONObject() with a full response string including
+ * response headers, then convert it back into an HTTP string.
+ */
+ @Test
+ public void convertHTTPResponseToString() {
+ String httpStr =
+ "HTTP/1.1 200 OK\n"+
+ "Content-Type: text/xml; charset=utf-8\n"+
+ "Content-Length: 100\n";
+ String expectedHTTPStr =
+ "{\"HTTP-Version\":\"HTTP/1.1\","+
+ "\"Status-Code\":\"200\","+
+ "\"Content-Length\":\"100\","+
+ "\"Reason-Phrase\":\"OK\","+
+ "\"Content-Type\":\"text/xml; charset=utf-8\"}";
+ JSONObject jsonObject = HTTP.toJSONObject(httpStr);
+ JSONObject expectedJsonObject = new JSONObject(expectedHTTPStr);
+ String httpToStr = HTTP.toString(jsonObject);
+ /**
+ * JSONObject objects to crlfs and any trailing chars.
+ * For the sake of the test, simplify the resulting string
+ */
+ httpToStr = httpToStr.replaceAll("("+HTTP.CRLF+HTTP.CRLF+")", "");
+ httpToStr = httpToStr.replaceAll(HTTP.CRLF, "\n");
+ JSONObject finalJsonObject = HTTP.toJSONObject(httpToStr);
+ Util.compareActualVsExpectedJsonObjects(jsonObject,expectedJsonObject);
+ Util.compareActualVsExpectedJsonObjects(finalJsonObject,expectedJsonObject);
+ }
+}
diff --git a/src/test/java/org/json/junit/JSONArrayTest.java b/src/test/java/org/json/junit/JSONArrayTest.java
new file mode 100644
index 0000000..5aef340
--- /dev/null
+++ b/src/test/java/org/json/junit/JSONArrayTest.java
@@ -0,0 +1,1073 @@
+package org.json.junit;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import java.io.IOException;
+import java.io.StringWriter;
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+import org.json.JSONPointerException;
+import org.junit.Test;
+
+import com.jayway.jsonpath.Configuration;
+import com.jayway.jsonpath.JsonPath;
+
+
+/**
+ * Tests for JSON-Java JSONArray.java
+ */
+public class JSONArrayTest {
+ private final 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\""+
+ "]";
+
+ /**
+ * Tests that the similar method is working as expected.
+ */
+ @Test
+ public void verifySimilar() {
+ final String string1 = "HasSameRef";
+ JSONArray obj1 = new JSONArray()
+ .put("abc")
+ .put(string1)
+ .put(2);
+
+ JSONArray obj2 = new JSONArray()
+ .put("abc")
+ .put(string1)
+ .put(3);
+
+ JSONArray obj3 = new JSONArray()
+ .put("abc")
+ .put(new String(string1))
+ .put(2);
+
+ assertFalse("Should eval to false", obj1.similar(obj2));
+
+ assertTrue("Should eval to true", obj1.similar(obj3));
+ }
+
+ /**
+ * Attempt to create a JSONArray with a null string.
+ * Expects a NullPointerException.
+ */
+ @Test(expected=NullPointerException.class)
+ public void nullException() {
+ String str = null;
+ assertNull("Should throw an exception", new JSONArray(str));
+ }
+
+ /**
+ * Attempt to create a JSONArray with an empty string.
+ * Expects a JSONException.
+ */
+ @Test
+ public void emptStr() {
+ String str = "";
+ try {
+ assertNull("Should throw an exception", new JSONArray(str));
+ } catch (JSONException e) {
+ assertEquals("Expected an exception message",
+ "A JSONArray text must start with '[' at 0 [character 1 line 1]",
+ e.getMessage());
+ }
+ }
+
+ /**
+ * Attempt to create a JSONArray with an unclosed array.
+ * Expects an exception
+ */
+ @Test
+ public void unclosedArray() {
+ try {
+ assertNull("Should throw an exception", new JSONArray("["));
+ } catch (JSONException e) {
+ assertEquals("Expected an exception message",
+ "Expected a ',' or ']' at 1 [character 2 line 1]",
+ e.getMessage());
+ }
+ }
+
+ /**
+ * Attempt to create a JSONArray with an unclosed array.
+ * Expects an exception
+ */
+ @Test
+ public void unclosedArray2() {
+ try {
+ assertNull("Should throw an exception", new JSONArray("[\"test\""));
+ } catch (JSONException e) {
+ assertEquals("Expected an exception message",
+ "Expected a ',' or ']' at 7 [character 8 line 1]",
+ e.getMessage());
+ }
+ }
+
+ /**
+ * Attempt to create a JSONArray with an unclosed array.
+ * Expects an exception
+ */
+ @Test
+ public void unclosedArray3() {
+ try {
+ assertNull("Should throw an exception", new JSONArray("[\"test\","));
+ } catch (JSONException e) {
+ assertEquals("Expected an exception message",
+ "Expected a ',' or ']' at 8 [character 9 line 1]",
+ e.getMessage());
+ }
+ }
+
+ /**
+ * Attempt to create a JSONArray with a string as object that is
+ * not a JSON array doc.
+ * Expects a JSONException.
+ */
+ @Test
+ public void badObject() {
+ String str = "abc";
+ try {
+ assertNull("Should throw an exception", new JSONArray((Object)str));
+ } catch (JSONException e) {
+ assertTrue("Expected an exception message",
+ "JSONArray initial value should be a string or collection or array.".
+ equals(e.getMessage()));
+ }
+ }
+
+ /**
+ * Verifies that the constructor has backwards compatibility with RAW types pre-java5.
+ */
+ @Test
+ public void verifyConstructor() {
+
+ final JSONArray expected = new JSONArray("[10]");
+
+ @SuppressWarnings("rawtypes")
+ Collection myRawC = Collections.singleton(Integer.valueOf(10));
+ JSONArray jaRaw = new JSONArray(myRawC);
+
+ Collection myCInt = Collections.singleton(Integer.valueOf(10));
+ JSONArray jaInt = new JSONArray(myCInt);
+
+ Collection