Beyond mvn install: A Deep Dive into Maven Plugin Core Principles

This article explains that Maven is essentially a plugin framework, details how plugins like flatten-maven-plugin and exec-maven-plugin are configured and executed, introduces the MOJO concept, walks through creating a custom Maven plugin, and shows how to bind plugin goals to the build lifecycle.

Java Companion
Java Companion
Java Companion
Beyond mvn install: A Deep Dive into Maven Plugin Core Principles

Maven itself is just the core framework that manages plugins; the plugins perform the actual operations such as creating JAR/WAR files, compiling code, running tests, and generating documentation.

In a typical

<build><plugins>…</plugins></build>

section of a pom.xml, Maven’s standard plugins enable basic commands like clean and compile even when no explicit plugin is declared, using default configurations.

flatten-maven-plugin example

The flatten-maven-plugin flattens a project’s dependencies by resolving all version placeholders and writing a simplified POM. Its configuration includes:

outputDirectory : directory for the generated flattened POM.

flattenMode : set to resolveCiFriendliesOnly, allowing placeholders such as ${revision}, ${sha1}, ${changelist} to be supplied via mvn -Drevision=2.0.0-SNAPSHOT clean package.

updatePomFile : updates the generated flattened POM.

ignoreTransitiveDependencies : excludes transitive dependencies from the flattened POM.

Two <execution> blocks are defined: one bound to the generate-resources phase with goal flatten, and another bound to the clean phase with goal clean. Running mvn generate-resources creates a .flattened-pom.xml in the specified directory.

exec-maven-plugin example

This plugin runs external programs during the build. The example configures it to invoke the Allatori obfuscation tool:

<plugin>
  <groupId>org.codehaus.mojo</groupId>
  <artifactId>exec-maven-plugin</artifactId>
  <executions>
    <execution>
      <id>obfuscate</id>
      <phase>package</phase>
      <goals><goal>exec</goal></goals>
      <configuration>
        <executable>java</executable>
        <arguments>
          <argument>-jar</argument>
          <argument>path/to/allatori.jar</argument>
          <argument>-config</argument>
          <argument>path/to/allatori-config.xml</argument>
          <argument>-in</argument>
          <argument>${project.build.directory}/${project.build.finalName}.jar</argument>
          <argument>-out</argument>
          <argument>${project.build.directory}/${project.build.finalName}-obfuscated.jar</argument>
        </arguments>
      </configuration>
    </execution>
  </executions>
</plugin>

When the package phase runs, Maven executes java -jar path/to/allatori.jar -config …, producing an obfuscated JAR whose class names may be changed (e.g., to VAR series) depending on the Allatori configuration.

Maven plugin fundamentals – MOJO

A Maven plugin is composed of one or more MOJOs (Maven Plain Old Java Objects). Each MOJO is a Java class, typically extending org.apache.maven.plugin.AbstractMojo, and defines one or more goals that can be invoked from the Maven lifecycle.

MOJOs use annotations such as @Mojo(name="goalName") to declare a goal and @Parameter to expose configuration fields. Maven maps XML elements in the pom.xml directly to these fields (e.g., <url> maps to a field annotated with @Parameter(property="url")).

@Mojo(name = "query")
public class MyQueryMojo extends AbstractMojo {
  @Parameter(property = "query.url", required = true)
  private String url;

  @Parameter(property = "timeout", defaultValue = "50")
  private int timeout;

  @Parameter(property = "options")
  private String[] options;

  @Override
  public void execute() throws MojoExecutionException {
    // ...
  }
}

To use this MOJO, the plugin is referenced in the project’s pom.xml and its configuration elements ( <url>, <timeout>, <options>) are supplied, which Maven injects into the MOJO fields before invoking execute().

Creating a custom Maven plugin

To build a plugin named hello-maven-plugin that prints “Hello, world.”, first create a Maven project with packaging set to maven-plugin and add the necessary dependencies and maven-plugin-plugin in pluginManagement. Then implement a MOJO:

package org.example;

import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugins.annotations.Mojo;

/**
 * Says "Hi" to the user.
 */
@Mojo(name = "sayhi")
public class GreetingMojo extends AbstractMojo {
  @Override
  public void execute() throws MojoExecutionException {
    getLog().info("Hello, world.");
  }
}

Run mvn install to install the plugin into the local repository. It can then be invoked from another project either directly:

mvn sample.plugin:hello-maven-plugin:1.0-SNAPSHOT:sayhi

or bound to a lifecycle phase (e.g., before clean) by adding an <execution> with <phase>clean</phase> and <goal>sayhi</goal> in the consuming project’s pom.xml. When mvn clean runs, the plugin’s goal executes automatically.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

mavenMOJOcustom pluginMaven Pluginbuild lifecycleflatten-maven-pluginexec-maven-plugin
Java Companion
Written by

Java Companion

A highly professional Java public account

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.