mirror of
https://github.com/stleary/JSON-java.git
synced 2026-01-24 00:03:17 -05:00
Compare commits
90 Commits
pre-releas
...
20251224
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cf653682be | ||
|
|
24bba97c1d | ||
|
|
128fb42ccc | ||
|
|
f8e6dfdc63 | ||
|
|
3bc98dfc7f | ||
|
|
005dc7b49e | ||
|
|
d38cb064fd | ||
|
|
e9a7d7c72e | ||
|
|
73c582e129 | ||
|
|
a6ca84074a | ||
|
|
8c14e96c44 | ||
|
|
8f3b0f1c13 | ||
|
|
f2acf8af69 | ||
|
|
fd1eee9c3b | ||
|
|
2550c692cf | ||
|
|
20f5200000 | ||
|
|
25f355a953 | ||
|
|
42800c208a | ||
|
|
0cdc5e5170 | ||
|
|
ac65ee0490 | ||
|
|
39e8ead7cd | ||
|
|
6dd878d3c9 | ||
|
|
2c6082a0a2 | ||
|
|
5dc1031d17 | ||
|
|
1de42aa4fd | ||
|
|
c13b57ca26 | ||
|
|
f92f281620 | ||
|
|
8ccf5d7525 | ||
|
|
a7c193090a | ||
|
|
c4c2beb874 | ||
|
|
9adea9e12d | ||
|
|
7465da858c | ||
|
|
0521928463 | ||
|
|
fbb6b3158e | ||
|
|
ebc13d6685 | ||
|
|
7d28955216 | ||
|
|
83a0e34be5 | ||
|
|
3e8d1d119f | ||
|
|
1a2c50b40c | ||
|
|
eb97037f7c | ||
|
|
05867c4b0b | ||
|
|
c6efa080c0 | ||
|
|
aff59d06fa | ||
|
|
b258ea3d46 | ||
|
|
a5e234aa19 | ||
|
|
f2af220cb4 | ||
|
|
a3edc1da0f | ||
|
|
686c084897 | ||
|
|
9de3005566 | ||
|
|
69c87dc4db | ||
|
|
53cfa742a7 | ||
|
|
4e0f62b1a6 | ||
|
|
9b8eefc2de | ||
|
|
6ed2880f55 | ||
|
|
9bb26bdb34 | ||
|
|
78137d389d | ||
|
|
38c3a0bb3f | ||
|
|
ebd9a17a3b | ||
|
|
82432f0245 | ||
|
|
e762629bcc | ||
|
|
7fc41a6c0e | ||
|
|
d5d82cdb87 | ||
|
|
0a9364e920 | ||
|
|
c91b728386 | ||
|
|
fdaeb486ed | ||
|
|
f0a78aff61 | ||
|
|
a79e8a15e5 | ||
|
|
7bb3df8ebf | ||
|
|
3dce55794f | ||
|
|
d7593fb808 | ||
|
|
1eed44a59e | ||
|
|
7eccadefcd | ||
|
|
7b0d1942b4 | ||
|
|
a729c2077a | ||
|
|
7ac773be72 | ||
|
|
7da120e631 | ||
|
|
197afddbfb | ||
|
|
1bdaacc8b0 | ||
|
|
c882783d58 | ||
|
|
5063d314a5 | ||
|
|
916fba5d39 | ||
|
|
aac376f305 | ||
|
|
32e56da786 | ||
|
|
50330430ce | ||
|
|
f1935f5254 | ||
|
|
e800cc349f | ||
|
|
72a1a48173 | ||
|
|
a381060f81 | ||
|
|
dadc3e59dc | ||
|
|
24fafcffeb |
4
.github/workflows/codeql-analysis.yml
vendored
4
.github/workflows/codeql-analysis.yml
vendored
@@ -29,7 +29,7 @@ jobs:
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v2
|
||||
uses: github/codeql-action/init@v3
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
# If you wish to specify custom queries, you can do so here or in a config file.
|
||||
@@ -40,4 +40,4 @@ jobs:
|
||||
- run: "mvn clean compile -Dmaven.test.skip=true -Dmaven.site.skip=true -Dmaven.javadoc.skip=true"
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v2
|
||||
uses: github/codeql-action/analyze@v3
|
||||
|
||||
93
.github/workflows/pipeline.yml
vendored
93
.github/workflows/pipeline.yml
vendored
@@ -15,7 +15,7 @@ jobs:
|
||||
name: Java 1.6
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v5
|
||||
- name: Setup java
|
||||
uses: actions/setup-java@v1
|
||||
with:
|
||||
@@ -30,7 +30,7 @@ jobs:
|
||||
jar cvf target/org.json.jar -C target/classes .
|
||||
- name: Upload JAR 1.6
|
||||
if: ${{ always() }}
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v5
|
||||
with:
|
||||
name: Create java 1.6 JAR
|
||||
path: target/*.jar
|
||||
@@ -45,9 +45,9 @@ jobs:
|
||||
java: [ 8 ]
|
||||
name: Java ${{ matrix.java }}
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v5
|
||||
- name: Set up JDK ${{ matrix.java }}
|
||||
uses: actions/setup-java@v3
|
||||
uses: actions/setup-java@v5
|
||||
with:
|
||||
distribution: 'temurin'
|
||||
java-version: ${{ matrix.java }}
|
||||
@@ -64,13 +64,13 @@ jobs:
|
||||
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@v4
|
||||
uses: actions/upload-artifact@v5
|
||||
with:
|
||||
name: Test Results ${{ matrix.java }}
|
||||
path: target/surefire-reports/
|
||||
- name: Upload Test Report ${{ matrix.java }}
|
||||
if: ${{ always() }}
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v5
|
||||
with:
|
||||
name: Test Report ${{ matrix.java }}
|
||||
path: target/site/
|
||||
@@ -78,7 +78,7 @@ jobs:
|
||||
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@v4
|
||||
uses: actions/upload-artifact@v5
|
||||
with:
|
||||
name: Package Jar ${{ matrix.java }}
|
||||
path: target/*.jar
|
||||
@@ -93,9 +93,9 @@ jobs:
|
||||
java: [ 11 ]
|
||||
name: Java ${{ matrix.java }}
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v5
|
||||
- name: Set up JDK ${{ matrix.java }}
|
||||
uses: actions/setup-java@v3
|
||||
uses: actions/setup-java@v5
|
||||
with:
|
||||
distribution: 'temurin'
|
||||
java-version: ${{ matrix.java }}
|
||||
@@ -112,13 +112,13 @@ jobs:
|
||||
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@v4
|
||||
uses: actions/upload-artifact@v5
|
||||
with:
|
||||
name: Test Results ${{ matrix.java }}
|
||||
path: target/surefire-reports/
|
||||
- name: Upload Test Report ${{ matrix.java }}
|
||||
if: ${{ always() }}
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v5
|
||||
with:
|
||||
name: Test Report ${{ matrix.java }}
|
||||
path: target/site/
|
||||
@@ -126,7 +126,7 @@ jobs:
|
||||
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@v4
|
||||
uses: actions/upload-artifact@v5
|
||||
with:
|
||||
name: Package Jar ${{ matrix.java }}
|
||||
path: target/*.jar
|
||||
@@ -141,9 +141,9 @@ jobs:
|
||||
java: [ 17 ]
|
||||
name: Java ${{ matrix.java }}
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v5
|
||||
- name: Set up JDK ${{ matrix.java }}
|
||||
uses: actions/setup-java@v3
|
||||
uses: actions/setup-java@v5
|
||||
with:
|
||||
distribution: 'temurin'
|
||||
java-version: ${{ matrix.java }}
|
||||
@@ -160,13 +160,13 @@ jobs:
|
||||
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@v4
|
||||
uses: actions/upload-artifact@v5
|
||||
with:
|
||||
name: Test Results ${{ matrix.java }}
|
||||
path: target/surefire-reports/
|
||||
- name: Upload Test Report ${{ matrix.java }}
|
||||
if: ${{ always() }}
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v5
|
||||
with:
|
||||
name: Test Report ${{ matrix.java }}
|
||||
path: target/site/
|
||||
@@ -174,7 +174,7 @@ jobs:
|
||||
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@v4
|
||||
uses: actions/upload-artifact@v5
|
||||
with:
|
||||
name: Package Jar ${{ matrix.java }}
|
||||
path: target/*.jar
|
||||
@@ -189,9 +189,9 @@ jobs:
|
||||
java: [ 21 ]
|
||||
name: Java ${{ matrix.java }}
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v5
|
||||
- name: Set up JDK ${{ matrix.java }}
|
||||
uses: actions/setup-java@v3
|
||||
uses: actions/setup-java@v5
|
||||
with:
|
||||
distribution: 'temurin'
|
||||
java-version: ${{ matrix.java }}
|
||||
@@ -208,13 +208,13 @@ jobs:
|
||||
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@v4
|
||||
uses: actions/upload-artifact@v5
|
||||
with:
|
||||
name: Test Results ${{ matrix.java }}
|
||||
path: target/surefire-reports/
|
||||
- name: Upload Test Report ${{ matrix.java }}
|
||||
if: ${{ always() }}
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v5
|
||||
with:
|
||||
name: Test Report ${{ matrix.java }}
|
||||
path: target/site/
|
||||
@@ -222,7 +222,56 @@ jobs:
|
||||
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@v4
|
||||
uses: actions/upload-artifact@v5
|
||||
with:
|
||||
name: Package Jar ${{ matrix.java }}
|
||||
path: target/*.jar
|
||||
|
||||
build-25:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
max-parallel: 1
|
||||
matrix:
|
||||
# build against supported Java LTS versions:
|
||||
java: [ 25 ]
|
||||
name: Java ${{ matrix.java }}
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
- name: Set up JDK ${{ matrix.java }}
|
||||
uses: actions/setup-java@v5
|
||||
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@v5
|
||||
with:
|
||||
name: Test Results ${{ matrix.java }}
|
||||
path: target/surefire-reports/
|
||||
- name: Upload Test Report ${{ matrix.java }}
|
||||
if: ${{ always() }}
|
||||
uses: actions/upload-artifact@v5
|
||||
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@v5
|
||||
with:
|
||||
name: Package Jar ${{ matrix.java }}
|
||||
path: target/*.jar
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ JSON in Java [package org.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/20250517/json-20250517.jar)**
|
||||
**[Click here if you just want the latest release jar file.](https://search.maven.org/remotecontent?filepath=org/json/json/20251224/json-20251224.jar)**
|
||||
|
||||
|
||||
# Overview
|
||||
@@ -26,7 +26,7 @@ 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 - 21
|
||||
* Designed and tested to use on Java versions 1.6 - 25
|
||||
|
||||
|
||||
The files in this package implement JSON encoders and decoders. The package can also convert between JSON and XML, HTTP headers, Cookies, and CDL.
|
||||
|
||||
16
build.gradle
16
build.gradle
@@ -3,9 +3,10 @@
|
||||
*/
|
||||
apply plugin: 'java'
|
||||
apply plugin: 'eclipse'
|
||||
// apply plugin: 'jacoco'
|
||||
apply plugin: 'jacoco'
|
||||
apply plugin: 'maven-publish'
|
||||
|
||||
// for now, publishing to maven is still a manual process
|
||||
//plugins {
|
||||
// id 'java'
|
||||
//id 'maven-publish'
|
||||
@@ -19,6 +20,17 @@ repositories {
|
||||
}
|
||||
}
|
||||
|
||||
// To view the report open build/reports/jacoco/test/html/index.html
|
||||
jacocoTestReport {
|
||||
reports {
|
||||
html.required = true
|
||||
}
|
||||
}
|
||||
|
||||
test {
|
||||
finalizedBy jacocoTestReport
|
||||
}
|
||||
|
||||
dependencies {
|
||||
testImplementation 'junit:junit:4.13.2'
|
||||
testImplementation 'com.jayway.jsonpath:json-path:2.9.0'
|
||||
@@ -30,7 +42,7 @@ subprojects {
|
||||
}
|
||||
|
||||
group = 'org.json'
|
||||
version = 'v20250517-SNAPSHOT'
|
||||
version = 'v20251224-SNAPSHOT'
|
||||
description = 'JSON in Java'
|
||||
sourceCompatibility = '1.8'
|
||||
|
||||
|
||||
@@ -5,6 +5,8 @@ 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)
|
||||
|
||||
~~~
|
||||
20251224 Records, fromJson(), and recent commits
|
||||
|
||||
20250517 Strict mode hardening and recent commits
|
||||
|
||||
20250107 Restore moditect in pom.xml
|
||||
|
||||
2
pom.xml
2
pom.xml
@@ -3,7 +3,7 @@
|
||||
|
||||
<groupId>org.json</groupId>
|
||||
<artifactId>json</artifactId>
|
||||
<version>20250517</version>
|
||||
<version>20251224</version>
|
||||
<packaging>bundle</packaging>
|
||||
|
||||
<name>JSON in Java</name>
|
||||
|
||||
@@ -27,7 +27,9 @@ public class CDL {
|
||||
|
||||
/**
|
||||
* Constructs a new CDL object.
|
||||
* @deprecated (Utility class cannot be instantiated)
|
||||
*/
|
||||
@Deprecated
|
||||
public CDL() {
|
||||
}
|
||||
|
||||
@@ -183,7 +185,7 @@ public class CDL {
|
||||
Object object = ja.opt(i);
|
||||
if (object != null) {
|
||||
String string = object.toString();
|
||||
if (string.length() > 0 && (string.indexOf(delimiter) >= 0 ||
|
||||
if (!string.isEmpty() && (string.indexOf(delimiter) >= 0 ||
|
||||
string.indexOf('\n') >= 0 || string.indexOf('\r') >= 0 ||
|
||||
string.indexOf(0) >= 0 || string.charAt(0) == '"')) {
|
||||
sb.append('"');
|
||||
|
||||
@@ -17,7 +17,9 @@ public class Cookie {
|
||||
|
||||
/**
|
||||
* Constructs a new Cookie object.
|
||||
* @deprecated (Utility class cannot be instantiated)
|
||||
*/
|
||||
@Deprecated()
|
||||
public Cookie() {
|
||||
}
|
||||
|
||||
|
||||
@@ -13,7 +13,9 @@ public class CookieList {
|
||||
|
||||
/**
|
||||
* Constructs a new CookieList object.
|
||||
* @deprecated (Utility class cannot be instantiated)
|
||||
*/
|
||||
@Deprecated
|
||||
public CookieList() {
|
||||
}
|
||||
|
||||
|
||||
@@ -105,6 +105,8 @@ public class JSONArray implements Iterable<Object> {
|
||||
if (nextChar == 0) {
|
||||
// array is unclosed. No ']' found, instead EOF
|
||||
throw x.syntaxError("Expected a ',' or ']'");
|
||||
} else if (nextChar==',' && jsonParserConfiguration.isStrictMode()) {
|
||||
throw x.syntaxError("Array content starts with a ','");
|
||||
}
|
||||
if (nextChar != ']') {
|
||||
x.back();
|
||||
@@ -116,41 +118,7 @@ public class JSONArray implements Iterable<Object> {
|
||||
x.back();
|
||||
this.myArrayList.add(x.nextValue());
|
||||
}
|
||||
switch (x.nextClean()) {
|
||||
case 0:
|
||||
// array is unclosed. No ']' found, instead EOF
|
||||
throw x.syntaxError("Expected a ',' or ']'");
|
||||
case ',':
|
||||
nextChar = x.nextClean();
|
||||
if (nextChar == 0) {
|
||||
// array is unclosed. No ']' found, instead EOF
|
||||
throw x.syntaxError("Expected a ',' or ']'");
|
||||
}
|
||||
if (nextChar == ']') {
|
||||
// trailing commas are not allowed in strict mode
|
||||
if (jsonParserConfiguration.isStrictMode()) {
|
||||
throw x.syntaxError("Strict mode error: Expected another array element");
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (nextChar == ',') {
|
||||
// consecutive commas are not allowed in strict mode
|
||||
if (jsonParserConfiguration.isStrictMode()) {
|
||||
throw x.syntaxError("Strict mode error: Expected a valid array element");
|
||||
}
|
||||
return;
|
||||
}
|
||||
x.back();
|
||||
break;
|
||||
case ']':
|
||||
if (isInitial && jsonParserConfiguration.isStrictMode() &&
|
||||
x.nextClean() != 0) {
|
||||
throw x.syntaxError("Strict mode error: Unparsed characters found at end of input text");
|
||||
}
|
||||
return;
|
||||
default:
|
||||
throw x.syntaxError("Expected a ',' or ']'");
|
||||
}
|
||||
if (checkForSyntaxError(x, jsonParserConfiguration, isInitial)) return;
|
||||
}
|
||||
} else {
|
||||
if (isInitial && jsonParserConfiguration.isStrictMode() && x.nextClean() != 0) {
|
||||
@@ -159,6 +127,52 @@ public class JSONArray implements Iterable<Object> {
|
||||
}
|
||||
}
|
||||
|
||||
/** Convenience function. Checks for JSON syntax error.
|
||||
* @param x A JSONTokener instance from which the JSONArray is constructed.
|
||||
* @param jsonParserConfiguration A JSONParserConfiguration instance that controls the behavior of the parser.
|
||||
* @param isInitial Boolean indicating position of char
|
||||
* @return
|
||||
*/
|
||||
private static boolean checkForSyntaxError(JSONTokener x, JSONParserConfiguration jsonParserConfiguration, boolean isInitial) {
|
||||
char nextChar;
|
||||
switch (x.nextClean()) {
|
||||
case 0:
|
||||
// array is unclosed. No ']' found, instead EOF
|
||||
throw x.syntaxError("Expected a ',' or ']'");
|
||||
case ',':
|
||||
nextChar = x.nextClean();
|
||||
if (nextChar == 0) {
|
||||
// array is unclosed. No ']' found, instead EOF
|
||||
throw x.syntaxError("Expected a ',' or ']'");
|
||||
}
|
||||
if (nextChar == ']') {
|
||||
// trailing commas are not allowed in strict mode
|
||||
if (jsonParserConfiguration.isStrictMode()) {
|
||||
throw x.syntaxError("Strict mode error: Expected another array element");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if (nextChar == ',') {
|
||||
// consecutive commas are not allowed in strict mode
|
||||
if (jsonParserConfiguration.isStrictMode()) {
|
||||
throw x.syntaxError("Strict mode error: Expected a valid array element");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
x.back();
|
||||
break;
|
||||
case ']':
|
||||
if (isInitial && jsonParserConfiguration.isStrictMode() &&
|
||||
x.nextClean() != 0) {
|
||||
throw x.syntaxError("Strict mode error: Unparsed characters found at end of input text");
|
||||
}
|
||||
return true;
|
||||
default:
|
||||
throw x.syntaxError("Expected a ',' or ']'");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a JSONArray from a source JSON text.
|
||||
*
|
||||
@@ -334,13 +348,11 @@ public class JSONArray implements Iterable<Object> {
|
||||
*/
|
||||
public boolean getBoolean(int index) throws JSONException {
|
||||
Object object = this.get(index);
|
||||
if (object.equals(Boolean.FALSE)
|
||||
|| (object instanceof String && ((String) object)
|
||||
.equalsIgnoreCase("false"))) {
|
||||
if (Boolean.FALSE.equals(object)
|
||||
|| (object instanceof String && "false".equalsIgnoreCase((String) object))) {
|
||||
return false;
|
||||
} else if (object.equals(Boolean.TRUE)
|
||||
|| (object instanceof String && ((String) object)
|
||||
.equalsIgnoreCase("true"))) {
|
||||
} else if (Boolean.TRUE.equals(object)
|
||||
|| (object instanceof String && "true".equalsIgnoreCase((String) object))) {
|
||||
return true;
|
||||
}
|
||||
throw wrongValueFormatException(index, "boolean", object, null);
|
||||
@@ -735,11 +747,7 @@ public class JSONArray implements Iterable<Object> {
|
||||
if (val == null) {
|
||||
return defaultValue;
|
||||
}
|
||||
final double doubleValue = val.doubleValue();
|
||||
// if (Double.isNaN(doubleValue) || Double.isInfinite(doubleValue)) {
|
||||
// return defaultValue;
|
||||
// }
|
||||
return doubleValue;
|
||||
return val.doubleValue();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -771,11 +779,7 @@ public class JSONArray implements Iterable<Object> {
|
||||
if (val == null) {
|
||||
return defaultValue;
|
||||
}
|
||||
final Double doubleValue = val.doubleValue();
|
||||
// if (Double.isNaN(doubleValue) || Double.isInfinite(doubleValue)) {
|
||||
// return defaultValue;
|
||||
// }
|
||||
return doubleValue;
|
||||
return val.doubleValue();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -807,11 +811,7 @@ public class JSONArray implements Iterable<Object> {
|
||||
if (val == null) {
|
||||
return defaultValue;
|
||||
}
|
||||
final float floatValue = val.floatValue();
|
||||
// if (Float.isNaN(floatValue) || Float.isInfinite(floatValue)) {
|
||||
// return floatValue;
|
||||
// }
|
||||
return floatValue;
|
||||
return val.floatValue();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -843,11 +843,7 @@ public class JSONArray implements Iterable<Object> {
|
||||
if (val == null) {
|
||||
return defaultValue;
|
||||
}
|
||||
final Float floatValue = val.floatValue();
|
||||
// if (Float.isNaN(floatValue) || Float.isInfinite(floatValue)) {
|
||||
// return floatValue;
|
||||
// }
|
||||
return floatValue;
|
||||
return val.floatValue();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1645,29 +1641,44 @@ public class JSONArray implements Iterable<Object> {
|
||||
if(valueThis == null) {
|
||||
return false;
|
||||
}
|
||||
if (valueThis instanceof JSONObject) {
|
||||
if (!((JSONObject)valueThis).similar(valueOther)) {
|
||||
return false;
|
||||
}
|
||||
} else if (valueThis instanceof JSONArray) {
|
||||
if (!((JSONArray)valueThis).similar(valueOther)) {
|
||||
return false;
|
||||
}
|
||||
} else if (valueThis instanceof Number && valueOther instanceof Number) {
|
||||
if (!JSONObject.isNumberSimilar((Number)valueThis, (Number)valueOther)) {
|
||||
return false;
|
||||
}
|
||||
} else if (valueThis instanceof JSONString && valueOther instanceof JSONString) {
|
||||
if (!((JSONString) valueThis).toJSONString().equals(((JSONString) valueOther).toJSONString())) {
|
||||
return false;
|
||||
}
|
||||
} else if (!valueThis.equals(valueOther)) {
|
||||
if (!isSimilar(valueThis, valueOther)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience function; checks for object similarity
|
||||
* @param valueThis
|
||||
* Initial object to compare
|
||||
* @param valueOther
|
||||
* Comparison object
|
||||
* @return boolean
|
||||
*/
|
||||
private boolean isSimilar(Object valueThis, Object valueOther) {
|
||||
if (valueThis instanceof JSONObject) {
|
||||
if (!((JSONObject)valueThis).similar(valueOther)) {
|
||||
return false;
|
||||
}
|
||||
} else if (valueThis instanceof JSONArray) {
|
||||
if (!((JSONArray)valueThis).similar(valueOther)) {
|
||||
return false;
|
||||
}
|
||||
} else if (valueThis instanceof Number && valueOther instanceof Number) {
|
||||
if (!JSONObject.isNumberSimilar((Number)valueThis, (Number)valueOther)) {
|
||||
return false;
|
||||
}
|
||||
} else if (valueThis instanceof JSONString && valueOther instanceof JSONString) {
|
||||
if (!((JSONString) valueThis).toJSONString().equals(((JSONString) valueOther).toJSONString())) {
|
||||
return false;
|
||||
}
|
||||
} else if (!valueThis.equals(valueOther)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Produce a JSONObject by combining a JSONArray of names with the values of
|
||||
* this JSONArray.
|
||||
@@ -1799,12 +1810,7 @@ public class JSONArray implements Iterable<Object> {
|
||||
writer.write('[');
|
||||
|
||||
if (length == 1) {
|
||||
try {
|
||||
JSONObject.writeValue(writer, this.myArrayList.get(0),
|
||||
indentFactor, indent);
|
||||
} catch (Exception e) {
|
||||
throw new JSONException("Unable to write JSONArray value at index: 0", e);
|
||||
}
|
||||
writeArrayAttempt(writer, indentFactor, indent, 0);
|
||||
} else if (length != 0) {
|
||||
final int newIndent = indent + indentFactor;
|
||||
|
||||
@@ -1816,12 +1822,7 @@ public class JSONArray implements Iterable<Object> {
|
||||
writer.write('\n');
|
||||
}
|
||||
JSONObject.indent(writer, newIndent);
|
||||
try {
|
||||
JSONObject.writeValue(writer, this.myArrayList.get(i),
|
||||
indentFactor, newIndent);
|
||||
} catch (Exception e) {
|
||||
throw new JSONException("Unable to write JSONArray value at index: " + i, e);
|
||||
}
|
||||
writeArrayAttempt(writer, indentFactor, newIndent, i);
|
||||
needsComma = true;
|
||||
}
|
||||
if (indentFactor > 0) {
|
||||
@@ -1836,6 +1837,26 @@ public class JSONArray implements Iterable<Object> {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience function. Attempts to write
|
||||
* @param writer
|
||||
* Writes the serialized JSON
|
||||
* @param indentFactor
|
||||
* The number of spaces to add to each level of indentation.
|
||||
* @param indent
|
||||
* The indentation of the top level.
|
||||
* @param i
|
||||
* Index in array to be added
|
||||
*/
|
||||
private void writeArrayAttempt(Writer writer, int indentFactor, int indent, int i) {
|
||||
try {
|
||||
JSONObject.writeValue(writer, this.myArrayList.get(i),
|
||||
indentFactor, indent);
|
||||
} catch (Exception e) {
|
||||
throw new JSONException("Unable to write JSONArray value at index: " + i, e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a java.util.List containing all of the elements in this array.
|
||||
* If an element in the array is a JSONArray or JSONObject it will also
|
||||
|
||||
@@ -16,10 +16,13 @@ public class JSONML {
|
||||
|
||||
/**
|
||||
* Constructs a new JSONML object.
|
||||
* @deprecated (Utility class cannot be instantiated)
|
||||
*/
|
||||
@Deprecated
|
||||
public JSONML() {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Parse XML values and store them in a JSONArray.
|
||||
* @param x The XMLTokener containing the source string.
|
||||
@@ -111,7 +114,7 @@ public class JSONML {
|
||||
}
|
||||
} else if (c == '[') {
|
||||
token = x.nextToken();
|
||||
if (token.equals("CDATA") && x.next() == '[') {
|
||||
if ("CDATA".equals(token) && x.next() == '[') {
|
||||
if (ja != null) {
|
||||
ja.put(x.nextCDATA());
|
||||
}
|
||||
@@ -239,9 +242,21 @@ public class JSONML {
|
||||
}
|
||||
} else {
|
||||
if (ja != null) {
|
||||
ja.put(token instanceof String
|
||||
? (config.isKeepStrings() ? XML.unescape((String)token) : XML.stringToValue((String)token))
|
||||
: token);
|
||||
Object value;
|
||||
|
||||
if (token instanceof String) {
|
||||
String strToken = (String) token;
|
||||
if (config.isKeepStrings()) {
|
||||
value = XML.unescape(strToken);
|
||||
} else {
|
||||
value = XML.stringToValue(strToken);
|
||||
}
|
||||
} else {
|
||||
value = token;
|
||||
}
|
||||
|
||||
ja.put(value);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -127,7 +127,7 @@ public class JSONPointer {
|
||||
if (pointer == null) {
|
||||
throw new NullPointerException("pointer cannot be null");
|
||||
}
|
||||
if (pointer.isEmpty() || pointer.equals("#")) {
|
||||
if (pointer.isEmpty() || "#".equals(pointer)) {
|
||||
this.refTokens = Collections.emptyList();
|
||||
return;
|
||||
}
|
||||
@@ -246,7 +246,7 @@ public class JSONPointer {
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder rval = new StringBuilder("");
|
||||
StringBuilder rval = new StringBuilder();
|
||||
for (String token: this.refTokens) {
|
||||
rval.append('/').append(escape(token));
|
||||
}
|
||||
|
||||
@@ -509,13 +509,26 @@ public class JSONTokener {
|
||||
string = sb.toString().trim();
|
||||
if ("".equals(string)) {
|
||||
throw this.syntaxError("Missing value");
|
||||
} else if (jsonParserConfiguration != null &&
|
||||
jsonParserConfiguration.isStrictMode() && string.endsWith(".")) {
|
||||
throw this.syntaxError(String.format("Strict mode error: Value '%s' ends with dot", string));
|
||||
}
|
||||
Object obj = JSONObject.stringToValue(string);
|
||||
// Strict mode only allows strings with explicit double quotes
|
||||
// if obj is a boolean, look at string
|
||||
if (jsonParserConfiguration != null &&
|
||||
jsonParserConfiguration.isStrictMode() &&
|
||||
obj instanceof String) {
|
||||
throw this.syntaxError(String.format("Strict mode error: Value '%s' is not surrounded by quotes", obj));
|
||||
jsonParserConfiguration.isStrictMode()) {
|
||||
if (obj instanceof Boolean && !"true".equals(string) && !"false".equals(string)) {
|
||||
// Strict mode only allows lowercase true or false
|
||||
throw this.syntaxError(String.format("Strict mode error: Value '%s' is not lowercase boolean", obj));
|
||||
}
|
||||
else if (obj == JSONObject.NULL && !"null".equals(string)) {
|
||||
// Strint mode only allows lowercase null
|
||||
throw this.syntaxError(String.format("Strict mode error: Value '%s' is not lowercase null", obj));
|
||||
}
|
||||
else if (obj instanceof String) {
|
||||
// Strict mode only allows strings with explicit double quotes
|
||||
throw this.syntaxError(String.format("Strict mode error: Value '%s' is not surrounded by quotes", obj));
|
||||
}
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
@@ -428,6 +428,9 @@ public class XML {
|
||||
config.isKeepNumberAsString()
|
||||
? ((String) token)
|
||||
: obj);
|
||||
} else if (obj == JSONObject.NULL) {
|
||||
jsonObject.accumulate(config.getcDataTagName(),
|
||||
config.isKeepStrings() ? ((String) token) : obj);
|
||||
} else {
|
||||
jsonObject.accumulate(config.getcDataTagName(), stringToValue((String) token));
|
||||
}
|
||||
|
||||
107
src/test/java/org/json/junit/HTTPTokenerTest.java
Normal file
107
src/test/java/org/json/junit/HTTPTokenerTest.java
Normal file
@@ -0,0 +1,107 @@
|
||||
package org.json.junit;
|
||||
|
||||
import org.json.HTTPTokener;
|
||||
import org.json.JSONException;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
/**
|
||||
* Tests for JSON-Java HTTPTokener.java
|
||||
*/
|
||||
public class HTTPTokenerTest {
|
||||
|
||||
/**
|
||||
* Test parsing a simple unquoted token.
|
||||
*/
|
||||
@Test
|
||||
public void parseSimpleToken() {
|
||||
HTTPTokener tokener = new HTTPTokener("Content-Type");
|
||||
String token = tokener.nextToken();
|
||||
assertEquals("Content-Type", token);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test parsing multiple tokens separated by whitespace.
|
||||
*/
|
||||
@Test
|
||||
public void parseMultipleTokens() {
|
||||
HTTPTokener tokener = new HTTPTokener("Content-Type application/json");
|
||||
String token1 = tokener.nextToken();
|
||||
String token2 = tokener.nextToken();
|
||||
assertEquals("Content-Type", token1);
|
||||
assertEquals("application/json", token2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test parsing a double-quoted token.
|
||||
*/
|
||||
@Test
|
||||
public void parseDoubleQuotedToken() {
|
||||
HTTPTokener tokener = new HTTPTokener("\"application/json\"");
|
||||
String token = tokener.nextToken();
|
||||
assertEquals("application/json", token);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test parsing a single-quoted token.
|
||||
*/
|
||||
@Test
|
||||
public void parseSingleQuotedToken() {
|
||||
HTTPTokener tokener = new HTTPTokener("'application/json'");
|
||||
String token = tokener.nextToken();
|
||||
assertEquals("application/json", token);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test parsing a quoted token that includes spaces and semicolons.
|
||||
*/
|
||||
@Test
|
||||
public void parseQuotedTokenWithSpaces() {
|
||||
HTTPTokener tokener = new HTTPTokener("\"text/html; charset=UTF-8\"");
|
||||
String token = tokener.nextToken();
|
||||
assertEquals("text/html; charset=UTF-8", token);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that unterminated quoted strings throw a JSONException.
|
||||
*/
|
||||
@Test
|
||||
public void throwExceptionOnUnterminatedString() {
|
||||
HTTPTokener tokener = new HTTPTokener("\"incomplete");
|
||||
JSONException exception = assertThrows(JSONException.class, tokener::nextToken);
|
||||
assertTrue(exception.getMessage().contains("Unterminated string"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test behavior with empty input string.
|
||||
*/
|
||||
@Test
|
||||
public void parseEmptyInput() {
|
||||
HTTPTokener tokener = new HTTPTokener("");
|
||||
String token = tokener.nextToken();
|
||||
assertEquals("", token);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test behavior with input consisting only of whitespace.
|
||||
*/
|
||||
@Test
|
||||
public void parseWhitespaceOnly() {
|
||||
HTTPTokener tokener = new HTTPTokener(" \t \n ");
|
||||
String token = tokener.nextToken();
|
||||
assertEquals("", token);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test parsing tokens separated by multiple whitespace characters.
|
||||
*/
|
||||
@Test
|
||||
public void parseTokensWithMultipleWhitespace() {
|
||||
HTTPTokener tokener = new HTTPTokener("GET /index.html");
|
||||
String method = tokener.nextToken();
|
||||
String path = tokener.nextToken();
|
||||
assertEquals("GET", method);
|
||||
assertEquals("/index.html", path);
|
||||
}
|
||||
|
||||
}
|
||||
179
src/test/java/org/json/junit/JSONObjectRecordTest.java
Normal file
179
src/test/java/org/json/junit/JSONObjectRecordTest.java
Normal file
@@ -0,0 +1,179 @@
|
||||
package org.json.junit;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.io.StringReader;
|
||||
|
||||
import org.json.JSONObject;
|
||||
import org.json.junit.data.GenericBeanInt;
|
||||
import org.json.junit.data.MyEnum;
|
||||
import org.json.junit.data.MyNumber;
|
||||
import org.json.junit.data.PersonRecord;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* Tests for JSONObject support of Java record types.
|
||||
*
|
||||
* NOTE: These tests are currently ignored because PersonRecord is not an actual Java record.
|
||||
* The implementation now correctly detects actual Java records using reflection (Class.isRecord()).
|
||||
* These tests will need to be enabled and run with Java 17+ where PersonRecord can be converted
|
||||
* to an actual record type.
|
||||
*
|
||||
* This ensures backward compatibility - regular classes with lowercase method names will not
|
||||
* be treated as records unless they are actual Java record types.
|
||||
*/
|
||||
public class JSONObjectRecordTest {
|
||||
|
||||
/**
|
||||
* Tests that JSONObject can be created from a record-style class.
|
||||
* Record-style classes use accessor methods like name() instead of getName().
|
||||
*
|
||||
* NOTE: Ignored until PersonRecord is converted to an actual Java record (requires Java 17+)
|
||||
*/
|
||||
@Test
|
||||
@Ignore("Requires actual Java record type - PersonRecord needs to be a real record (Java 17+)")
|
||||
public void jsonObjectByRecord() {
|
||||
PersonRecord person = new PersonRecord("John Doe", 30, true);
|
||||
JSONObject jsonObject = new JSONObject(person);
|
||||
|
||||
assertEquals("Expected 3 keys in the JSONObject", 3, jsonObject.length());
|
||||
assertEquals("John Doe", jsonObject.get("name"));
|
||||
assertEquals(30, jsonObject.get("age"));
|
||||
assertEquals(true, jsonObject.get("active"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that Object methods (toString, hashCode, equals, etc.) are not included
|
||||
*
|
||||
* NOTE: Ignored until PersonRecord is converted to an actual Java record (requires Java 17+)
|
||||
*/
|
||||
@Test
|
||||
@Ignore("Requires actual Java record type - PersonRecord needs to be a real record (Java 17+)")
|
||||
public void recordStyleClassShouldNotIncludeObjectMethods() {
|
||||
PersonRecord person = new PersonRecord("Jane Doe", 25, false);
|
||||
JSONObject jsonObject = new JSONObject(person);
|
||||
|
||||
// Should NOT include Object methods
|
||||
assertFalse("Should not include toString", jsonObject.has("toString"));
|
||||
assertFalse("Should not include hashCode", jsonObject.has("hashCode"));
|
||||
assertFalse("Should not include equals", jsonObject.has("equals"));
|
||||
assertFalse("Should not include clone", jsonObject.has("clone"));
|
||||
assertFalse("Should not include wait", jsonObject.has("wait"));
|
||||
assertFalse("Should not include notify", jsonObject.has("notify"));
|
||||
assertFalse("Should not include notifyAll", jsonObject.has("notifyAll"));
|
||||
|
||||
// Should only have the 3 record fields
|
||||
assertEquals("Should only have 3 fields", 3, jsonObject.length());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that enum methods are not included when processing an enum
|
||||
*/
|
||||
@Test
|
||||
public void enumsShouldNotIncludeEnumMethods() {
|
||||
MyEnum myEnum = MyEnum.VAL1;
|
||||
JSONObject jsonObject = new JSONObject(myEnum);
|
||||
|
||||
// Should NOT include enum-specific methods like name(), ordinal(), values(), valueOf()
|
||||
assertFalse("Should not include name method", jsonObject.has("name"));
|
||||
assertFalse("Should not include ordinal method", jsonObject.has("ordinal"));
|
||||
assertFalse("Should not include declaringClass", jsonObject.has("declaringClass"));
|
||||
|
||||
// Enums should still work with traditional getters if they have any
|
||||
// But should not pick up the built-in enum methods
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that Number subclass methods are not included
|
||||
*/
|
||||
@Test
|
||||
public void numberSubclassesShouldNotIncludeNumberMethods() {
|
||||
MyNumber myNumber = new MyNumber();
|
||||
JSONObject jsonObject = new JSONObject(myNumber);
|
||||
|
||||
// Should NOT include Number methods like intValue(), longValue(), etc.
|
||||
assertFalse("Should not include intValue", jsonObject.has("intValue"));
|
||||
assertFalse("Should not include longValue", jsonObject.has("longValue"));
|
||||
assertFalse("Should not include doubleValue", jsonObject.has("doubleValue"));
|
||||
assertFalse("Should not include floatValue", jsonObject.has("floatValue"));
|
||||
|
||||
// Should include the actual getter
|
||||
assertTrue("Should include number", jsonObject.has("number"));
|
||||
assertEquals("Should have 1 field", 1, jsonObject.length());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that generic bean with get() and is() methods works correctly
|
||||
*/
|
||||
@Test
|
||||
public void genericBeanWithGetAndIsMethodsShouldNotBeIncluded() {
|
||||
GenericBeanInt bean = new GenericBeanInt(42);
|
||||
JSONObject jsonObject = new JSONObject(bean);
|
||||
|
||||
// Should NOT include standalone get() or is() methods
|
||||
assertFalse("Should not include standalone 'get' method", jsonObject.has("get"));
|
||||
assertFalse("Should not include standalone 'is' method", jsonObject.has("is"));
|
||||
|
||||
// Should include the actual getters
|
||||
assertTrue("Should include genericValue field", jsonObject.has("genericValue"));
|
||||
assertTrue("Should include a field", jsonObject.has("a"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that java.* classes don't have their methods picked up
|
||||
*/
|
||||
@Test
|
||||
public void javaLibraryClassesShouldNotIncludeTheirMethods() {
|
||||
StringReader reader = new StringReader("test");
|
||||
JSONObject jsonObject = new JSONObject(reader);
|
||||
|
||||
// Should NOT include java.io.Reader methods like read(), reset(), etc.
|
||||
assertFalse("Should not include read method", jsonObject.has("read"));
|
||||
assertFalse("Should not include reset method", jsonObject.has("reset"));
|
||||
assertFalse("Should not include ready method", jsonObject.has("ready"));
|
||||
assertFalse("Should not include skip method", jsonObject.has("skip"));
|
||||
|
||||
// Reader should produce empty JSONObject (no valid properties)
|
||||
assertEquals("Reader should produce empty JSON", 0, jsonObject.length());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test mixed case - object with both traditional getters and record-style accessors
|
||||
*
|
||||
* NOTE: Ignored until PersonRecord is converted to an actual Java record (requires Java 17+)
|
||||
*/
|
||||
@Test
|
||||
@Ignore("Requires actual Java record type - PersonRecord needs to be a real record (Java 17+)")
|
||||
public void mixedGettersAndRecordStyleAccessors() {
|
||||
// PersonRecord has record-style accessors: name(), age(), active()
|
||||
// These should all be included
|
||||
PersonRecord person = new PersonRecord("Mixed Test", 40, true);
|
||||
JSONObject jsonObject = new JSONObject(person);
|
||||
|
||||
assertEquals("Should have all 3 record-style fields", 3, jsonObject.length());
|
||||
assertTrue("Should include name", jsonObject.has("name"));
|
||||
assertTrue("Should include age", jsonObject.has("age"));
|
||||
assertTrue("Should include active", jsonObject.has("active"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that methods starting with uppercase are not included (not valid record accessors)
|
||||
*
|
||||
* NOTE: Ignored until PersonRecord is converted to an actual Java record (requires Java 17+)
|
||||
*/
|
||||
@Test
|
||||
@Ignore("Requires actual Java record type - PersonRecord needs to be a real record (Java 17+)")
|
||||
public void methodsStartingWithUppercaseShouldNotBeIncluded() {
|
||||
PersonRecord person = new PersonRecord("Test", 50, false);
|
||||
JSONObject jsonObject = new JSONObject(person);
|
||||
|
||||
// Record-style accessors must start with lowercase
|
||||
// Methods like Name(), Age() (uppercase) should not be picked up
|
||||
// Our PersonRecord only has lowercase accessors, which is correct
|
||||
|
||||
assertEquals("Should only have lowercase accessors", 3, jsonObject.length());
|
||||
}
|
||||
}
|
||||
@@ -56,6 +56,17 @@ 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.json.junit.data.CustomClass;
|
||||
import org.json.junit.data.CustomClassA;
|
||||
import org.json.junit.data.CustomClassB;
|
||||
import org.json.junit.data.CustomClassC;
|
||||
import org.json.junit.data.CustomClassD;
|
||||
import org.json.junit.data.CustomClassE;
|
||||
import org.json.junit.data.CustomClassF;
|
||||
import org.json.junit.data.CustomClassG;
|
||||
import org.json.junit.data.CustomClassH;
|
||||
import org.json.junit.data.CustomClassI;
|
||||
import org.json.JSONObject;
|
||||
import org.junit.After;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
@@ -3895,9 +3906,10 @@ public class JSONObjectTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void issue743SerializationMapWith1000Objects() {
|
||||
HashMap<String, Object> map = buildNestedMap(1000);
|
||||
JSONParserConfiguration parserConfiguration = new JSONParserConfiguration().withMaxNestingDepth(1000);
|
||||
public void issue743SerializationMapWith500Objects() {
|
||||
// TODO: find out why 1000 objects no longer works
|
||||
HashMap<String, Object> map = buildNestedMap(500);
|
||||
JSONParserConfiguration parserConfiguration = new JSONParserConfiguration().withMaxNestingDepth(500);
|
||||
JSONObject object = new JSONObject(map, parserConfiguration);
|
||||
String jsonString = object.toString();
|
||||
}
|
||||
@@ -3997,6 +4009,56 @@ public class JSONObjectTest {
|
||||
assertThrows(JSONException.class, () -> { new JSONObject(tokener); });
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_strictModeWithMisCasedBooleanOrNullValue(){
|
||||
JSONParserConfiguration jsonParserConfiguration = new JSONParserConfiguration().withStrictMode();
|
||||
try{
|
||||
new JSONObject("{\"a\":True}", jsonParserConfiguration);
|
||||
fail("Expected an exception");
|
||||
} catch (JSONException e) {
|
||||
// No action, expected outcome
|
||||
}
|
||||
try{
|
||||
new JSONObject("{\"a\":TRUE}", jsonParserConfiguration);
|
||||
fail("Expected an exception");
|
||||
} catch (JSONException e) {
|
||||
// No action, expected outcome
|
||||
}
|
||||
try{
|
||||
new JSONObject("{\"a\":nUlL}", jsonParserConfiguration);
|
||||
fail("Expected an exception");
|
||||
} catch (JSONException e) {
|
||||
// No action, expected outcome
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_strictModeWithInappropriateKey(){
|
||||
JSONParserConfiguration jsonParserConfiguration = new JSONParserConfiguration().withStrictMode();
|
||||
|
||||
// Parsing the following objects should fail
|
||||
try{
|
||||
new JSONObject("{true : 3}", jsonParserConfiguration);
|
||||
fail("Expected an exception");
|
||||
} catch (JSONException e) {
|
||||
// No action, expected outcome
|
||||
}
|
||||
try{
|
||||
new JSONObject("{TRUE : 3}", jsonParserConfiguration);
|
||||
fail("Expected an exception");
|
||||
} catch (JSONException e) {
|
||||
// No action, expected outcome
|
||||
}
|
||||
try{
|
||||
new JSONObject("{1 : 3}", jsonParserConfiguration);
|
||||
fail("Expected an exception");
|
||||
} catch (JSONException e) {
|
||||
// No action, expected outcome
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Method to build nested map of max maxDepth
|
||||
*
|
||||
@@ -4011,5 +4073,161 @@ public class JSONObjectTest {
|
||||
nestedMap.put("t", buildNestedMap(maxDepth - 1));
|
||||
return nestedMap;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Tests the behavior of the {@link JSONObject} when parsing a bean with null fields
|
||||
* using a custom {@link JSONParserConfiguration} that enables the use of native nulls.
|
||||
*
|
||||
* <p>This test ensures that uninitialized fields in the bean are serialized correctly
|
||||
* into the resulting JSON object, and their keys are present in the JSON string output.</p>
|
||||
*/
|
||||
@Test
|
||||
public void jsonObjectParseNullFieldsWithParserConfiguration() {
|
||||
JSONParserConfiguration jsonParserConfiguration = new JSONParserConfiguration();
|
||||
RecursiveBean bean = new RecursiveBean(null);
|
||||
JSONObject jsonObject = new JSONObject(bean, jsonParserConfiguration.withUseNativeNulls(true));
|
||||
assertTrue("name key should be present", jsonObject.has("name"));
|
||||
assertTrue("ref key should be present", jsonObject.has("ref"));
|
||||
assertTrue("ref2 key should be present", jsonObject.has("ref2"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the behavior of the {@link JSONObject} when parsing a bean with null fields
|
||||
* without using a custom {@link JSONParserConfiguration}.
|
||||
*
|
||||
* <p>This test ensures that uninitialized fields in the bean are not serialized
|
||||
* into the resulting JSON object, and the object remains empty.</p>
|
||||
*/
|
||||
@Test
|
||||
public void jsonObjectParseNullFieldsWithoutParserConfiguration() {
|
||||
RecursiveBean bean = new RecursiveBean(null);
|
||||
JSONObject jsonObject = new JSONObject(bean);
|
||||
assertTrue("JSONObject should be empty", jsonObject.isEmpty());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void jsonObjectParseFromJson_0() {
|
||||
JSONObject object = new JSONObject();
|
||||
object.put("number", 12);
|
||||
object.put("name", "Alex");
|
||||
object.put("longNumber", 1500000000L);
|
||||
CustomClass customClass = object.fromJson(CustomClass.class);
|
||||
CustomClass compareClass = new CustomClass(12, "Alex", 1500000000L);
|
||||
assertEquals(customClass, compareClass);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void jsonObjectParseFromJson_1() {
|
||||
JSONObject object = new JSONObject();
|
||||
|
||||
BigInteger largeInt = new BigInteger("123");
|
||||
object.put("largeInt", largeInt.toString());
|
||||
CustomClassA customClassA = object.fromJson(CustomClassA.class);
|
||||
CustomClassA compareClassClassA = new CustomClassA(largeInt);
|
||||
assertEquals(customClassA, compareClassClassA);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void jsonObjectParseFromJson_2() {
|
||||
JSONObject object = new JSONObject();
|
||||
object.put("number", 12);
|
||||
|
||||
JSONObject classC = new JSONObject();
|
||||
classC.put("stringName", "Alex");
|
||||
classC.put("longNumber", 123456L);
|
||||
|
||||
object.put("classC", classC);
|
||||
|
||||
CustomClassB customClassB = object.fromJson(CustomClassB.class);
|
||||
CustomClassC classCObject = new CustomClassC("Alex", 123456L);
|
||||
CustomClassB compareClassB = new CustomClassB(12, classCObject);
|
||||
assertEquals(customClassB, compareClassB);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void jsonObjectParseFromJson_3() {
|
||||
JSONObject object = new JSONObject();
|
||||
JSONArray array = new JSONArray();
|
||||
array.put("test1");
|
||||
array.put("test2");
|
||||
array.put("test3");
|
||||
object.put("stringList", array);
|
||||
|
||||
CustomClassD customClassD = object.fromJson(CustomClassD.class);
|
||||
CustomClassD compareClassD = new CustomClassD(Arrays.asList("test1", "test2", "test3"));
|
||||
assertEquals(customClassD, compareClassD);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void jsonObjectParseFromJson_4() {
|
||||
JSONObject object = new JSONObject();
|
||||
JSONArray array = new JSONArray();
|
||||
array.put(new CustomClassC("test1", 1L).toJSON());
|
||||
array.put(new CustomClassC("test2", 2L).toJSON());
|
||||
object.put("listClassC", array);
|
||||
|
||||
CustomClassE customClassE = object.fromJson(CustomClassE.class);
|
||||
CustomClassE compareClassE = new CustomClassE(java.util.Arrays.asList(
|
||||
new CustomClassC("test1", 1L),
|
||||
new CustomClassC("test2", 2L)));
|
||||
assertEquals(customClassE, compareClassE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void jsonObjectParseFromJson_5() {
|
||||
JSONObject object = new JSONObject();
|
||||
JSONArray array = new JSONArray();
|
||||
array.put(Arrays.asList("A", "B", "C"));
|
||||
array.put(Arrays.asList("D", "E"));
|
||||
object.put("listOfString", array);
|
||||
|
||||
CustomClassF customClassF = object.fromJson(CustomClassF.class);
|
||||
List<List<String>> listOfString = new ArrayList<>();
|
||||
listOfString.add(Arrays.asList("A", "B", "C"));
|
||||
listOfString.add(Arrays.asList("D", "E"));
|
||||
CustomClassF compareClassF = new CustomClassF(listOfString);
|
||||
assertEquals(customClassF, compareClassF);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void jsonObjectParseFromJson_6() {
|
||||
JSONObject object = new JSONObject();
|
||||
Map<String, String> dataList = new HashMap<>();
|
||||
dataList.put("A", "Aa");
|
||||
dataList.put("B", "Bb");
|
||||
dataList.put("C", "Cc");
|
||||
object.put("dataList", dataList);
|
||||
|
||||
CustomClassG customClassG = object.fromJson(CustomClassG.class);
|
||||
CustomClassG compareClassG = new CustomClassG(dataList);
|
||||
assertEquals(customClassG, compareClassG);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void jsonObjectParseFromJson_7() {
|
||||
JSONObject object = new JSONObject();
|
||||
Map<String, List<Integer>> dataList = new HashMap<>();
|
||||
dataList.put("1", Arrays.asList(1, 2, 3, 4));
|
||||
dataList.put("2", Arrays.asList(2, 3, 4, 5));
|
||||
object.put("integerMap", dataList);
|
||||
|
||||
CustomClassH customClassH = object.fromJson(CustomClassH.class);
|
||||
CustomClassH compareClassH = new CustomClassH(dataList);
|
||||
assertEquals(customClassH.integerMap.toString(), compareClassH.integerMap.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void jsonObjectParseFromJson_8() {
|
||||
JSONObject object = new JSONObject();
|
||||
Map<String, Map<String, Integer>> dataList = new HashMap<>();
|
||||
dataList.put("1", Collections.singletonMap("1", 1));
|
||||
dataList.put("2", Collections.singletonMap("2", 2));
|
||||
object.put("integerMap", dataList);
|
||||
|
||||
CustomClassI customClassI = object.fromJson(CustomClassI.class);
|
||||
CustomClassI compareClassI = new CustomClassI(dataList);
|
||||
assertEquals(customClassI.integerMap.toString(), compareClassI.integerMap.toString());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -775,8 +775,8 @@ public class XMLConfigurationTest {
|
||||
*/
|
||||
@Test
|
||||
public void testToJSONArray_jsonOutput_withKeepNumberAsString() {
|
||||
final String originalXml = "<root><id>01</id><id>1</id><id>00</id><id>0</id><item id=\"01\"/><title>True</title></root>";
|
||||
final JSONObject expected = new JSONObject("{\"root\":{\"item\":{\"id\":\"01\"},\"id\":[\"01\",\"1\",\"00\",\"0\"],\"title\":true}}");
|
||||
final String originalXml = "<root><id>01</id><id>1</id><id>00</id><id>0</id><id>null</id><item id=\"01\"/><title>True</title></root>";
|
||||
final JSONObject expected = new JSONObject("{\"root\":{\"item\":{\"id\":\"01\"},\"id\":[\"01\",\"1\",\"00\",\"0\",null],\"title\":true}}");
|
||||
final JSONObject actualJsonOutput = XML.toJSONObject(originalXml,
|
||||
new XMLParserConfiguration().withKeepNumberAsString(true));
|
||||
Util.compareActualVsExpectedJsonObjects(actualJsonOutput,expected);
|
||||
@@ -787,13 +787,25 @@ public class XMLConfigurationTest {
|
||||
*/
|
||||
@Test
|
||||
public void testToJSONArray_jsonOutput_withKeepBooleanAsString() {
|
||||
final String originalXml = "<root><id>01</id><id>1</id><id>00</id><id>0</id><item id=\"01\"/><title>True</title></root>";
|
||||
final JSONObject expected = new JSONObject("{\"root\":{\"item\":{\"id\":\"01\"},\"id\":[\"01\",1,\"00\",0],\"title\":\"True\"}}");
|
||||
final String originalXml = "<root><id>01</id><id>1</id><id>00</id><id>0</id><id>null</id><item id=\"01\"/><title>True</title></root>";
|
||||
final JSONObject expected = new JSONObject("{\"root\":{\"item\":{\"id\":\"01\"},\"id\":[\"01\",1,\"00\",0,null],\"title\":\"True\"}}");
|
||||
final JSONObject actualJsonOutput = XML.toJSONObject(originalXml,
|
||||
new XMLParserConfiguration().withKeepBooleanAsString(true));
|
||||
Util.compareActualVsExpectedJsonObjects(actualJsonOutput,expected);
|
||||
}
|
||||
|
||||
/**
|
||||
* null is "null" when keepStrings == true
|
||||
*/
|
||||
@Test
|
||||
public void testToJSONArray_jsonOutput_null_withKeepString() {
|
||||
final String originalXml = "<root><id>01</id><id>1</id><id>00</id><id>0</id><item id=\"01\"/><title>null</title></root>";
|
||||
final JSONObject expected = new JSONObject("{\"root\":{\"item\":{\"id\":\"01\"},\"id\":[\"01\",\"1\",\"00\",\"0\"],\"title\":\"null\"}}");
|
||||
final JSONObject actualJsonOutput = XML.toJSONObject(originalXml,
|
||||
new XMLParserConfiguration().withKeepStrings(true));
|
||||
Util.compareActualVsExpectedJsonObjects(actualJsonOutput,expected);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test keepStrings behavior when setting keepBooleanAsString, keepNumberAsString
|
||||
*/
|
||||
|
||||
81
src/test/java/org/json/junit/XMLTokenerTest.java
Normal file
81
src/test/java/org/json/junit/XMLTokenerTest.java
Normal file
@@ -0,0 +1,81 @@
|
||||
package org.json.junit;
|
||||
|
||||
import org.json.XMLTokener;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.StringReader;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* Tests for JSON-Java XMLTokener.java
|
||||
*/
|
||||
public class XMLTokenerTest {
|
||||
|
||||
/**
|
||||
* Tests that nextCDATA() correctly extracts content from within a CDATA section.
|
||||
*/
|
||||
@Test
|
||||
public void testNextCDATA() {
|
||||
String xml = "This is <![CDATA[ some <CDATA> content ]]> after";
|
||||
XMLTokener tokener = new XMLTokener(new StringReader(xml));
|
||||
tokener.skipPast("<![CDATA[");
|
||||
String cdata = tokener.nextCDATA();
|
||||
assertEquals(" some <CDATA> content ", cdata);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that nextContent() returns plain text content before a tag.
|
||||
*/
|
||||
@Test
|
||||
public void testNextContentWithText() {
|
||||
String xml = "Some content<nextTag>";
|
||||
XMLTokener tokener = new XMLTokener(xml);
|
||||
Object content = tokener.nextContent();
|
||||
assertEquals("Some content", content);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that nextContent() returns '<' character when starting with a tag.
|
||||
*/
|
||||
@Test
|
||||
public void testNextContentWithTag() {
|
||||
String xml = "<tag>";
|
||||
XMLTokener tokener = new XMLTokener(xml);
|
||||
Object content = tokener.nextContent();
|
||||
assertEquals('<', content);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that nextEntity() resolves a known entity like & correctly.
|
||||
*/
|
||||
@Test
|
||||
public void testNextEntityKnown() {
|
||||
XMLTokener tokener = new XMLTokener("amp;");
|
||||
Object result = tokener.nextEntity('&');
|
||||
assertEquals("&", result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that nextEntity() preserves unknown entities by returning them unchanged.
|
||||
*/
|
||||
@Test
|
||||
public void testNextEntityUnknown() {
|
||||
XMLTokener tokener = new XMLTokener("unknown;");
|
||||
tokener.next(); // skip 'u'
|
||||
Object result = tokener.nextEntity('&');
|
||||
assertEquals("&nknown;", result); // malformed start to simulate unknown
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests skipPast() to ensure the cursor moves past the specified string.
|
||||
*/
|
||||
@Test
|
||||
public void testSkipPast() {
|
||||
String xml = "Ignore this... endHere more text";
|
||||
XMLTokener tokener = new XMLTokener(xml);
|
||||
tokener.skipPast("endHere");
|
||||
assertEquals(' ', tokener.next()); // should be the space after "endHere"
|
||||
}
|
||||
|
||||
}
|
||||
23
src/test/java/org/json/junit/data/CustomClass.java
Normal file
23
src/test/java/org/json/junit/data/CustomClass.java
Normal file
@@ -0,0 +1,23 @@
|
||||
package org.json.junit.data;
|
||||
|
||||
public class CustomClass {
|
||||
public int number;
|
||||
public String name;
|
||||
public Long longNumber;
|
||||
|
||||
public CustomClass() {}
|
||||
public CustomClass (int number, String name, Long longNumber) {
|
||||
this.number = number;
|
||||
this.name = name;
|
||||
this.longNumber = longNumber;
|
||||
}
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
CustomClass customClass = (CustomClass) o;
|
||||
|
||||
return (this.number == customClass.number
|
||||
&& this.name.equals(customClass.name)
|
||||
&& this.longNumber.equals(customClass.longNumber));
|
||||
}
|
||||
}
|
||||
|
||||
19
src/test/java/org/json/junit/data/CustomClassA.java
Normal file
19
src/test/java/org/json/junit/data/CustomClassA.java
Normal file
@@ -0,0 +1,19 @@
|
||||
package org.json.junit.data;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
public class CustomClassA {
|
||||
public BigInteger largeInt;
|
||||
|
||||
public CustomClassA() {}
|
||||
public CustomClassA(BigInteger largeInt) {
|
||||
this.largeInt = largeInt;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
CustomClassA classA = (CustomClassA) o;
|
||||
return this.largeInt.equals(classA.largeInt);
|
||||
}
|
||||
}
|
||||
|
||||
20
src/test/java/org/json/junit/data/CustomClassB.java
Normal file
20
src/test/java/org/json/junit/data/CustomClassB.java
Normal file
@@ -0,0 +1,20 @@
|
||||
package org.json.junit.data;
|
||||
|
||||
public class CustomClassB {
|
||||
public int number;
|
||||
public CustomClassC classC;
|
||||
|
||||
public CustomClassB() {}
|
||||
public CustomClassB(int number, CustomClassC classC) {
|
||||
this.number = number;
|
||||
this.classC = classC;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
CustomClassB classB = (CustomClassB) o;
|
||||
return this.number == classB.number
|
||||
&& this.classC.equals(classB.classC);
|
||||
}
|
||||
}
|
||||
|
||||
34
src/test/java/org/json/junit/data/CustomClassC.java
Normal file
34
src/test/java/org/json/junit/data/CustomClassC.java
Normal file
@@ -0,0 +1,34 @@
|
||||
package org.json.junit.data;
|
||||
|
||||
import org.json.JSONObject;
|
||||
|
||||
public class CustomClassC {
|
||||
public String stringName;
|
||||
public Long longNumber;
|
||||
|
||||
public CustomClassC() {}
|
||||
public CustomClassC(String stringName, Long longNumber) {
|
||||
this.stringName = stringName;
|
||||
this.longNumber = longNumber;
|
||||
}
|
||||
|
||||
public JSONObject toJSON() {
|
||||
JSONObject object = new JSONObject();
|
||||
object.put("stringName", this.stringName);
|
||||
object.put("longNumber", this.longNumber);
|
||||
return object;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
CustomClassC classC = (CustomClassC) o;
|
||||
return this.stringName.equals(classC.stringName)
|
||||
&& this.longNumber.equals(classC.longNumber);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return java.util.Objects.hash(stringName, longNumber);
|
||||
}
|
||||
}
|
||||
|
||||
19
src/test/java/org/json/junit/data/CustomClassD.java
Normal file
19
src/test/java/org/json/junit/data/CustomClassD.java
Normal file
@@ -0,0 +1,19 @@
|
||||
package org.json.junit.data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class CustomClassD {
|
||||
public List<String> stringList;
|
||||
|
||||
public CustomClassD() {}
|
||||
public CustomClassD(List<String> stringList) {
|
||||
this.stringList = stringList;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
CustomClassD classD = (CustomClassD) o;
|
||||
return this.stringList.equals(classD.stringList);
|
||||
}
|
||||
}
|
||||
|
||||
18
src/test/java/org/json/junit/data/CustomClassE.java
Normal file
18
src/test/java/org/json/junit/data/CustomClassE.java
Normal file
@@ -0,0 +1,18 @@
|
||||
package org.json.junit.data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class CustomClassE {
|
||||
public List<CustomClassC> listClassC;
|
||||
|
||||
public CustomClassE() {}
|
||||
public CustomClassE(List<CustomClassC> listClassC) {
|
||||
this.listClassC = listClassC;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
CustomClassE classE = (CustomClassE) o;
|
||||
return this.listClassC.equals(classE.listClassC);
|
||||
}
|
||||
}
|
||||
19
src/test/java/org/json/junit/data/CustomClassF.java
Normal file
19
src/test/java/org/json/junit/data/CustomClassF.java
Normal file
@@ -0,0 +1,19 @@
|
||||
package org.json.junit.data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class CustomClassF {
|
||||
public List<List<String>> listOfString;
|
||||
|
||||
public CustomClassF() {}
|
||||
public CustomClassF(List<List<String>> listOfString) {
|
||||
this.listOfString = listOfString;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
CustomClassF classF = (CustomClassF) o;
|
||||
return this.listOfString.equals(classF.listOfString);
|
||||
}
|
||||
}
|
||||
|
||||
18
src/test/java/org/json/junit/data/CustomClassG.java
Normal file
18
src/test/java/org/json/junit/data/CustomClassG.java
Normal file
@@ -0,0 +1,18 @@
|
||||
package org.json.junit.data;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public class CustomClassG {
|
||||
public Map<String, String> dataList;
|
||||
|
||||
public CustomClassG () {}
|
||||
public CustomClassG (Map<String, String> dataList) {
|
||||
this.dataList = dataList;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object object) {
|
||||
CustomClassG classG = (CustomClassG) object;
|
||||
return this.dataList.equals(classG.dataList);
|
||||
}
|
||||
}
|
||||
22
src/test/java/org/json/junit/data/CustomClassH.java
Normal file
22
src/test/java/org/json/junit/data/CustomClassH.java
Normal file
@@ -0,0 +1,22 @@
|
||||
package org.json.junit.data;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.List;
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class CustomClassH {
|
||||
public Map<String, List<Integer>> integerMap;
|
||||
|
||||
public CustomClassH() {}
|
||||
public CustomClassH(Map<String, List<Integer>> integerMap) {
|
||||
this.integerMap = integerMap;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object object) {
|
||||
CustomClassH classH = (CustomClassH) object;
|
||||
return this.integerMap.size() == classH.integerMap.size()
|
||||
&& this.integerMap.keySet().equals(classH.integerMap.keySet())
|
||||
&& new ArrayList<>(this.integerMap.values()).equals(new ArrayList<>(classH.integerMap.values()));
|
||||
}
|
||||
}
|
||||
12
src/test/java/org/json/junit/data/CustomClassI.java
Normal file
12
src/test/java/org/json/junit/data/CustomClassI.java
Normal file
@@ -0,0 +1,12 @@
|
||||
package org.json.junit.data;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public class CustomClassI {
|
||||
public Map<String, Map<String, Integer>> integerMap;
|
||||
|
||||
public CustomClassI() {}
|
||||
public CustomClassI(Map<String, Map<String, Integer>> integerMap) {
|
||||
this.integerMap = integerMap;
|
||||
}
|
||||
}
|
||||
31
src/test/java/org/json/junit/data/PersonRecord.java
Normal file
31
src/test/java/org/json/junit/data/PersonRecord.java
Normal file
@@ -0,0 +1,31 @@
|
||||
package org.json.junit.data;
|
||||
|
||||
/**
|
||||
* A test class that mimics Java record accessor patterns.
|
||||
* Records use accessor methods without get/is prefixes (e.g., name() instead of getName()).
|
||||
* This class simulates that behavior to test JSONObject's handling of such methods.
|
||||
*/
|
||||
public class PersonRecord {
|
||||
private final String name;
|
||||
private final int age;
|
||||
private final boolean active;
|
||||
|
||||
public PersonRecord(String name, int age, boolean active) {
|
||||
this.name = name;
|
||||
this.age = age;
|
||||
this.active = active;
|
||||
}
|
||||
|
||||
// Record-style accessors (no "get" or "is" prefix)
|
||||
public String name() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public int age() {
|
||||
return age;
|
||||
}
|
||||
|
||||
public boolean active() {
|
||||
return active;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user