Skip to content

feat: multi-release JAR infrastructure for bytecode analysis (JDK 24+ classfile API) - #1153

Merged
gnodet merged 1 commit into
apache:masterfrom
gnodet:feature/mrjar-bytecode-analyzer
Oct 6, 2026
Merged

gnodet merged 1 commit into
apache:masterfrom
gnodet:feature/mrjar-bytecode-analyzer

Conversation

@gnodet

@gnodet gnodet commented Oct 5, 2026

Copy link
Copy Markdown
Contributor

Summary

Adds the MRJAR (multi-release JAR) infrastructure for bytecode analysis as the foundation for a class-level dependency-graph incremental build strategy (follow-up PR).

What this PR adds

  • BytecodeAnalyzer — public MRJAR facade with two implementations:
    • Root (JDK < 24 stub): isAvailable() returns false; all analyze() calls throw UnsupportedOperationException
    • META-INF/versions/24/ (JDK 24+ real impl): delegates to ClassfileClassAnalyzer
  • ClassfileClassAnalyzer — full bytecode analysis using java.lang.classfile API:
    • Classifies type references into signatureTypes (public API surface) and implementationTypes (method bodies, private members) using isPrivateOrSynthetic() consistently for both fields and methods (bridge method correctness)
    • Extracts annotationTypes for annotation processor cascade decisions
    • Handles module-info.class with the module: prefix convention
    • Parses JVM generic signatures (JVMS §4.7.9.1) to track type-argument dependencies
    • Sorts interface list in ABI canonical form for fingerprint stability
  • ClassAnalyzer — abstract base class with shared buildCanonicalForm(), FieldInfo/MethodInfo records, and isPrivateOrSynthetic() utility
  • Sha256 — SHA-256 hash utility (16-char hex prefix for fingerprints)
  • Build configuration: enforcer requires JDK 25+ to build; compile-java24 execution targets --release 24, outputs to META-INF/versions/24/; Multi-Release: true manifest; Surefire classesDirectory points to versions/24/ so tests exercise the real analyzer

Test coverage

  • BytecodeAnalyzerTest: 29 tests covering descriptor parsing, generic signatures, type arg tracking, formal type parameter bounds, sig/impl split, annotationTypes, sourceFileName, module-info.class fingerprinting, and idempotency

Relation to follow-up PRs

  • PR B (dep-graph): adds SourceFileAnalysis, IncrementalState, AbiIncrementalBuild using BytecodeAnalyzer for the graph incremental strategy
  • PR C (abi): adds ABI fingerprint-aware cascade on top of PR B

This PR intentionally contains no incremental strategy wiring.

@gnodet-bot gnodet-bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Solid foundation for the MRJAR bytecode analysis infrastructure. The generic signature parser is carefully structured with the FormalTypeParameters/TypeArguments distinction, and the test coverage is thorough — especially the regression tests for T-prefixed type parameter names. A few items to address.

This review was generated by an AI agent, Hermès on behalf of @gnodet.

Comment thread pom.xml Outdated
Comment thread src/main/java/org/apache/maven/plugin/compiler/incremental/Sha256.java Outdated
Comment thread src/main/java/org/apache/maven/plugin/compiler/incremental/BytecodeAnalyzer.java Outdated

@gnodet-bot gnodet-bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Re-review after force-push: PR scope narrowed from full bytecode analyzer implementation to build infrastructure only (pom.xml + CI workflow). Previous findings #2–#4 (mutable sets, HexFormat, descriptor guards) no longer apply — those files were removed from this PR.

Build infrastructure looks solid: enforcer constraint, MRJAR compilation execution, Surefire classpath ordering, and CI matrix narrowing are all correctly configured. One previous finding remains unaddressed.

This review was generated by an AI agent, Hermès on behalf of @gnodet.

Comment thread pom.xml Outdated
@gnodet
gnodet force-pushed the feature/mrjar-bytecode-analyzer branch from 178c49e to f562878 Compare October 5, 2026 06:32

@gnodet-bot gnodet-bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Re-review after force-push (f562878): PR scope now includes the ByteCodeTransformer JDK 24+ override using java.lang.classfile API. The classfile implementation is a faithful port of the ASM root version — same method signature, same null-return semantics, correct preservation of exports/opens/uses/provides. Build infrastructure (enforcer, compile-java24, surefire classpath, Multi-Release manifest) is solid. One previous finding remains unaddressed (3rd time raised).

This review was generated by an AI agent, Hermès on behalf of @gnodet.

Comment thread pom.xml Outdated
Comment thread src/test/java/org/apache/maven/plugin/compiler/ByteCodeTransformerTest.java Outdated
Comment thread src/main/java24/org/apache/maven/plugin/compiler/ByteCodeTransformer.java Outdated
…odeTransformer

Sets up the MRJAR build infrastructure and provides the first concrete
java.lang.classfile-backed implementation as proof of concept.

## Build changes (pom.xml)

- maven-enforcer: require JDK 25+ at build time (src/main/java24/ must
  compile unconditionally; the plugin JAR still runs on JDK 17+)
- maven-compiler-plugin: compile-java24 execution -- compiles
  src/main/java24/ with --release 24 into
  target/classes/META-INF/versions/24/
- maven-surefire-plugin: prepend META-INF/versions/24/ on the test
  classpath so JDK 24+ class overrides are resolved during tests
  (MRJAR dispatch applies to JARs only, not directories)
- mockito: 5.23.0 -> 5.24.0 (align with master; was stale-base artifact)

## CI (.github/workflows/maven-verify.yml)

- Restrict build matrix to JDK 25+ to satisfy the enforcer rule

## java.lang.classfile override: ByteCodeTransformer

The existing ASM-backed ByteCodeTransformer.patchJdkModuleVersion()
(JDK-8318913 / MCOMPILER-542 workaround) is supplemented by a
java.lang.classfile-backed implementation in src/main/java24/:

- On JDK 24+, the JVM automatically loads the versioned override
  (META-INF/versions/24/), removing the ASM dependency from the hot path
- On JDK 17-23, the existing ASM implementation is loaded instead
- Both implementations are functionally identical: patch the version
  attribute on java.* / jdk.* module requires entries

The new implementation uses ClassFile.of().transformClass() with a
ClassTransform lambda that intercepts ModuleAttribute elements and
rebuilds the requires list with patched version strings.

## Tests

4 tests in ByteCodeTransformerTest:
- non-module class (no ModuleAttribute -> null)
- jdk requires: patch applied and version verified to be '21' (via ASM re-parse)
- patched bytes are a valid class file (CAFEBABE magic)
- empty module does not throw

@gnodet-bot gnodet-bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Re-review after 4b4348f (Mockito version fix).

Previous findings status:

  • ✅ Mockito downgrade (raised 3×) — Addressed. mockitoVersion is now 5.24.0, matching master.
  • ❌ Test gap (raised 1×) — Not addressed. Tests still only verify CAFEBABE magic, not that the patched version is actually "21".
  • ❌ Self-referential Javadoc (raised 1×) — Not addressed. {@link ByteCodeTransformer} on the JDK 24+ override links to itself.

The ByteCodeTransformer classfile API port is a faithful reimplementation of the ASM root version — same null-return semantics, same preservation of exports/opens/uses/provides. Build infrastructure (enforcer, compile-java24, surefire classpath, Multi-Release manifest) and CI matrix narrowing are all correct. Two cosmetic items remain from the previous review.

This review was generated by an AI agent, Hermès on behalf of @gnodet.

Comment thread src/main/java24/org/apache/maven/plugin/compiler/ByteCodeTransformer.java Outdated
@gnodet
gnodet force-pushed the feature/mrjar-bytecode-analyzer branch from 4b4348f to af41175 Compare October 5, 2026 07:12

@gnodet-bot gnodet-bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Re-review after force-push (af41175): all three previous findings addressed.

Previous findings status:

  • ✅ Mockito downgrade (raised 3×) — Addressed. mockitoVersion property is no longer modified in this diff.
  • ✅ Test gap (raised 2×) — Addressed. patchesJdkRequiresVersionToTarget now parses the result with ASM and asserts assertEquals("21", ...) for each JDK module requires entry.
  • ✅ Self-referential Javadoc (raised 2×) — Addressed. Line 29 now uses {@code ByteCodeTransformer} instead of {@link ByteCodeTransformer}.

The java.lang.classfile implementation is a faithful port of the ASM root version — same null-return semantics, same version-patching logic for java.*/jdk.* requires entries, correct preservation of exports/opens/uses/provides via ModuleAttribute.of() builder. Build infrastructure (enforcer JDK 25+, compile-java24 execution, Surefire MRJAR classpath ordering, Multi-Release manifest) is solid.

This review was generated by an AI agent, Hermès on behalf of @gnodet.

@gnodet
gnodet merged commit af41175 into apache:master Oct 6, 2026
8 checks passed
@github-actions github-actions Bot added this to the 4.0.0-beta-6 milestone Oct 6, 2026
@github-actions

github-actions Bot commented Oct 6, 2026

Copy link
Copy Markdown

@gnodet Please assign appropriate label to PR according to the type of change.

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.

2 participants