You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
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.
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).
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):
booleanisParent = acc.parentPomPaths.contains(sourcePath);
if (!isParent && !acc.orphanPomPaths.contains(sourcePath)) {
returntree;
}
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.
Summary
When
AddAnnotationProcessoris 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
EnableLombokAnnotationProcessorrecipe inrewrite-migrate-javaexhibits 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>): declareslombokonly in<dependencyManagement>, does not pull it in as a dependency. Defines nomaven-compiler-pluginconfiguration of its own.Child
with-lombok: declaresorg.projectlombok:lombokas a runtime dependency.Child
without-lombok: no Lombok.Recipe applied:
AddAnnotationProcessor(org.projectlombok, lombok, …)gated byModuleHasDependency(org.projectlombok:lombok).with-lombok's own<build><plugins>.without-lombokunchanged.Observed: no pom is modified.
Root cause
rewrite-maven8.81.7,AddAnnotationProcessor.javalines 268–271 (the visitor's first gate after extractingsourcePath):The visitor only accepts files in
parentPomPathsororphanPomPaths. A child with an in-reactor parent is in neither set — afterScanned.resolve(), the child's tentative parent is promoted toparentPomPathsand the child itself is not added anywhere.The scanner phase iterates the full LST and populates
parentPomPathscorrectly. 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
annotationProcessorPathsinto the parent's<pluginManagement>. By standard Maven pluginManagement inheritance, that configuration is applied to every child'smaven-compiler-plugininvocation — 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 motivatedModuleHasDependency-style preconditions in the first place.Proposed direction (for discussion, not prescriptive)
Expose an explicit
scopeparameter onAddAnnotationProcessor(e.g.CHILD_ONLY | PARENT_PLUGIN_MANAGEMENT | AUTO) so callers can pick the write target. This would letEnableLombokAnnotationProcessoropt 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
EnableLombokAnnotationProcessor's precondition fromRepositoryHasDependencytoModuleHasDependency, exposing this gap.