Skip to content

fix!: align APT and KSP metamodel generation and make the Java processor incremental-safe - #439

Merged
zantvoort merged 2 commits into
mainfrom
fix/metamodel-processor-parity
Aug 10, 2026
Merged

fix!: align APT and KSP metamodel generation and make the Java processor incremental-safe#439
zantvoort merged 2 commits into
mainfrom
fix/metamodel-processor-parity

Conversation

@zantvoort

Copy link
Copy Markdown
Collaborator

Aligns the Java (APT) and Kotlin (KSP) metamodel processors on one contract and makes the Java processor safe for Gradle incremental annotation processing.

Java processor quality

  • META-INF/gradle/incremental.annotation.processors registers MetamodelProcessor and TypeIndexProcessor as aggregating, so attaching them no longer disables incremental compilation for the whole source set. Isolating is not an option: the instantiator services file and the type index aggregate cross-record state. The processors keep @SupportedAnnotationTypes("*") and root-element iteration deliberately — discovery is interface-based, and a record may implement Data/Projection with no annotations at all, so claiming specific annotation types would make javac skip the processor for such files in every build system. KSP discovers the same way through getAllFiles().
  • A generation failure now reports an ERROR anchored to the failing record element, includes the stack trace, and rethrows to abort — the KSP semantics. The inner catch-alls are narrowed to IOException, so a codegen defect propagates with a source location instead of printing a bare Error: java.lang.NullPointerException and continuing.

APT/KSP divergence

  • APT emits the <Type>NullableMetamodel chain variant for every record and sealed interface and selects child metamodel fields by derived nullability (explicit annotations, null-marked default), so Owner_.address has the same static type in Java and Kotlin. instance() stays on the base Data variant, validation diagnostics print once per record (gated to the base pass, in both processors), and the GraalVM feature already registers both class names, so native images need no change.
  • KSP sources components from the primary constructor: a body-declared property (val display: String get() = ...) or an inherited one has no column and no longer receives a metamodel field pointing at a nonexistent column. Sealed interfaces contribute abstract properties only, matching APT's abstract-getter filter, and hasNullableLeaf walks the same component set.
  • KSP escapes keyword-named properties (`object`, `fun`, …) at every identifier emission site; path and field string literals keep the raw name, so column derivation is unchanged. Java needs no counterpart: javac rejects keyword-named record components at declaration.

Verification

  • New tests in both MetamodelProcessorTest suites: nullable child selection, nullable-variant emission and descriptor registration (Java); constructor-only components and keyword-named property compilation (KSP).
  • Full reactor clean install green on JDK 21.

Fixes #411

…sor incremental-safe

The Java processor generates the <Type>NullableMetamodel chain variant and
selects child metamodel fields by derived nullability, so a field reads as
the same static type from Java and Kotlin. KSP sources components from the
primary constructor (a body-declared or inherited property has no column),
filters sealed interface properties to abstract ones, and escapes
keyword-named properties at every emission site.

The Java processors register with Gradle as aggregating incremental
annotation processors, and a generation failure reports the failing record
with its stack trace and aborts instead of continuing without a source
location.
@zantvoort zantvoort added this to the 1.14.0 milestone Aug 10, 2026
…g and keyword escaping in the Data paths

The Owner_ interface types a nullable foreign key as the nullable-chain
child metamodel, sealed Data interfaces get both chain variants, the
unique-key nullability warning prints once per record, and KSP escapes
keyword-named properties in the metamodel interface and the primary-key
isSame comparison. The KSP suite also locks child selection by property
nullability, mirroring the Java assertions.
@codecov

codecov Bot commented Aug 10, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@zantvoort
zantvoort merged commit 27d0025 into main Aug 10, 2026
8 checks passed
@zantvoort
zantvoort deleted the fix/metamodel-processor-parity branch August 10, 2026 18:20
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.

Metamodel processors: the Java processor is non-incremental with weak error reporting, and KSP diverges from APT

1 participant