Sunday, 11 September 2016

Making a simple maven plugin

I had a look around for a how to create simple maven 3 plugins. There is a mixture of maven 2 and maven 3 tutorials doing it different ways. Here is one that just does a simple printout. It can be expanded to anything you can dream of.
The project below creates a maven 2 setup but I have added extra steps to make it maven 3 setup

Running this command to create a plugin project
 
mvn archetype:create -DgroupId=com.naughton \ 
-DartifactId=simple-maven-plugin \ 
-DarchetypeGroupId=org.apache.maven.archetypes \ 
-DarchetypeArtifactId=maven-archetype-mojo

It will create this project structure for you
 .  
 ./src  
 ./src/main  
 ./src/main/java  
 ./src/main/java/com  
 ./src/main/java/com/naughton  
 ./src/main/java/com/naughton/MyMojo.java  
 ./pom.xml  

The pom file should look like this. It will include the maven plugin api as a dependency and packaging will be maven-plugin. That is the only different from a default pom.

 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">  
  <modelVersion>4.0.0</modelVersion>  
  <groupId>com.naughton</groupId>  
  <artifactId>simple-maven-plugin</artifactId>  
  <packaging>maven-plugin</packaging>  
  <version>1.0-SNAPSHOT</version>  
  <name>simple-maven-plugin Maven Mojo</name>  
  <url>http://maven.apache.org</url>  
  <dependencies>  
   <dependency>  
    <groupId>org.apache.maven</groupId>  
    <artifactId>maven-plugin-api</artifactId>  
    <version>2.0</version>  
   </dependency>  
   <dependency>  
    <groupId>junit</groupId>  
    <artifactId>junit</artifactId>  
    <version>3.8.1</version>  
    <scope>test</scope>  
   </dependency>  
  </dependencies>  
 </project>  

Add in the following to the pom.xml to complete the project

This will let you add annotations in your Mojo files
 <dependency>  
       <groupId>org.apache.maven.plugin-tools</groupId>  
       <artifactId>maven-plugin-annotations</artifactId>  
       <version>3.4</version>  
       <scope>provided</scope>  
 </dependency>   

Change the MyMojo.java file to this. I have gotten rid of the Javadoc entries. Previously in maven 2 it got the goal name and phase from the Javadoc. Now you can use annotations in maven 3.
 /**  
  * Goal which prints a sentence.  
  */  
 @Mojo(name = "print",defaultPhase = LifecyclePhase.PACKAGE)  
 public class MyMojo extends AbstractMojo  
 {  
   public void execute() throws MojoExecutionException  
   {  
     getLog().info("It executed the goal by printing this sentence.");  
   }  
 }  

You can see in the build that it will find no javadoc descriptors but one annotation descriptor. That is the annotation named print above.
 [INFO] --- maven-plugin-plugin:3.4:descriptor (default-descriptor) @ simple-maven-plugin ---  
 [WARNING] Using platform encoding (UTF-8 actually) to read mojo metadata, i.e. build is platform dependent!  
 [INFO] Mojo extractor with id: java-javadoc found 0 mojo descriptors.  
 [INFO] Mojo extractor with id: java-annotations found 1 mojo descriptors.  

Add this to generate the descriptor plugin.xml file automatically
 <build>  
     <plugins>  
       <plugin>  
         <groupId>org.apache.maven.plugins</groupId>  
         <artifactId>maven-plugin-plugin</artifactId>  
         <version>3.4</version>  
       </plugin>  
     </plugins>  
   </build>   

This is what a plugin.xml file looks like. It includes the goals that the plugins supports. This is the file maven reads to understand your plugin.
 <plugin>  
  <name>simple-maven-plugin Maven Mojo</name>  
  <description></description>  
  <groupId>com.naughton</groupId>  
  <artifactId>simple-maven-plugin</artifactId>  
  <version>1.0-SNAPSHOT</version>  
  <goalPrefix>simple</goalPrefix>  
  <isolatedRealm>false</isolatedRealm>  
  <inheritedByDefault>true</inheritedByDefault>  
  <mojos>  
   <mojo>  
    <goal>print</goal>  
    <description>Goal which touches a timestamp file.</description>  
    <requiresDirectInvocation>false</requiresDirectInvocation>  
    <requiresProject>true</requiresProject>  
    <requiresReports>false</requiresReports>  
    <aggregator>false</aggregator>  
    <requiresOnline>false</requiresOnline>  
    <inheritedByDefault>true</inheritedByDefault>  
    <phase>package</phase>  
    <implementation>com.naughton.MyMojo</implementation>  
    <language>java</language>  
    <instantiationStrategy>per-lookup</instantiationStrategy>  
    <executionStrategy>once-per-session</executionStrategy>  
    <threadSafe>false</threadSafe>  
    <parameters/>  
   </mojo>  
  </mojos>  
  <dependencies>  
   <dependency>  
    <groupId>org.apache.maven</groupId>  
    <artifactId>maven-plugin-api</artifactId>  
    <type>jar</type>  
    <version>2.0</version>  
   </dependency>  
  </dependencies>  
 </plugin>  

Structure of the plugin jar file

You can see that the plugin.xml is generated by the pluging plugin.
 META-INF/  
 META-INF/MANIFEST.MF  
 META-INF/maven/  
 META-INF/maven/com.naughton/  
 META-INF/maven/com.naughton/simple-maven-plugin/  
 com/  
 com/naughton/  
 META-INF/maven/com.naughton/simple-maven-plugin/plugin-help.xml  
 META-INF/maven/plugin.xml  
 com/naughton/MyMojo.class  
 META-INF/maven/com.naughton/simple-maven-plugin/pom.xml  
 META-INF/maven/com.naughton/simple-maven-plugin/pom.properties  

How to test your new plugin

Quickest way to test is your plugin it though a command line call to one of the goals defined in the new plugin. You must first install the plugin in to your local .m2 repo by running this command in the root plugin project.

mvn install

Example: 
mvn com.naughton:simple-maven-plugin:1.0-SNAPSHOT:print


 [INFO] Scanning for projects...  
 [INFO]                                      
 [INFO] ------------------------------------------------------------------------  
 [INFO] Building simple-maven-plugin Maven Mojo 1.0-SNAPSHOT  
 [INFO] ------------------------------------------------------------------------  
 [INFO]  
 [INFO] --- simple-maven-plugin:1.0-SNAPSHOT:print (default-cli) @ simple-maven-plugin ---  
 [INFO] It executed the goal by printing this sentence.  
 [INFO] ------------------------------------------------------------------------  
 [INFO] BUILD SUCCESS  
 [INFO] ------------------------------------------------------------------------  
 [INFO] Total time: 0.238 s  
 [INFO] Finished at: 2016-09-11T19:38:39+01:00  
 [INFO] Final Memory: 7M/110M  
 [INFO] ------------------------------------------------------------------------  

How to test your plugin in another project.

Your plugin should now be in your local .m2 repository after mvn install.  To use the simple plugin use this in plugin entry in the other project pom.xml

 <build>  
   <plugins>  
    <plugin>  
     <groupId>com.naughton</groupId>  
     <artifactId>simple-maven-plugin</artifactId>  
     <version>1.0-SNAPSHOT</version>  
     <executions>  
      <execution>  
       <goals>  
        <goal>print</goal>  
       </goals>  
      </execution>  
     </executions>  
    </plugin>  
   </plugins>  
  </build>  


I have added the simple maven plugin to github to hack around with: 


References:

No comments:

Post a Comment