Question

I have created a new compiler for the maven-compiler-plugin. This compiler likes to look for compile sources in both src/main/groovy and src/main/java. Similarly, test sources are in both src/test/groovy and src/test/java.

I am aware of the build-helper-maven-plugin that allows users to augment their pom to specify new source folders for a build, but using this plugin is not ideal since it requires more than 20 lines of extra configuration in the pom.

I would like to create a mojo that configures the extra source folders automatically.

Here is the mojo that I have created, but I do not know how to ensure that the mojo is executed at the right time.

/**
 * @goal add-groovy-source
 * @phase generate-sources
 * @requiresDependencyResolution compile
 * @execute phase="compile"
 */
public class AddGroovySourceFolders extends AbstractMojo {
    /**
     * @parameter expression="${project}"
     * @required
     * @readonly
     */
    private MavenProject project;

    public void execute() throws MojoExecutionException, MojoFailureException {
        getLog().info("Adding /src/main/groovy to the list of source folders");
        this.project.addCompileSourceRoot(project.getBasedir() + "/src/main/groovy");
    }
}

Again, my goal is to ensure the minimal amount of configuration in the user's pom. By this I mean that there should only be a declaration of a dependency to the plugin that contains this mojo and no further configuration.

Was it helpful?

Solution

It is possible by defining a custom lifecycle.

Step 1: Define the MOJO to add paths. You did this already with AddGroovySourceFolders.

Step 2: Create a META-INF/plexus/components.xml file in src/main/resources:

<component-set>
    <components>
        <component>
            <role>org.apache.maven.lifecycle.mapping.LifecycleMapping</role>
            <role-hint>jar</role-hint>
            <implementation>org.apache.maven.lifecycle.mapping.DefaultLifecycleMapping</implementation>
            <configuration>
                <lifecycles>
                    <lifecycle>
                        <id>default</id>

                        <phases>
                            <!-- I added this one, use appropriate plugin groupId/artifactId instead-->
                            <initialize>groovyadd:maven-groovyadd-plugin:add-build-paths</initialize>
                            <process-resources>org.apache.maven.plugins:maven-resources-plugin:2.4.3:resources</process-resources>
                            <compile>org.apache.maven.plugins:maven-compiler-plugin:2.3.2:compile</compile>
                            <process-test-resources>org.apache.maven.plugins:maven-resources-plugin:2.4.3:testResources</process-test-resources>
                            <test-compile>org.apache.maven.plugins:maven-compiler-plugin:2.3.2:testCompile</test-compile>
                            <test>org.apache.maven.plugins:maven-surefire-plugin:2.7.2:test</test>
                            <package>org.apache.maven.plugins:maven-jar-plugin:2.3.1:jar</package>
                            <install>org.apache.maven.plugins:maven-install-plugin:2.3.1:install</install>
                            <deploy>org.apache.maven.plugins:maven-deploy-plugin:2.5:deploy</deploy>
                        </phases>
                    </lifecycle>
                </lifecycles>
            </configuration>
        </component>
    </components>
</component-set>

The element specifies the packaging the lifecycle is for. Apparently you can override the jar lifecycle (I got this working with Maven 3.0.3). I copied everything apart from the initialize phase from the appropriate component in maven-core-3.0.3.jar\META-INF\plexus\components.xml.

The side effect of overriding Maven's JAR lifecycle is that you have now hardcoded the compile and other plugin's versions what is in your plugin instead of what is in Maven. I'm not sure whether that's a bad or good thing.

Step 3: When using your plugin from another project, all you need is:

<plugins>
    ...
    <plugin>
        <groupId>groovyadd</groupId>
        <artifactId>maven-groovyadd-plugin</artifactId>
        <version>1.0-SNAPSHOT</version>
        <extensions>true</extensions>
    </plugin>
    ...
</plugins>

The important part is the extensions element. Without it, the custom lifecycle from your plugin will not be picked up.

You can also add other plugins to other phases in the lifecycle (e.g. compile groovy code in the compile phase in a separate plugin rather than add a compiler for the maven-compiler-plugin).

References: Overriding the Default Lifecycle from the Maven book

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top