Skip to content

Instantly share code, notes, and snippets.

@gnodet
Last active January 9, 2025 00:48
Show Gist options
  • Save gnodet/68ed6d5ef589d6cd84f73c68f5f6092b to your computer and use it in GitHub Desktop.
Save gnodet/68ed6d5ef589d6cd84f73c68f5f6092b to your computer and use it in GitHub Desktop.
Migrating a plugin to Maven 4

Script

The below rules and steps are mostly automated by simply running the Maven4Migration.java jbang script in the plugin directory.

Rules

The rules are quite simple

  • the plugin can only depend on org.apache.maven:maven-api-* artifacts (no any other maven related artifacts) at compile time
  • avoid plexus artifacts at compile time
  • mojo annotations are now in org.apache.maven.api.plugin.annotations package
  • injection annotations come from org.apache.maven.api.di
  • replace MavenSession with org.apache.maven.api.Session
  • replace MavenProject with org.apache.maven.api.Project
  • replace classes from org.apache.maven.model with their counterparts from org.apache.maven.api.model
  • unit test needs JUnit 5 and need to use the org.apache.maven.api.plugin.testing package

Example

Let's migrate the maven-remote-resources-plugin.

First create a branch for out work:

git checkout -b migrate-to-maven4

POM changes

The first things to do are pom changes:

  • Maven 4 plugins require JDK 17:
    <javaVersion>17</javaVersion>
  • and Maven 4
    <mavenVersion>4.0.0-rc-2</mavenVersion>
  • we need to depend on the new Maven API, so add the following dependencies:
    <!-- maven api -->
    <dependency>
      <groupId>org.apache.maven</groupId>
      <artifactId>maven-api-core</artifactId>
      <version>${mavenVersion}</version>
    </dependency>
    <dependency>
      <groupId>org.apache.maven</groupId>
      <artifactId>maven-api-model</artifactId>
      <version>${mavenVersion}</version>
    </dependency>
    <dependency>
      <groupId>org.apache.maven</groupId>
      <artifactId>maven-api-di</artifactId>
      <version>${mavenVersion}</version>
    </dependency>
    <dependency>
      <groupId>org.apache.maven</groupId>
      <artifactId>maven-api-plugin</artifactId>
      <version>${mavenVersion}</version>
    </dependency>

MOJOs definitions

  • replace org.apache.maven.plugins.annotations.Mojo with org.apache.maven.api.plugin.annotations.Mojo
  • defaultPhase is now a String, but constants are available by importing org.apache.maven.api.Lifecycle (note that due to lifecycle changes, you may need to use phase qualifiers. For example GENERATE_RESOURCES needs to be replaced with Lifecycle.BEFORE + Lifecycle.Phase.RESOURCES
  • if your mojo is using requiresDependencyResolution or requiresDependencyCollection to retrieve artifacts from the executed project, remove add one or more fields annotated with org.apache.maven.plugins.annotation.Resolution. In the case of maven-remote-resources-plugin, we have two cases (TODO)
  • remove threadSafe attribute, Maven 4 plugins are required to be thread safe

@Parameter and @Component

  • replace org.apache.maven.plugins.annotations.Parameter with org.apache.maven.api.plugin.annotations.Parameter

  • replace org.apache.maven.plugins.annotations.Component with org.apache.maven.api.di.Inject (though, most components classes/interfaces will have to be replaced)

  • it's usually a good idea to replace any injected File parameter with a Path object as they are now supported

Dependency injection

If you use Plexus or Sisu to configure your plugin, you need to switch to the Maven DI API.

  • replace javax\.inject\.([A-Z][a-zA-Z]+) with org.apache.maven.di.$1

Model

  • replace org\.apache\.maven\.model\.([A-Z][a-zA-Z]+) with org.apache.maven.api.model.$1
  • replace org\.apache\.maven\.project\.MavenProject with org.apache.maven.api.MavenProject, and then MavenProject with Project
  • the MavenProject has quite a lot of helper methods to access informations from the model, most of which are not available anymore, so you'll need to go to the model directly using project.getModel().getResources() for example
  • model objects are now immutable, so if you plugin was creating or modifying model objects, the code will have to be adapted
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment