skip to content

How does Maven know what goals a plugin offers, and how do you bind a goal to a lifecycle phase?

level: juniorimportance: should knowfreq 30%

answer

  1. META-INF/maven/plugin.xml = descriptor
  2. generated by maven-plugin-plugin
  3. descriptor + helpmojo goals
  4. defaultPhase on @Mojo
  5. <execution><phase> in consumer POM

basics

~20 s

The plugin ships a descriptor file, META-INF/maven/plugin.xml, generated from your @Mojo/@Parameter annotations by the maven-plugin-plugin. To bind a goal to a phase, set defaultPhase on @Mojo or add an <execution> with a <phase> in the consumer POM.

solid answer

~40 s

Every Maven plugin JAR carries a **plugin descriptor** at `META-INF/maven/plugin.xml`. It lists each goal, its implementing Mojo class, parameters, defaults, and lifecycle binding. You almost never write it by hand — the **maven-plugin-plugin**'s `descriptor` goal scans your `@Mojo`/`@Parameter` annotations at build time and generates it (it also generates a `help` goal if you bind `helpmojo`). For binding: a Mojo can declare `@Mojo(name = "x", defaultPhase = LifecyclePhase.PACKAGE)`, which auto-binds when the user just lists the plugin. More commonly the consumer POM controls it with an `<execution>` that sets `<phase>` and `<goals>`. So binding is two-sided: the plugin suggests a default phase, the POM can override or pin it explicitly. Maven uses the descriptor at runtime to map `prefix:goal` or `g:a:v:goal` to the class and inject parameters.

code

xml · 12 lines
xml
<plugin>
  <groupId>com.example</groupId>
  <artifactId>greeting-maven-plugin</artifactId>
  <version>1.0.0</version>
  <executions>
    <execution>
      <id>greet-on-package</id>
      <phase>package</phase>
      <goals><goal>greet</goal></goals>
    </execution>
  </executions>
</plugin>

go deeper

for a junior

Knows plugin.xml exists, is generated, and that goals bind to phases via executions.

for a middle

Configures maven-plugin-plugin (descriptor + helpmojo) and writes correct <execution> bindings.

for a senior

Chooses good default phases, manages goal prefixes, understands override precedence.

for a principal

Defines org conventions for plugin naming/prefixes and lifecycle binding so plugins behave predictably across teams.

## The plugin descriptor A plugin JAR contains `META-INF/maven/plugin.xml` — the **plugin descriptor**. For each goal it records: the goal name, the fully-qualified Mojo class, every parameter (name, type, required, default, expression), the requested dependency-resolution scope, thread-safety, and any default lifecycle phase. Maven reads this to know what the plugin can do and how to configure it. ## You don't hand-write it The **maven-plugin-plugin** generates the descriptor from annotations. In your plugin POM: ```xml <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-plugin-plugin</artifactId> <version>3.x.x</version> <executions> <execution> <id>default-descriptor</id> <goals><goal>descriptor</goal></goals> </execution> <execution> <id>help-goal</id> <goals><goal>helpmojo</goal></goals> </execution> </executions> </plugin> ``` The `descriptor` goal (bound to `process-classes` for `maven-plugin` packaging) scans `@Mojo`/`@Parameter` and writes `plugin.xml`. `helpmojo` generates a `help` goal so users can run `mvn yourplugin:help`. ## Goal prefix The descriptor also carries a **goalPrefix** (e.g. `greeting`) so users can run `mvn greeting:greet` instead of the full `g:a:v:greet`. By convention it's derived from `*-maven-plugin` / `maven-*-plugin` naming, or set explicitly. ## Binding a goal to a phase Maven's build **lifecycle** is an ordered list of phases (validate → compile → test → package → install → deploy). A goal does nothing on its own until it's bound to a phase or invoked directly. **Two ways to bind:** 1. **Plugin-side default** — `@Mojo(name = "greet", defaultPhase = LifecyclePhase.PROCESS_RESOURCES)`. If the consumer just declares the plugin with an execution and no `<phase>`, this default applies. 2. **Consumer-side execution** — explicit and authoritative: ```xml <plugin> <groupId>com.example</groupId> <artifactId>greeting-maven-plugin</artifactId> <version>1.0.0</version> <executions> <execution> <id>greet-on-package</id> <phase>package</phase> <goals><goal>greet</goal></goals> </execution> </executions> </plugin> ``` Now `mvn package` triggers the goal automatically. You can also run it ad hoc with `mvn greeting:greet`, which ignores phase binding entirely.

  • Where does the goal prefix (so you can type mvn greeting:greet) come from?
    From the goalPrefix in the descriptor, conventionally derived from the *-maven-plugin / maven-*-plugin artifact name, or set explicitly via the maven-plugin-plugin configuration.
  • If you set defaultPhase on the Mojo and the consumer also specifies <phase>, which wins?
    The consumer's explicit <phase> in the execution wins; defaultPhase is only the fallback when no phase is specified.

saying these in an interview costs you the question

  • Saying you write plugin.xml by hand
  • Thinking a goal runs automatically with no phase binding and no direct invocation
  • Confusing the lifecycle phase with the goal name
  • Believing defaultPhase can't be overridden by the POM

context