What is a Mojo in Maven, and what are the minimum pieces you write to create a custom plugin goal?
answer
- Mojo = Maven plain Old Java Object
- extends AbstractMojo, implement execute()
- @Mojo(name) + @Parameter
- packaging maven-plugin
- ExecutionException vs FailureException
basics
~10 sA Mojo is the Java class behind one Maven goal. You extend AbstractMojo, annotate the class with @Mojo(name = "..."), implement execute(), and package it as a maven-plugin artifact so Maven can run it.
solid answer
~40 sMojo = "Maven plain Old Java Object" — the implementation of a single goal. You write a class extending `AbstractMojo` (which gives you `getLog()` and forces you to implement `execute()`), annotate it `@Mojo(name = "greet")`, and expose configurable inputs as fields annotated `@Parameter`. The project that contains it must have `<packaging>maven-plugin</packaging>` and depend on `maven-plugin-api` plus `maven-plugin-annotations`. The `maven-plugin-plugin` scans those annotations at build time and generates `META-INF/maven/plugin.xml` (the plugin descriptor) so Maven knows which goals exist, their parameters, and lifecycle binding. `execute()` throws `MojoExecutionException` (unexpected/build-breaking error) or `MojoFailureException` (expected failure, e.g. a rule violation). Users then run it as `groupId:artifactId:version:goal` or via a short prefix.
code
java · 10 lines@Mojo(name = "greet", defaultPhase = LifecyclePhase.PROCESS_RESOURCES, threadSafe = true)
public class GreetMojo extends AbstractMojo {
@Parameter(property = "greet.name", defaultValue = "world")
private String name;
@Override
public void execute() throws MojoExecutionException {
getLog().info("Hello, " + name + "!");
}
}go deeper
Knows a Mojo is the Java class for a goal and that you extend AbstractMojo and implement execute().
Wires the full plugin project: maven-plugin packaging, plugin-api/annotations deps, @Mojo/@Parameter, and the two exception types.
Chooses sensible defaults (threadSafe, defaultPhase, requiresDependencyResolution) and uses the right exception for the right failure mode.
Sets conventions for in-house plugins: naming, versioning, descriptor generation, testing strategy, and when a plugin vs. a script is the right tool.
## What a Mojo is **Mojo** stands for "**M**aven plain **O**ld **J**ava **O**bject". A Maven *plugin* is a JAR that bundles one or more Mojos; each Mojo implements exactly one **goal** (the unit of work you invoke, e.g. `compiler:compile`). So `org.apache.maven.plugins:maven-compiler-plugin` is the plugin, and `compile` / `testCompile` are goals, each backed by a Mojo class. ## The minimum pieces 1. **A plugin project** with `<packaging>maven-plugin</packaging>`. 2. **Dependencies**: `maven-plugin-api` (the `AbstractMojo` base class, exceptions, the `Log`) and `maven-plugin-annotations` (provided scope — only needed at compile/descriptor-generation time). 3. **The maven-plugin-plugin** configured in the build so it generates the descriptor. 4. **A Mojo class** extending `AbstractMojo`, annotated `@Mojo(name = "...")`, implementing `execute()`. ## The Mojo class - Extend `org.apache.maven.plugin.AbstractMojo` — it supplies `getLog()` (a `Log` for `info`/`warn`/`error`) and declares the abstract `execute()`. - `@Mojo(name = "greet")` names the goal. Common attributes: `defaultPhase` (auto-bind to a lifecycle phase), `requiresDependencyResolution`, `threadSafe = true`. - `@Parameter` on fields exposes configuration; `@Parameter(defaultValue = "${project}", readonly = true)` injects Maven objects like the `MavenProject`. ## Errors - `MojoExecutionException` — something went genuinely wrong (I/O error, bad state); fails the build with a stack trace. - `MojoFailureException` — an *expected* failure such as a checkstyle/enforcer violation; cleaner message, no "internal error" framing. ## Example ```java @Mojo(name = "greet", defaultPhase = LifecyclePhase.PROCESS_RESOURCES, threadSafe = true) public class GreetMojo extends AbstractMojo { @Parameter(property = "greet.name", defaultValue = "world") private String name; @Override public void execute() throws MojoExecutionException { getLog().info("Hello, " + name + "!"); } } ``` Run it directly: `mvn com.example:greeting-maven-plugin:1.0.0:greet -Dgreet.name=Ada`. ## How Maven finds the goal At plugin build time, `maven-plugin-plugin`'s `descriptor` goal scans the annotations and writes `META-INF/maven/plugin.xml`. At consume time Maven reads that descriptor, maps the goal name to your class, injects the parameters from POM configuration / `-D` properties, and calls `execute()`.
- What is the difference between MojoExecutionException and MojoFailureException?ExecutionException signals an unexpected internal error (I/O, bad state) and Maven shows it as a build error with stack trace; FailureException signals an expected, user-facing failure like a rule violation and is reported more cleanly. Both fail the build.
- Why do you depend on maven-plugin-annotations in provided scope?The annotations are only read at compile time by the descriptor generator (APT/scanning); they aren't needed at runtime, so provided scope keeps them off the consumer's classpath.
A plugin is a toolbox JAR; each Mojo is one tool (goal) inside it. AbstractMojo is the standard handle every tool shares.
saying these in an interview costs you the question
- Saying a Mojo must implement an interface other than extending AbstractMojo / implementing Mojo
- Confusing plugin (the JAR) with goal (one Mojo)
- Claiming you must hand-write plugin.xml
- Thinking both exceptions mean the same thing