mirror of
https://github.com/stleary/JSON-java.git
synced 2026-01-24 00:03:17 -05:00
Compare commits
109 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f9b5587c87 | ||
|
|
3d69990ab5 | ||
|
|
ba05e1a98c | ||
|
|
390d442054 | ||
|
|
3eb8a62af6 | ||
|
|
989cdb61bc | ||
|
|
8de0628bd1 | ||
|
|
569be9d19e | ||
|
|
3f97826462 | ||
|
|
d520210ea2 | ||
|
|
898288810f | ||
|
|
771c82c4eb | ||
|
|
d36066cf82 | ||
|
|
c1107fa987 | ||
|
|
cd631d970e | ||
|
|
f0289413d6 | ||
|
|
b4b39bb441 | ||
|
|
86253211c2 | ||
|
|
77c899d325 | ||
|
|
f164b8c597 | ||
|
|
6358b7f681 | ||
|
|
8550175556 | ||
|
|
72214f1b43 | ||
|
|
99c84fdf3a | ||
|
|
010e83b925 | ||
|
|
9865dbbebe | ||
|
|
4548696c8d | ||
|
|
f0308a3475 | ||
|
|
19dec1bb5f | ||
|
|
f2d20988de | ||
|
|
7915d8518f | ||
|
|
55b824d4c4 | ||
|
|
ac7806d060 | ||
|
|
86bb0a1a02 | ||
|
|
5ddb8c3d35 | ||
|
|
23ac2e7bca | ||
|
|
d7819a4fa2 | ||
|
|
7701f21839 | ||
|
|
ffd48afa42 | ||
|
|
abea194120 | ||
|
|
dcac3bc18e | ||
|
|
6d811607dd | ||
|
|
4d6de8c00a | ||
|
|
6dba7220e1 | ||
|
|
d4521696a9 | ||
|
|
e430db40aa | ||
|
|
7cbeb35498 | ||
|
|
aba82d9cc4 | ||
|
|
9ee10fdfc8 | ||
|
|
4a468d163a | ||
|
|
92991770ca | ||
|
|
09f35372d4 | ||
|
|
30f5b2de79 | ||
|
|
7f1cb8bf62 | ||
|
|
75419e3f25 | ||
|
|
097a401f3f | ||
|
|
5c4a7a1b1f | ||
|
|
b5f9febfe9 | ||
|
|
1a61af8255 | ||
|
|
11c29c366d | ||
|
|
a3742acf74 | ||
|
|
783d298f99 | ||
|
|
6c1bc0660a | ||
|
|
8ec822c575 | ||
|
|
1ceb70b525 | ||
|
|
c05d7058ff | ||
|
|
07a358449a | ||
|
|
7fe2fd95a5 | ||
|
|
b5b9f636ff | ||
|
|
c6ec2f0e4c | ||
|
|
1a2108efa2 | ||
|
|
caadcba30e | ||
|
|
ea842b437c | ||
|
|
a2a8240d0d | ||
|
|
1ab11d0802 | ||
|
|
5539722c69 | ||
|
|
98b79ae7bf | ||
|
|
04a4c5a3ec | ||
|
|
6007165c17 | ||
|
|
411f71137b | ||
|
|
e9117dbe5c | ||
|
|
7a85b514a9 | ||
|
|
82c8f486c5 | ||
|
|
006b29bda3 | ||
|
|
996d3a5fad | ||
|
|
de745e9c81 | ||
|
|
2374766018 | ||
|
|
1d0775cce7 | ||
|
|
d677a99f4e | ||
|
|
e6d37c469d | ||
|
|
f074bed732 | ||
|
|
e8f125fb6e | ||
|
|
ed183e6142 | ||
|
|
a86786a5f5 | ||
|
|
7c4f98c42c | ||
|
|
3894483560 | ||
|
|
be115059e9 | ||
|
|
2b41cf44b5 | ||
|
|
9a9efac2af | ||
|
|
134074aeaa | ||
|
|
8540bb80c0 | ||
|
|
4dfd779b1c | ||
|
|
7b2677ac5a | ||
|
|
29a7f4622d | ||
|
|
e4aa7f1308 | ||
|
|
228598ca84 | ||
|
|
0a6fb1d578 | ||
|
|
ca88454f1c | ||
|
|
becc1631e6 |
197
.github/workflows/pipeline.yml
vendored
197
.github/workflows/pipeline.yml
vendored
@@ -1,5 +1,5 @@
|
||||
# This workflow will build a Java project with Maven
|
||||
# For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-maven
|
||||
# For more information see: https://docs.github.com/en/actions/learn-github-actions or https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions
|
||||
|
||||
name: Java CI with Maven
|
||||
|
||||
@@ -10,12 +10,39 @@ on:
|
||||
branches: [ master ]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
# old-school build and jar method. No tests run or compiled.
|
||||
build-1_6:
|
||||
name: Java 1.6
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Setup java
|
||||
uses: actions/setup-java@v1
|
||||
with:
|
||||
java-version: 1.6
|
||||
- name: Compile Java 1.6
|
||||
run: |
|
||||
mkdir -p target/classes
|
||||
javac -version
|
||||
javac -source 1.6 -target 1.6 -d target/classes/ src/main/java/org/json/*.java
|
||||
- name: Create java 1.6 JAR
|
||||
run: |
|
||||
jar cvf target/org.json.jar -C target/classes .
|
||||
- name: Upload JAR 1.6
|
||||
if: ${{ always() }}
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: Create java 1.6 JAR
|
||||
path: target/*.jar
|
||||
|
||||
build-8:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
max-parallel: 1
|
||||
matrix:
|
||||
# build against supported Java LTS versions:
|
||||
java: [ 8, 11, 17 ]
|
||||
java: [ 8 ]
|
||||
name: Java ${{ matrix.java }}
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
@@ -26,24 +53,176 @@ jobs:
|
||||
java-version: ${{ matrix.java }}
|
||||
cache: 'maven'
|
||||
- name: Compile Java ${{ matrix.java }}
|
||||
run: mvn clean compile -Dmaven.compiler.source=${{ matrix.java }} -Dmaven.compiler.target=${{ matrix.java }} -Dmaven.test.skip=true -Dmaven.site.skip=true -Dmaven.javadoc.skip=true
|
||||
run: mvn clean compile -D maven.compiler.source=${{ matrix.java }} -D maven.compiler.target=${{ matrix.java }} -D maven.test.skip=true -D maven.site.skip=true -D maven.javadoc.skip=true
|
||||
- name: Run Tests ${{ matrix.java }}
|
||||
run: |
|
||||
mvn test -Dmaven.compiler.source=${{ matrix.java }} -Dmaven.compiler.target=${{ matrix.java }}
|
||||
mvn test -D maven.compiler.source=${{ matrix.java }} -D maven.compiler.target=${{ matrix.java }}
|
||||
- name: Build Test Report ${{ matrix.java }}
|
||||
if: ${{ always() }}
|
||||
run: |
|
||||
mvn surefire-report:report-only -Dmaven.compiler.source=${{ matrix.java }} -Dmaven.compiler.target=${{ matrix.java }}
|
||||
mvn site -DgenerateReports=false -Dmaven.compiler.source=${{ matrix.java }} -Dmaven.compiler.target=${{ matrix.java }}
|
||||
mvn surefire-report:report-only -D maven.compiler.source=${{ matrix.java }} -D maven.compiler.target=${{ matrix.java }}
|
||||
mvn site -D generateReports=false -D maven.compiler.source=${{ matrix.java }} -D maven.compiler.target=${{ matrix.java }}
|
||||
- name: Upload Test Results ${{ matrix.java }}
|
||||
if: ${{ always() }}
|
||||
uses: actions/upload-artifact@v1
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: Test Results ${{ matrix.java }}
|
||||
path: target/surefire-reports/
|
||||
- name: Upload Test Report ${{ matrix.java }}
|
||||
if: ${{ always() }}
|
||||
uses: actions/upload-artifact@v1
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: Test Report ${{ matrix.java }}
|
||||
path: target/site/
|
||||
- name: Package Jar ${{ matrix.java }}
|
||||
run: mvn clean package -D maven.compiler.source=${{ matrix.java }} -D maven.compiler.target=${{ matrix.java }} -D maven.test.skip=true -D maven.site.skip=true
|
||||
- name: Upload Package Results ${{ matrix.java }}
|
||||
if: ${{ always() }}
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: Package Jar ${{ matrix.java }}
|
||||
path: target/*.jar
|
||||
|
||||
build-11:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
max-parallel: 1
|
||||
matrix:
|
||||
# build against supported Java LTS versions:
|
||||
java: [ 11 ]
|
||||
name: Java ${{ matrix.java }}
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Set up JDK ${{ matrix.java }}
|
||||
uses: actions/setup-java@v3
|
||||
with:
|
||||
distribution: 'temurin'
|
||||
java-version: ${{ matrix.java }}
|
||||
cache: 'maven'
|
||||
- name: Compile Java ${{ matrix.java }}
|
||||
run: mvn clean compile -D maven.compiler.source=${{ matrix.java }} -D maven.compiler.target=${{ matrix.java }} -D maven.test.skip=true -D maven.site.skip=true -D maven.javadoc.skip=true
|
||||
- name: Run Tests ${{ matrix.java }}
|
||||
run: |
|
||||
mvn test -D maven.compiler.source=${{ matrix.java }} -D maven.compiler.target=${{ matrix.java }}
|
||||
- name: Build Test Report ${{ matrix.java }}
|
||||
if: ${{ always() }}
|
||||
run: |
|
||||
mvn surefire-report:report-only -D maven.compiler.source=${{ matrix.java }} -D maven.compiler.target=${{ matrix.java }}
|
||||
mvn site -D generateReports=false -D maven.compiler.source=${{ matrix.java }} -D maven.compiler.target=${{ matrix.java }}
|
||||
- name: Upload Test Results ${{ matrix.java }}
|
||||
if: ${{ always() }}
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: Test Results ${{ matrix.java }}
|
||||
path: target/surefire-reports/
|
||||
- name: Upload Test Report ${{ matrix.java }}
|
||||
if: ${{ always() }}
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: Test Report ${{ matrix.java }}
|
||||
path: target/site/
|
||||
- name: Package Jar ${{ matrix.java }}
|
||||
run: mvn clean package -D maven.compiler.source=${{ matrix.java }} -D maven.compiler.target=${{ matrix.java }} -D maven.test.skip=true -D maven.site.skip=true
|
||||
- name: Upload Package Results ${{ matrix.java }}
|
||||
if: ${{ always() }}
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: Package Jar ${{ matrix.java }}
|
||||
path: target/*.jar
|
||||
|
||||
build-17:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
max-parallel: 1
|
||||
matrix:
|
||||
# build against supported Java LTS versions:
|
||||
java: [ 17 ]
|
||||
name: Java ${{ matrix.java }}
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Set up JDK ${{ matrix.java }}
|
||||
uses: actions/setup-java@v3
|
||||
with:
|
||||
distribution: 'temurin'
|
||||
java-version: ${{ matrix.java }}
|
||||
cache: 'maven'
|
||||
- name: Compile Java ${{ matrix.java }}
|
||||
run: mvn clean compile -D maven.compiler.source=${{ matrix.java }} -D maven.compiler.target=${{ matrix.java }} -D maven.test.skip=true -D maven.site.skip=true -D maven.javadoc.skip=true
|
||||
- name: Run Tests ${{ matrix.java }}
|
||||
run: |
|
||||
mvn test -D maven.compiler.source=${{ matrix.java }} -D maven.compiler.target=${{ matrix.java }}
|
||||
- name: Build Test Report ${{ matrix.java }}
|
||||
if: ${{ always() }}
|
||||
run: |
|
||||
mvn surefire-report:report-only -D maven.compiler.source=${{ matrix.java }} -D maven.compiler.target=${{ matrix.java }}
|
||||
mvn site -D generateReports=false -D maven.compiler.source=${{ matrix.java }} -D maven.compiler.target=${{ matrix.java }}
|
||||
- name: Upload Test Results ${{ matrix.java }}
|
||||
if: ${{ always() }}
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: Test Results ${{ matrix.java }}
|
||||
path: target/surefire-reports/
|
||||
- name: Upload Test Report ${{ matrix.java }}
|
||||
if: ${{ always() }}
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: Test Report ${{ matrix.java }}
|
||||
path: target/site/
|
||||
- name: Package Jar ${{ matrix.java }}
|
||||
run: mvn clean package -D maven.compiler.source=${{ matrix.java }} -D maven.compiler.target=${{ matrix.java }} -D maven.test.skip=true -D maven.site.skip=true
|
||||
- name: Upload Package Results ${{ matrix.java }}
|
||||
if: ${{ always() }}
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: Package Jar ${{ matrix.java }}
|
||||
path: target/*.jar
|
||||
|
||||
build-21:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
max-parallel: 1
|
||||
matrix:
|
||||
# build against supported Java LTS versions:
|
||||
java: [ 21 ]
|
||||
name: Java ${{ matrix.java }}
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Set up JDK ${{ matrix.java }}
|
||||
uses: actions/setup-java@v3
|
||||
with:
|
||||
distribution: 'temurin'
|
||||
java-version: ${{ matrix.java }}
|
||||
cache: 'maven'
|
||||
- name: Compile Java ${{ matrix.java }}
|
||||
run: mvn clean compile -D maven.compiler.source=${{ matrix.java }} -D maven.compiler.target=${{ matrix.java }} -D maven.test.skip=true -D maven.site.skip=true -D maven.javadoc.skip=true
|
||||
- name: Run Tests ${{ matrix.java }}
|
||||
run: |
|
||||
mvn test -D maven.compiler.source=${{ matrix.java }} -D maven.compiler.target=${{ matrix.java }}
|
||||
- name: Build Test Report ${{ matrix.java }}
|
||||
if: ${{ always() }}
|
||||
run: |
|
||||
mvn surefire-report:report-only -D maven.compiler.source=${{ matrix.java }} -D maven.compiler.target=${{ matrix.java }}
|
||||
mvn site -D generateReports=false -D maven.compiler.source=${{ matrix.java }} -D maven.compiler.target=${{ matrix.java }}
|
||||
- name: Upload Test Results ${{ matrix.java }}
|
||||
if: ${{ always() }}
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: Test Results ${{ matrix.java }}
|
||||
path: target/surefire-reports/
|
||||
- name: Upload Test Report ${{ matrix.java }}
|
||||
if: ${{ always() }}
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: Test Report ${{ matrix.java }}
|
||||
path: target/site/
|
||||
- name: Package Jar ${{ matrix.java }}
|
||||
run: mvn clean package -D maven.compiler.source=${{ matrix.java }} -D maven.compiler.target=${{ matrix.java }} -D maven.test.skip=true -D maven.site.skip=true
|
||||
- name: Upload Package Results ${{ matrix.java }}
|
||||
if: ${{ always() }}
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: Package Jar ${{ matrix.java }}
|
||||
path: target/*.jar
|
||||
|
||||
2
.gitignore
vendored
2
.gitignore
vendored
@@ -1,6 +1,8 @@
|
||||
# ignore eclipse project files
|
||||
.project
|
||||
.classpath
|
||||
# ignore vscode files
|
||||
.vscode
|
||||
# ignore Intellij Idea project files
|
||||
.idea
|
||||
*.iml
|
||||
|
||||
37
README.md
37
README.md
@@ -7,8 +7,10 @@ JSON in Java [package org.json]
|
||||
===============================
|
||||
|
||||
[](https://mvnrepository.com/artifact/org.json/json)
|
||||
[](https://github.com/stleary/JSON-java/actions/workflows/pipeline.yml)
|
||||
[](https://github.com/stleary/JSON-java/actions/workflows/codeql-analysis.yml)
|
||||
|
||||
**[Click here if you just want the latest release jar file.](https://search.maven.org/remotecontent?filepath=org/json/json/20231013/json-20231013.jar)**
|
||||
**[Click here if you just want the latest release jar file.](https://search.maven.org/remotecontent?filepath=org/json/json/20240205/json-20240303.jar)**
|
||||
|
||||
|
||||
# Overview
|
||||
@@ -24,7 +26,8 @@ Project goals include:
|
||||
* No external dependencies
|
||||
* Fast execution and low memory footprint
|
||||
* Maintain backward compatibility
|
||||
* Designed and tested to use on Java versions 1.6 - 1.11
|
||||
* Designed and tested to use on Java versions 1.6 - 21
|
||||
|
||||
|
||||
The files in this package implement JSON encoders and decoders. The package can also convert between JSON and XML, HTTP headers, Cookies, and CDL.
|
||||
|
||||
@@ -41,56 +44,56 @@ The org.json package can be built from the command line, Maven, and Gradle. The
|
||||
**Building from the command line**
|
||||
|
||||
*Build the class files from the package root directory src/main/java*
|
||||
````
|
||||
```shell
|
||||
javac org/json/*.java
|
||||
````
|
||||
```
|
||||
|
||||
*Create the jar file in the current directory*
|
||||
````
|
||||
```shell
|
||||
jar cf json-java.jar org/json/*.class
|
||||
````
|
||||
```
|
||||
|
||||
*Compile a program that uses the jar (see example code below)*
|
||||
````
|
||||
```shell
|
||||
javac -cp .;json-java.jar Test.java (Windows)
|
||||
javac -cp .:json-java.jar Test.java (Unix Systems)
|
||||
````
|
||||
```
|
||||
|
||||
*Test file contents*
|
||||
|
||||
````
|
||||
```java
|
||||
import org.json.JSONObject;
|
||||
public class Test {
|
||||
public static void main(String args[]){
|
||||
JSONObject jo = new JSONObject("{ \"abc\" : \"def\" }");
|
||||
System.out.println(jo.toString());
|
||||
System.out.println(jo);
|
||||
}
|
||||
}
|
||||
````
|
||||
```
|
||||
|
||||
*Execute the Test file*
|
||||
````
|
||||
```shell
|
||||
java -cp .;json-java.jar Test (Windows)
|
||||
java -cp .:json-java.jar Test (Unix Systems)
|
||||
````
|
||||
```
|
||||
|
||||
*Expected output*
|
||||
|
||||
````
|
||||
```json
|
||||
{"abc":"def"}
|
||||
````
|
||||
```
|
||||
|
||||
|
||||
**Tools to build the package and execute the unit tests**
|
||||
|
||||
Execute the test suite with Maven:
|
||||
```
|
||||
```shell
|
||||
mvn clean test
|
||||
```
|
||||
|
||||
Execute the test suite with Gradlew:
|
||||
|
||||
```
|
||||
```shell
|
||||
gradlew clean build test
|
||||
```
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ repositories {
|
||||
|
||||
dependencies {
|
||||
testImplementation 'junit:junit:4.13.2'
|
||||
testImplementation 'com.jayway.jsonpath:json-path:2.1.0'
|
||||
testImplementation 'com.jayway.jsonpath:json-path:2.4.0'
|
||||
testImplementation 'org.mockito:mockito-core:4.2.0'
|
||||
}
|
||||
|
||||
|
||||
@@ -5,6 +5,10 @@ and artifactId "json". For example:
|
||||
[https://search.maven.org/search?q=g:org.json%20AND%20a:json&core=gav](https://search.maven.org/search?q=g:org.json%20AND%20a:json&core=gav)
|
||||
|
||||
~~~
|
||||
20240303 Revert optLong/getLong changes, and recent commits.
|
||||
|
||||
20240205 Recent commits.
|
||||
|
||||
20231013 First release with minimum Java version 1.8. Recent commits, including fixes for CVE-2023-5072.
|
||||
|
||||
20230618 Final release with Java 1.6 compatibility. Future releases will require Java 1.8 or greater.
|
||||
|
||||
57
pom.xml
57
pom.xml
@@ -3,7 +3,7 @@
|
||||
|
||||
<groupId>org.json</groupId>
|
||||
<artifactId>json</artifactId>
|
||||
<version>20231013</version>
|
||||
<version>20240303</version>
|
||||
<packaging>bundle</packaging>
|
||||
|
||||
<name>JSON in Java</name>
|
||||
@@ -21,12 +21,6 @@
|
||||
</description>
|
||||
<url>https://github.com/douglascrockford/JSON-java</url>
|
||||
|
||||
<parent>
|
||||
<groupId>org.sonatype.oss</groupId>
|
||||
<artifactId>oss-parent</artifactId>
|
||||
<version>9</version>
|
||||
</parent>
|
||||
|
||||
<scm>
|
||||
<url>https://github.com/douglascrockford/JSON-java.git</url>
|
||||
<connection>scm:git:git://github.com/douglascrockford/JSON-java.git</connection>
|
||||
@@ -53,6 +47,19 @@
|
||||
</properties>
|
||||
|
||||
|
||||
<distributionManagement>
|
||||
<repository>
|
||||
<id>ossrh</id>
|
||||
<name>Central Repository OSSRH</name>
|
||||
<url>https://oss.sonatype.org/service/local/staging/deploy/maven2/</url>
|
||||
</repository>
|
||||
<snapshotRepository>
|
||||
<id>ossrh</id>
|
||||
<url>https://oss.sonatype.org/content/repositories/snapshots</url>
|
||||
</snapshotRepository>
|
||||
</distributionManagement>
|
||||
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
@@ -63,7 +70,7 @@
|
||||
<dependency>
|
||||
<groupId>com.jayway.jsonpath</groupId>
|
||||
<artifactId>json-path</artifactId>
|
||||
<version>2.1.0</version>
|
||||
<version>2.4.0</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
@@ -97,6 +104,9 @@
|
||||
<configuration>
|
||||
<source>1.8</source>
|
||||
<target>1.8</target>
|
||||
<compilerArgs>
|
||||
<arg>-Xlint:unchecked</arg>
|
||||
</compilerArgs>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
@@ -159,17 +169,34 @@
|
||||
<autoReleaseAfterClose>false</autoReleaseAfterClose>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.moditect</groupId>
|
||||
<artifactId>moditect-maven-plugin</artifactId>
|
||||
<version>1.0.0.Final</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>add-module-infos</id>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>add-module-info</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<jvmVersion>9</jvmVersion>
|
||||
<module>
|
||||
<moduleInfoSource>
|
||||
module org.json {
|
||||
exports org.json;
|
||||
}
|
||||
</moduleInfoSource>
|
||||
</module>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-jar-plugin</artifactId>
|
||||
<version>3.3.0</version>
|
||||
<configuration>
|
||||
<archive>
|
||||
<manifestEntries>
|
||||
<Automatic-Module-Name>org.json</Automatic-Module-Name>
|
||||
</manifestEntries>
|
||||
</archive>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
@@ -5,15 +5,15 @@ Public Domain.
|
||||
*/
|
||||
|
||||
/**
|
||||
* This provides static methods to convert comma delimited text into a
|
||||
* JSONArray, and to convert a JSONArray into comma delimited text. Comma
|
||||
* This provides static methods to convert comma (or otherwise) delimited text into a
|
||||
* JSONArray, and to convert a JSONArray into comma (or otherwise) delimited text. Comma
|
||||
* delimited text is a very popular format for data interchange. It is
|
||||
* understood by most database, spreadsheet, and organizer programs.
|
||||
* <p>
|
||||
* Each row of text represents a row in a table or a data record. Each row
|
||||
* ends with a NEWLINE character. Each row contains one or more values.
|
||||
* Values are separated by commas. A value can contain any character except
|
||||
* for comma, unless is is wrapped in single quotes or double quotes.
|
||||
* for comma, unless it is wrapped in single quotes or double quotes.
|
||||
* <p>
|
||||
* The first row usually contains the names of the columns.
|
||||
* <p>
|
||||
@@ -25,25 +25,30 @@ Public Domain.
|
||||
*/
|
||||
public class CDL {
|
||||
|
||||
/**
|
||||
* Constructs a new CDL object.
|
||||
*/
|
||||
public CDL() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the next value. The value can be wrapped in quotes. The value can
|
||||
* be empty.
|
||||
* @param x A JSONTokener of the source text.
|
||||
* @param delimiter used in the file
|
||||
* @return The value string, or null if empty.
|
||||
* @throws JSONException if the quoted string is badly formed.
|
||||
*/
|
||||
private static String getValue(JSONTokener x) throws JSONException {
|
||||
private static String getValue(JSONTokener x, char delimiter) throws JSONException {
|
||||
char c;
|
||||
char q;
|
||||
StringBuilder sb;
|
||||
do {
|
||||
c = x.next();
|
||||
} while (c == ' ' || c == '\t');
|
||||
switch (c) {
|
||||
case 0:
|
||||
if (c == 0) {
|
||||
return null;
|
||||
case '"':
|
||||
case '\'':
|
||||
} else if (c == '"' || c == '\'') {
|
||||
q = c;
|
||||
sb = new StringBuilder();
|
||||
for (;;) {
|
||||
@@ -51,9 +56,9 @@ public class CDL {
|
||||
if (c == q) {
|
||||
//Handle escaped double-quote
|
||||
char nextC = x.next();
|
||||
if(nextC != '\"') {
|
||||
if (nextC != '\"') {
|
||||
// if our quote was the end of the file, don't step
|
||||
if(nextC > 0) {
|
||||
if (nextC > 0) {
|
||||
x.back();
|
||||
}
|
||||
break;
|
||||
@@ -65,13 +70,12 @@ public class CDL {
|
||||
sb.append(c);
|
||||
}
|
||||
return sb.toString();
|
||||
case ',':
|
||||
} else if (c == delimiter) {
|
||||
x.back();
|
||||
return "";
|
||||
default:
|
||||
x.back();
|
||||
return x.nextTo(',');
|
||||
}
|
||||
x.back();
|
||||
return x.nextTo(delimiter);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -81,17 +85,28 @@ public class CDL {
|
||||
* @throws JSONException if a called function fails
|
||||
*/
|
||||
public static JSONArray rowToJSONArray(JSONTokener x) throws JSONException {
|
||||
return rowToJSONArray(x, ',');
|
||||
}
|
||||
|
||||
/**
|
||||
* Produce a JSONArray of strings from a row of comma delimited values.
|
||||
* @param x A JSONTokener of the source text.
|
||||
* @param delimiter custom delimiter char
|
||||
* @return A JSONArray of strings.
|
||||
* @throws JSONException if a called function fails
|
||||
*/
|
||||
public static JSONArray rowToJSONArray(JSONTokener x, char delimiter) throws JSONException {
|
||||
JSONArray ja = new JSONArray();
|
||||
for (;;) {
|
||||
String value = getValue(x);
|
||||
String value = getValue(x,delimiter);
|
||||
char c = x.next();
|
||||
if (value == null ||
|
||||
(ja.length() == 0 && value.length() == 0 && c != ',')) {
|
||||
(ja.length() == 0 && value.length() == 0 && c != delimiter)) {
|
||||
return null;
|
||||
}
|
||||
ja.put(value);
|
||||
for (;;) {
|
||||
if (c == ',') {
|
||||
if (c == delimiter) {
|
||||
break;
|
||||
}
|
||||
if (c != ' ') {
|
||||
@@ -116,9 +131,23 @@ public class CDL {
|
||||
* @return A JSONObject combining the names and values.
|
||||
* @throws JSONException if a called function fails
|
||||
*/
|
||||
public static JSONObject rowToJSONObject(JSONArray names, JSONTokener x)
|
||||
throws JSONException {
|
||||
JSONArray ja = rowToJSONArray(x);
|
||||
public static JSONObject rowToJSONObject(JSONArray names, JSONTokener x) throws JSONException {
|
||||
return rowToJSONObject(names, x, ',');
|
||||
}
|
||||
|
||||
/**
|
||||
* Produce a JSONObject from a row of comma delimited text, using a
|
||||
* parallel JSONArray of strings to provides the names of the elements.
|
||||
* @param names A JSONArray of names. This is commonly obtained from the
|
||||
* first row of a comma delimited text file using the rowToJSONArray
|
||||
* method.
|
||||
* @param x A JSONTokener of the source text.
|
||||
* @param delimiter custom delimiter char
|
||||
* @return A JSONObject combining the names and values.
|
||||
* @throws JSONException if a called function fails
|
||||
*/
|
||||
public static JSONObject rowToJSONObject(JSONArray names, JSONTokener x, char delimiter) throws JSONException {
|
||||
JSONArray ja = rowToJSONArray(x, delimiter);
|
||||
return ja != null ? ja.toJSONObject(names) : null;
|
||||
}
|
||||
|
||||
@@ -130,15 +159,27 @@ public class CDL {
|
||||
* @return A string ending in NEWLINE.
|
||||
*/
|
||||
public static String rowToString(JSONArray ja) {
|
||||
return rowToString(ja, ',');
|
||||
}
|
||||
|
||||
/**
|
||||
* Produce a comma delimited text row from a JSONArray. Values containing
|
||||
* the comma character will be quoted. Troublesome characters may be
|
||||
* removed.
|
||||
* @param ja A JSONArray of strings.
|
||||
* @param delimiter custom delimiter char
|
||||
* @return A string ending in NEWLINE.
|
||||
*/
|
||||
public static String rowToString(JSONArray ja, char delimiter) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (int i = 0; i < ja.length(); i += 1) {
|
||||
if (i > 0) {
|
||||
sb.append(',');
|
||||
sb.append(delimiter);
|
||||
}
|
||||
Object object = ja.opt(i);
|
||||
if (object != null) {
|
||||
String string = object.toString();
|
||||
if (string.length() > 0 && (string.indexOf(',') >= 0 ||
|
||||
if (string.length() > 0 && (string.indexOf(delimiter) >= 0 ||
|
||||
string.indexOf('\n') >= 0 || string.indexOf('\r') >= 0 ||
|
||||
string.indexOf(0) >= 0 || string.charAt(0) == '"')) {
|
||||
sb.append('"');
|
||||
@@ -167,7 +208,19 @@ public class CDL {
|
||||
* @throws JSONException if a called function fails
|
||||
*/
|
||||
public static JSONArray toJSONArray(String string) throws JSONException {
|
||||
return toJSONArray(new JSONTokener(string));
|
||||
return toJSONArray(string, ',');
|
||||
}
|
||||
|
||||
/**
|
||||
* Produce a JSONArray of JSONObjects from a comma delimited text string,
|
||||
* using the first row as a source of names.
|
||||
* @param string The comma delimited text.
|
||||
* @param delimiter custom delimiter char
|
||||
* @return A JSONArray of JSONObjects.
|
||||
* @throws JSONException if a called function fails
|
||||
*/
|
||||
public static JSONArray toJSONArray(String string, char delimiter) throws JSONException {
|
||||
return toJSONArray(new JSONTokener(string), delimiter);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -178,7 +231,19 @@ public class CDL {
|
||||
* @throws JSONException if a called function fails
|
||||
*/
|
||||
public static JSONArray toJSONArray(JSONTokener x) throws JSONException {
|
||||
return toJSONArray(rowToJSONArray(x), x);
|
||||
return toJSONArray(x, ',');
|
||||
}
|
||||
|
||||
/**
|
||||
* Produce a JSONArray of JSONObjects from a comma delimited text string,
|
||||
* using the first row as a source of names.
|
||||
* @param x The JSONTokener containing the comma delimited text.
|
||||
* @param delimiter custom delimiter char
|
||||
* @return A JSONArray of JSONObjects.
|
||||
* @throws JSONException if a called function fails
|
||||
*/
|
||||
public static JSONArray toJSONArray(JSONTokener x, char delimiter) throws JSONException {
|
||||
return toJSONArray(rowToJSONArray(x, delimiter), x, delimiter);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -189,9 +254,21 @@ public class CDL {
|
||||
* @return A JSONArray of JSONObjects.
|
||||
* @throws JSONException if a called function fails
|
||||
*/
|
||||
public static JSONArray toJSONArray(JSONArray names, String string)
|
||||
throws JSONException {
|
||||
return toJSONArray(names, new JSONTokener(string));
|
||||
public static JSONArray toJSONArray(JSONArray names, String string) throws JSONException {
|
||||
return toJSONArray(names, string, ',');
|
||||
}
|
||||
|
||||
/**
|
||||
* Produce a JSONArray of JSONObjects from a comma delimited text string
|
||||
* using a supplied JSONArray as the source of element names.
|
||||
* @param names A JSONArray of strings.
|
||||
* @param string The comma delimited text.
|
||||
* @param delimiter custom delimiter char
|
||||
* @return A JSONArray of JSONObjects.
|
||||
* @throws JSONException if a called function fails
|
||||
*/
|
||||
public static JSONArray toJSONArray(JSONArray names, String string, char delimiter) throws JSONException {
|
||||
return toJSONArray(names, new JSONTokener(string), delimiter);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -202,14 +279,26 @@ public class CDL {
|
||||
* @return A JSONArray of JSONObjects.
|
||||
* @throws JSONException if a called function fails
|
||||
*/
|
||||
public static JSONArray toJSONArray(JSONArray names, JSONTokener x)
|
||||
throws JSONException {
|
||||
public static JSONArray toJSONArray(JSONArray names, JSONTokener x) throws JSONException {
|
||||
return toJSONArray(names, x, ',');
|
||||
}
|
||||
|
||||
/**
|
||||
* Produce a JSONArray of JSONObjects from a comma delimited text string
|
||||
* using a supplied JSONArray as the source of element names.
|
||||
* @param names A JSONArray of strings.
|
||||
* @param x A JSONTokener of the source text.
|
||||
* @param delimiter custom delimiter char
|
||||
* @return A JSONArray of JSONObjects.
|
||||
* @throws JSONException if a called function fails
|
||||
*/
|
||||
public static JSONArray toJSONArray(JSONArray names, JSONTokener x, char delimiter) throws JSONException {
|
||||
if (names == null || names.length() == 0) {
|
||||
return null;
|
||||
}
|
||||
JSONArray ja = new JSONArray();
|
||||
for (;;) {
|
||||
JSONObject jo = rowToJSONObject(names, x);
|
||||
JSONObject jo = rowToJSONObject(names, x, delimiter);
|
||||
if (jo == null) {
|
||||
break;
|
||||
}
|
||||
@@ -231,11 +320,24 @@ public class CDL {
|
||||
* @throws JSONException if a called function fails
|
||||
*/
|
||||
public static String toString(JSONArray ja) throws JSONException {
|
||||
return toString(ja, ',');
|
||||
}
|
||||
|
||||
/**
|
||||
* Produce a comma delimited text from a JSONArray of JSONObjects. The
|
||||
* first row will be a list of names obtained by inspecting the first
|
||||
* JSONObject.
|
||||
* @param ja A JSONArray of JSONObjects.
|
||||
* @param delimiter custom delimiter char
|
||||
* @return A comma delimited text.
|
||||
* @throws JSONException if a called function fails
|
||||
*/
|
||||
public static String toString(JSONArray ja, char delimiter) throws JSONException {
|
||||
JSONObject jo = ja.optJSONObject(0);
|
||||
if (jo != null) {
|
||||
JSONArray names = jo.names();
|
||||
if (names != null) {
|
||||
return rowToString(names) + toString(names, ja);
|
||||
return rowToString(names, delimiter) + toString(names, ja, delimiter);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
@@ -250,8 +352,21 @@ public class CDL {
|
||||
* @return A comma delimited text.
|
||||
* @throws JSONException if a called function fails
|
||||
*/
|
||||
public static String toString(JSONArray names, JSONArray ja)
|
||||
throws JSONException {
|
||||
public static String toString(JSONArray names, JSONArray ja) throws JSONException {
|
||||
return toString(names, ja, ',');
|
||||
}
|
||||
|
||||
/**
|
||||
* Produce a comma delimited text from a JSONArray of JSONObjects using
|
||||
* a provided list of names. The list of names is not included in the
|
||||
* output.
|
||||
* @param names A JSONArray of strings.
|
||||
* @param ja A JSONArray of JSONObjects.
|
||||
* @param delimiter custom delimiter char
|
||||
* @return A comma delimited text.
|
||||
* @throws JSONException if a called function fails
|
||||
*/
|
||||
public static String toString(JSONArray names, JSONArray ja, char delimiter) throws JSONException {
|
||||
if (names == null || names.length() == 0) {
|
||||
return null;
|
||||
}
|
||||
@@ -259,7 +374,7 @@ public class CDL {
|
||||
for (int i = 0; i < ja.length(); i += 1) {
|
||||
JSONObject jo = ja.optJSONObject(i);
|
||||
if (jo != null) {
|
||||
sb.append(rowToString(jo.toJSONArray(names)));
|
||||
sb.append(rowToString(jo.toJSONArray(names), delimiter));
|
||||
}
|
||||
}
|
||||
return sb.toString();
|
||||
|
||||
@@ -15,6 +15,12 @@ Public Domain.
|
||||
*/
|
||||
public class Cookie {
|
||||
|
||||
/**
|
||||
* Constructs a new Cookie object.
|
||||
*/
|
||||
public Cookie() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Produce a copy of a string in which the characters '+', '%', '=', ';'
|
||||
* and control characters are replaced with "%hh". This is a gentle form
|
||||
|
||||
@@ -11,6 +11,12 @@ Public Domain.
|
||||
*/
|
||||
public class CookieList {
|
||||
|
||||
/**
|
||||
* Constructs a new CookieList object.
|
||||
*/
|
||||
public CookieList() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a cookie list into a JSONObject. A cookie list is a sequence
|
||||
* of name/value pairs. The names are separated from the values by '='.
|
||||
@@ -46,19 +52,19 @@ public class CookieList {
|
||||
* @throws JSONException if a called function fails
|
||||
*/
|
||||
public static String toString(JSONObject jo) throws JSONException {
|
||||
boolean b = false;
|
||||
boolean isEndOfPair = false;
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
// Don't use the new entrySet API to maintain Android support
|
||||
for (final String key : jo.keySet()) {
|
||||
final Object value = jo.opt(key);
|
||||
if (!JSONObject.NULL.equals(value)) {
|
||||
if (b) {
|
||||
if (isEndOfPair) {
|
||||
sb.append(';');
|
||||
}
|
||||
sb.append(Cookie.escape(key));
|
||||
sb.append("=");
|
||||
sb.append(Cookie.escape(value.toString()));
|
||||
b = true;
|
||||
isEndOfPair = true;
|
||||
}
|
||||
}
|
||||
return sb.toString();
|
||||
|
||||
@@ -13,6 +13,12 @@ import java.util.Locale;
|
||||
*/
|
||||
public class HTTP {
|
||||
|
||||
/**
|
||||
* Constructs a new HTTP object.
|
||||
*/
|
||||
public HTTP() {
|
||||
}
|
||||
|
||||
/** Carriage return/line feed. */
|
||||
public static final String CRLF = "\r\n";
|
||||
|
||||
|
||||
@@ -149,11 +149,40 @@ public class JSONArray implements Iterable<Object> {
|
||||
* A Collection.
|
||||
*/
|
||||
public JSONArray(Collection<?> collection) {
|
||||
this(collection, 0, new JSONParserConfiguration());
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a JSONArray from a Collection.
|
||||
*
|
||||
* @param collection
|
||||
* A Collection.
|
||||
* @param jsonParserConfiguration
|
||||
* Configuration object for the JSON parser
|
||||
*/
|
||||
public JSONArray(Collection<?> collection, JSONParserConfiguration jsonParserConfiguration) {
|
||||
this(collection, 0, jsonParserConfiguration);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a JSONArray from a collection with recursion depth.
|
||||
*
|
||||
* @param collection
|
||||
* A Collection.
|
||||
* @param recursionDepth
|
||||
* Variable for tracking the count of nested object creations.
|
||||
* @param jsonParserConfiguration
|
||||
* Configuration object for the JSON parser
|
||||
*/
|
||||
JSONArray(Collection<?> collection, int recursionDepth, JSONParserConfiguration jsonParserConfiguration) {
|
||||
if (recursionDepth > jsonParserConfiguration.getMaxNestingDepth()) {
|
||||
throw new JSONException("JSONArray has reached recursion depth limit of " + jsonParserConfiguration.getMaxNestingDepth());
|
||||
}
|
||||
if (collection == null) {
|
||||
this.myArrayList = new ArrayList<Object>();
|
||||
} else {
|
||||
this.myArrayList = new ArrayList<Object>(collection.size());
|
||||
this.addAll(collection, true);
|
||||
this.addAll(collection, true, recursionDepth, jsonParserConfiguration);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -205,7 +234,7 @@ public class JSONArray implements Iterable<Object> {
|
||||
throw new JSONException(
|
||||
"JSONArray initial value should be a string or collection or array.");
|
||||
}
|
||||
this.addAll(array, true);
|
||||
this.addAll(array, true, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1330,7 +1359,8 @@ public class JSONArray implements Iterable<Object> {
|
||||
* The subscript.
|
||||
* @param value
|
||||
* The Map value.
|
||||
* @return this.
|
||||
* @return
|
||||
* reference to self
|
||||
* @throws JSONException
|
||||
* If the index is negative or if the value is an invalid
|
||||
* number.
|
||||
@@ -1338,7 +1368,27 @@ public class JSONArray implements Iterable<Object> {
|
||||
* If a key in the map is <code>null</code>
|
||||
*/
|
||||
public JSONArray put(int index, Map<?, ?> value) throws JSONException {
|
||||
this.put(index, new JSONObject(value));
|
||||
this.put(index, new JSONObject(value, new JSONParserConfiguration()));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Put a value in the JSONArray, where the value will be a JSONObject that
|
||||
* is produced from a Map.
|
||||
*
|
||||
* @param index
|
||||
* The subscript
|
||||
* @param value
|
||||
* The Map value.
|
||||
* @param jsonParserConfiguration
|
||||
* Configuration object for the JSON parser
|
||||
* @return reference to self
|
||||
* @throws JSONException
|
||||
* If the index is negative or if the value is an invalid
|
||||
* number.
|
||||
*/
|
||||
public JSONArray put(int index, Map<?, ?> value, JSONParserConfiguration jsonParserConfiguration) throws JSONException {
|
||||
this.put(index, new JSONObject(value, jsonParserConfiguration));
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -1779,13 +1829,14 @@ public class JSONArray implements Iterable<Object> {
|
||||
* @param wrap
|
||||
* {@code true} to call {@link JSONObject#wrap(Object)} for each item,
|
||||
* {@code false} to add the items directly
|
||||
*
|
||||
* @param recursionDepth
|
||||
* Variable for tracking the count of nested object creations.
|
||||
*/
|
||||
private void addAll(Collection<?> collection, boolean wrap) {
|
||||
private void addAll(Collection<?> collection, boolean wrap, int recursionDepth, JSONParserConfiguration jsonParserConfiguration) {
|
||||
this.myArrayList.ensureCapacity(this.myArrayList.size() + collection.size());
|
||||
if (wrap) {
|
||||
for (Object o: collection){
|
||||
this.put(JSONObject.wrap(o));
|
||||
this.put(JSONObject.wrap(o, recursionDepth + 1, jsonParserConfiguration));
|
||||
}
|
||||
} else {
|
||||
for (Object o: collection){
|
||||
@@ -1814,7 +1865,24 @@ public class JSONArray implements Iterable<Object> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Add an array's elements to the JSONArray.
|
||||
*
|
||||
* @param array
|
||||
* Array. If the parameter passed is null, or not an array,
|
||||
* JSONArray, Collection, or Iterable, an exception will be
|
||||
* thrown.
|
||||
* @param wrap
|
||||
* {@code true} to call {@link JSONObject#wrap(Object)} for each item,
|
||||
* {@code false} to add the items directly
|
||||
* @throws JSONException
|
||||
* If not an array or if an array value is non-finite number.
|
||||
*/
|
||||
private void addAll(Object array, boolean wrap) throws JSONException {
|
||||
this.addAll(array, wrap, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an array's elements to the JSONArray.
|
||||
*
|
||||
@@ -1823,21 +1891,40 @@ public class JSONArray implements Iterable<Object> {
|
||||
* JSONArray, Collection, or Iterable, an exception will be
|
||||
* thrown.
|
||||
* @param wrap
|
||||
* {@code true} to call {@link JSONObject#wrap(Object)} for each item,
|
||||
* {@code false} to add the items directly
|
||||
* @param recursionDepth
|
||||
* Variable for tracking the count of nested object creations.
|
||||
*/
|
||||
private void addAll(Object array, boolean wrap, int recursionDepth) {
|
||||
addAll(array, wrap, recursionDepth, new JSONParserConfiguration());
|
||||
}
|
||||
/**
|
||||
* Add an array's elements to the JSONArray.
|
||||
*`
|
||||
* @param array
|
||||
* Array. If the parameter passed is null, or not an array,
|
||||
* JSONArray, Collection, or Iterable, an exception will be
|
||||
* thrown.
|
||||
* @param wrap
|
||||
* {@code true} to call {@link JSONObject#wrap(Object)} for each item,
|
||||
* {@code false} to add the items directly
|
||||
*
|
||||
* @param recursionDepth
|
||||
* Variable for tracking the count of nested object creations.
|
||||
* @param jsonParserConfiguration
|
||||
* Variable to pass parser custom configuration for json parsing.
|
||||
* @throws JSONException
|
||||
* If not an array or if an array value is non-finite number.
|
||||
* @throws NullPointerException
|
||||
* Thrown if the array parameter is null.
|
||||
*/
|
||||
private void addAll(Object array, boolean wrap) throws JSONException {
|
||||
private void addAll(Object array, boolean wrap, int recursionDepth, JSONParserConfiguration jsonParserConfiguration) throws JSONException {
|
||||
if (array.getClass().isArray()) {
|
||||
int length = Array.getLength(array);
|
||||
this.myArrayList.ensureCapacity(this.myArrayList.size() + length);
|
||||
if (wrap) {
|
||||
for (int i = 0; i < length; i += 1) {
|
||||
this.put(JSONObject.wrap(Array.get(array, i)));
|
||||
this.put(JSONObject.wrap(Array.get(array, i), recursionDepth + 1, jsonParserConfiguration));
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; i < length; i += 1) {
|
||||
@@ -1850,7 +1937,7 @@ public class JSONArray implements Iterable<Object> {
|
||||
// JSONArray
|
||||
this.myArrayList.addAll(((JSONArray)array).myArrayList);
|
||||
} else if (array instanceof Collection) {
|
||||
this.addAll((Collection<?>)array, wrap);
|
||||
this.addAll((Collection<?>)array, wrap, recursionDepth);
|
||||
} else if (array instanceof Iterable) {
|
||||
this.addAll((Iterable<?>)array, wrap);
|
||||
} else {
|
||||
|
||||
@@ -13,6 +13,13 @@ Public Domain.
|
||||
* @version 2016-01-30
|
||||
*/
|
||||
public class JSONML {
|
||||
|
||||
/**
|
||||
* Constructs a new JSONML object.
|
||||
*/
|
||||
public JSONML() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse XML values and store them in a JSONArray.
|
||||
* @param x The XMLTokener containing the source string.
|
||||
|
||||
@@ -55,11 +55,13 @@ public class JSONMLParserConfiguration extends ParserConfiguration {
|
||||
);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public JSONMLParserConfiguration withKeepStrings(final boolean newVal) {
|
||||
return super.withKeepStrings(newVal);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public JSONMLParserConfiguration withMaxNestingDepth(int maxNestingDepth) {
|
||||
return super.withMaxNestingDepth(maxNestingDepth);
|
||||
|
||||
@@ -145,6 +145,11 @@ public class JSONObject {
|
||||
*/
|
||||
private final Map<String, Object> map;
|
||||
|
||||
/**
|
||||
* Retrieves the type of the underlying Map in this class.
|
||||
*
|
||||
* @return The class object representing the type of the underlying Map.
|
||||
*/
|
||||
public Class<? extends Map> getMapType() {
|
||||
return map.getClass();
|
||||
}
|
||||
@@ -273,6 +278,30 @@ public class JSONObject {
|
||||
* If a key in the map is <code>null</code>
|
||||
*/
|
||||
public JSONObject(Map<?, ?> m) {
|
||||
this(m, 0, new JSONParserConfiguration());
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a JSONObject from a Map with custom json parse configurations.
|
||||
*
|
||||
* @param m
|
||||
* A map object that can be used to initialize the contents of
|
||||
* the JSONObject.
|
||||
* @param jsonParserConfiguration
|
||||
* Variable to pass parser custom configuration for json parsing.
|
||||
*/
|
||||
public JSONObject(Map<?, ?> m, JSONParserConfiguration jsonParserConfiguration) {
|
||||
this(m, 0, jsonParserConfiguration);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a JSONObject from a map with recursion depth.
|
||||
*
|
||||
*/
|
||||
private JSONObject(Map<?, ?> m, int recursionDepth, JSONParserConfiguration jsonParserConfiguration) {
|
||||
if (recursionDepth > jsonParserConfiguration.getMaxNestingDepth()) {
|
||||
throw new JSONException("JSONObject has reached recursion depth limit of " + jsonParserConfiguration.getMaxNestingDepth());
|
||||
}
|
||||
if (m == null) {
|
||||
this.map = new HashMap<String, Object>();
|
||||
} else {
|
||||
@@ -284,7 +313,7 @@ public class JSONObject {
|
||||
final Object value = e.getValue();
|
||||
if (value != null) {
|
||||
testValidity(value);
|
||||
this.map.put(String.valueOf(e.getKey()), wrap(value));
|
||||
this.map.put(String.valueOf(e.getKey()), wrap(value, recursionDepth + 1, jsonParserConfiguration));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -342,7 +371,6 @@ public class JSONObject {
|
||||
* @JSONPropertyIgnore
|
||||
* public String getName() { return this.name; }
|
||||
* </pre>
|
||||
* <p>
|
||||
*
|
||||
* @param bean
|
||||
* An object that has getter methods that should be used to make
|
||||
@@ -1838,6 +1866,10 @@ public class JSONObject {
|
||||
}
|
||||
}
|
||||
|
||||
//If the superclass is Object, no annotations will be found any more
|
||||
if (c.getSuperclass().equals(Object.class))
|
||||
return null;
|
||||
|
||||
try {
|
||||
return getAnnotation(
|
||||
c.getSuperclass().getMethod(m.getName(), m.getParameterTypes()),
|
||||
@@ -1892,6 +1924,10 @@ public class JSONObject {
|
||||
}
|
||||
}
|
||||
|
||||
//If the superclass is Object, no annotations will be found any more
|
||||
if (c.getSuperclass().equals(Object.class))
|
||||
return -1;
|
||||
|
||||
try {
|
||||
int d = getAnnotationDepth(
|
||||
c.getSuperclass().getMethod(m.getName(), m.getParameterTypes()),
|
||||
@@ -2197,6 +2233,14 @@ public class JSONObject {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Quotes a string and appends the result to a given Writer.
|
||||
*
|
||||
* @param string The input string to be quoted.
|
||||
* @param w The Writer to which the quoted string will be appended.
|
||||
* @return The same Writer instance after appending the quoted string.
|
||||
* @throws IOException If an I/O error occurs while writing to the Writer.
|
||||
*/
|
||||
public static Writer quote(String string, Writer w) throws IOException {
|
||||
if (string == null || string.isEmpty()) {
|
||||
w.write("\"\"");
|
||||
@@ -2380,84 +2424,6 @@ public class JSONObject {
|
||||
|| val.indexOf('E') > -1 || "-0".equals(val);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a string to a number using the narrowest possible type. Possible
|
||||
* returns for this function are BigDecimal, Double, BigInteger, Long, and Integer.
|
||||
* When a Double is returned, it should always be a valid Double and not NaN or +-infinity.
|
||||
*
|
||||
* @param input value to convert
|
||||
* @return Number representation of the value.
|
||||
* @throws NumberFormatException thrown if the value is not a valid number. A public
|
||||
* caller should catch this and wrap it in a {@link JSONException} if applicable.
|
||||
*/
|
||||
protected static Number stringToNumber(final String input) throws NumberFormatException {
|
||||
String val = input;
|
||||
if (val.startsWith(".")){
|
||||
val = "0"+val;
|
||||
}
|
||||
if (val.startsWith("-.")){
|
||||
val = "-0."+val.substring(2);
|
||||
}
|
||||
char initial = val.charAt(0);
|
||||
if ((initial >= '0' && initial <= '9') || initial == '-' ) {
|
||||
// decimal representation
|
||||
if (isDecimalNotation(val)) {
|
||||
// Use a BigDecimal all the time so we keep the original
|
||||
// representation. BigDecimal doesn't support -0.0, ensure we
|
||||
// keep that by forcing a decimal.
|
||||
try {
|
||||
BigDecimal bd = new BigDecimal(val);
|
||||
if(initial == '-' && BigDecimal.ZERO.compareTo(bd)==0) {
|
||||
return Double.valueOf(-0.0);
|
||||
}
|
||||
return bd;
|
||||
} catch (NumberFormatException retryAsDouble) {
|
||||
// this is to support "Hex Floats" like this: 0x1.0P-1074
|
||||
try {
|
||||
Double d = Double.valueOf(val);
|
||||
if(d.isNaN() || d.isInfinite()) {
|
||||
throw new NumberFormatException("val ["+input+"] is not a valid number.");
|
||||
}
|
||||
return d;
|
||||
} catch (NumberFormatException ignore) {
|
||||
throw new NumberFormatException("val ["+input+"] is not a valid number.");
|
||||
}
|
||||
}
|
||||
}
|
||||
val = removeLeadingZerosOfNumber(input);
|
||||
initial = val.charAt(0);
|
||||
if(initial == '0' && val.length() > 1) {
|
||||
char at1 = val.charAt(1);
|
||||
if(at1 >= '0' && at1 <= '9') {
|
||||
throw new NumberFormatException("val ["+input+"] is not a valid number.");
|
||||
}
|
||||
} else if (initial == '-' && val.length() > 2) {
|
||||
char at1 = val.charAt(1);
|
||||
char at2 = val.charAt(2);
|
||||
if(at1 == '0' && at2 >= '0' && at2 <= '9') {
|
||||
throw new NumberFormatException("val ["+input+"] is not a valid number.");
|
||||
}
|
||||
}
|
||||
// integer representation.
|
||||
// This will narrow any values to the smallest reasonable Object representation
|
||||
// (Integer, Long, or BigInteger)
|
||||
|
||||
// BigInteger down conversion: We use a similar bitLength compare as
|
||||
// BigInteger#intValueExact uses. Increases GC, but objects hold
|
||||
// only what they need. i.e. Less runtime overhead if the value is
|
||||
// long lived.
|
||||
BigInteger bi = new BigInteger(val);
|
||||
if(bi.bitLength() <= 31){
|
||||
return Integer.valueOf(bi.intValue());
|
||||
}
|
||||
if(bi.bitLength() <= 63){
|
||||
return Long.valueOf(bi.longValue());
|
||||
}
|
||||
return bi;
|
||||
}
|
||||
throw new NumberFormatException("val ["+input+"] is not a valid number.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to convert a string into a number, boolean, or null. If the string
|
||||
* can't be converted, return the string.
|
||||
@@ -2491,7 +2457,8 @@ public class JSONObject {
|
||||
* produced, then the value will just be a string.
|
||||
*/
|
||||
|
||||
if (potentialNumber(string)) {
|
||||
char initial = string.charAt(0);
|
||||
if ((initial >= '0' && initial <= '9') || initial == '-') {
|
||||
try {
|
||||
return stringToNumber(string);
|
||||
} catch (Exception ignore) {
|
||||
@@ -2500,26 +2467,74 @@ public class JSONObject {
|
||||
return string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a string to a number using the narrowest possible type. Possible
|
||||
* returns for this function are BigDecimal, Double, BigInteger, Long, and Integer.
|
||||
* When a Double is returned, it should always be a valid Double and not NaN or +-infinity.
|
||||
*
|
||||
* @param val value to convert
|
||||
* @return Number representation of the value.
|
||||
* @throws NumberFormatException thrown if the value is not a valid number. A public
|
||||
* caller should catch this and wrap it in a {@link JSONException} if applicable.
|
||||
*/
|
||||
protected static Number stringToNumber(final String val) throws NumberFormatException {
|
||||
char initial = val.charAt(0);
|
||||
if ((initial >= '0' && initial <= '9') || initial == '-') {
|
||||
// decimal representation
|
||||
if (isDecimalNotation(val)) {
|
||||
// Use a BigDecimal all the time so we keep the original
|
||||
// representation. BigDecimal doesn't support -0.0, ensure we
|
||||
// keep that by forcing a decimal.
|
||||
try {
|
||||
BigDecimal bd = new BigDecimal(val);
|
||||
if(initial == '-' && BigDecimal.ZERO.compareTo(bd)==0) {
|
||||
return Double.valueOf(-0.0);
|
||||
}
|
||||
return bd;
|
||||
} catch (NumberFormatException retryAsDouble) {
|
||||
// this is to support "Hex Floats" like this: 0x1.0P-1074
|
||||
try {
|
||||
Double d = Double.valueOf(val);
|
||||
if(d.isNaN() || d.isInfinite()) {
|
||||
throw new NumberFormatException("val ["+val+"] is not a valid number.");
|
||||
}
|
||||
return d;
|
||||
} catch (NumberFormatException ignore) {
|
||||
throw new NumberFormatException("val ["+val+"] is not a valid number.");
|
||||
}
|
||||
}
|
||||
}
|
||||
// block items like 00 01 etc. Java number parsers treat these as Octal.
|
||||
if(initial == '0' && val.length() > 1) {
|
||||
char at1 = val.charAt(1);
|
||||
if(at1 >= '0' && at1 <= '9') {
|
||||
throw new NumberFormatException("val ["+val+"] is not a valid number.");
|
||||
}
|
||||
} else if (initial == '-' && val.length() > 2) {
|
||||
char at1 = val.charAt(1);
|
||||
char at2 = val.charAt(2);
|
||||
if(at1 == '0' && at2 >= '0' && at2 <= '9') {
|
||||
throw new NumberFormatException("val ["+val+"] is not a valid number.");
|
||||
}
|
||||
}
|
||||
// integer representation.
|
||||
// This will narrow any values to the smallest reasonable Object representation
|
||||
// (Integer, Long, or BigInteger)
|
||||
|
||||
private static boolean potentialNumber(String value){
|
||||
if (value == null || value.isEmpty()){
|
||||
return false;
|
||||
// BigInteger down conversion: We use a similar bitLength compare as
|
||||
// BigInteger#intValueExact uses. Increases GC, but objects hold
|
||||
// only what they need. i.e. Less runtime overhead if the value is
|
||||
// long lived.
|
||||
BigInteger bi = new BigInteger(val);
|
||||
if(bi.bitLength() <= 31){
|
||||
return Integer.valueOf(bi.intValue());
|
||||
}
|
||||
if(bi.bitLength() <= 63){
|
||||
return Long.valueOf(bi.longValue());
|
||||
}
|
||||
return bi;
|
||||
}
|
||||
return potentialPositiveNumberStartingAtIndex(value, (value.charAt(0)=='-'?1:0));
|
||||
}
|
||||
|
||||
private static boolean potentialPositiveNumberStartingAtIndex(String value,int index){
|
||||
if (index >= value.length()){
|
||||
return false;
|
||||
}
|
||||
return digitAtIndex(value, (value.charAt(index)=='.'?index+1:index));
|
||||
}
|
||||
|
||||
private static boolean digitAtIndex(String value, int index){
|
||||
if (index >= value.length()){
|
||||
return false;
|
||||
}
|
||||
return value.charAt(index) >= '0' && value.charAt(index) <= '9';
|
||||
throw new NumberFormatException("val ["+val+"] is not a valid number.");
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2660,7 +2675,31 @@ public class JSONObject {
|
||||
return wrap(object, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrap an object, if necessary. If the object is <code>null</code>, return the NULL
|
||||
* object. If it is an array or collection, wrap it in a JSONArray. If it is
|
||||
* a map, wrap it in a JSONObject. If it is a standard property (Double,
|
||||
* String, et al) then it is already wrapped. Otherwise, if it comes from
|
||||
* one of the java packages, turn it into a string. And if it doesn't, try
|
||||
* to wrap it in a JSONObject. If the wrapping fails, then null is returned.
|
||||
*
|
||||
* @param object
|
||||
* The object to wrap
|
||||
* @param recursionDepth
|
||||
* Variable for tracking the count of nested object creations.
|
||||
* @param jsonParserConfiguration
|
||||
* Variable to pass parser custom configuration for json parsing.
|
||||
* @return The wrapped value
|
||||
*/
|
||||
static Object wrap(Object object, int recursionDepth, JSONParserConfiguration jsonParserConfiguration) {
|
||||
return wrap(object, null, recursionDepth, jsonParserConfiguration);
|
||||
}
|
||||
|
||||
private static Object wrap(Object object, Set<Object> objectsRecord) {
|
||||
return wrap(object, objectsRecord, 0, new JSONParserConfiguration());
|
||||
}
|
||||
|
||||
private static Object wrap(Object object, Set<Object> objectsRecord, int recursionDepth, JSONParserConfiguration jsonParserConfiguration) {
|
||||
try {
|
||||
if (NULL.equals(object)) {
|
||||
return NULL;
|
||||
@@ -2678,14 +2717,14 @@ public class JSONObject {
|
||||
|
||||
if (object instanceof Collection) {
|
||||
Collection<?> coll = (Collection<?>) object;
|
||||
return new JSONArray(coll);
|
||||
return new JSONArray(coll, recursionDepth, jsonParserConfiguration);
|
||||
}
|
||||
if (object.getClass().isArray()) {
|
||||
return new JSONArray(object);
|
||||
}
|
||||
if (object instanceof Map) {
|
||||
Map<?, ?> map = (Map<?, ?>) object;
|
||||
return new JSONObject(map);
|
||||
return new JSONObject(map, recursionDepth, jsonParserConfiguration);
|
||||
}
|
||||
Package objectPackage = object.getClass().getPackage();
|
||||
String objectPackageName = objectPackage != null ? objectPackage
|
||||
|
||||
26
src/main/java/org/json/JSONParserConfiguration.java
Normal file
26
src/main/java/org/json/JSONParserConfiguration.java
Normal file
@@ -0,0 +1,26 @@
|
||||
package org.json;
|
||||
|
||||
/**
|
||||
* Configuration object for the JSON parser. The configuration is immutable.
|
||||
*/
|
||||
public class JSONParserConfiguration extends ParserConfiguration {
|
||||
|
||||
/**
|
||||
* Configuration with the default values.
|
||||
*/
|
||||
public JSONParserConfiguration() {
|
||||
super();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected JSONParserConfiguration clone() {
|
||||
return new JSONParserConfiguration();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public JSONParserConfiguration withMaxNestingDepth(final int maxNestingDepth) {
|
||||
return super.withMaxNestingDepth(maxNestingDepth);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -42,6 +42,12 @@ public class JSONPointer {
|
||||
*/
|
||||
public static class Builder {
|
||||
|
||||
/**
|
||||
* Constructs a new Builder object.
|
||||
*/
|
||||
public Builder() {
|
||||
}
|
||||
|
||||
// Segments for the eventual JSONPointer string
|
||||
private final List<String> refTokens = new ArrayList<String>();
|
||||
|
||||
@@ -163,6 +169,12 @@ public class JSONPointer {
|
||||
//}
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new JSONPointer instance with the provided list of reference tokens.
|
||||
*
|
||||
* @param refTokens A list of strings representing the reference tokens for the JSON Pointer.
|
||||
* Each token identifies a step in the path to the targeted value.
|
||||
*/
|
||||
public JSONPointer(List<String> refTokens) {
|
||||
this.refTokens = new ArrayList<String>(refTokens);
|
||||
}
|
||||
|
||||
@@ -14,10 +14,21 @@ Public Domain.
|
||||
public class JSONPointerException extends JSONException {
|
||||
private static final long serialVersionUID = 8872944667561856751L;
|
||||
|
||||
/**
|
||||
* Constructs a new JSONPointerException with the specified error message.
|
||||
*
|
||||
* @param message The detail message describing the reason for the exception.
|
||||
*/
|
||||
public JSONPointerException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new JSONPointerException with the specified error message and cause.
|
||||
*
|
||||
* @param message The detail message describing the reason for the exception.
|
||||
* @param cause The cause of the exception.
|
||||
*/
|
||||
public JSONPointerException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ import java.lang.annotation.Target;
|
||||
@Target({METHOD})
|
||||
public @interface JSONPropertyName {
|
||||
/**
|
||||
* The value of the JSON property.
|
||||
* @return The name of the property as to be used in the JSON Object.
|
||||
*/
|
||||
String value();
|
||||
|
||||
@@ -525,6 +525,11 @@ public class JSONTokener {
|
||||
this.line + "]";
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the underlying reader, releasing any resources associated with it.
|
||||
*
|
||||
* @throws IOException If an I/O error occurs while closing the reader.
|
||||
*/
|
||||
public void close() throws IOException {
|
||||
if(reader!=null){
|
||||
reader.close();
|
||||
|
||||
@@ -29,11 +29,20 @@ public class ParserConfiguration {
|
||||
*/
|
||||
protected int maxNestingDepth;
|
||||
|
||||
/**
|
||||
* Constructs a new ParserConfiguration with default settings.
|
||||
*/
|
||||
public ParserConfiguration() {
|
||||
this.keepStrings = false;
|
||||
this.maxNestingDepth = DEFAULT_MAXIMUM_NESTING_DEPTH;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new ParserConfiguration with the specified settings.
|
||||
*
|
||||
* @param keepStrings A boolean indicating whether to preserve strings during parsing.
|
||||
* @param maxNestingDepth An integer representing the maximum allowed nesting depth.
|
||||
*/
|
||||
protected ParserConfiguration(final boolean keepStrings, final int maxNestingDepth) {
|
||||
this.keepStrings = keepStrings;
|
||||
this.maxNestingDepth = maxNestingDepth;
|
||||
@@ -71,9 +80,11 @@ public class ParserConfiguration {
|
||||
*
|
||||
* @param newVal
|
||||
* new value to use for the <code>keepStrings</code> configuration option.
|
||||
*
|
||||
* @param <T> the type of the configuration object
|
||||
*
|
||||
* @return The existing configuration will not be modified. A new configuration is returned.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T extends ParserConfiguration> T withKeepStrings(final boolean newVal) {
|
||||
T newConfig = (T)this.clone();
|
||||
newConfig.keepStrings = newVal;
|
||||
@@ -96,8 +107,11 @@ public class ParserConfiguration {
|
||||
* Using any negative value as a parameter is equivalent to setting no limit to the nesting depth,
|
||||
* which means the parses will go as deep as the maximum call stack size allows.
|
||||
* @param maxNestingDepth the maximum nesting depth allowed to the XML parser
|
||||
* @param <T> the type of the configuration object
|
||||
*
|
||||
* @return The existing configuration will not be modified. A new configuration is returned.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T extends ParserConfiguration> T withMaxNestingDepth(int maxNestingDepth) {
|
||||
T newConfig = (T)this.clone();
|
||||
|
||||
|
||||
@@ -13,6 +13,13 @@ import java.util.Properties;
|
||||
* @version 2015-05-05
|
||||
*/
|
||||
public class Property {
|
||||
|
||||
/**
|
||||
* Constructs a new Property object.
|
||||
*/
|
||||
public Property() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a property file object into a JSONObject. The property file object is a table of name value pairs.
|
||||
* @param properties java.util.Properties
|
||||
|
||||
@@ -10,7 +10,6 @@ import java.math.BigDecimal;
|
||||
import java.math.BigInteger;
|
||||
import java.util.Iterator;
|
||||
|
||||
|
||||
/**
|
||||
* This provides static methods to convert an XML text into a JSONObject, and to
|
||||
* covert a JSONObject into an XML text.
|
||||
@@ -21,6 +20,12 @@ import java.util.Iterator;
|
||||
@SuppressWarnings("boxing")
|
||||
public class XML {
|
||||
|
||||
/**
|
||||
* Constructs a new XML object.
|
||||
*/
|
||||
public XML() {
|
||||
}
|
||||
|
||||
/** The Character '&'. */
|
||||
public static final Character AMP = '&';
|
||||
|
||||
@@ -53,6 +58,9 @@ public class XML {
|
||||
*/
|
||||
public static final String NULL_ATTR = "xsi:nil";
|
||||
|
||||
/**
|
||||
* Represents the XML attribute name for specifying type information.
|
||||
*/
|
||||
public static final String TYPE_ATTR = "xsi:type";
|
||||
|
||||
/**
|
||||
@@ -428,6 +436,9 @@ public class XML {
|
||||
&& jsonObject.opt(config.getcDataTagName()) != null) {
|
||||
context.accumulate(tagName, jsonObject.opt(config.getcDataTagName()));
|
||||
} else {
|
||||
if (!config.shouldTrimWhiteSpace()) {
|
||||
removeEmpty(jsonObject, config);
|
||||
}
|
||||
context.accumulate(tagName, jsonObject);
|
||||
}
|
||||
}
|
||||
@@ -442,58 +453,46 @@ public class XML {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method tries to convert the given string value to the target object
|
||||
* @param string String to convert
|
||||
* @param typeConverter value converter to convert string to integer, boolean e.t.c
|
||||
* @return JSON value of this string or the string
|
||||
* This method removes any JSON entry which has the key set by XMLParserConfiguration.cDataTagName
|
||||
* and contains whitespace as this is caused by whitespace between tags. See test XMLTest.testNestedWithWhitespaceTrimmingDisabled.
|
||||
* @param jsonObject JSONObject which may require deletion
|
||||
* @param config The XMLParserConfiguration which includes the cDataTagName
|
||||
*/
|
||||
public static Object stringToValue(String string, XMLXsiTypeConverter<?> typeConverter) {
|
||||
if(typeConverter != null) {
|
||||
return typeConverter.convert(string);
|
||||
}
|
||||
return stringToValue(string);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is the same as {@link JSONObject#stringToValue(String)}.
|
||||
*
|
||||
* @param string String to convert
|
||||
* @return JSON value of this string or the string
|
||||
*/
|
||||
// To maintain compatibility with the Android API, this method is a direct copy of
|
||||
// the one in JSONObject. Changes made here should be reflected there.
|
||||
// This method should not make calls out of the XML object.
|
||||
public static Object stringToValue(String string) {
|
||||
if ("".equals(string)) {
|
||||
return string;
|
||||
}
|
||||
|
||||
// check JSON key words true/false/null
|
||||
if ("true".equalsIgnoreCase(string)) {
|
||||
return Boolean.TRUE;
|
||||
}
|
||||
if ("false".equalsIgnoreCase(string)) {
|
||||
return Boolean.FALSE;
|
||||
}
|
||||
if ("null".equalsIgnoreCase(string)) {
|
||||
return JSONObject.NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* If it might be a number, try converting it. If a number cannot be
|
||||
* produced, then the value will just be a string.
|
||||
*/
|
||||
|
||||
char initial = string.charAt(0);
|
||||
if ((initial >= '0' && initial <= '9') || initial == '-') {
|
||||
try {
|
||||
return stringToNumber(string);
|
||||
} catch (Exception ignore) {
|
||||
private static void removeEmpty(final JSONObject jsonObject, final XMLParserConfiguration config) {
|
||||
if (jsonObject.has(config.getcDataTagName())) {
|
||||
final Object s = jsonObject.get(config.getcDataTagName());
|
||||
if (s instanceof String) {
|
||||
if (isStringAllWhiteSpace(s.toString())) {
|
||||
jsonObject.remove(config.getcDataTagName());
|
||||
}
|
||||
}
|
||||
else if (s instanceof JSONArray) {
|
||||
final JSONArray sArray = (JSONArray) s;
|
||||
for (int k = sArray.length()-1; k >= 0; k--){
|
||||
final Object eachString = sArray.get(k);
|
||||
if (eachString instanceof String) {
|
||||
String s1 = (String) eachString;
|
||||
if (isStringAllWhiteSpace(s1)) {
|
||||
sArray.remove(k);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (sArray.isEmpty()) {
|
||||
jsonObject.remove(config.getcDataTagName());
|
||||
}
|
||||
}
|
||||
}
|
||||
return string;
|
||||
}
|
||||
|
||||
private static boolean isStringAllWhiteSpace(final String s) {
|
||||
for (int k = 0; k<s.length(); k++){
|
||||
final char eachChar = s.charAt(k);
|
||||
if (!Character.isWhitespace(eachChar)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -567,6 +566,58 @@ public class XML {
|
||||
|| val.indexOf('E') > -1 || "-0".equals(val);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method tries to convert the given string value to the target object
|
||||
* @param string String to convert
|
||||
* @param typeConverter value converter to convert string to integer, boolean e.t.c
|
||||
* @return JSON value of this string or the string
|
||||
*/
|
||||
public static Object stringToValue(String string, XMLXsiTypeConverter<?> typeConverter) {
|
||||
if(typeConverter != null) {
|
||||
return typeConverter.convert(string);
|
||||
}
|
||||
return stringToValue(string);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is the same as {@link JSONObject#stringToValue(String)}.
|
||||
*
|
||||
* @param string String to convert
|
||||
* @return JSON value of this string or the string
|
||||
*/
|
||||
// To maintain compatibility with the Android API, this method is a direct copy of
|
||||
// the one in JSONObject. Changes made here should be reflected there.
|
||||
// This method should not make calls out of the XML object.
|
||||
public static Object stringToValue(String string) {
|
||||
if ("".equals(string)) {
|
||||
return string;
|
||||
}
|
||||
|
||||
// check JSON key words true/false/null
|
||||
if ("true".equalsIgnoreCase(string)) {
|
||||
return Boolean.TRUE;
|
||||
}
|
||||
if ("false".equalsIgnoreCase(string)) {
|
||||
return Boolean.FALSE;
|
||||
}
|
||||
if ("null".equalsIgnoreCase(string)) {
|
||||
return JSONObject.NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* If it might be a number, try converting it. If a number cannot be
|
||||
* produced, then the value will just be a string.
|
||||
*/
|
||||
|
||||
char initial = string.charAt(0);
|
||||
if ((initial >= '0' && initial <= '9') || initial == '-') {
|
||||
try {
|
||||
return stringToNumber(string);
|
||||
} catch (Exception ignore) {
|
||||
}
|
||||
}
|
||||
return string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a well-formed (but not necessarily valid) XML string into a
|
||||
@@ -659,7 +710,7 @@ public class XML {
|
||||
*/
|
||||
public static JSONObject toJSONObject(Reader reader, XMLParserConfiguration config) throws JSONException {
|
||||
JSONObject jo = new JSONObject();
|
||||
XMLTokener x = new XMLTokener(reader);
|
||||
XMLTokener x = new XMLTokener(reader, config);
|
||||
while (x.more()) {
|
||||
x.skipPast("<");
|
||||
if(x.more()) {
|
||||
@@ -850,12 +901,25 @@ public class XML {
|
||||
}
|
||||
}
|
||||
} else if ("".equals(value)) {
|
||||
sb.append(indent(indent));
|
||||
sb.append('<');
|
||||
sb.append(key);
|
||||
sb.append("/>");
|
||||
if(indentFactor > 0){
|
||||
sb.append("\n");
|
||||
if (config.isCloseEmptyTag()){
|
||||
sb.append(indent(indent));
|
||||
sb.append('<');
|
||||
sb.append(key);
|
||||
sb.append(">");
|
||||
sb.append("</");
|
||||
sb.append(key);
|
||||
sb.append(">");
|
||||
if (indentFactor > 0) {
|
||||
sb.append("\n");
|
||||
}
|
||||
}else {
|
||||
sb.append(indent(indent));
|
||||
sb.append('<');
|
||||
sb.append(key);
|
||||
sb.append("/>");
|
||||
if (indentFactor > 0) {
|
||||
sb.append("\n");
|
||||
}
|
||||
}
|
||||
|
||||
// Emit a new tag <k>
|
||||
@@ -899,14 +963,14 @@ public class XML {
|
||||
|
||||
|
||||
string = (object == null) ? "null" : escape(object.toString());
|
||||
|
||||
String indentationSuffix = (indentFactor > 0) ? "\n" : "";
|
||||
if(tagName == null){
|
||||
return indent(indent) + "\"" + string + "\"" + ((indentFactor > 0) ? "\n" : "");
|
||||
return indent(indent) + "\"" + string + "\"" + indentationSuffix;
|
||||
} else if(string.length() == 0){
|
||||
return indent(indent) + "<" + tagName + "/>" + ((indentFactor > 0) ? "\n" : "");
|
||||
return indent(indent) + "<" + tagName + "/>" + indentationSuffix;
|
||||
} else {
|
||||
return indent(indent) + "<" + tagName
|
||||
+ ">" + string + "</" + tagName + ">" + ((indentFactor > 0) ? "\n" : "");
|
||||
+ ">" + string + "</" + tagName + ">" + indentationSuffix;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -43,6 +43,13 @@ public class XMLParserConfiguration extends ParserConfiguration {
|
||||
*/
|
||||
private boolean convertNilAttributeToNull;
|
||||
|
||||
/**
|
||||
* When creating an XML from JSON Object, an empty tag by default will self-close.
|
||||
* If it has to be closed explicitly, with empty content between start and end tag,
|
||||
* this flag is to be turned on.
|
||||
*/
|
||||
private boolean closeEmptyTag;
|
||||
|
||||
/**
|
||||
* This will allow type conversion for values in XML if xsi:type attribute is defined
|
||||
*/
|
||||
@@ -54,9 +61,18 @@ public class XMLParserConfiguration extends ParserConfiguration {
|
||||
*/
|
||||
private Set<String> forceList;
|
||||
|
||||
|
||||
/**
|
||||
* Flag to indicate whether white space should be trimmed when parsing XML.
|
||||
* The default behaviour is to trim white space. When this is set to false, inputting XML
|
||||
* with tags that are the same as the value of cDataTagName is unsupported. It is recommended to set cDataTagName
|
||||
* to a distinct value in this case.
|
||||
*/
|
||||
private boolean shouldTrimWhiteSpace;
|
||||
|
||||
/**
|
||||
* Default parser configuration. Does not keep strings (tries to implicitly convert
|
||||
* values), and the CDATA Tag Name is "content".
|
||||
* values), and the CDATA Tag Name is "content". Trims whitespace.
|
||||
*/
|
||||
public XMLParserConfiguration () {
|
||||
super();
|
||||
@@ -64,6 +80,7 @@ public class XMLParserConfiguration extends ParserConfiguration {
|
||||
this.convertNilAttributeToNull = false;
|
||||
this.xsiTypeMap = Collections.emptyMap();
|
||||
this.forceList = Collections.emptySet();
|
||||
this.shouldTrimWhiteSpace = true;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -142,15 +159,17 @@ public class XMLParserConfiguration extends ParserConfiguration {
|
||||
* xsi:type="integer" as integer, xsi:type="string" as string
|
||||
* @param forceList <code>new HashSet<String>()</code> to parse the provided tags' values as arrays
|
||||
* @param maxNestingDepth <code>int</code> to limit the nesting depth
|
||||
* @param closeEmptyTag <code>boolean</code> to turn on explicit end tag for tag with empty value
|
||||
*/
|
||||
private XMLParserConfiguration (final boolean keepStrings, final String cDataTagName,
|
||||
final boolean convertNilAttributeToNull, final Map<String, XMLXsiTypeConverter<?>> xsiTypeMap, final Set<String> forceList,
|
||||
final int maxNestingDepth) {
|
||||
final int maxNestingDepth, final boolean closeEmptyTag) {
|
||||
super(keepStrings, maxNestingDepth);
|
||||
this.cDataTagName = cDataTagName;
|
||||
this.convertNilAttributeToNull = convertNilAttributeToNull;
|
||||
this.xsiTypeMap = Collections.unmodifiableMap(xsiTypeMap);
|
||||
this.forceList = Collections.unmodifiableSet(forceList);
|
||||
this.closeEmptyTag = closeEmptyTag;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -163,14 +182,17 @@ public class XMLParserConfiguration extends ParserConfiguration {
|
||||
// item, a new map instance should be created and if possible each value in the
|
||||
// map should be cloned as well. If the values of the map are known to also
|
||||
// be immutable, then a shallow clone of the map is acceptable.
|
||||
return new XMLParserConfiguration(
|
||||
final XMLParserConfiguration config = new XMLParserConfiguration(
|
||||
this.keepStrings,
|
||||
this.cDataTagName,
|
||||
this.convertNilAttributeToNull,
|
||||
this.xsiTypeMap,
|
||||
this.forceList,
|
||||
this.maxNestingDepth
|
||||
this.maxNestingDepth,
|
||||
this.closeEmptyTag
|
||||
);
|
||||
config.shouldTrimWhiteSpace = this.shouldTrimWhiteSpace;
|
||||
return config;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -182,6 +204,7 @@ public class XMLParserConfiguration extends ParserConfiguration {
|
||||
*
|
||||
* @return The existing configuration will not be modified. A new configuration is returned.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public XMLParserConfiguration withKeepStrings(final boolean newVal) {
|
||||
return super.withKeepStrings(newVal);
|
||||
@@ -299,8 +322,51 @@ public class XMLParserConfiguration extends ParserConfiguration {
|
||||
* @param maxNestingDepth the maximum nesting depth allowed to the XML parser
|
||||
* @return The existing configuration will not be modified. A new configuration is returned.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public XMLParserConfiguration withMaxNestingDepth(int maxNestingDepth) {
|
||||
return super.withMaxNestingDepth(maxNestingDepth);
|
||||
}
|
||||
|
||||
/**
|
||||
* To enable explicit end tag with empty value.
|
||||
* @param closeEmptyTag new value for the closeEmptyTag property
|
||||
* @return same instance of configuration with empty tag config updated
|
||||
*/
|
||||
public XMLParserConfiguration withCloseEmptyTag(boolean closeEmptyTag){
|
||||
XMLParserConfiguration clonedConfiguration = this.clone();
|
||||
clonedConfiguration.closeEmptyTag = closeEmptyTag;
|
||||
return clonedConfiguration;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether whitespace should be trimmed inside of tags. *NOTE* Do not use this if
|
||||
* you expect your XML tags to have names that are the same as cDataTagName as this is unsupported.
|
||||
* cDataTagName should be set to a distinct value in these cases.
|
||||
* @param shouldTrimWhiteSpace boolean to set trimming on or off. Off is default.
|
||||
* @return same instance of configuration with empty tag config updated
|
||||
*/
|
||||
public XMLParserConfiguration withShouldTrimWhitespace(boolean shouldTrimWhiteSpace){
|
||||
XMLParserConfiguration clonedConfiguration = this.clone();
|
||||
clonedConfiguration.shouldTrimWhiteSpace = shouldTrimWhiteSpace;
|
||||
return clonedConfiguration;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the parser should automatically close empty XML tags.
|
||||
*
|
||||
* @return {@code true} if empty XML tags should be automatically closed, {@code false} otherwise.
|
||||
*/
|
||||
public boolean isCloseEmptyTag() {
|
||||
return this.closeEmptyTag;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the parser should trim white spaces from XML content.
|
||||
*
|
||||
* @return {@code true} if white spaces should be trimmed, {@code false} otherwise.
|
||||
*/
|
||||
public boolean shouldTrimWhiteSpace() {
|
||||
return this.shouldTrimWhiteSpace;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,6 +20,8 @@ public class XMLTokener extends JSONTokener {
|
||||
*/
|
||||
public static final java.util.HashMap<String, Character> entity;
|
||||
|
||||
private XMLParserConfiguration configuration = XMLParserConfiguration.ORIGINAL;
|
||||
|
||||
static {
|
||||
entity = new java.util.HashMap<String, Character>(8);
|
||||
entity.put("amp", XML.AMP);
|
||||
@@ -45,6 +47,16 @@ public class XMLTokener extends JSONTokener {
|
||||
super(s);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct an XMLTokener from a Reader and an XMLParserConfiguration.
|
||||
* @param r A source reader.
|
||||
* @param configuration the configuration that can be used to set certain flags
|
||||
*/
|
||||
public XMLTokener(Reader r, XMLParserConfiguration configuration) {
|
||||
super(r);
|
||||
this.configuration = configuration;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the text in the CDATA block.
|
||||
* @return The string up to the <code>]]></code>.
|
||||
@@ -83,7 +95,7 @@ public class XMLTokener extends JSONTokener {
|
||||
StringBuilder sb;
|
||||
do {
|
||||
c = next();
|
||||
} while (Character.isWhitespace(c));
|
||||
} while (Character.isWhitespace(c) && configuration.shouldTrimWhiteSpace());
|
||||
if (c == 0) {
|
||||
return null;
|
||||
}
|
||||
@@ -97,7 +109,9 @@ public class XMLTokener extends JSONTokener {
|
||||
}
|
||||
if (c == '<') {
|
||||
back();
|
||||
return sb.toString().trim();
|
||||
if (configuration.shouldTrimWhiteSpace()) {
|
||||
return sb.toString().trim();
|
||||
} else return sb.toString();
|
||||
}
|
||||
if (c == '&') {
|
||||
sb.append(nextEntity(c));
|
||||
|
||||
@@ -42,5 +42,12 @@ Public Domain.
|
||||
* @param <T> return type of convert method
|
||||
*/
|
||||
public interface XMLXsiTypeConverter<T> {
|
||||
|
||||
/**
|
||||
* Converts an XML xsi:type attribute value to the specified type {@code T}.
|
||||
*
|
||||
* @param value The string representation of the XML xsi:type attribute value to be converted.
|
||||
* @return An object of type {@code T} representing the converted value.
|
||||
*/
|
||||
T convert(String value);
|
||||
}
|
||||
|
||||
@@ -24,14 +24,13 @@ 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"
|
||||
);
|
||||
private static final String LINES = "Col 1, Col 2, \tCol 3, Col 4, Col 5, Col 6, Col 7\n" +
|
||||
"val1, val2, val3, val4, val5, val6, val7\n" +
|
||||
"1, 2, 3, 4\t, 5, 6, 7\n" +
|
||||
"true, false, true, true, false, false, false\n" +
|
||||
"0.23, 57.42, 5e27, -234.879, 2.34e5, 0.0, 9e-3\n" +
|
||||
"\"va\tl1\", \"v\bal2\", \"val3\", \"val\f4\", \"val5\", va'l6, val7\n";
|
||||
|
||||
|
||||
/**
|
||||
* CDL.toJSONArray() adds all values as strings, with no filtering or
|
||||
@@ -39,12 +38,11 @@ public class CDLTest {
|
||||
* 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}]");
|
||||
private static final String EXPECTED_LINES = "[{Col 1:val1, Col 2:val2, Col 3:val3, Col 4:val4, Col 5:val5, Col 6:val6, Col 7:val7}, " +
|
||||
"{Col 1:\"1\", Col 2:\"2\", Col 3:\"3\", Col 4:\"4\", Col 5:\"5\", Col 6:\"6\", Col 7:\"7\"}, " +
|
||||
"{Col 1:\"true\", Col 2:\"false\", Col 3:\"true\", Col 4:\"true\", Col 5:\"false\", Col 6:\"false\", Col 7:\"false\"}, " +
|
||||
"{Col 1:\"0.23\", Col 2:\"57.42\", Col 3:\"5e27\", Col 4:\"-234.879\", Col 5:\"2.34e5\", Col 6:\"0.0\", Col 7:\"9e-3\"}, " +
|
||||
"{Col 1:\"va\tl1\", Col 2:\"v\bal2\", Col 3:val3, Col 4:\"val\f4\", Col 5:val5, Col 6:va'l6, Col 7:val7}]";
|
||||
|
||||
/**
|
||||
* Attempts to create a JSONArray from a null string.
|
||||
@@ -194,8 +192,7 @@ public class CDLTest {
|
||||
public void emptyString() {
|
||||
String emptyStr = "";
|
||||
JSONArray jsonArray = CDL.toJSONArray(emptyStr);
|
||||
assertTrue("CDL should return null when the input string is empty",
|
||||
jsonArray == null);
|
||||
assertNull("CDL should return null when the input string is empty", jsonArray);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -254,7 +251,7 @@ public class CDLTest {
|
||||
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);
|
||||
assertEquals("expected length should be 1", 1, jsonArray.length());
|
||||
String cdlStr = CDL.toString(jsonArray);
|
||||
jsonObject = jsonArray.getJSONObject(0);
|
||||
assertTrue(cdlStr.contains("\"Col 1\""));
|
||||
@@ -268,8 +265,15 @@ public class CDLTest {
|
||||
*/
|
||||
@Test
|
||||
public void textToJSONArray() {
|
||||
JSONArray jsonArray = CDL.toJSONArray(this.lines);
|
||||
JSONArray expectedJsonArray = new JSONArray(this.expectedLines);
|
||||
JSONArray jsonArray = CDL.toJSONArray(LINES);
|
||||
JSONArray expectedJsonArray = new JSONArray(EXPECTED_LINES);
|
||||
Util.compareActualVsExpectedJsonArrays(jsonArray, expectedJsonArray);
|
||||
}
|
||||
@Test
|
||||
public void textToJSONArrayPipeDelimited() {
|
||||
char delimiter = '|';
|
||||
JSONArray jsonArray = CDL.toJSONArray(LINES.replaceAll(",", String.valueOf(delimiter)), delimiter);
|
||||
JSONArray expectedJsonArray = new JSONArray(EXPECTED_LINES);
|
||||
Util.compareActualVsExpectedJsonArrays(jsonArray, expectedJsonArray);
|
||||
}
|
||||
|
||||
@@ -293,10 +297,24 @@ public class CDLTest {
|
||||
*/
|
||||
@Test
|
||||
public void textToJSONArrayAndBackToString() {
|
||||
JSONArray jsonArray = CDL.toJSONArray(this.lines);
|
||||
JSONArray jsonArray = CDL.toJSONArray(LINES);
|
||||
String jsonStr = CDL.toString(jsonArray);
|
||||
JSONArray finalJsonArray = CDL.toJSONArray(jsonStr);
|
||||
JSONArray expectedJsonArray = new JSONArray(this.expectedLines);
|
||||
JSONArray expectedJsonArray = new JSONArray(EXPECTED_LINES);
|
||||
Util.compareActualVsExpectedJsonArrays(finalJsonArray, expectedJsonArray);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a JSONArray from a string of lines,
|
||||
* then convert to string and then back to JSONArray
|
||||
* with a custom delimiter
|
||||
*/
|
||||
@Test
|
||||
public void textToJSONArrayAndBackToStringCustomDelimiter() {
|
||||
JSONArray jsonArray = CDL.toJSONArray(LINES, ',');
|
||||
String jsonStr = CDL.toString(jsonArray, ';');
|
||||
JSONArray finalJsonArray = CDL.toJSONArray(jsonStr, ';');
|
||||
JSONArray expectedJsonArray = new JSONArray(EXPECTED_LINES);
|
||||
Util.compareActualVsExpectedJsonArrays(finalJsonArray, expectedJsonArray);
|
||||
}
|
||||
|
||||
|
||||
@@ -28,10 +28,13 @@ import java.util.Map;
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
import org.json.JSONParserConfiguration;
|
||||
import org.json.JSONPointerException;
|
||||
import org.json.JSONString;
|
||||
import org.json.JSONTokener;
|
||||
import org.json.ParserConfiguration;
|
||||
import org.json.junit.data.MyJsonString;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
|
||||
import com.jayway.jsonpath.Configuration;
|
||||
@@ -1384,6 +1387,7 @@ public class JSONArrayTest {
|
||||
/**
|
||||
* Tests for stack overflow. See https://github.com/stleary/JSON-java/issues/654
|
||||
*/
|
||||
@Ignore("This test relies on system constraints and may not always pass. See: https://github.com/stleary/JSON-java/issues/821")
|
||||
@Test(expected = JSONException.class)
|
||||
public void issue654StackOverflowInputWellFormed() {
|
||||
//String input = new String(java.util.Base64.getDecoder().decode(base64Bytes));
|
||||
@@ -1391,7 +1395,7 @@ public class JSONArrayTest {
|
||||
JSONTokener tokener = new JSONTokener(resourceAsStream);
|
||||
JSONArray json_input = new JSONArray(tokener);
|
||||
assertNotNull(json_input);
|
||||
fail("Excepected Exception.");
|
||||
fail("Excepected Exception due to stack overflow.");
|
||||
Util.checkJSONArrayMaps(json_input);
|
||||
}
|
||||
|
||||
@@ -1415,4 +1419,92 @@ public class JSONArrayTest {
|
||||
.put(2);
|
||||
assertFalse(ja1.similar(ja3));
|
||||
}
|
||||
|
||||
@Test(expected = JSONException.class)
|
||||
public void testRecursiveDepth() {
|
||||
HashMap<String, Object> map = new HashMap<>();
|
||||
map.put("t", map);
|
||||
new JSONArray().put(map);
|
||||
}
|
||||
|
||||
@Test(expected = JSONException.class)
|
||||
public void testRecursiveDepthAtPosition() {
|
||||
HashMap<String, Object> map = new HashMap<>();
|
||||
map.put("t", map);
|
||||
new JSONArray().put(0, map);
|
||||
}
|
||||
|
||||
@Test(expected = JSONException.class)
|
||||
public void testRecursiveDepthArray() {
|
||||
ArrayList<Object> array = new ArrayList<>();
|
||||
array.add(array);
|
||||
new JSONArray(array);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRecursiveDepthAtPositionDefaultObject() {
|
||||
HashMap<String, Object> map = JSONObjectTest.buildNestedMap(ParserConfiguration.DEFAULT_MAXIMUM_NESTING_DEPTH);
|
||||
new JSONArray().put(0, map);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRecursiveDepthAtPosition1000Object() {
|
||||
HashMap<String, Object> map = JSONObjectTest.buildNestedMap(1000);
|
||||
new JSONArray().put(0, map, new JSONParserConfiguration().withMaxNestingDepth(1000));
|
||||
}
|
||||
|
||||
@Test(expected = JSONException.class)
|
||||
public void testRecursiveDepthAtPosition1001Object() {
|
||||
HashMap<String, Object> map = JSONObjectTest.buildNestedMap(1001);
|
||||
new JSONArray().put(0, map);
|
||||
}
|
||||
|
||||
@Test(expected = JSONException.class)
|
||||
public void testRecursiveDepthArrayLimitedMaps() {
|
||||
ArrayList<Object> array = new ArrayList<>();
|
||||
array.add(array);
|
||||
new JSONArray(array);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRecursiveDepthArrayForDefaultLevels() {
|
||||
ArrayList<Object> array = buildNestedArray(ParserConfiguration.DEFAULT_MAXIMUM_NESTING_DEPTH);
|
||||
new JSONArray(array, new JSONParserConfiguration());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRecursiveDepthArrayFor1000Levels() {
|
||||
try {
|
||||
ArrayList<Object> array = buildNestedArray(1000);
|
||||
JSONParserConfiguration parserConfiguration = new JSONParserConfiguration().withMaxNestingDepth(1000);
|
||||
new JSONArray(array, parserConfiguration);
|
||||
} catch (StackOverflowError e) {
|
||||
String javaVersion = System.getProperty("java.version");
|
||||
if (javaVersion.startsWith("11.")) {
|
||||
System.out.println(
|
||||
"testRecursiveDepthArrayFor1000Levels() allowing intermittent stackoverflow, Java Version: "
|
||||
+ javaVersion);
|
||||
} else {
|
||||
String errorStr = "testRecursiveDepthArrayFor1000Levels() unexpected stackoverflow, Java Version: "
|
||||
+ javaVersion;
|
||||
System.out.println(errorStr);
|
||||
throw new RuntimeException(errorStr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test(expected = JSONException.class)
|
||||
public void testRecursiveDepthArrayFor1001Levels() {
|
||||
ArrayList<Object> array = buildNestedArray(1001);
|
||||
new JSONArray(array);
|
||||
}
|
||||
|
||||
public static ArrayList<Object> buildNestedArray(int maxDepth) {
|
||||
if (maxDepth <= 0) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
ArrayList<Object> nestedArray = new ArrayList<>();
|
||||
nestedArray.add(buildNestedArray(maxDepth - 1));
|
||||
return nestedArray;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -762,8 +762,8 @@ public class JSONMLTest {
|
||||
final String xml = JSONML.toString(originalObject);
|
||||
final JSONObject revertedObject = JSONML.toJSONObject(xml, false);
|
||||
final String newJson = revertedObject.toString();
|
||||
assertTrue("JSON Objects are not similar",originalObject.similar(revertedObject));
|
||||
assertEquals("original JSON does not equal the new JSON",originalJson, newJson);
|
||||
assertTrue("JSON Objects are not similar", originalObject.similar(revertedObject));
|
||||
assertTrue("JSON Strings are not similar", new JSONObject(originalJson).similar(new JSONObject(newJson)));
|
||||
}
|
||||
|
||||
// these tests do not pass for the following reasons:
|
||||
|
||||
@@ -1,100 +0,0 @@
|
||||
package org.json.junit;
|
||||
|
||||
import org.json.JSONObject;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.BigInteger;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
public class JSONObjectDecimalTest {
|
||||
|
||||
@Test
|
||||
public void shouldParseDecimalNumberThatStartsWithDecimalPoint(){
|
||||
JSONObject jsonObject = new JSONObject("{value:0.50}");
|
||||
assertEquals("Float not recognized", 0.5f, jsonObject.getFloat("value"), 0.0f);
|
||||
assertEquals("Float not recognized", 0.5f, jsonObject.optFloat("value"), 0.0f);
|
||||
assertEquals("Float not recognized", 0.5f, jsonObject.optFloatObject("value"), 0.0f);
|
||||
assertEquals("Double not recognized", 0.5d, jsonObject.optDouble("value"), 0.0f);
|
||||
assertEquals("Double not recognized", 0.5d, jsonObject.optDoubleObject("value"), 0.0f);
|
||||
assertEquals("Double not recognized", 0.5d, jsonObject.getDouble("value"), 0.0f);
|
||||
assertEquals("Long not recognized", 0, jsonObject.optLong("value"), 0);
|
||||
assertEquals("Long not recognized", 0, jsonObject.getLong("value"), 0);
|
||||
assertEquals("Long not recognized", 0, jsonObject.optLongObject("value"), 0);
|
||||
assertEquals("Integer not recognized", 0, jsonObject.optInt("value"), 0);
|
||||
assertEquals("Integer not recognized", 0, jsonObject.getInt("value"), 0);
|
||||
assertEquals("Integer not recognized", 0, jsonObject.optIntegerObject("value"), 0);
|
||||
assertEquals("Number not recognized", 0, jsonObject.getNumber("value").intValue(), 0);
|
||||
assertEquals("Number not recognized", 0, jsonObject.getNumber("value").longValue(), 0);
|
||||
assertEquals("BigDecimal not recognized", 0, BigDecimal.valueOf(.5).compareTo(jsonObject.getBigDecimal("value")));
|
||||
assertEquals("BigInteger not recognized",0, BigInteger.valueOf(0).compareTo(jsonObject.getBigInteger("value")));
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Test
|
||||
public void shouldParseNegativeDecimalNumberThatStartsWithDecimalPoint(){
|
||||
JSONObject jsonObject = new JSONObject("{value:-.50}");
|
||||
assertEquals("Float not recognized", -0.5f, jsonObject.getFloat("value"), 0.0f);
|
||||
assertEquals("Float not recognized", -0.5f, jsonObject.optFloat("value"), 0.0f);
|
||||
assertEquals("Float not recognized", -0.5f, jsonObject.optFloatObject("value"), 0.0f);
|
||||
assertEquals("Double not recognized", -0.5d, jsonObject.optDouble("value"), 0.0f);
|
||||
assertEquals("Double not recognized", -0.5d, jsonObject.optDoubleObject("value"), 0.0f);
|
||||
assertEquals("Double not recognized", -0.5d, jsonObject.getDouble("value"), 0.0f);
|
||||
assertEquals("Long not recognized", 0, jsonObject.optLong("value"), 0);
|
||||
assertEquals("Long not recognized", 0, jsonObject.getLong("value"), 0);
|
||||
assertEquals("Long not recognized", 0, jsonObject.optLongObject("value"), 0);
|
||||
assertEquals("Integer not recognized", 0, jsonObject.optInt("value"), 0);
|
||||
assertEquals("Integer not recognized", 0, jsonObject.getInt("value"), 0);
|
||||
assertEquals("Integer not recognized", 0, jsonObject.optIntegerObject("value"), 0);
|
||||
assertEquals("Number not recognized", 0, jsonObject.getNumber("value").intValue(), 0);
|
||||
assertEquals("Number not recognized", 0, jsonObject.getNumber("value").longValue(), 0);
|
||||
assertEquals("BigDecimal not recognized", 0, BigDecimal.valueOf(-.5).compareTo(jsonObject.getBigDecimal("value")));
|
||||
assertEquals("BigInteger not recognized",0, BigInteger.valueOf(0).compareTo(jsonObject.getBigInteger("value")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldParseDecimalNumberThatHasZeroBeforeWithDecimalPoint(){
|
||||
JSONObject jsonObject = new JSONObject("{value:00.050}");
|
||||
assertEquals("Float not recognized", 0.05f, jsonObject.getFloat("value"), 0.0f);
|
||||
assertEquals("Float not recognized", 0.05f, jsonObject.optFloat("value"), 0.0f);
|
||||
assertEquals("Float not recognized", 0.05f, jsonObject.optFloatObject("value"), 0.0f);
|
||||
assertEquals("Double not recognized", 0.05d, jsonObject.optDouble("value"), 0.0f);
|
||||
assertEquals("Double not recognized", 0.05d, jsonObject.optDoubleObject("value"), 0.0f);
|
||||
assertEquals("Double not recognized", 0.05d, jsonObject.getDouble("value"), 0.0f);
|
||||
assertEquals("Long not recognized", 0, jsonObject.optLong("value"), 0);
|
||||
assertEquals("Long not recognized", 0, jsonObject.getLong("value"), 0);
|
||||
assertEquals("Long not recognized", 0, jsonObject.optLongObject("value"), 0);
|
||||
assertEquals("Integer not recognized", 0, jsonObject.optInt("value"), 0);
|
||||
assertEquals("Integer not recognized", 0, jsonObject.getInt("value"), 0);
|
||||
assertEquals("Integer not recognized", 0, jsonObject.optIntegerObject("value"), 0);
|
||||
assertEquals("Number not recognized", 0, jsonObject.getNumber("value").intValue(), 0);
|
||||
assertEquals("Number not recognized", 0, jsonObject.getNumber("value").longValue(), 0);
|
||||
assertEquals("BigDecimal not recognized", 0, BigDecimal.valueOf(.05).compareTo(jsonObject.getBigDecimal("value")));
|
||||
assertEquals("BigInteger not recognized",0, BigInteger.valueOf(0).compareTo(jsonObject.getBigInteger("value")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldParseNegativeDecimalNumberThatHasZeroBeforeWithDecimalPoint(){
|
||||
JSONObject jsonObject = new JSONObject("{value:-00.050}");
|
||||
assertEquals("Float not recognized", -0.05f, jsonObject.getFloat("value"), 0.0f);
|
||||
assertEquals("Float not recognized", -0.05f, jsonObject.optFloat("value"), 0.0f);
|
||||
assertEquals("Float not recognized", -0.05f, jsonObject.optFloatObject("value"), 0.0f);
|
||||
assertEquals("Double not recognized", -0.05d, jsonObject.optDouble("value"), 0.0f);
|
||||
assertEquals("Double not recognized", -0.05d, jsonObject.optDoubleObject("value"), 0.0f);
|
||||
assertEquals("Double not recognized", -0.05d, jsonObject.getDouble("value"), 0.0f);
|
||||
assertEquals("Long not recognized", 0, jsonObject.optLong("value"), 0);
|
||||
assertEquals("Long not recognized", 0, jsonObject.getLong("value"), 0);
|
||||
assertEquals("Long not recognized", 0, jsonObject.optLongObject("value"), 0);
|
||||
assertEquals("Integer not recognized", 0, jsonObject.optInt("value"), 0);
|
||||
assertEquals("Integer not recognized", 0, jsonObject.getInt("value"), 0);
|
||||
assertEquals("Integer not recognized", 0, jsonObject.optIntegerObject("value"), 0);
|
||||
assertEquals("Number not recognized", 0, jsonObject.getNumber("value").intValue(), 0);
|
||||
assertEquals("Number not recognized", 0, jsonObject.getNumber("value").longValue(), 0);
|
||||
assertEquals("BigDecimal not recognized", 0, BigDecimal.valueOf(-.05).compareTo(jsonObject.getBigDecimal("value")));
|
||||
assertEquals("BigInteger not recognized",0, BigInteger.valueOf(0).compareTo(jsonObject.getBigInteger("value")));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -23,10 +23,7 @@ public class JSONObjectNumberTest {
|
||||
@Parameters(name = "{index}: {0}")
|
||||
public static Collection<Object[]> data() {
|
||||
return Arrays.asList(new Object[][]{
|
||||
{"{value:0050}", 1},
|
||||
{"{value:0050.0000}", 1},
|
||||
{"{value:-0050}", -1},
|
||||
{"{value:-0050.0000}", -1},
|
||||
{"{value:50}", 1},
|
||||
{"{value:50.0}", 1},
|
||||
{"{value:5e1}", 1},
|
||||
{"{value:5E1}", 1},
|
||||
@@ -35,7 +32,6 @@ public class JSONObjectNumberTest {
|
||||
{"{value:-50}", -1},
|
||||
{"{value:-50.0}", -1},
|
||||
{"{value:-5e1}", -1},
|
||||
{"{value:-0005e1}", -1},
|
||||
{"{value:-5E1}", -1},
|
||||
{"{value:-5e1}", -1},
|
||||
{"{value:'-50'}", -1}
|
||||
|
||||
@@ -4,7 +4,6 @@ package org.json.junit;
|
||||
Public Domain.
|
||||
*/
|
||||
|
||||
import static java.lang.Double.NaN;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotEquals;
|
||||
@@ -32,8 +31,10 @@ import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
import org.json.JSONPointerException;
|
||||
import org.json.JSONParserConfiguration;
|
||||
import org.json.JSONString;
|
||||
import org.json.JSONTokener;
|
||||
import org.json.ParserConfiguration;
|
||||
import org.json.XML;
|
||||
import org.json.junit.data.BrokenToString;
|
||||
import org.json.junit.data.ExceptionalBean;
|
||||
@@ -55,6 +56,7 @@ import org.json.junit.data.RecursiveBeanEquals;
|
||||
import org.json.junit.data.Singleton;
|
||||
import org.json.junit.data.SingletonEnum;
|
||||
import org.json.junit.data.WeirdList;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
|
||||
import com.jayway.jsonpath.Configuration;
|
||||
@@ -783,7 +785,7 @@ public class JSONObjectTest {
|
||||
jsonObject.accumulate("myArray", -23.45e7);
|
||||
// include an unsupported object for coverage
|
||||
try {
|
||||
jsonObject.accumulate("myArray", NaN);
|
||||
jsonObject.accumulate("myArray", Double.NaN);
|
||||
fail("Expected exception");
|
||||
} catch (JSONException ignored) {}
|
||||
|
||||
@@ -815,7 +817,7 @@ public class JSONObjectTest {
|
||||
jsonObject.append("myArray", -23.45e7);
|
||||
// include an unsupported object for coverage
|
||||
try {
|
||||
jsonObject.append("myArray", NaN);
|
||||
jsonObject.append("myArray", Double.NaN);
|
||||
fail("Expected exception");
|
||||
} catch (JSONException ignored) {}
|
||||
|
||||
@@ -840,7 +842,7 @@ public class JSONObjectTest {
|
||||
public void jsonObjectDoubleToString() {
|
||||
String [] expectedStrs = {"1", "1", "-23.4", "-2.345E68", "null", "null" };
|
||||
Double [] doubles = { 1.0, 00001.00000, -23.4, -23.45e67,
|
||||
NaN, Double.NEGATIVE_INFINITY };
|
||||
Double.NaN, Double.NEGATIVE_INFINITY };
|
||||
for (int i = 0; i < expectedStrs.length; ++i) {
|
||||
String actualStr = JSONObject.doubleToString(doubles[i]);
|
||||
assertTrue("value expected ["+expectedStrs[i]+
|
||||
@@ -895,11 +897,11 @@ public class JSONObjectTest {
|
||||
assertTrue("opt doubleKey should be double",
|
||||
jsonObject.optDouble("doubleKey") == -23.45e7);
|
||||
assertTrue("opt doubleKey with Default should be double",
|
||||
jsonObject.optDouble("doubleStrKey", NaN) == 1);
|
||||
jsonObject.optDouble("doubleStrKey", Double.NaN) == 1);
|
||||
assertTrue("opt doubleKey should be Double",
|
||||
Double.valueOf(-23.45e7).equals(jsonObject.optDoubleObject("doubleKey")));
|
||||
assertTrue("opt doubleKey with Default should be Double",
|
||||
Double.valueOf(1).equals(jsonObject.optDoubleObject("doubleStrKey", NaN)));
|
||||
Double.valueOf(1).equals(jsonObject.optDoubleObject("doubleStrKey", Double.NaN)));
|
||||
assertTrue("opt negZeroKey should be a Double",
|
||||
jsonObject.opt("negZeroKey") instanceof Double);
|
||||
assertTrue("get negZeroKey should be a Double",
|
||||
@@ -1065,21 +1067,12 @@ public class JSONObjectTest {
|
||||
"\"tooManyZeros\":00,"+
|
||||
"\"negativeInfinite\":-Infinity,"+
|
||||
"\"negativeNaN\":-NaN,"+
|
||||
"\"negativeNaNWithLeadingZeros\":-00NaN,"+
|
||||
"\"negativeFraction\":-.01,"+
|
||||
"\"tooManyZerosFraction\":00.001,"+
|
||||
"\"negativeHexFloat\":-0x1.fffp1,"+
|
||||
"\"hexFloat\":0x1.0P-1074,"+
|
||||
"\"floatIdentifier\":0.1f,"+
|
||||
"\"doubleIdentifier\":0.1d,"+
|
||||
"\"doubleIdentifierWithMultipleLeadingZerosBeforeDecimal\":0000000.1d,"+
|
||||
"\"negativeDoubleIdentifierWithMultipleLeadingZerosBeforeDecimal\":-0000000.1d,"+
|
||||
"\"doubleIdentifierWithMultipleLeadingZerosAfterDecimal\":0000000.0001d,"+
|
||||
"\"negativeDoubleIdentifierWithMultipleLeadingZerosAfterDecimal\":-0000000.0001d,"+
|
||||
"\"integerWithLeadingZeros\":000900,"+
|
||||
"\"integerWithAllZeros\":00000,"+
|
||||
"\"compositeWithLeadingZeros\":00800.90d,"+
|
||||
"\"decimalPositiveWithoutNumberBeforeDecimalPoint\":.90,"+
|
||||
"\"doubleIdentifier\":0.1d"+
|
||||
"}";
|
||||
JSONObject jsonObject = new JSONObject(str);
|
||||
Object obj;
|
||||
@@ -1089,22 +1082,15 @@ public class JSONObjectTest {
|
||||
assertTrue("hexNumber currently evaluates to string",
|
||||
obj.equals("-0x123"));
|
||||
assertTrue( "tooManyZeros currently evaluates to string",
|
||||
jsonObject.get( "tooManyZeros" ).equals(0));
|
||||
jsonObject.get( "tooManyZeros" ).equals("00"));
|
||||
obj = jsonObject.get("negativeInfinite");
|
||||
assertTrue( "negativeInfinite currently evaluates to string",
|
||||
obj.equals("-Infinity"));
|
||||
obj = jsonObject.get("negativeNaN");
|
||||
assertTrue( "negativeNaN currently evaluates to string",
|
||||
obj.equals("-NaN"));
|
||||
obj = jsonObject.get("negativeNaNWithLeadingZeros");
|
||||
assertTrue( "negativeNaNWithLeadingZeros currently evaluates to string",
|
||||
obj.equals("-00NaN"));
|
||||
assertTrue( "negativeFraction currently evaluates to double -0.01",
|
||||
jsonObject.get( "negativeFraction" ).equals(BigDecimal.valueOf(-0.01)));
|
||||
assertTrue( "tooManyZerosFraction currently evaluates to double 0.001",
|
||||
jsonObject.get( "tooManyZerosFraction" ).equals(BigDecimal.valueOf(0.001)));
|
||||
assertTrue( "tooManyZerosFraction currently evaluates to double 0.001",
|
||||
jsonObject.getLong( "tooManyZerosFraction" )==0);
|
||||
assertTrue( "tooManyZerosFraction currently evaluates to double 0.001",
|
||||
jsonObject.optLong( "tooManyZerosFraction" )==0);
|
||||
assertTrue( "negativeHexFloat currently evaluates to double -3.99951171875",
|
||||
@@ -1115,53 +1101,6 @@ public class JSONObjectTest {
|
||||
jsonObject.get("floatIdentifier").equals(Double.valueOf(0.1)));
|
||||
assertTrue("doubleIdentifier currently evaluates to double 0.1",
|
||||
jsonObject.get("doubleIdentifier").equals(Double.valueOf(0.1)));
|
||||
assertTrue("doubleIdentifierWithMultipleLeadingZerosBeforeDecimal currently evaluates to double 0.1",
|
||||
jsonObject.get("doubleIdentifierWithMultipleLeadingZerosBeforeDecimal").equals(Double.valueOf(0.1)));
|
||||
assertTrue("negativeDoubleIdentifierWithMultipleLeadingZerosBeforeDecimal currently evaluates to double -0.1",
|
||||
jsonObject.get("negativeDoubleIdentifierWithMultipleLeadingZerosBeforeDecimal").equals(Double.valueOf(-0.1)));
|
||||
assertTrue("doubleIdentifierWithMultipleLeadingZerosAfterDecimal currently evaluates to double 0.0001",
|
||||
jsonObject.get("doubleIdentifierWithMultipleLeadingZerosAfterDecimal").equals(Double.valueOf(0.0001)));
|
||||
assertTrue("doubleIdentifierWithMultipleLeadingZerosAfterDecimal currently evaluates to double 0.0001",
|
||||
jsonObject.get("doubleIdentifierWithMultipleLeadingZerosAfterDecimal").equals(Double.valueOf(0.0001)));
|
||||
assertTrue("negativeDoubleIdentifierWithMultipleLeadingZerosAfterDecimal currently evaluates to double -0.0001",
|
||||
jsonObject.get("negativeDoubleIdentifierWithMultipleLeadingZerosAfterDecimal").equals(Double.valueOf(-0.0001)));
|
||||
assertTrue("Integer does not evaluate to 900",
|
||||
jsonObject.get("integerWithLeadingZeros").equals(900));
|
||||
assertTrue("Integer does not evaluate to 900",
|
||||
jsonObject.getInt("integerWithLeadingZeros")==900);
|
||||
assertTrue("Integer does not evaluate to 900",
|
||||
jsonObject.optInt("integerWithLeadingZeros")==900);
|
||||
assertTrue("Integer does not evaluate to 0",
|
||||
jsonObject.get("integerWithAllZeros").equals(0));
|
||||
assertTrue("Integer does not evaluate to 0",
|
||||
jsonObject.getInt("integerWithAllZeros")==0);
|
||||
assertTrue("Integer does not evaluate to 0",
|
||||
jsonObject.optInt("integerWithAllZeros")==0);
|
||||
assertTrue("Double does not evaluate to 800.90",
|
||||
jsonObject.get("compositeWithLeadingZeros").equals(800.90));
|
||||
assertTrue("Double does not evaluate to 800.90",
|
||||
jsonObject.getDouble("compositeWithLeadingZeros")==800.9d);
|
||||
assertTrue("Integer does not evaluate to 800",
|
||||
jsonObject.optInt("compositeWithLeadingZeros")==800);
|
||||
assertTrue("Long does not evaluate to 800.90",
|
||||
jsonObject.getLong("compositeWithLeadingZeros")==800);
|
||||
assertTrue("Long does not evaluate to 800.90",
|
||||
jsonObject.optLong("compositeWithLeadingZeros")==800);
|
||||
assertEquals("Get long of decimalPositiveWithoutNumberBeforeDecimalPoint does not match",
|
||||
0.9d,jsonObject.getDouble("decimalPositiveWithoutNumberBeforeDecimalPoint"), 0.0d);
|
||||
assertEquals("Get long of decimalPositiveWithoutNumberBeforeDecimalPoint does not match",
|
||||
0.9d,jsonObject.optDouble("decimalPositiveWithoutNumberBeforeDecimalPoint"), 0.0d);
|
||||
assertEquals("Get long of decimalPositiveWithoutNumberBeforeDecimalPoint does not match",
|
||||
0.0d,jsonObject.optLong("decimalPositiveWithoutNumberBeforeDecimalPoint"), 0.0d);
|
||||
|
||||
assertEquals("Get long of doubleIdentifierWithMultipleLeadingZerosAfterDecimal does not match",
|
||||
0.0001d,jsonObject.getDouble("doubleIdentifierWithMultipleLeadingZerosAfterDecimal"), 0.0d);
|
||||
assertEquals("Get long of doubleIdentifierWithMultipleLeadingZerosAfterDecimal does not match",
|
||||
0.0001d,jsonObject.optDouble("doubleIdentifierWithMultipleLeadingZerosAfterDecimal"), 0.0d);
|
||||
assertEquals("Get long of doubleIdentifierWithMultipleLeadingZerosAfterDecimal does not match",
|
||||
0.0d, jsonObject.getLong("doubleIdentifierWithMultipleLeadingZerosAfterDecimal") , 0.0d);
|
||||
assertEquals("Get long of doubleIdentifierWithMultipleLeadingZerosAfterDecimal does not match",
|
||||
0.0d,jsonObject.optLong("doubleIdentifierWithMultipleLeadingZerosAfterDecimal"), 0.0d);
|
||||
Util.checkJSONObjectMaps(jsonObject);
|
||||
}
|
||||
|
||||
@@ -2095,7 +2034,9 @@ public class JSONObjectTest {
|
||||
"}";
|
||||
JSONObject jsonObject = new JSONObject(jsonObjectStr);
|
||||
assertTrue("jsonObject valueToString() incorrect",
|
||||
JSONObject.valueToString(jsonObject).equals(jsonObject.toString()));
|
||||
new JSONObject(JSONObject.valueToString(jsonObject))
|
||||
.similar(new JSONObject(jsonObject.toString()))
|
||||
);
|
||||
String jsonArrayStr =
|
||||
"[1,2,3]";
|
||||
JSONArray jsonArray = new JSONArray(jsonArrayStr);
|
||||
@@ -2106,7 +2047,8 @@ public class JSONObjectTest {
|
||||
map.put("key2", "val2");
|
||||
map.put("key3", "val3");
|
||||
assertTrue("map valueToString() incorrect",
|
||||
jsonObject.toString().equals(JSONObject.valueToString(map)));
|
||||
new JSONObject(jsonObject.toString())
|
||||
.similar(new JSONObject(JSONObject.valueToString(map))));
|
||||
Collection<Integer> collection = new ArrayList<Integer>();
|
||||
collection.add(Integer.valueOf(1));
|
||||
collection.add(Integer.valueOf(2));
|
||||
@@ -2392,7 +2334,7 @@ public class JSONObjectTest {
|
||||
}
|
||||
try {
|
||||
// test validity of invalid double
|
||||
JSONObject.testValidity(NaN);
|
||||
JSONObject.testValidity(Double.NaN);
|
||||
fail("Expected an exception");
|
||||
} catch (JSONException e) {
|
||||
assertTrue("", true);
|
||||
@@ -3662,6 +3604,7 @@ public class JSONObjectTest {
|
||||
/**
|
||||
* Tests for stack overflow. See https://github.com/stleary/JSON-java/issues/654
|
||||
*/
|
||||
@Ignore("This test relies on system constraints and may not always pass. See: https://github.com/stleary/JSON-java/issues/821")
|
||||
@Test(expected = JSONException.class)
|
||||
public void issue654StackOverflowInputWellFormed() {
|
||||
//String input = new String(java.util.Base64.getDecoder().decode(base64Bytes));
|
||||
@@ -3669,7 +3612,7 @@ public class JSONObjectTest {
|
||||
JSONTokener tokener = new JSONTokener(resourceAsStream);
|
||||
JSONObject json_input = new JSONObject(tokener);
|
||||
assertNotNull(json_input);
|
||||
fail("Excepected Exception.");
|
||||
fail("Excepected Exception due to stack overflow.");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -3713,4 +3656,138 @@ public class JSONObjectTest {
|
||||
assertThrows(JSONException.class, () -> new JSONObject(bean));
|
||||
}
|
||||
}
|
||||
|
||||
@Test(expected = JSONException.class)
|
||||
public void issue743SerializationMap() {
|
||||
HashMap<String, Object> map = new HashMap<>();
|
||||
map.put("t", map);
|
||||
JSONObject object = new JSONObject(map);
|
||||
String jsonString = object.toString();
|
||||
}
|
||||
|
||||
@Test(expected = JSONException.class)
|
||||
public void testCircularReferenceMultipleLevel() {
|
||||
HashMap<String, Object> inside = new HashMap<>();
|
||||
HashMap<String, Object> jsonObject = new HashMap<>();
|
||||
inside.put("inside", jsonObject);
|
||||
jsonObject.put("test", inside);
|
||||
new JSONObject(jsonObject);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void issue743SerializationMapWith512Objects() {
|
||||
HashMap<String, Object> map = buildNestedMap(ParserConfiguration.DEFAULT_MAXIMUM_NESTING_DEPTH);
|
||||
JSONObject object = new JSONObject(map);
|
||||
String jsonString = object.toString();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void issue743SerializationMapWith1000Objects() {
|
||||
HashMap<String, Object> map = buildNestedMap(1000);
|
||||
JSONParserConfiguration parserConfiguration = new JSONParserConfiguration().withMaxNestingDepth(1000);
|
||||
JSONObject object = new JSONObject(map, parserConfiguration);
|
||||
String jsonString = object.toString();
|
||||
}
|
||||
|
||||
@Test(expected = JSONException.class)
|
||||
public void issue743SerializationMapWith1001Objects() {
|
||||
HashMap<String, Object> map = buildNestedMap(1001);
|
||||
JSONObject object = new JSONObject(map);
|
||||
String jsonString = object.toString();
|
||||
}
|
||||
|
||||
@Test(expected = JSONException.class)
|
||||
public void testCircleReferenceFirstLevel() {
|
||||
Map<Object, Object> jsonObject = new HashMap<>();
|
||||
|
||||
jsonObject.put("test", jsonObject);
|
||||
|
||||
new JSONObject(jsonObject, new JSONParserConfiguration());
|
||||
}
|
||||
|
||||
@Test(expected = StackOverflowError.class)
|
||||
public void testCircleReferenceMultiplyLevel_notConfigured_expectedStackOverflow() {
|
||||
Map<Object, Object> inside = new HashMap<>();
|
||||
|
||||
Map<Object, Object> jsonObject = new HashMap<>();
|
||||
inside.put("test", jsonObject);
|
||||
jsonObject.put("test", inside);
|
||||
|
||||
new JSONObject(jsonObject, new JSONParserConfiguration().withMaxNestingDepth(99999));
|
||||
}
|
||||
|
||||
@Test(expected = JSONException.class)
|
||||
public void testCircleReferenceMultiplyLevel_configured_expectedJSONException() {
|
||||
Map<Object, Object> inside = new HashMap<>();
|
||||
|
||||
Map<Object, Object> jsonObject = new HashMap<>();
|
||||
inside.put("test", jsonObject);
|
||||
jsonObject.put("test", inside);
|
||||
|
||||
new JSONObject(jsonObject, new JSONParserConfiguration());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDifferentKeySameInstanceNotACircleReference() {
|
||||
Map<Object, Object> map1 = new HashMap<>();
|
||||
Map<Object, Object> map2 = new HashMap<>();
|
||||
|
||||
map1.put("test1", map2);
|
||||
map1.put("test2", map2);
|
||||
|
||||
new JSONObject(map1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void clarifyCurrentBehavior() {
|
||||
// Behavior documented in #653 optLong vs getLong inconsistencies
|
||||
// This problem still exists.
|
||||
// Internally, both number_1 and number_2 are stored as strings. This is reasonable since they are parsed as strings.
|
||||
// However, getLong and optLong should return similar results
|
||||
JSONObject json = new JSONObject("{\"number_1\":\"01234\", \"number_2\": \"332211\"}");
|
||||
assertEquals(json.getLong("number_1"), 1234L);
|
||||
assertEquals(json.optLong("number_1"), 0); //THIS VALUE IS NOT RETURNED AS A NUMBER
|
||||
assertEquals(json.getLong("number_2"), 332211L);
|
||||
assertEquals(json.optLong("number_2"), 332211L);
|
||||
|
||||
// Behavior documented in #826 JSONObject parsing 0-led numeric strings as ints
|
||||
// After reverting the code, personId is stored as a string, and the behavior is as expected
|
||||
String personId = "0123";
|
||||
JSONObject j1 = new JSONObject("{personId: " + personId + "}");
|
||||
assertEquals(j1.getString("personId"), "0123");
|
||||
|
||||
// Also #826. Here is input with missing quotes. Because of the leading zero, it should not be parsed as a number.
|
||||
// This example was mentioned in the same ticket
|
||||
// After reverting the code, personId is stored as a string, and the behavior is as expected
|
||||
JSONObject j2 = new JSONObject("{\"personId\":0123}");
|
||||
assertEquals(j2.getString("personId"), "0123");
|
||||
|
||||
// Behavior uncovered while working on the code
|
||||
// All of the values are stored as strings except for hex4, which is stored as a number. This is probably incorrect
|
||||
JSONObject j3 = new JSONObject("{ " +
|
||||
"\"hex1\": \"010e4\", \"hex2\": \"00f0\", \"hex3\": \"0011\", " +
|
||||
"\"hex4\": 00e0, \"hex5\": 00f0, \"hex6\": 0011 }");
|
||||
assertEquals(j3.getString("hex1"), "010e4");
|
||||
assertEquals(j3.getString("hex2"), "00f0");
|
||||
assertEquals(j3.getString("hex3"), "0011");
|
||||
assertEquals(j3.getLong("hex4"), 0, .1);
|
||||
assertEquals(j3.getString("hex5"), "00f0");
|
||||
assertEquals(j3.getString("hex6"), "0011");
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to build nested map of max maxDepth
|
||||
*
|
||||
* @param maxDepth
|
||||
* @return
|
||||
*/
|
||||
public static HashMap<String, Object> buildNestedMap(int maxDepth) {
|
||||
if (maxDepth <= 0) {
|
||||
return new HashMap<>();
|
||||
}
|
||||
HashMap<String, Object> nestedMap = new HashMap<>();
|
||||
nestedMap.put("t", buildNestedMap(maxDepth - 1));
|
||||
return nestedMap;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,55 +0,0 @@
|
||||
package org.json.junit;
|
||||
|
||||
import org.json.JSONObject;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.BigInteger;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
public class JsonNumberZeroTest {
|
||||
|
||||
@Test
|
||||
public void shouldParseNegativeZeroValueWithMultipleZeroDigit(){
|
||||
JSONObject jsonObject = new JSONObject("{value:-0000}");
|
||||
assertEquals("Float not recognized", -0f, jsonObject.getFloat("value"), 0.0f);
|
||||
assertEquals("Float not recognized", -0f, jsonObject.optFloat("value"), 0.0f);
|
||||
assertEquals("Float not recognized", -0f, jsonObject.optFloatObject("value"), 0.0f);
|
||||
assertEquals("Double not recognized", -0d, jsonObject.optDouble("value"), 0.0f);
|
||||
assertEquals("Double not recognized", -0.0d, jsonObject.optDoubleObject("value"), 0.0f);
|
||||
assertEquals("Double not recognized", -0.0d, jsonObject.getDouble("value"), 0.0f);
|
||||
assertEquals("Long not recognized", 0, jsonObject.optLong("value"), 0);
|
||||
assertEquals("Long not recognized", 0, jsonObject.getLong("value"), 0);
|
||||
assertEquals("Long not recognized", 0, jsonObject.optLongObject("value"), 0);
|
||||
assertEquals("Integer not recognized", 0, jsonObject.optInt("value"), 0);
|
||||
assertEquals("Integer not recognized", 0, jsonObject.getInt("value"), 0);
|
||||
assertEquals("Integer not recognized", 0, jsonObject.optIntegerObject("value"), 0);
|
||||
assertEquals("Number not recognized", 0, jsonObject.getNumber("value").intValue(), 0);
|
||||
assertEquals("Number not recognized", 0, jsonObject.getNumber("value").longValue(), 0);
|
||||
assertEquals("BigDecimal not recognized", 0, BigDecimal.valueOf(-0).compareTo(jsonObject.getBigDecimal("value")));
|
||||
assertEquals("BigInteger not recognized",0, BigInteger.valueOf(0).compareTo(jsonObject.getBigInteger("value")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldParseZeroValueWithMultipleZeroDigit(){
|
||||
JSONObject jsonObject = new JSONObject("{value:0000}");
|
||||
assertEquals("Float not recognized", 0f, jsonObject.getFloat("value"), 0.0f);
|
||||
assertEquals("Float not recognized", 0f, jsonObject.optFloat("value"), 0.0f);
|
||||
assertEquals("Float not recognized", 0f, jsonObject.optFloatObject("value"), 0.0f);
|
||||
assertEquals("Double not recognized", 0d, jsonObject.optDouble("value"), 0.0f);
|
||||
assertEquals("Double not recognized", 0.0d, jsonObject.optDoubleObject("value"), 0.0f);
|
||||
assertEquals("Double not recognized", 0.0d, jsonObject.getDouble("value"), 0.0f);
|
||||
assertEquals("Long not recognized", 0, jsonObject.optLong("value"), 0);
|
||||
assertEquals("Long not recognized", 0, jsonObject.getLong("value"), 0);
|
||||
assertEquals("Long not recognized", 0, jsonObject.optLongObject("value"), 0);
|
||||
assertEquals("Integer not recognized", 0, jsonObject.optInt("value"), 0);
|
||||
assertEquals("Integer not recognized", 0, jsonObject.getInt("value"), 0);
|
||||
assertEquals("Integer not recognized", 0, jsonObject.optIntegerObject("value"), 0);
|
||||
assertEquals("Number not recognized", 0, jsonObject.getNumber("value").intValue(), 0);
|
||||
assertEquals("Number not recognized", 0, jsonObject.getNumber("value").longValue(), 0);
|
||||
assertEquals("BigDecimal not recognized", 0, BigDecimal.valueOf(-0).compareTo(jsonObject.getBigDecimal("value")));
|
||||
assertEquals("BigInteger not recognized",0, BigInteger.valueOf(0).compareTo(jsonObject.getBigInteger("value")));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -4,11 +4,6 @@ package org.json.junit;
|
||||
Public Domain.
|
||||
*/
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileReader;
|
||||
import java.io.FileWriter;
|
||||
@@ -27,6 +22,8 @@ import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.TemporaryFolder;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
|
||||
/**
|
||||
* Tests for JSON-Java XML.java with XMLParserConfiguration.java
|
||||
@@ -557,6 +554,37 @@ public class XMLConfigurationTest {
|
||||
assertEquals(actualXML, resultXML);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldHandleEmptyNodeValue()
|
||||
{
|
||||
JSONObject inputJSON = new JSONObject();
|
||||
inputJSON.put("Emptyness", "");
|
||||
String expectedXmlWithoutExplicitEndTag = "<Emptyness/>";
|
||||
String expectedXmlWithExplicitEndTag = "<Emptyness></Emptyness>";
|
||||
assertEquals(expectedXmlWithoutExplicitEndTag, XML.toString(inputJSON, null,
|
||||
new XMLParserConfiguration().withCloseEmptyTag(false)));
|
||||
assertEquals(expectedXmlWithExplicitEndTag, XML.toString(inputJSON, null,
|
||||
new XMLParserConfiguration().withCloseEmptyTag(true)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldKeepConfigurationIntactAndUpdateCloseEmptyTagChoice()
|
||||
{
|
||||
XMLParserConfiguration keepStrings = XMLParserConfiguration.KEEP_STRINGS;
|
||||
XMLParserConfiguration keepStringsAndCloseEmptyTag = keepStrings.withCloseEmptyTag(true);
|
||||
XMLParserConfiguration keepDigits = keepStringsAndCloseEmptyTag.withKeepStrings(false);
|
||||
XMLParserConfiguration keepDigitsAndNoCloseEmptyTag = keepDigits.withCloseEmptyTag(false);
|
||||
assertTrue(keepStrings.isKeepStrings());
|
||||
assertFalse(keepStrings.isCloseEmptyTag());
|
||||
assertTrue(keepStringsAndCloseEmptyTag.isKeepStrings());
|
||||
assertTrue(keepStringsAndCloseEmptyTag.isCloseEmptyTag());
|
||||
assertFalse(keepDigits.isKeepStrings());
|
||||
assertTrue(keepDigits.isCloseEmptyTag());
|
||||
assertFalse(keepDigitsAndNoCloseEmptyTag.isKeepStrings());
|
||||
assertFalse(keepDigitsAndNoCloseEmptyTag.isCloseEmptyTag());
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Investigate exactly how the "content" keyword works
|
||||
*/
|
||||
@@ -1153,4 +1181,4 @@ public class XMLConfigurationTest {
|
||||
assertTrue("Error: " +e.getMessage(), false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1177,6 +1177,30 @@ public class XMLTest {
|
||||
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldCreateExplicitEndTagWithEmptyValueWhenConfigured(){
|
||||
String jsonString = "{outer:{innerOne:\"\", innerTwo:\"two\"}}";
|
||||
JSONObject jsonObject = new JSONObject(jsonString);
|
||||
String expectedXmlString = "<encloser><outer><innerOne></innerOne><innerTwo>two</innerTwo></outer></encloser>";
|
||||
String xmlForm = XML.toString(jsonObject,"encloser", new XMLParserConfiguration().withCloseEmptyTag(true));
|
||||
JSONObject actualJsonObject = XML.toJSONObject(xmlForm);
|
||||
JSONObject expectedJsonObject = XML.toJSONObject(expectedXmlString);
|
||||
assertTrue(expectedJsonObject.similar(actualJsonObject));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldNotCreateExplicitEndTagWithEmptyValueWhenNotConfigured(){
|
||||
String jsonString = "{outer:{innerOne:\"\", innerTwo:\"two\"}}";
|
||||
JSONObject jsonObject = new JSONObject(jsonString);
|
||||
String expectedXmlString = "<encloser><outer><innerOne/><innerTwo>two</innerTwo></outer></encloser>";
|
||||
String xmlForm = XML.toString(jsonObject,"encloser", new XMLParserConfiguration().withCloseEmptyTag(false));
|
||||
JSONObject actualJsonObject = XML.toJSONObject(xmlForm);
|
||||
JSONObject expectedJsonObject = XML.toJSONObject(expectedXmlString);
|
||||
assertTrue(expectedJsonObject.similar(actualJsonObject));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testIndentSimpleJsonObject(){
|
||||
String str = "{ \"employee\": { \n" +
|
||||
@@ -1234,7 +1258,7 @@ public class XMLTest {
|
||||
for (int numRead; (numRead = in.read(buffer, 0, buffer.length)) > 0; ) {
|
||||
expected.append(buffer, 0, numRead);
|
||||
}
|
||||
assertEquals(expected.toString(), actualString);
|
||||
assertTrue(XML.toJSONObject(expected.toString()).similar(XML.toJSONObject(actualString)));
|
||||
}
|
||||
} catch (IOException e) {
|
||||
fail("file writer error: " +e.getMessage());
|
||||
@@ -1299,6 +1323,109 @@ public class XMLTest {
|
||||
"parameter of the XMLParserConfiguration used");
|
||||
}
|
||||
}
|
||||
@Test
|
||||
public void testWithWhitespaceTrimmingDisabled() {
|
||||
String originalXml = "<testXml> Test Whitespace String \t </testXml>";
|
||||
|
||||
JSONObject actualJson = XML.toJSONObject(originalXml, new XMLParserConfiguration().withShouldTrimWhitespace(false));
|
||||
String expectedJsonString = "{\"testXml\":\" Test Whitespace String \t \"}";
|
||||
JSONObject expectedJson = new JSONObject(expectedJsonString);
|
||||
Util.compareActualVsExpectedJsonObjects(actualJson,expectedJson);
|
||||
}
|
||||
@Test
|
||||
public void testNestedWithWhitespaceTrimmingDisabled() {
|
||||
String originalXml =
|
||||
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"+
|
||||
"<addresses>\n"+
|
||||
" <address>\n"+
|
||||
" <name> Sherlock Holmes </name>\n"+
|
||||
" </address>\n"+
|
||||
"</addresses>";
|
||||
|
||||
JSONObject actualJson = XML.toJSONObject(originalXml, new XMLParserConfiguration().withShouldTrimWhitespace(false));
|
||||
String expectedJsonString = "{\"addresses\":{\"address\":{\"name\":\" Sherlock Holmes \"}}}";
|
||||
JSONObject expectedJson = new JSONObject(expectedJsonString);
|
||||
Util.compareActualVsExpectedJsonObjects(actualJson,expectedJson);
|
||||
}
|
||||
@Test
|
||||
public void shouldTrimWhitespaceDoesNotSupportTagsEqualingCDataTagName() {
|
||||
// When using withShouldTrimWhitespace = true, input containing tags with same name as cDataTagName is unsupported and should not be used in conjunction
|
||||
String originalXml =
|
||||
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"+
|
||||
"<addresses>\n"+
|
||||
" <address>\n"+
|
||||
" <content> Sherlock Holmes </content>\n"+
|
||||
" </address>\n"+
|
||||
"</addresses>";
|
||||
|
||||
JSONObject actualJson = XML.toJSONObject(originalXml, new XMLParserConfiguration().withShouldTrimWhitespace(false).withcDataTagName("content"));
|
||||
String expectedJsonString = "{\"addresses\":{\"address\":[[\"\\n \",\" Sherlock Holmes \",\"\\n \"]]}}";
|
||||
JSONObject expectedJson = new JSONObject(expectedJsonString);
|
||||
Util.compareActualVsExpectedJsonObjects(actualJson,expectedJson);
|
||||
}
|
||||
@Test
|
||||
public void shouldTrimWhitespaceEnabledDropsTagsEqualingCDataTagNameButValueRemains() {
|
||||
String originalXml =
|
||||
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"+
|
||||
"<addresses>\n"+
|
||||
" <address>\n"+
|
||||
" <content> Sherlock Holmes </content>\n"+
|
||||
" </address>\n"+
|
||||
"</addresses>";
|
||||
|
||||
JSONObject actualJson = XML.toJSONObject(originalXml, new XMLParserConfiguration().withShouldTrimWhitespace(true).withcDataTagName("content"));
|
||||
String expectedJsonString = "{\"addresses\":{\"address\":\"Sherlock Holmes\"}}";
|
||||
JSONObject expectedJson = new JSONObject(expectedJsonString);
|
||||
Util.compareActualVsExpectedJsonObjects(actualJson,expectedJson);
|
||||
}
|
||||
@Test
|
||||
public void testWithWhitespaceTrimmingEnabled() {
|
||||
String originalXml = "<testXml> Test Whitespace String \t </testXml>";
|
||||
|
||||
JSONObject actualJson = XML.toJSONObject(originalXml, new XMLParserConfiguration().withShouldTrimWhitespace(true));
|
||||
String expectedJsonString = "{\"testXml\":\"Test Whitespace String\"}";
|
||||
JSONObject expectedJson = new JSONObject(expectedJsonString);
|
||||
Util.compareActualVsExpectedJsonObjects(actualJson,expectedJson);
|
||||
}
|
||||
@Test
|
||||
public void testWithWhitespaceTrimmingEnabledByDefault() {
|
||||
String originalXml = "<testXml> Test Whitespace String \t </testXml>";
|
||||
|
||||
JSONObject actualJson = XML.toJSONObject(originalXml, new XMLParserConfiguration());
|
||||
String expectedJsonString = "{\"testXml\":\"Test Whitespace String\"}";
|
||||
JSONObject expectedJson = new JSONObject(expectedJsonString);
|
||||
Util.compareActualVsExpectedJsonObjects(actualJson,expectedJson);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void clarifyCurrentBehavior() {
|
||||
|
||||
// Behavior documented in #826
|
||||
// After reverting the code, amount is stored as numeric, and phone is stored as string
|
||||
String str1 =
|
||||
" <datatypes>\n" +
|
||||
" <telephone>0123456789</telephone>\n" +
|
||||
" <amount>0.1230</amount>\n" +
|
||||
" <boolean>true</boolean>\n" +
|
||||
" </datatypes>";
|
||||
JSONObject jsonObject1 = XML.toJSONObject(str1,
|
||||
new XMLParserConfiguration().withKeepStrings(false));
|
||||
assertEquals(jsonObject1.getJSONObject("datatypes").getFloat("amount"), 0.123, .1);
|
||||
assertEquals(jsonObject1.getJSONObject("datatypes").getString("telephone"), "0123456789");
|
||||
|
||||
|
||||
// Behavior documented in #852
|
||||
// After reverting the code, value is still stored as a number. This is due to how XML.isDecimalNotation() works
|
||||
// and is probably a bug. JSONObject has a similar problem.
|
||||
String str2 = "<color> <color_type>primary</color_type> <value>008E97</value> </color>";
|
||||
JSONObject jsonObject2 = XML.toJSONObject(str2);
|
||||
assertEquals(jsonObject2.getJSONObject("color").getLong("value"), 0e897, .1);
|
||||
|
||||
// Workaround for now is to use keepStrings
|
||||
JSONObject jsonObject3 = XML.toJSONObject(str2, new XMLParserConfiguration().withKeepStrings(true));
|
||||
assertEquals(jsonObject3.getJSONObject("color").getString("value"), "008E97");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ import java.util.List;
|
||||
*/
|
||||
public class WeirdList {
|
||||
/** */
|
||||
private final List<Integer> list = new ArrayList();
|
||||
private final List<Integer> list = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* @param vals
|
||||
@@ -25,14 +25,14 @@ public class WeirdList {
|
||||
* @return a copy of the list
|
||||
*/
|
||||
public List<Integer> get() {
|
||||
return new ArrayList(this.list);
|
||||
return new ArrayList<>(this.list);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return a copy of the list
|
||||
*/
|
||||
public List<Integer> getALL() {
|
||||
return new ArrayList(this.list);
|
||||
return new ArrayList<>(this.list);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user