openrewrite / openrewrite/rewrite

AddAnnotationProcessor: child with in-reactor parent is silently skipped when only the child passes the precondition

Open
#7,850 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Java
Stars
3.7k
Forks
570
Avg merge
13h 12m
Merged PRs (30d)
261

Description

Summary

When AddAnnotationProcessor is used in a Maven multi-module reactor and wrapped with a precondition that matches only the dependency-owning child (e.g. ModuleHasDependency), the recipe produces no write on any pom. The child is filtered out of the visitor's "parent or orphan" gate, and the parent never reaches the visitor because the precondition excludes it.

Reproduction

  • The EnableLombokAnnotationProcessor recipe in rewrite-migrate-java exhibits this — see openrewrite/rewrite-migrate-java#1119 for a full minimal reproducer (root pom + with-lombok + without-lombok). In short:

  • Parent pom (<packaging>pom</packaging>): declares lombok only in <dependencyManagement>, does not pull it in as a dependency. Defines no maven-compiler-plugin configuration of its own.

  • Child with-lombok: declares org.projectlombok:lombok as a runtime dependency.

  • Child without-lombok: no Lombok.

Recipe applied: AddAnnotationProcessor(org.projectlombok, lombok, …) gated by ModuleHasDependency(org.projectlombok:lombok).

  • Expected (per the issue reporter and the intent of openrewrite/rewrite-migrate-java#1031):
  • Annotation processor added to with-lombok's own <build><plugins>.
  • Root pom unchanged.
  • without-lombok unchanged.

Observed: no pom is modified.

Root cause

rewrite-maven 8.81.7, AddAnnotationProcessor.java lines 268–271 (the visitor's first gate after extracting sourcePath):

boolean isParent = acc.parentPomPaths.contains(sourcePath);
if (!isParent && !acc.orphanPomPaths.contains(sourcePath)) {
    return tree;
}

The visitor only accepts files in parentPomPaths or orphanPomPaths. A child with an in-reactor parent is in neither set — after Scanned.resolve(), the child's tentative parent is promoted to parentPomPaths and the child itself is not added anywhere.

The scanner phase iterates the full LST and populates parentPomPaths correctly. But when the outer precondition filters the visitor down to the child only, no in-scope file passes the gate, so no write happens. The corresponding "write to parent's <pluginManagement>" path is unreachable because the parent never reaches the visitor.

Why "broaden the precondition to mark the parent too" isn't a clean fix

If the precondition is widened so the parent also passes, the recipe writes annotationProcessorPaths into the parent's <pluginManagement>. By standard Maven pluginManagement inheritance, that configuration is applied to every child's maven-compiler-plugin invocation — including children that don't use the dependency. They will resolve and run the annotation processor at compile (no-ops on classes without the matching annotations, but the jar is downloaded and the processor is invoked). This contradicts the per-module scoping intent that motivated ModuleHasDependency-style preconditions in the first place.

Proposed direction (for discussion, not prescriptive)

Expose an explicit scope parameter on AddAnnotationProcessor (e.g. CHILD_ONLY | PARENT_PLUGIN_MANAGEMENT | AUTO) so callers can pick the write target. This would let EnableLombokAnnotationProcessor opt into child-only writes and avoid the inheritance side effect.

Either approach also needs the existing "already configured in effective POM" check to keep working so the recipe stays idempotent.

Related

  • openrewrite/rewrite-migrate-java#1119 — downstream bug report (Maven multi-module reactor; full minimal reproducer).
  • openrewrite/rewrite-migrate-java#1031 — PR that switched EnableLombokAnnotationProcessor's precondition from RepositoryHasDependency to ModuleHasDependency, exposing this gap.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with rewrite-maven's AddAnnotationProcessor.java around lines 268–271 and trace how Scanned.resolve() populates parentPomPaths and orphanPomPaths. Reproduce the reactor case from openrewrite/rewrite-migrate-java#1119, including the ModuleHasDependency precondition, then verify that the selected scope writes only to the intended POM and preserves the effective-POM idempotence check.

Written by the indexing model from the issue text.

Assessment

Tech stack
java
Domain
build-system
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Needs clarification
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.