Beginner’s Guide to Creating a Maven Plugin

Swathi Prasad

Maven plugins are nothing but software components that allow reuse of common build logic across multiple projects or modules. In this article, I would like to demonstrate how to build a maven plugin and test it.

Maven

Creating a Maven Plugin Project

This article assumes that you have already installed Maven. In this article, I am going to create small plugin which creates a zip file for multiple files listed in a directory. Create a Maven project using maven-archetype-mojo.

Maven archetype mojo

Provide a suitable GroupId and ArtifactId. Make sure your GroupId and ArtifactId follows the guidelines provided here. This is important if you want to publish your plugin to Maven Central repository.

GoupId and ArtifactId for new project

Continue by clicking Next. Once you click Finish, you will see that a POM file and a Mojo class has been created. Mojo is nothing but a goal in Maven. We can define metadata such as goal name, lifecycle phase and so on within a Mojo.

In pom.xml, make sure to add the following plugin to be able to use maven plugin annotations.

<dependency>
<groupId>org.apache.maven.plugin-tools</groupId>
<artifactId>maven-plugin-annotations</artifactId>
<version>3.6.0</version>
<scope>provided</scope>
</dependency>

Add the maven project plugin. I will explain the purpose of this plugin in a bit.

<dependency>
  
<groupId>org.apache.maven</groupId>

<artifactId>maven-project</artifactId>

<version>2.2.1</version>

</dependency>

This Mojo class always extends an abstract class AbstractMojo which provides the infrastructure to implement a plugin.

When we create a maven project in IDE, the default name for Mojo class would be something like MyMojo. I have renamed it to FileZipMojo since our plugin would be about creating a zip file.

@Mojo (name = "zip", defaultPhase = LifecyclePhase.GENERATE_RESOURCES)
public class FileZipMojo extends AbstractMojo {

The goal name for this plugin is “zip” and lifecycle phase is GENERATE_RESOURCES because it generates a zip file. I will show you how to use it in a bit later in this article.

In the next step, I will define 3 parameters required for our plugin execution.

@Parameter (required = true)
private File input;

@Parameter
private File zipName;

/**
* @parameter default-value="${project}"
* @required
* @readonly
*/
@Parameter(defaultValue = "${project}", required = true, readonly = true)
MavenProject project;

The parameter input is mandatory which accepts file directory path. The plugin scans this directory path and creates a zip file. The parameter zipName is zip file name which is optional. If not provided, we will use the default name.

If we want to use project information where this plugin is included, we can define MavenProject to get access to the project information such as project name, version and so on. Therefore, we included maven-project plugin.

Let us complete our plugin execution. Here is the complete code.

/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.techshard;

import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugins.annotations.LifecyclePhase;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Parameter;
import org.apache.maven.project.MavenProject;

import java.io.*;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

/**
* Main class for creating file zip.
*
* @author Swathi Prasad
*
*/
@Mojo (name = "zip", defaultPhase = LifecyclePhase.GENERATE_RESOURCES)
public class FileZipMojo extends AbstractMojo {

@Parameter (required = true)
private File input;

@Parameter
private File zipName;

/**
* @parameter default-value="${project}"
* @required
* @readonly
*/
@Parameter(defaultValue = "${project}", required = true, readonly = true)
MavenProject project;

private static final String FILE_EXTENSION= ".zip";

public void execute() throws MojoExecutionException {
getLog().info("Zipping files in \"" + input.getPath() + "\".");

final String outputFileName = zipName != null ? zipName + FILE_EXTENSION : project.getName() + "-" + project.getVersion() + FILE_EXTENSION;

try {
final File dir = new File(input.getPath());
final File[] files = dir.listFiles();

if (files != null) {
final FileOutputStream fos = new FileOutputStream(outputFileName);
final ZipOutputStream zipOut = new ZipOutputStream(fos);
for (final File file : files) {
final String fileName = file.getName();

getLog().info("Zipping File " + fileName);

final FileInputStream fis = new FileInputStream(file);
final ZipEntry zipEntry = new ZipEntry(file.getName());

if (file.isDirectory()){
if (fileName.endsWith("/")){
zipOut.putNextEntry(new ZipEntry(fileName));
} else {
zipOut.putNextEntry(new ZipEntry(fileName + "/"));
}
} else {
zipOut.putNextEntry(zipEntry);
}

final byte[] bytes = new byte[2048];
int length;
while((length = fis.read(bytes)) >= 0) {
zipOut.write(bytes, 0, length);
}
fis.close();
}
zipOut.close();
fos.close();
}
} catch(final FileNotFoundException e) {
throw new MojoExecutionException("No file found", e);
} catch(final IOException e) {
throw new MojoExecutionException("Exception reading files", e);
}
}
}

Now that we have completed the execution code. Let us install the plugin in our local repository.

In pom.xml, I have included some additional plugins to generate sources and documentation. In addition to these plugins, I have added information about GitHub repository URL, license and so on. Here is the complete 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.techshard.filezip</groupId>
<artifactId>filezip-maven-plugin</artifactId>
<packaging>maven-plugin</packaging>
<version>1.0-SNAPSHOT</version>
<name>filezip-maven-plugin Maven Mojo</name>
<url>http://maven.apache.org</url>

<scm>
<connection>scm:git:https://github.com/swathisprasad/filezip-maven-plugin.git</connection>
<developerConnection>scm:git:https://github.com/swathisprasad/filezip-maven-plugin.git</developerConnection>
<url>https://github.com/swathisprasad/filezip-maven-plugin</url>
<tag>HEAD</tag>
</scm>

<licenses>
<license>
<name>Apache 2.0 License</name>
<url>http://www.apache.org/licenses/LICENSE-2.0.html</url>
<distribution>repo</distribution>
</license>
</licenses>

<issueManagement>
<system>Github</system>
<url>https://github.com/swathisprasad/filezip-maven-plugin/issues</url>
</issueManagement>

<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>

<dependencies>
<dependency>
<groupId>org.apache.maven</groupId>
<artifactId>maven-plugin-api</artifactId>
<version>2.0</version>
</dependency>
<dependency>
<groupId>org.apache.maven.plugin-tools</groupId>
<artifactId>maven-plugin-annotations</artifactId>
<version>3.6.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.maven</groupId>
<artifactId>maven-project</artifactId>
<version>2.2.1</version>
</dependency>
</dependencies>

<build>
<resources>
<resource>
<directory>${project.basedir}</directory>
<includes>
<include>LICENSE*</include>
</includes>
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>3.0.1</version>
<executions>
<execution>
<id>attach-sources</id>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>2.10.4</version>
<configuration>
<encoding>UTF-8</encoding>
</configuration>
<executions>
<execution>
<id>attach-javadoc</id>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

We are now ready to install the plugin in our local Maven repository. Run mvn clean install in your terminal.

Testing the Maven Plugin

I will create a simple maven project to test our filezip-maven-plugin.

In pom.xml, let us add the following section.

<build>
<plugins>
<plugin>
<groupId>com.techshard</groupId>
<artifactId>filezip-maven-plugin</artifactId>
<version>1.0-SNAPSHOT</version>
<executions>
<execution>
<configuration>

<input>${project.basedir}/src/main/resources</input>
<zipName>test</zipName>

</configuration>
<goals>
<goal>zip</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>

We have specified the goal as zip in “goals” section and provided required and optional parameters in the “executions” section. This is just an example, we can include the plugin wherever required.

Create some text files in project resources folder which would be used for creating zip file.

Run mvn clean install. Once the build is complete, navigate to the project root folder and we should see test.zip file.

Conclusion

I hope this article serves as a starting reference point for anyone who wants to create a Maven plugin. The plugin described in this article is just an example. Let me know if you have any suggestions or comments.

The example explained in this article can be found on GitHub repository.

This article was originally published on Techshard.com.

Swathi Prasad

Written by

Hey, I am Swathi. A software developer since 2010. I am a programming addict. I love learning and sharing knowledge. https://techshard.com/

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade