Skip to content

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

Description

@Jenson3210

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 Lombok annotation processor not added to modules of a Maven multi-module project 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).

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    Status
    Backlog

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions