Compare commits

81 Commits

Author SHA1 Message Date
Sean Leary
e635f40238 Merge pull request #1027 from Simulant87/1023-set-default-locale
Save/restore default locale in test
2025-12-29 19:42:57 -06:00
Sean Leary
d5e744ca90 Merge pull request #1028 from Simulant87/fix-sonarqube-reliability-issues
Refactoring: Fix sonarqube reliability issues
2025-12-29 19:42:02 -06:00
Sean Leary
e0c4086168 Merge pull request #1029 from Simulant87/external-javadoc-badge
add badge to external hosted javadoc
2025-12-29 19:41:31 -06:00
Sean Leary
cf653682be Merge pull request #1030 from stleary/pre-release-20251224
pre-release-20251224 Prep for next release
2025-12-24 09:16:47 -06:00
Sean Leary
24bba97c1d pre-release-20251224 update docs and builds for next release 2025-12-24 09:05:18 -06:00
Simulant
96353de304 add badge to external hosted javadoc 2025-12-21 23:16:01 +01:00
Simulant
8cbb4d5bb3 Fix sonarqube reliability issues 2025-12-20 22:57:24 +01:00
Simulant
421abfdc1f save and restore the current default locale, to avoid any side effects on other executions in the same JVM 2025-12-20 22:27:45 +01:00
Sean Leary
128fb42ccc Merge pull request #1021 from Simulant87/update-build-script
Update github build actions, add LTS JDK 25 build
2025-11-18 07:26:35 -06:00
Simulant87
f8e6dfdc63 Merge pull request #3 from Simulant87/update-readme
Update README.md tested on java 25
2025-11-14 15:49:30 +01:00
Simulant87
3bc98dfc7f Update README.md tested on java 25 2025-11-14 15:49:09 +01:00
Simulant87
005dc7b49e add build for LTS JDK 25 2025-11-14 15:47:58 +01:00
Simulant87
d38cb064fd reset setup-java to version 1 for 1.6 build 2025-11-14 15:45:41 +01:00
Simulant87
e9a7d7c72e add distribution to java 1.6 build 2025-11-14 15:40:21 +01:00
Simulant87
73c582e129 update github actions to version 5
consistently update all actions checkout, setup-java, upload-artifactory to version 5
2025-11-14 15:29:52 +01:00
Sean Leary
a6ca84074a Merge pull request #1020 from Abhineshhh/fix/support-java-records
Fix: Support Java record accessors in JSONObject
2025-11-11 20:19:42 -06:00
Sean Leary
8c14e96c44 Merge pull request #1017 from Md-Yasir/enhancement/refactors
Code Refactors
2025-11-09 19:02:49 -06:00
AbhineshJha
8f3b0f1c13 Add runtime record detection for backward compatibility 2025-11-02 22:32:44 +05:30
AbhineshJha
f2acf8af69 Optimize method name exclusion using Set lookup instead of multiple equals checks 2025-11-01 19:33:29 +05:30
AbhineshJha
fd1eee9c3b Add comprehensive edge case tests for record support 2025-11-01 19:33:29 +05:30
AbhineshJha
2550c692cf Refactor: Extract isRecordStyleAccessor helper method 2025-11-01 19:33:29 +05:30
AbhineshJha
20f5200000 Fix: Support Java record accessors in JSONObject 2025-11-01 19:33:29 +05:30
Sean Leary
25f355a953 Merge pull request #1006 from sk02241994/feature-1003
1003: Implement JSONObject.fromJson() with unit tests
2025-10-31 11:25:03 -05:00
sk02241994
42800c208a Updating to work with java 1.6 2025-10-28 13:06:11 +11:00
md-yasir
0cdc5e5170 Reverted Constructor access to public 2025-10-25 20:51:50 +05:30
md-yasir
ac65ee0490 Revert "Refactored stop conditions to be invariant by using while loop."
This issue can be ignored
2025-10-25 20:37:54 +05:30
md-yasir
39e8ead7cd Added java doc for deprecated decoration 2025-10-24 09:37:46 +05:30
md-yasir
6dd878d3c9 Deprecated public constructors instead of making it private. 2025-10-24 09:10:53 +05:30
md-yasir
2c6082a0a2 Refactored stop conditions to be invariant by using while loop. 2025-10-23 22:50:12 +05:30
md-yasir
5dc1031d17 Made JSONMl constructor to private and refactored ternary operations to independent statement in L243 2025-10-23 22:38:01 +05:30
md-yasir
1de42aa4fd Made CookieList constructor to private. 2025-10-23 22:37:00 +05:30
md-yasir
c13b57ca26 Made Cookie constructor to private. 2025-10-23 22:36:53 +05:30
sk02241994
f92f281620 Updating to work with java 1.6 2025-10-23 17:33:37 +11:00
sk02241994
8ccf5d7525 Removing the interface classes and simplifying the implementation to use if else instead 2025-10-23 17:32:07 +11:00
sk02241994
a7c193090a Updating docs 2025-10-16 14:23:30 +11:00
sk02241994
c4c2beb874 Limiting implemetation by removing the new classes. 2025-10-16 14:19:19 +11:00
sk02241994
9adea9e12d Updating to work with java 1.6 2025-10-13 12:39:15 +11:00
sk02241994
7465da858c - Updating for java 1.6
- Resolving Sonar cube issues.
2025-10-13 12:39:15 +11:00
sk02241994
0521928463 - Added implementation for Enum and Map
- Moving the CustomClass to data folder.
- Removing JSONBuilder.java
- Moving the implementation of JSONBuilder to JSONObject.
2025-10-13 12:39:14 +11:00
sk02241994
fbb6b3158e Updating to work with java 1.6 2025-10-13 12:39:14 +11:00
sk02241994
ebc13d6685 Updating to work with java 1.6 2025-10-13 12:39:13 +11:00
sk02241994
7d28955216 Updating to work with java 1.6 2025-10-13 12:39:13 +11:00
sk02241994
83a0e34be5 1003: Implement JSONObject.fromJson() with unit tests 2025-10-13 12:39:12 +11:00
Sean Leary
3e8d1d119f Merge pull request #1014 from Md-Yasir/enhancement/string-check
changed string checking logic
2025-10-11 21:02:44 -05:00
md-yasir
1a2c50b40c changed string checking logic >> string.length() > 0 to !string.isEmpty() 2025-10-11 19:48:33 +05:30
Sean Leary
eb97037f7c Merge pull request #1013 from marilynel/master
sonarqube changes to jsonarray
2025-09-24 12:38:56 -05:00
marilynel
05867c4b0b Merge branch 'master' of https://github.com/marilynel/JSON-java 2025-09-21 16:37:20 -08:00
marilynel
c6efa080c0 more cleanup sonarqube JSONArray 2025-09-21 16:36:52 -08:00
Sean Leary
aff59d06fa Merge pull request #1011 from marilynel/master
more sonarcube fixes
2025-09-18 20:13:43 -05:00
Sean Leary
b258ea3d46 Merge pull request #1008 from eleumik/eleumik-patch-1007-array
Update JSONArray.java for #1007
2025-09-18 20:12:55 -05:00
Sean Leary
a5e234aa19 Merge pull request #1009 from eleumik/eleumik-patch-1
Update JSONTokener.java for #1007
2025-09-18 20:12:03 -05:00
marilynel
f2af220cb4 more sonarcube fixes 2025-09-14 10:59:39 -08:00
Sean Leary
a3edc1da0f Merge pull request #1005 from marilynel/master
fixing sonar cube issues
2025-09-11 15:42:48 -05:00
Michele Vivoda
686c084897 Update JSONTokener.java for #1007
fixed parse of `0.` in strict mode
2025-09-10 02:30:19 +02:00
Michele Vivoda
9de3005566 Update JSONArray.java for #1007
fix array content starting with ',' in strict mode
2025-09-10 02:21:16 +02:00
marilynel
69c87dc4db more sonarcube optimization in jsonobject.java 2025-09-07 12:52:59 -08:00
marilynel
53cfa742a7 more sonarcube optimization in jsonobject.java 2025-09-07 12:41:37 -08:00
marilynel
4e0f62b1a6 more sonarcube optimization in jsonobject.java 2025-09-07 12:28:52 -08:00
Sean Leary
9b8eefc2de Merge pull request #1004 from marilynel/master
sonarcube cleanup in JSONObject; more to do
2025-08-29 07:49:28 -05:00
marilynel
6ed2880f55 more sonarcube cleanup 2025-08-24 12:55:49 -08:00
marilynel
9bb26bdb34 sonar cube stuff 2025-08-03 11:52:20 -08:00
Sean Leary
78137d389d Merge pull request #1001 from marilynel/master
addressing sonarqube concerns in JSONObject
2025-07-31 20:54:08 -05:00
marilynel
38c3a0bb3f more sonarcube issues 2025-07-27 11:45:07 -08:00
marilynel
ebd9a17a3b addressing minor sonarqube concerns 2025-07-27 11:26:50 -08:00
Sean Leary
82432f0245 Merge pull request #1000 from marilynel/master
fixing sonarcube issues
2025-07-23 20:46:33 -05:00
marilynel
e762629bcc oops one more sonarcube issue lol 2025-07-20 12:04:51 -08:00
marilynel
7fc41a6c0e addressing cognitive complextity 2025-07-20 11:58:30 -08:00
marilynel
d5d82cdb87 fixing sonarcube issues 2025-07-20 11:31:29 -08:00
Sean Leary
0a9364e920 Merge pull request #999 from marilynel/master
fixed some strict mode issues
2025-07-16 20:12:57 -05:00
marilynel
c91b728386 oops forgot null 2025-07-13 12:52:42 -08:00
marilynel
fdaeb486ed fixed some strict mode issues 980 2025-07-13 12:41:17 -08:00
Sean Leary
f0a78aff61 Merge pull request #995 from marilynel/master
Fix regression XML parsing null with keepStrings
2025-07-09 20:18:48 -05:00
Sean Leary
a79e8a15e5 Merge pull request #994 from stleary/tech-debt-20250701
tech-debt-25250701
2025-07-08 11:04:29 -05:00
marilynel
7bb3df8ebf added test details 2025-07-06 12:41:44 -08:00
marilynel
3dce55794f fixed keeping null as string 2025-07-06 12:37:05 -08:00
Sean Leary
d7593fb808 Merge pull request #992 from surajdm123/add-tests
Added JUnit test cases for HTTPTokener
2025-07-06 08:27:59 -05:00
Sean Leary
1eed44a59e Merge pull request #993 from surajdm123/add-tests-2
Added JUnit tests for XMLTokenerTest
2025-07-06 08:27:20 -05:00
Sean Leary
7eccadefcd Merge pull request #991 from Simulant87/update-codeql-v3
update CodeQL to v3
2025-07-04 16:39:18 -05:00
surajdm123
a729c2077a Added JUnit tests for XMLTokenerTest 2025-07-03 01:23:46 -07:00
surajdm123
7ac773be72 Added JUnit test cases for HTTPTokener 2025-07-03 00:58:15 -07:00
Simulant
7da120e631 update CodeQL to v3 2025-07-01 22:57:36 +02:00
31 changed files with 1810 additions and 394 deletions

View File

@@ -29,7 +29,7 @@ jobs:
# Initializes the CodeQL tools for scanning. # Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL - name: Initialize CodeQL
uses: github/codeql-action/init@v2 uses: github/codeql-action/init@v3
with: with:
languages: ${{ matrix.language }} languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file. # 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" - run: "mvn clean compile -Dmaven.test.skip=true -Dmaven.site.skip=true -Dmaven.javadoc.skip=true"
- name: Perform CodeQL Analysis - name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v2 uses: github/codeql-action/analyze@v3

View File

@@ -15,7 +15,7 @@ jobs:
name: Java 1.6 name: Java 1.6
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v5
- name: Setup java - name: Setup java
uses: actions/setup-java@v1 uses: actions/setup-java@v1
with: with:
@@ -30,7 +30,7 @@ jobs:
jar cvf target/org.json.jar -C target/classes . jar cvf target/org.json.jar -C target/classes .
- name: Upload JAR 1.6 - name: Upload JAR 1.6
if: ${{ always() }} if: ${{ always() }}
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v5
with: with:
name: Create java 1.6 JAR name: Create java 1.6 JAR
path: target/*.jar path: target/*.jar
@@ -45,9 +45,9 @@ jobs:
java: [ 8 ] java: [ 8 ]
name: Java ${{ matrix.java }} name: Java ${{ matrix.java }}
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v5
- name: Set up JDK ${{ matrix.java }} - name: Set up JDK ${{ matrix.java }}
uses: actions/setup-java@v3 uses: actions/setup-java@v5
with: with:
distribution: 'temurin' distribution: 'temurin'
java-version: ${{ matrix.java }} 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 }} mvn site -D generateReports=false -D maven.compiler.source=${{ matrix.java }} -D maven.compiler.target=${{ matrix.java }}
- name: Upload Test Results ${{ matrix.java }} - name: Upload Test Results ${{ matrix.java }}
if: ${{ always() }} if: ${{ always() }}
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v5
with: with:
name: Test Results ${{ matrix.java }} name: Test Results ${{ matrix.java }}
path: target/surefire-reports/ path: target/surefire-reports/
- name: Upload Test Report ${{ matrix.java }} - name: Upload Test Report ${{ matrix.java }}
if: ${{ always() }} if: ${{ always() }}
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v5
with: with:
name: Test Report ${{ matrix.java }} name: Test Report ${{ matrix.java }}
path: target/site/ 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 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 }} - name: Upload Package Results ${{ matrix.java }}
if: ${{ always() }} if: ${{ always() }}
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v5
with: with:
name: Package Jar ${{ matrix.java }} name: Package Jar ${{ matrix.java }}
path: target/*.jar path: target/*.jar
@@ -93,9 +93,9 @@ jobs:
java: [ 11 ] java: [ 11 ]
name: Java ${{ matrix.java }} name: Java ${{ matrix.java }}
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v5
- name: Set up JDK ${{ matrix.java }} - name: Set up JDK ${{ matrix.java }}
uses: actions/setup-java@v3 uses: actions/setup-java@v5
with: with:
distribution: 'temurin' distribution: 'temurin'
java-version: ${{ matrix.java }} 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 }} mvn site -D generateReports=false -D maven.compiler.source=${{ matrix.java }} -D maven.compiler.target=${{ matrix.java }}
- name: Upload Test Results ${{ matrix.java }} - name: Upload Test Results ${{ matrix.java }}
if: ${{ always() }} if: ${{ always() }}
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v5
with: with:
name: Test Results ${{ matrix.java }} name: Test Results ${{ matrix.java }}
path: target/surefire-reports/ path: target/surefire-reports/
- name: Upload Test Report ${{ matrix.java }} - name: Upload Test Report ${{ matrix.java }}
if: ${{ always() }} if: ${{ always() }}
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v5
with: with:
name: Test Report ${{ matrix.java }} name: Test Report ${{ matrix.java }}
path: target/site/ 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 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 }} - name: Upload Package Results ${{ matrix.java }}
if: ${{ always() }} if: ${{ always() }}
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v5
with: with:
name: Package Jar ${{ matrix.java }} name: Package Jar ${{ matrix.java }}
path: target/*.jar path: target/*.jar
@@ -141,9 +141,9 @@ jobs:
java: [ 17 ] java: [ 17 ]
name: Java ${{ matrix.java }} name: Java ${{ matrix.java }}
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v5
- name: Set up JDK ${{ matrix.java }} - name: Set up JDK ${{ matrix.java }}
uses: actions/setup-java@v3 uses: actions/setup-java@v5
with: with:
distribution: 'temurin' distribution: 'temurin'
java-version: ${{ matrix.java }} 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 }} mvn site -D generateReports=false -D maven.compiler.source=${{ matrix.java }} -D maven.compiler.target=${{ matrix.java }}
- name: Upload Test Results ${{ matrix.java }} - name: Upload Test Results ${{ matrix.java }}
if: ${{ always() }} if: ${{ always() }}
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v5
with: with:
name: Test Results ${{ matrix.java }} name: Test Results ${{ matrix.java }}
path: target/surefire-reports/ path: target/surefire-reports/
- name: Upload Test Report ${{ matrix.java }} - name: Upload Test Report ${{ matrix.java }}
if: ${{ always() }} if: ${{ always() }}
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v5
with: with:
name: Test Report ${{ matrix.java }} name: Test Report ${{ matrix.java }}
path: target/site/ 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 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 }} - name: Upload Package Results ${{ matrix.java }}
if: ${{ always() }} if: ${{ always() }}
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v5
with: with:
name: Package Jar ${{ matrix.java }} name: Package Jar ${{ matrix.java }}
path: target/*.jar path: target/*.jar
@@ -189,9 +189,9 @@ jobs:
java: [ 21 ] java: [ 21 ]
name: Java ${{ matrix.java }} name: Java ${{ matrix.java }}
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v5
- name: Set up JDK ${{ matrix.java }} - name: Set up JDK ${{ matrix.java }}
uses: actions/setup-java@v3 uses: actions/setup-java@v5
with: with:
distribution: 'temurin' distribution: 'temurin'
java-version: ${{ matrix.java }} 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 }} mvn site -D generateReports=false -D maven.compiler.source=${{ matrix.java }} -D maven.compiler.target=${{ matrix.java }}
- name: Upload Test Results ${{ matrix.java }} - name: Upload Test Results ${{ matrix.java }}
if: ${{ always() }} if: ${{ always() }}
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v5
with: with:
name: Test Results ${{ matrix.java }} name: Test Results ${{ matrix.java }}
path: target/surefire-reports/ path: target/surefire-reports/
- name: Upload Test Report ${{ matrix.java }} - name: Upload Test Report ${{ matrix.java }}
if: ${{ always() }} if: ${{ always() }}
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v5
with: with:
name: Test Report ${{ matrix.java }} name: Test Report ${{ matrix.java }}
path: target/site/ 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 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 }} - name: Upload Package Results ${{ matrix.java }}
if: ${{ always() }} if: ${{ always() }}
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v5
with: with:
name: Package Jar ${{ matrix.java }} name: Package Jar ${{ matrix.java }}
path: target/*.jar 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

View File

@@ -9,8 +9,9 @@ JSON in Java [package org.json]
[![Maven Central](https://img.shields.io/maven-central/v/org.json/json.svg)](https://mvnrepository.com/artifact/org.json/json) [![Maven Central](https://img.shields.io/maven-central/v/org.json/json.svg)](https://mvnrepository.com/artifact/org.json/json)
[![Java CI with Maven](https://github.com/stleary/JSON-java/actions/workflows/pipeline.yml/badge.svg)](https://github.com/stleary/JSON-java/actions/workflows/pipeline.yml) [![Java CI with Maven](https://github.com/stleary/JSON-java/actions/workflows/pipeline.yml/badge.svg)](https://github.com/stleary/JSON-java/actions/workflows/pipeline.yml)
[![CodeQL](https://github.com/stleary/JSON-java/actions/workflows/codeql-analysis.yml/badge.svg)](https://github.com/stleary/JSON-java/actions/workflows/codeql-analysis.yml) [![CodeQL](https://github.com/stleary/JSON-java/actions/workflows/codeql-analysis.yml/badge.svg)](https://github.com/stleary/JSON-java/actions/workflows/codeql-analysis.yml)
[![javadoc](https://javadoc.io/badge2/org.json/json/javadoc.svg)](https://javadoc.io/doc/org.json/json)
**[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 # Overview
@@ -26,7 +27,7 @@ Project goals include:
* No external dependencies * No external dependencies
* Fast execution and low memory footprint * Fast execution and low memory footprint
* Maintain backward compatibility * 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. The files in this package implement JSON encoders and decoders. The package can also convert between JSON and XML, HTTP headers, Cookies, and CDL.

View File

@@ -42,7 +42,7 @@ subprojects {
} }
group = 'org.json' group = 'org.json'
version = 'v20250517-SNAPSHOT' version = 'v20251224-SNAPSHOT'
description = 'JSON in Java' description = 'JSON in Java'
sourceCompatibility = '1.8' sourceCompatibility = '1.8'

View File

@@ -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) [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 20250517 Strict mode hardening and recent commits
20250107 Restore moditect in pom.xml 20250107 Restore moditect in pom.xml

View File

@@ -3,7 +3,7 @@
<groupId>org.json</groupId> <groupId>org.json</groupId>
<artifactId>json</artifactId> <artifactId>json</artifactId>
<version>20250517</version> <version>20251224</version>
<packaging>bundle</packaging> <packaging>bundle</packaging>
<name>JSON in Java</name> <name>JSON in Java</name>

View File

@@ -27,7 +27,9 @@ public class CDL {
/** /**
* Constructs a new CDL object. * Constructs a new CDL object.
* @deprecated (Utility class cannot be instantiated)
*/ */
@Deprecated
public CDL() { public CDL() {
} }
@@ -183,7 +185,7 @@ public class CDL {
Object object = ja.opt(i); Object object = ja.opt(i);
if (object != null) { if (object != null) {
String string = object.toString(); 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('\n') >= 0 || string.indexOf('\r') >= 0 ||
string.indexOf(0) >= 0 || string.charAt(0) == '"')) { string.indexOf(0) >= 0 || string.charAt(0) == '"')) {
sb.append('"'); sb.append('"');

View File

@@ -17,7 +17,9 @@ public class Cookie {
/** /**
* Constructs a new Cookie object. * Constructs a new Cookie object.
* @deprecated (Utility class cannot be instantiated)
*/ */
@Deprecated()
public Cookie() { public Cookie() {
} }

View File

@@ -13,7 +13,9 @@ public class CookieList {
/** /**
* Constructs a new CookieList object. * Constructs a new CookieList object.
* @deprecated (Utility class cannot be instantiated)
*/ */
@Deprecated
public CookieList() { public CookieList() {
} }

View File

@@ -105,6 +105,8 @@ public class JSONArray implements Iterable<Object> {
if (nextChar == 0) { if (nextChar == 0) {
// array is unclosed. No ']' found, instead EOF // array is unclosed. No ']' found, instead EOF
throw x.syntaxError("Expected a ',' or ']'"); throw x.syntaxError("Expected a ',' or ']'");
} else if (nextChar==',' && jsonParserConfiguration.isStrictMode()) {
throw x.syntaxError("Array content starts with a ','");
} }
if (nextChar != ']') { if (nextChar != ']') {
x.back(); x.back();
@@ -116,41 +118,7 @@ public class JSONArray implements Iterable<Object> {
x.back(); x.back();
this.myArrayList.add(x.nextValue()); this.myArrayList.add(x.nextValue());
} }
switch (x.nextClean()) { if (checkForSyntaxError(x, jsonParserConfiguration, isInitial)) return;
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 ']'");
}
} }
} else { } else {
if (isInitial && jsonParserConfiguration.isStrictMode() && x.nextClean() != 0) { 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. * Construct a JSONArray from a source JSON text.
* *
@@ -733,11 +747,7 @@ public class JSONArray implements Iterable<Object> {
if (val == null) { if (val == null) {
return defaultValue; return defaultValue;
} }
final double doubleValue = val.doubleValue(); return val.doubleValue();
// if (Double.isNaN(doubleValue) || Double.isInfinite(doubleValue)) {
// return defaultValue;
// }
return doubleValue;
} }
/** /**
@@ -769,11 +779,7 @@ public class JSONArray implements Iterable<Object> {
if (val == null) { if (val == null) {
return defaultValue; return defaultValue;
} }
final Double doubleValue = val.doubleValue(); return val.doubleValue();
// if (Double.isNaN(doubleValue) || Double.isInfinite(doubleValue)) {
// return defaultValue;
// }
return doubleValue;
} }
/** /**
@@ -805,11 +811,7 @@ public class JSONArray implements Iterable<Object> {
if (val == null) { if (val == null) {
return defaultValue; return defaultValue;
} }
final float floatValue = val.floatValue(); return val.floatValue();
// if (Float.isNaN(floatValue) || Float.isInfinite(floatValue)) {
// return floatValue;
// }
return floatValue;
} }
/** /**
@@ -841,11 +843,7 @@ public class JSONArray implements Iterable<Object> {
if (val == null) { if (val == null) {
return defaultValue; return defaultValue;
} }
final Float floatValue = val.floatValue(); return val.floatValue();
// if (Float.isNaN(floatValue) || Float.isInfinite(floatValue)) {
// return floatValue;
// }
return floatValue;
} }
/** /**
@@ -1643,29 +1641,44 @@ public class JSONArray implements Iterable<Object> {
if(valueThis == null) { if(valueThis == null) {
return false; return false;
} }
if (valueThis instanceof JSONObject) { if (!isSimilar(valueThis, valueOther)) {
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 false;
} }
} }
return true; 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 * Produce a JSONObject by combining a JSONArray of names with the values of
* this JSONArray. * this JSONArray.
@@ -1797,12 +1810,7 @@ public class JSONArray implements Iterable<Object> {
writer.write('['); writer.write('[');
if (length == 1) { if (length == 1) {
try { writeArrayAttempt(writer, indentFactor, indent, 0);
JSONObject.writeValue(writer, this.myArrayList.get(0),
indentFactor, indent);
} catch (Exception e) {
throw new JSONException("Unable to write JSONArray value at index: 0", e);
}
} else if (length != 0) { } else if (length != 0) {
final int newIndent = indent + indentFactor; final int newIndent = indent + indentFactor;
@@ -1814,12 +1822,7 @@ public class JSONArray implements Iterable<Object> {
writer.write('\n'); writer.write('\n');
} }
JSONObject.indent(writer, newIndent); JSONObject.indent(writer, newIndent);
try { writeArrayAttempt(writer, indentFactor, newIndent, i);
JSONObject.writeValue(writer, this.myArrayList.get(i),
indentFactor, newIndent);
} catch (Exception e) {
throw new JSONException("Unable to write JSONArray value at index: " + i, e);
}
needsComma = true; needsComma = true;
} }
if (indentFactor > 0) { if (indentFactor > 0) {
@@ -1834,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. * 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 * If an element in the array is a JSONArray or JSONObject it will also

View File

@@ -16,10 +16,13 @@ public class JSONML {
/** /**
* Constructs a new JSONML object. * Constructs a new JSONML object.
* @deprecated (Utility class cannot be instantiated)
*/ */
@Deprecated
public JSONML() { public JSONML() {
} }
/** /**
* Parse XML values and store them in a JSONArray. * Parse XML values and store them in a JSONArray.
* @param x The XMLTokener containing the source string. * @param x The XMLTokener containing the source string.
@@ -239,9 +242,21 @@ public class JSONML {
} }
} else { } else {
if (ja != null) { if (ja != null) {
ja.put(token instanceof String Object value;
? (config.isKeepStrings() ? XML.unescape((String)token) : XML.stringToValue((String)token))
: token); 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

View File

@@ -509,13 +509,26 @@ public class JSONTokener {
string = sb.toString().trim(); string = sb.toString().trim();
if ("".equals(string)) { if ("".equals(string)) {
throw this.syntaxError("Missing value"); 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); 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 && if (jsonParserConfiguration != null &&
jsonParserConfiguration.isStrictMode() && jsonParserConfiguration.isStrictMode()) {
obj instanceof String) { if (obj instanceof Boolean && !"true".equals(string) && !"false".equals(string)) {
throw this.syntaxError(String.format("Strict mode error: Value '%s' is not surrounded by quotes", obj)); // 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; return obj;
} }

View File

@@ -9,6 +9,7 @@ import java.io.StringReader;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.math.BigInteger; import java.math.BigInteger;
import java.util.Iterator; import java.util.Iterator;
import java.util.NoSuchElementException;
/** /**
* This provides static methods to convert an XML text into a JSONObject, and to * This provides static methods to convert an XML text into a JSONObject, and to
@@ -80,7 +81,7 @@ public class XML {
public Iterator<Integer> iterator() { public Iterator<Integer> iterator() {
return new Iterator<Integer>() { return new Iterator<Integer>() {
private int nextIndex = 0; private int nextIndex = 0;
private int length = string.length(); private final int length = string.length();
@Override @Override
public boolean hasNext() { public boolean hasNext() {
@@ -89,6 +90,9 @@ public class XML {
@Override @Override
public Integer next() { public Integer next() {
if (!hasNext()) {
throw new NoSuchElementException();
}
int result = string.codePointAt(this.nextIndex); int result = string.codePointAt(this.nextIndex);
this.nextIndex += Character.charCount(result); this.nextIndex += Character.charCount(result);
return result; return result;
@@ -428,6 +432,9 @@ public class XML {
config.isKeepNumberAsString() config.isKeepNumberAsString()
? ((String) token) ? ((String) token)
: obj); : obj);
} else if (obj == JSONObject.NULL) {
jsonObject.accumulate(config.getcDataTagName(),
config.isKeepStrings() ? ((String) token) : obj);
} else { } else {
jsonObject.accumulate(config.getcDataTagName(), stringToValue((String) token)); jsonObject.accumulate(config.getcDataTagName(), stringToValue((String) token));
} }

View 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);
}
}

View File

@@ -36,25 +36,31 @@ public class JSONObjectLocaleTest {
MyLocaleBean myLocaleBean = new MyLocaleBean(); MyLocaleBean myLocaleBean = new MyLocaleBean();
/** // save and restore the current default locale, to avoid any side effects on other executions in the same JVM
* This is just the control case which happens when the locale.ROOT Locale defaultLocale = Locale.getDefault();
* lowercasing behavior is the same as the current locale. try {
*/ /**
Locale.setDefault(new Locale("en")); * This is just the control case which happens when the locale.ROOT
JSONObject jsonen = new JSONObject(myLocaleBean); * lowercasing behavior is the same as the current locale.
assertEquals("expected size 2, found: " +jsonen.length(), 2, jsonen.length()); */
assertEquals("expected jsonen[i] == beanI", "beanI", jsonen.getString("i")); Locale.setDefault(new Locale("en"));
assertEquals("expected jsonen[id] == beanId", "beanId", jsonen.getString("id")); JSONObject jsonen = new JSONObject(myLocaleBean);
assertEquals("expected size 2, found: " +jsonen.length(), 2, jsonen.length());
assertEquals("expected jsonen[i] == beanI", "beanI", jsonen.getString("i"));
assertEquals("expected jsonen[id] == beanId", "beanId", jsonen.getString("id"));
/** /**
* Without the JSON-Java change, these keys would be stored internally as * Without the JSON-Java change, these keys would be stored internally as
* starting with the letter, 'ı' (dotless i), since the lowercasing of * starting with the letter, 'ı' (dotless i), since the lowercasing of
* the getI and getId keys would be specific to the Turkish locale. * the getI and getId keys would be specific to the Turkish locale.
*/ */
Locale.setDefault(new Locale("tr")); Locale.setDefault(new Locale("tr"));
JSONObject jsontr = new JSONObject(myLocaleBean); JSONObject jsontr = new JSONObject(myLocaleBean);
assertEquals("expected size 2, found: " +jsontr.length(), 2, jsontr.length()); assertEquals("expected size 2, found: " +jsontr.length(), 2, jsontr.length());
assertEquals("expected jsontr[i] == beanI", "beanI", jsontr.getString("i")); assertEquals("expected jsontr[i] == beanI", "beanI", jsontr.getString("i"));
assertEquals("expected jsontr[id] == beanId", "beanId", jsontr.getString("id")); assertEquals("expected jsontr[id] == beanId", "beanId", jsontr.getString("id"));
} finally {
Locale.setDefault(defaultLocale);
}
} }
} }

View 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());
}
}

View File

@@ -56,6 +56,17 @@ import org.json.junit.data.RecursiveBeanEquals;
import org.json.junit.data.Singleton; import org.json.junit.data.Singleton;
import org.json.junit.data.SingletonEnum; import org.json.junit.data.SingletonEnum;
import org.json.junit.data.WeirdList; 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.After;
import org.junit.Ignore; import org.junit.Ignore;
import org.junit.Test; import org.junit.Test;
@@ -3106,12 +3117,13 @@ public class JSONObjectTest {
// test a more complex object // test a more complex object
writer = new StringWriter(); writer = new StringWriter();
try {
new JSONObject() JSONObject object = new JSONObject()
.put("somethingElse", "a value") .put("somethingElse", "a value")
.put("someKey", new JSONArray() .put("someKey", new JSONArray()
.put(new JSONObject().put("key1", new BrokenToString()))) .put(new JSONObject().put("key1", new BrokenToString())));
.write(writer).toString(); try {
object.write(writer).toString();
fail("Expected an exception, got a String value"); fail("Expected an exception, got a String value");
} catch (JSONException e) { } catch (JSONException e) {
assertEquals("Unable to write JSONObject value for key: someKey", e.getMessage()); assertEquals("Unable to write JSONObject value for key: someKey", e.getMessage());
@@ -3122,17 +3134,18 @@ public class JSONObjectTest {
writer.close(); writer.close();
} catch (Exception e) {} } catch (Exception e) {}
} }
// test a more slightly complex object // test a more slightly complex object
writer = new StringWriter(); writer = new StringWriter();
try {
new JSONObject() object = new JSONObject()
.put("somethingElse", "a value") .put("somethingElse", "a value")
.put("someKey", new JSONArray() .put("someKey", new JSONArray()
.put(new JSONObject().put("key1", new BrokenToString())) .put(new JSONObject().put("key1", new BrokenToString()))
.put(12345) .put(12345)
) );
.write(writer).toString(); try {
object.write(writer).toString();
fail("Expected an exception, got a String value"); fail("Expected an exception, got a String value");
} catch (JSONException e) { } catch (JSONException e) {
assertEquals("Unable to write JSONObject value for key: someKey", e.getMessage()); assertEquals("Unable to write JSONObject value for key: someKey", e.getMessage());
@@ -3895,9 +3908,10 @@ public class JSONObjectTest {
} }
@Test @Test
public void issue743SerializationMapWith1000Objects() { public void issue743SerializationMapWith500Objects() {
HashMap<String, Object> map = buildNestedMap(1000); // TODO: find out why 1000 objects no longer works
JSONParserConfiguration parserConfiguration = new JSONParserConfiguration().withMaxNestingDepth(1000); HashMap<String, Object> map = buildNestedMap(500);
JSONParserConfiguration parserConfiguration = new JSONParserConfiguration().withMaxNestingDepth(500);
JSONObject object = new JSONObject(map, parserConfiguration); JSONObject object = new JSONObject(map, parserConfiguration);
String jsonString = object.toString(); String jsonString = object.toString();
} }
@@ -3997,6 +4011,56 @@ public class JSONObjectTest {
assertThrows(JSONException.class, () -> { new JSONObject(tokener); }); 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 * Method to build nested map of max maxDepth
* *
@@ -4044,4 +4108,128 @@ public class JSONObjectTest {
assertTrue("JSONObject should be empty", jsonObject.isEmpty()); 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());
}
} }

View File

@@ -775,8 +775,8 @@ public class XMLConfigurationTest {
*/ */
@Test @Test
public void testToJSONArray_jsonOutput_withKeepNumberAsString() { 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 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\"],\"title\":true}}"); final JSONObject expected = new JSONObject("{\"root\":{\"item\":{\"id\":\"01\"},\"id\":[\"01\",\"1\",\"00\",\"0\",null],\"title\":true}}");
final JSONObject actualJsonOutput = XML.toJSONObject(originalXml, final JSONObject actualJsonOutput = XML.toJSONObject(originalXml,
new XMLParserConfiguration().withKeepNumberAsString(true)); new XMLParserConfiguration().withKeepNumberAsString(true));
Util.compareActualVsExpectedJsonObjects(actualJsonOutput,expected); Util.compareActualVsExpectedJsonObjects(actualJsonOutput,expected);
@@ -787,13 +787,25 @@ public class XMLConfigurationTest {
*/ */
@Test @Test
public void testToJSONArray_jsonOutput_withKeepBooleanAsString() { 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 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],\"title\":\"True\"}}"); final JSONObject expected = new JSONObject("{\"root\":{\"item\":{\"id\":\"01\"},\"id\":[\"01\",1,\"00\",0,null],\"title\":\"True\"}}");
final JSONObject actualJsonOutput = XML.toJSONObject(originalXml, final JSONObject actualJsonOutput = XML.toJSONObject(originalXml,
new XMLParserConfiguration().withKeepBooleanAsString(true)); new XMLParserConfiguration().withKeepBooleanAsString(true));
Util.compareActualVsExpectedJsonObjects(actualJsonOutput,expected); 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 * Test keepStrings behavior when setting keepBooleanAsString, keepNumberAsString
*/ */

View 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 &amp; 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"
}
}

View 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));
}
}

View 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);
}
}

View 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);
}
}

View 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);
}
}

View 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);
}
}

View 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);
}
}

View 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);
}
}

View 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);
}
}

View 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()));
}
}

View 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;
}
}

View 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;
}
}