Skip to content

JEXL-472 : Add property access for Java record component accessors - #416

Merged
henrib merged 6 commits into
masterfrom
JEXL-472
Sep 14, 2026
Merged

henrib merged 6 commits into
masterfrom
JEXL-472

Conversation

@henrib

@henrib henrib commented Sep 14, 2026

Copy link
Copy Markdown
Contributor

No description provided.

murdos and others added 3 commits September 14, 2026 08:14
foo.bar never resolved to a record's generated bar() accessor, only
to getBar()/isBar(), a public field, or duck-typed get(Object). Add a
RecordGetExecutor that matches property to record component and
lets Introspector resolve the actual accessor Method, so it still
goes through the usual permission checks.

Detection is done entirely via reflection (Class#isRecord(),
Class#getRecordComponents()) since this module still targets Java 8;
on such a runtime these methods simply don't exist and discovery
quietly reports no match.

The new test compiles its record fixtures on the fly with
javax.tools.JavaCompiler and skips itself below Java 16, since
'record' isn't valid syntax at this module's source level either.
…ture

Move the Class#isRecord()/getRecordComponents() reflection out of
RecordGetExecutor and into the existing ClassTool backport utility,
resolved via MethodHandle to match how it already backports Java 9+
module reflection, instead of duplicating a separate Method-based
lookup.

Fix RecordPropertyAccessTest's on-the-fly compiled record fixture to
actually compile into org.apache.commons.jexl3 (it previously compiled
with no package, then looked itself up under that package, which does
not resolve). Also switch the test to extend JexlTestCase and use the
shared restricted-permissions engine instead of a bespoke
UNRESTRICTED-permissions one, matching the rest of the suite.

Builds on the record accessor support originally proposed by
Aurelien Mino in #415.

Co-Authored-By: Claude Code <noreply@anthropic.com>
- Builds on the record accessor support originally proposed by
Aurelien Mino in #415.

- Move the Class#isRecord()/getRecordComponents() reflection out of
RecordGetExecutor and into the existing ClassTool backport utility,
resolved via MethodHandle to match how it already backports Java 9+
module reflection, instead of duplicating a separate Method-based
lookup.

- Fix RecordPropertyAccessTest's on-the-fly compiled record fixture to
actually compile into org.apache.commons.jexl3. Also switch the test to extend JexlTestCase and use the shared restricted-permissions engine instead of a bespoke
UNRESTRICTED-permissions one, matching the rest of the suite.

- Correct @SInCE on the namespaceInstantiation additions (JexlFeatures,    JexlOptions) from stale 3.6 to 3.7.1, and RecordGetExecutor from 3.7.2 to 3.7.1, matching the actual in-flight version.
- Reorder actions within each changes.xml section by descending JEXL issue number.
Copilot AI lite review requested due to automatic review settings September 14, 2026 13:46

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Changes recommended

Test artifacts are not cleaned up, and unrelated Checkstyle and ignore exclusions should be removed.

Get a fresh assessment by requesting another Copilot review.

Pull request overview

Adds Java record component accessor support as JEXL properties with Java 8-compatible reflective discovery.

Changes:

  • Adds record-aware introspection and property execution.
  • Adds runtime-compiled record property tests.
  • Updates API metadata, release notes, and build configuration.
File summaries
File Summary
src/test/java/org/apache/commons/jexl3/RecordPropertyAccessTest.java Tests record property access.
src/main/java/org/apache/commons/jexl3/JexlOptions.java Updates API version metadata.
src/main/java/org/apache/commons/jexl3/JexlFeatures.java Updates API version metadata.
src/main/java/org/apache/commons/jexl3/internal/introspection/Uberspect.java Integrates record getter resolution.
src/main/java/org/apache/commons/jexl3/internal/introspection/RecordGetExecutor.java Resolves record component accessors.
src/main/java/org/apache/commons/jexl3/internal/introspection/ClassTool.java Provides reflective record introspection.
src/changes/changes.xml Documents JEXL-472.
pom.xml Adds Checkstyle exclusions.
.gitignore Ignores scratch files.
Review details

Suppressed comments (1)

src/test/java/org/apache/commons/jexl3/RecordPropertyAccessTest.java:60

  • Each invocation creates a source/class-file tree under java.io.tmpdir and never removes it. Repeated test runs therefore accumulate jexl-record-test* directories; close the class loader and recursively delete dir in a finally block after loading the class.
        final Path dir = Files.createTempDirectory("jexl-record-test");
        final Path javaFile = dir.resolve(name + ".java");
        Files.write(javaFile, source.getBytes(StandardCharsets.UTF_8));
  • Files reviewed: 8/9 changed files
  • Comments generated: 1
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread pom.xml Outdated

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Changes recommended

The Checkstyle configurations are inconsistent, and the public resolver documentation omits record accessor support.

Get a fresh assessment by requesting another Copilot review.

Review details

Suppressed comments (1)

src/main/java/org/apache/commons/jexl3/internal/introspection/Uberspect.java:352

  • The PROPERTY resolver's public documentation still says it only seeks get{P,p} and is{P,p} methods (JexlUberspect.java:48-49). This branch also resolves record component accessors named foo(), so please update that contract documentation or users configuring resolver strategies will not know that record properties are supported.
                        if (executor == null) {
                            // or a record component accessor, foo() rather than getFoo()
                            executor = RecordGetExecutor.discover(is, clazz, property);
  • Files reviewed: 8/9 changed files
  • Comments generated: 1
  • Review effort level: Lite

Comment thread pom.xml Outdated

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟢 Approval recommended

No unresolved review issues were identified.

Review details
  • Files reviewed: 7/8 changed files
  • Comments generated: 0 new
  • Review effort level: Lite

@henrib
henrib merged commit 07ca868 into master Sep 14, 2026
17 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.

3 participants