skip to content

How does the <packaging> value determine which plugin goals are bound to lifecycle phases by default?

level: middleimportance: must knowfreq 60%

answer

  1. packaging = binding switch
  2. jar→jar:jar at package, war→war:war
  3. pom = only install+deploy, no compile/jar
  4. maven-plugin adds descriptor goals
  5. help:describe -Dcmd=<phase>

basics

~10 s

The packaging type selects a default set of goal-to-phase bindings. For example jar binds jar:jar at package, while pom binds almost nothing and war binds war:war instead.

solid answer

~30 s

Each `<packaging>` (jar, war, ear, pom, maven-plugin, etc.) defines a default lifecycle binding map. For `jar`: process-resources→resources:resources, compile→compiler:compile, test-compile→compiler:testCompile, test→surefire:test, package→jar:jar, install→install:install, deploy→deploy:deploy. For `war` the package binding is war:war instead of jar:jar. For `pom` (an aggregator/parent), only install:install and deploy:deploy are bound — there is nothing to compile or package, which is why a parent POM has no jar. For `maven-plugin` packaging, extra plugin-plugin goals are added to generate plugin descriptors. So choosing the packaging is effectively choosing which core plugin produces the primary artifact and which phases do real work.

code

bash · 3 lines
bash
# Show which plugin goals are bound to a phase for this project's packaging
mvn help:describe -Dcmd=package
mvn help:describe -Dcmd=deploy

go deeper

for a junior

Know that jar packaging produces a JAR and pom produces nothing buildable.

for a middle

Recite the jar binding table and the war/pom differences.

for a senior

Choose packaging correctly for parents/BOMs and explain why mis-set packaging breaks builds.

for a principal

Standardize packaging choices and custom lifecycle extensions across a multi-module platform, and document them for teams.

## Why packaging drives bindings The **default lifecycle** has phases (validate, compile, test, package, install, deploy, ...). But a phase only *does* something if a plugin goal is **bound** to it. Maven ships built-in binding tables keyed by `<packaging>`. So `packaging` is the switch that wires the right plugins for the right artifact type. ## The common binding tables **jar / ejb (and similar) packaging:** - `process-resources` → `maven-resources-plugin:resources` - `compile` → `maven-compiler-plugin:compile` - `process-test-resources` → `maven-resources-plugin:testResources` - `test-compile` → `maven-compiler-plugin:testCompile` - `test` → `maven-surefire-plugin:test` - `package` → `maven-jar-plugin:jar` - `install` → `maven-install-plugin:install` - `deploy` → `maven-deploy-plugin:deploy` **war packaging:** identical, except `package` → `maven-war-plugin:war`. **pom packaging:** only `package` → `site:attach-descriptor` (in some Maven versions), `install` → install:install, `deploy` → deploy:deploy. Crucially there is **no compile, no test, no jar** — a POM is a parent/aggregator and produces no code artifact. **maven-plugin packaging:** the jar set PLUS `process-classes`/`package` bindings for `maven-plugin-plugin` (descriptor + helpmojo) so the plugin metadata is generated. ## Practical consequences - A parent/BOM project must use `<packaging>pom</packaging>` — otherwise Maven tries to compile/jar a module that has no sources and fails or produces an empty jar. - Switching jar→war changes only the artifact-producing step; clean/resources/install/deploy are unchanged. - You can still add or override bindings via `<executions>` in a plugin, but the *defaults* come from packaging. ```xml <!-- A parent aggregator: no jar produced --> <project> <groupId>com.example</groupId> <artifactId>platform-parent</artifactId> <version>1.0.0</version> <packaging>pom</packaging> <modules> <module>service-api</module> <module>service-impl</module> </modules> </project> ``` ## How to inspect it Run `mvn help:describe -Dcmd=package` or `mvn help:describe -Dcmd=compile` to print the goals bound to a phase for the current packaging.

  • Why does a parent/BOM project use packaging pom?
    Because pom packaging binds only install and deploy (no compile/test/jar). The module has no source to build; it exists to aggregate modules and/or centralize dependency and plugin management.
  • How can you find out which goals are bound to the package phase?
    Run mvn help:describe -Dcmd=package, which lists the lifecycle bindings for the current project's packaging.

saying these in an interview costs you the question

  • Saying pom packaging compiles and jars code — it does not.
  • Believing the bindings are hardcoded regardless of packaging.
  • Thinking you must manually bind jar:jar for a normal jar project.

context