Skip to content

Maven annotation processor and plugin recipes should correctly handle parent and aggregator poms#6546

Merged
MBoegers merged 13 commits intomainfrom
boeg/add-annotation-processor-enhancement
Jan 28, 2026
Merged

Maven annotation processor and plugin recipes should correctly handle parent and aggregator poms#6546
MBoegers merged 13 commits intomainfrom
boeg/add-annotation-processor-enhancement

Conversation

@MBoegers
Copy link
Copy Markdown
Contributor

@MBoegers MBoegers commented Jan 16, 2026

What's changed?

From the tests, AddAnnotationProcessor deals with managed plugins and has the assumption, that the tag /project/build/plugins/plugin/configuration/annotationProcessorPaths is present.
In many cases in the Java 23 migration, all the annotation processors have to be added, so this assumption is weak.

The MavenPlugin trait got an improvement to be able to match plugins and managed plugins more precisely, even with group and artifact id.
The AddPlugin recipes visitor got extracted and is reused to have a AddManagedPlugin recipe.

Both backward compatible, proven with tests.

What's your motivation?

  • Enable declarative recipes to add annotation processors to the Maven compiler plugin.
  • Ability to add maven managed plugins.
  • advance the MavenPlugin trait for more precise visitors.

Anything in particular you'd like reviewers to focus on?

Anyone you would like to review specifically?

@Laurens-W @timtebeek

Have you considered any alternatives or workarounds?

Imperative recipe every time we have want to configure an annotation processor safely.

Any additional context

We expect a behavior change here; see the comment for the logic.

Checklist

  • I've added unit tests to cover both positive and negative cases
  • I've read and applied the recipe conventions and best practices
  • I've used the IntelliJ IDEA auto-formatter on affected files

@MBoegers MBoegers self-assigned this Jan 16, 2026
@MBoegers MBoegers added enhancement New feature or request maven labels Jan 16, 2026
@github-project-automation github-project-automation Bot moved this to In Progress in OpenRewrite Jan 16, 2026
Comment thread rewrite-maven/src/test/java/org/openrewrite/maven/AddAnnotationProcessorTest.java Outdated
@MBoegers
Copy link
Copy Markdown
Contributor Author

Overview

The AddAnnotationProcessor recipe adds an annotation processor to the maven-compiler-plugin configuration.
The behavior differs based on whether the project is single-module or multi-module.
Single modules should use the build/plugin section to configure and invoke their plugins in the same location.
Multi-module projects should only define the configuration once in the root pom.

Single-Module Projects

For single-module Maven projects, the annotation processor is added to the <build><plugins> section.

Scenario Action
Plugin exists in build/plugins Add annotation processor path there
Plugin only in pluginManagement Create new plugin in build/plugins
Plugin in both locations Add to build/plugins only
No compiler plugin anywhere Create plugin in build/plugins
No build section Create entire build/plugins/plugin structure

Multi-Module Projects

For multi-module Maven projects, the annotation processor is added to the <build><pluginManagement><plugins> section in the root pom only. Child modules are never modified.

Scenario Action
Root: Plugin in pluginManagement Add annotation processor path there
Root: Plugin only in build/plugins Create in pluginManagement, leave build/plugins alone
Root: Plugin in both locations Add to pluginManagement only
Root: No compiler plugin Create pluginManagement with the plugin
Child modules Never modified - always skipped

Version Handling

Version handling applies to both single-module and multi-module projects:

Scenario Action
Processor exists with older version Upgrade to specified version
Processor exists with same version No change
Version defined as Maven property Update the property value

…vior

Restructure tests into @nested classes to clearly define expected behavior:
- SingleModuleProject: add to build/plugins
- MultiModuleProject: add to build/pluginManagement/plugins in root pom only

Remove redundant tests, keeping @DocumentExample and version handling tests.
@MBoegers MBoegers force-pushed the boeg/add-annotation-processor-enhancement branch from ade42af to e318692 Compare January 22, 2026 17:36
@MBoegers MBoegers marked this pull request as ready for review January 22, 2026 20:03
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Could we generalize this visitor and the AddPlugin and AddManagedPlugin recipes into a single recipe that takes an xpath expression as input to determine whether to add a plugin to build/plugin or pluginManagement? We could define that option with allowed values to prevent someone from using the recipe with an odd xpath expression

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

We could define that option with allowed values to prevent someone from using the recipe with an odd xpath expression
Sorry, I don't understand this sentence.

I can help you understand my decision for two recipes using the same visitor:

  1. I don't want to break existing usages of AddPlugin with a new constructor, as its central
  2. Both recipes have fixed XPaths where plugins are added as they are defined by Maven's POM model; build/plugins vs. build/pluginManagement/plugins there is no need for a custom XPath.
  3. The visitor takes a boolean flag instead of an XPath because we need the knowledge if it is a managed or build plugin not only for the location where to add the plugin but also for the case that the build tags do not contain the plugins or pluginMangement/plugins path.
  4. Reusing the AddPlugin or AddManagedPlugin in imperative recipes is easier with a dedicated visitor, and it also reduces the code/test to maintain.

@Laurens-W
Copy link
Copy Markdown
Contributor

What if the root pom is only an aggregating pom, but not a parent pom? Iirc we can determine whether a pom is an aggregating pom and/or a parent pom. We should probably aim to add to the parent pom in this case 🙈
If the parent pom is outside of this module it shouldn't make any changes -> the correct thing to do would be release train planning

@MBoegers
Copy link
Copy Markdown
Contributor Author

MBoegers commented Jan 23, 2026

Good call, this is a valid setup that, especially in legacy code, is used. This reconsideration should address these concerns.

Scenarios

Scenario 1: Single module

project/
└── pom.xml              ← no parent, no modules

Scenario 2: Separated aggregator/parent

root/
├── pom.xml              ← Aggregator only
├── parent/
│   └── pom.xml          ← Parent POM
├── module-a/
│   └── pom.xml          ← extends parent
├── module-b/
│   └── pom.xml          ← extends parent
└── module-orphan/
    └── pom.xml          ← NO parent

Scenario 3: Combined aggregator/parent

root/
├── pom.xml              ← Aggregator AND Parent
├── module-a/
│   └── pom.xml          ← extends root
├── module-b/
│   └── pom.xml          ← extends root
└── module-orphan/
    └── pom.xml          ← NO parent

Decision Tree

For each module:
  Has parent within the reactor?
    ├─ YES → Mark parent for pluginManagement update (deduplicated)
    └─ NO  → Add to this module's build/plugins

Phases

  1. Scan: Identify all modules and their parent relationships; Determine if parent is in-reactor or external/absent

  2. Apply: Modify POMs like parents → build/pluginManagement/plugins, orphans → `build/plugins'

Target Matrix

Scenario Target POM Location
Single module pom.xml build/plugins
Separated aggregator/parent parent/pom.xml build/pluginManagement/plugins
↳ orphan module module-orphan/pom.xml build/plugins
Combined aggregator/parent root pom.xml build/pluginManagement/plugins
↳ orphan module module-orphan/pom.xml build/plugins

Other decision

  • Existing annotationProcessorPaths — merge are merged, like in the current implementation
  • Version management for processor artifact — updates version tag if processor with older version is already used

@timtebeek timtebeek changed the title Enhance AddAnnotationProcessor Maven annotation processor and plugin recipes should correctly handle parent and aggregator poms Jan 23, 2026
@MBoegers
Copy link
Copy Markdown
Contributor Author

MBoegers commented Jan 23, 2026

@timtebeek @Laurens-W pulling back to draft due to the substantial logic refinements for AddAnnotationProcessor recipe.

Done, RFR again

@timtebeek timtebeek moved this from In Progress to Ready to Review in OpenRewrite Jan 25, 2026
# Conflicts:
#	rewrite-maven/src/main/resources/META-INF/rewrite/recipes.csv
@Laurens-W
Copy link
Copy Markdown
Contributor

There's some helper methods in AddDependency that we may be able to move to the MavenResolutionResult (or ResolvedPom) to generically determine parent vs aggregator, but if that's undesired this LGTM :)

@MBoegers MBoegers merged commit 29b630b into main Jan 28, 2026
2 checks passed
@MBoegers MBoegers deleted the boeg/add-annotation-processor-enhancement branch January 28, 2026 10:05
@github-project-automation github-project-automation Bot moved this from Ready to Review to Done in OpenRewrite Jan 28, 2026

@Value
@EqualsAndHashCode(callSuper = false)
public class AddPluginVisitor extends MavenIsoVisitor<ExecutionContext> {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Bit late now, but can we limit visibility by default on new classes? I don't see an immediate need for this to be part of the exposed API. I'd rather we open up when those needs trickle in.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request maven

Projects

Archived in project

Development

Successfully merging this pull request may close these issues.

3 participants