Lukas Eder
Lukas Eder

Reputation: 220877

How to let plugin execution inherit project dependencies with Maven

I'm using Maven and I would like to execute a plugin without repeating some of the required dependencies:

<build>
<plugins>
<plugin>
    <groupId>org.codehaus.mojo</groupId>
    <artifactId>sql-maven-plugin</artifactId>
    <version>1.5</version>

    <dependencies>
        <dependency>
            <groupId>com.h2database</groupId>
            <artifactId>h2</artifactId>
            <version>1.3.168</version>
        </dependency>
        <!-- ^^^ unnecessary duplication, IMO, because the project
                 already imports the dependency below -->
    </dependencies>

    <!-- ... -->
</plugin>
</plugins>
</build>

<dependencies>
    <dependency>
        <groupId>com.h2database</groupId>
        <artifactId>h2</artifactId>
        <version>1.3.168</version>
    </dependency>
</dependencies>

In the above example, I would like to omit the com.h2database:h2 dependency, because I have already specified that in the project. Can this be done? How?

Upvotes: 3

Views: 1710

Answers (2)

Lukas Eder
Lukas Eder

Reputation: 220877

While plugins don't automatically inherit dependencies from the modules / projects that include them (see khmarbaise's answer), it is still possible for a plugin author to implement their plugin in a way for the module / project classpath to be available to the plugin as well. The Flyway migration plugin or the jOOQ code generator do that, for instance.

One example how this can be done inside the plugin is this:

@Mojo
public class Plugin extends AbstractMojo {

    @Parameter(property = "project", required = true, readonly = true)
    private MavenProject project;

    @Override
    public void execute() throws MojoExecutionException {
        ClassLoader oldCL = Thread.currentThread().getContextClassLoader();

        try {
            Thread.currentThread().setContextClassLoader(getClassLoader());
            // Plugin logic
        }
        finally {
            Thread.currentThread().setContextClassLoader(oldCL);
        }
    }

    @SuppressWarnings("unchecked")
    private ClassLoader getClassLoader() throws MojoExecutionException {
        try {
            List<String> classpathElements = project.getRuntimeClasspathElements();
            URL urls[] = new URL[classpathElements.size()];

            for (int i = 0; i < urls.length; i++)
                urls[i] = new File(classpathElements.get(i)).toURI().toURL();

            return new URLClassLoader(urls, getClass().getClassLoader());
        }
        catch (Exception e) {
            throw new MojoExecutionException("Couldn't create a classloader.", e);
        }
    }
}

Upvotes: 0

khmarbaise
khmarbaise

Reputation: 97399

You can do that by using the pluginManagement block in your parent like this:

<pluginManagement>
  <plugins>
   <plugin>
    <groupId>org.codehaus.mojo</groupId>
    <artifactId>sql-maven-plugin</artifactId>
    <version>1.5</version>
    <dependencies>
        <dependency>
            <groupId>com.h2database</groupId>
            <artifactId>h2</artifactId>
            <version>1.3.168</version>
        </dependency>
    </dependencies>
  </plugin> 
  </plugins>
</pluginManagement>

Within your childs you only need to use the execution like this:

 <build>
  <plugins>
    <plugin>
        <groupId>org.codehaus.mojo</groupId>
        <artifactId>sql-maven-plugin</artifactId>
        <executions>
          <execution>
           ....
          </execution>
        </executions>
    </plugin>
  </plugins>
 </build>

This will solve your problem to maintain the supplemental classpath dependencies (h2) only a single place.

Upvotes: 4

Related Questions