Skip to content

Conversation

@Abhineshhh
Copy link
Contributor

Fixes : #1015

Problem

new JSONObject(recordInstance) or JSONObject.wrap(recordInstance) produces an empty object {} when the object is a Java record (or any class using record-style accessors without @JSONPropertyName annotations).

Root Cause

Java records use accessor methods without the traditional JavaBean get/is prefixes:

  • Traditional class: getName() → works
  • Java record: name() → fails (returns {})

The getKeyNameFromMethod() logic only checked for methods starting with get or is, causing it to ignore record accessors.

Solution

Modified getKeyNameFromMethod() in JSONObject.java to recognize record-style accessor methods:

  • Now supports lowercase method names (e.g., name(), age(), active())
  • Excludes methods from Object, Enum, Number, and all java.*/javax.* classes
  • Excludes common method names (hashCode, toString, equals, etc.)

Changes

  • Modified: src/main/java/org/json/JSONObject.java - Added record accessor support
  • Added: src/test/java/org/json/junit/data/PersonRecord.java - Test class mimicking record behavior
  • Added: Test case jsonObjectByRecord() in JSONObjectTest.java

Testing

All 735 existing tests pass
New test for record-style classes passes
No breaking changes - fully backward compatible

Example

// Before: returns {}
record Person(String name, int age) {}
Person person = new Person("John", 30);
JSONObject json = new JSONObject(person);
// Result: {}

// After: returns {"name":"John","age":30}
JSONObject json = new JSONObject(person);
// Result: {"name":"John","age":30}

@Abhineshhh
Copy link
Contributor Author

Abhineshhh commented Oct 25, 2025

have a review @stleary !

}

// Exclude common bean/Object method names
if ("get".equals(methodName) || "is".equals(methodName) || "set".equals(methodName)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A static hard-coded Set with these values and then a call to contains would be way more performant, right? Since it would behave like a lookup table, and there are a lot of conditions.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good work by the way :D

Copy link
Contributor Author

@Abhineshhh Abhineshhh Oct 30, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great suggestion ! I have refactored the code to use a Set with contains() instead of multiple equals() calls

  • Added EXCLUDED_RECORD_METHOD_NAMES Set containing all the excluded method names
  • Made it unmodifiable using Collections.unmodifiableSet() for thread safety
  • Updated isRecordStyleAccessor() to use Set.contains() instead of chained equals() calls

@stleary
Copy link
Owner

stleary commented Nov 1, 2025

@Abhineshhh Please resync your branch to include the latest changes from #1006

@Abhineshhh Abhineshhh force-pushed the fix/support-java-records branch from a7eb236 to f2acf8a Compare November 1, 2025 14:04
@Abhineshhh
Copy link
Contributor Author

done @stleary

@stleary
Copy link
Owner

stleary commented Nov 2, 2025

@Abhineshhh This is a needed change, and the code looks fine in general, but there are some concerns:

  • What if the class has some properties with record-like accessors and other properties with bean-like accessors? The new code should not change existing behavior. I think the code needs to know if it is parsing a record or a class. You should be able to determine this at runtime with the Java6 jvm.
  • The project will need to test real record types, using e.g. Java17. Not sure yet how this should work.

@sonarqubecloud
Copy link

sonarqubecloud bot commented Nov 2, 2025

@Abhineshhh
Copy link
Contributor Author

Abhineshhh commented Nov 2, 2025

Thank you for the feedback @stleary ! I've addressed both concerns:

@stleary
Copy link
Owner

stleary commented Nov 8, 2025

What problem does this code solve?
Add support for record type when parsing Java objects

Does the code still compile with Java6?
Yes

Risks
Moderate. Will need to add a test run using Java v17 or greater that instantiates and tests records.

Changes to the API?
No

Will this require a new release?
No

Should the documentation be updated?
No

Does it break the unit tests?
No, new unit tests were added

Was any code refactored in this commit?
No

Review status
APPROVED

Starting 3-day comment window

@stleary stleary merged commit a6ca840 into stleary:master Nov 12, 2025
8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

JSONObject does not work with records without field annotations

4 participants