skip to content

Packaging & Assembly

Turning compiled classes into shippable artifacts: JAR manifests, uber-jars, assemblies, WAR and EAR archives, executable jars, and reproducible output. Interviewers ask because 'how does this become deployable?' ends every build discussion.

on this pageshow

explore

questions

26

What does the <packaging> element control in a Maven POM, and what is the difference between jar, war, and ear packaging?

level: juniorimportance: must knowfreq 70%

answer

  1. packaging selects artifact + lifecycle
  2. war = WEB-INF/lib + classes
  3. ear = multi-module + application.xml
  4. pom = no artifact

basics

~20 s

<packaging> tells Maven what artifact to build and which lifecycle to use. jar makes a plain Java archive, war makes a web app archive for a servlet container, and ear bundles multiple modules for a Java EE app server.

solid answer

~40 s

The <packaging> element selects the artifact type and binds a default set of plugin goals to the build lifecycle. jar (the default) produces an ordinary archive of compiled classes and resources. war produces a Web Application Archive with a WEB-INF/classes folder, WEB-INF/lib for dependency jars, and web resources at the root — deployed to a servlet container like Tomcat via the maven-war-plugin. ear produces an Enterprise Application Archive grouping several modules (wars, ejb-jars, libraries) plus an application.xml, built by the maven-ear-plugin and deployed to a full Java EE/Jakarta EE server. There is also pom packaging for aggregator/parent projects that build no artifact. Each packaging changes which lifecycle bindings run, so choosing war versus jar fundamentally changes what mvn package emits.

code

xml · 2 lines
xml
<packaging>war</packaging>
<!-- emits target/shop-web-1.0.0.war with WEB-INF/classes, WEB-INF/lib -->

go deeper

for a junior

Know the three names and that war is for web apps, jar is the default.

for a middle

Explain the WEB-INF layout and that packaging changes lifecycle bindings.

for a senior

Discuss provided scope, ear-vs-war target runtimes, and when to choose each.

for a principal

Set org-wide conventions: executable jars for cloud vs war/ear for legacy app servers, and standardize packaging across the module graph.

## What <packaging> is Every Maven project declares a `<packaging>` in its `pom.xml` (Project Object Model — the XML file describing the build). It defaults to `jar`. This single element does two things: it decides the **type of artifact** produced by `mvn package`, and it selects a **lifecycle mapping** — the set of plugin goals automatically bound to each build phase (`compile`, `test`, `package`, etc.). ## The common packaging types - **jar** — a Java ARchive, a zip of `.class` files and resources. The default. Built by `maven-jar-plugin`. - **war** — a Web Application aRchive. Built by `maven-war-plugin`. Its layout is fixed: compiled classes go to `WEB-INF/classes`, runtime dependency jars go to `WEB-INF/lib`, and static web content (HTML, JSP) sits at the archive root. A war is deployed into a **servlet container** (Tomcat, Jetty). - **ear** — an Enterprise ARchive. Built by `maven-ear-plugin`. It aggregates **multiple modules** — wars, EJB jars, and shared libraries — and carries an `application.xml` deployment descriptor. An ear targets a **full Jakarta/Java EE application server** (WildFly, WebLogic), not a plain servlet container. - **pom** — no binary artifact; used by parent/aggregator projects that only build child modules. ## Why it matters Because packaging swaps the lifecycle bindings, the same `mvn package` command does very different work. For a war, dependencies are folded into the archive; for a jar, they are not. Picking the wrong packaging produces an artifact your runtime cannot deploy. ```xml <project> <modelVersion>4.0.0</modelVersion> <groupId>com.example</groupId> <artifactId>shop-web</artifactId> <version>1.0.0</version> <packaging>war</packaging> </project> ``` Modern cloud deployment increasingly favors an **executable jar** (a war/jar that embeds its own server) over the war-into-container model, but war and ear remain common in enterprise and app-server environments.

  • Where do a war's dependency jars end up?
    Runtime/compile-scoped dependencies are copied into WEB-INF/lib inside the archive; provided-scoped ones (like the servlet API) are excluded because the container supplies them.
  • What packaging does a parent/aggregator project use?
    pom packaging — it produces no binary artifact and just coordinates its child modules.

saying these in an interview costs you the question

  • Saying war and jar are interchangeable
  • Claiming the servlet-api jar is bundled into a war (it is provided by the container)
  • Thinking ear is just a renamed war rather than a multi-module container

context

open as a page

What does the maven-assembly-plugin do, and when would you reach for it instead of the default jar packaging?

level: juniorimportance: must knowfreq 55%

basics

~20 s

The assembly plugin bundles your project output plus extra files (dependencies, scripts, docs) into a single distributable archive like a zip, tar.gz, or a fat jar. The default jar packaging only packs your own compiled classes.

open as a page

What is the MANIFEST.MF file inside a JAR, and how does Maven create it for you?

level: juniorimportance: must knowfreq 60%

basics

~10 s

MANIFEST.MF lives in META-INF/ inside a JAR and holds metadata as key: value lines (like the entry-point class). The maven-jar-plugin generates it automatically when you build with packaging jar.

open as a page

What is an uber-JAR (fat JAR) and how does the maven-shade-plugin build one?

level: juniorimportance: must knowfreq 70%

basics

~10 s

An uber-JAR is a single JAR that bundles your code plus all dependency classes, so it runs standalone with java -jar. maven-shade-plugin unpacks every dependency JAR and merges the classes into one output JAR.

open as a page

What does the spring-boot-maven-plugin's repackage goal do, and what is a layered jar?

level: middleimportance: must knowfreq 65%

basics

~20 s

The repackage goal takes the plain jar Maven built and rewrites it into an executable fat jar that embeds all dependencies and a launcher, so you can run it with java -jar. A layered jar splits it into layers ordered by change frequency to make Docker image builds cache better.

open as a page

How do you make a JAR runnable with `java -jar` and how does the Class-Path header relate to dependencies?

level: middleimportance: must knowfreq 65%

basics

~10 s

Set <mainClass> under <archive><manifest> so Maven writes Main-Class to the manifest; then java -jar works. Add <addClasspath>true</addClasspath> to write a Class-Path header pointing at dependency JARs.

open as a page

What is a reproducible build in Maven, and why would a team want byte-for-byte stable artifacts?

level: middleimportance: must knowfreq 55%

basics

~10 s

A reproducible build produces the exact same bytes in the output JAR/WAR every time you build the same source, regardless of when or where you build. It improves verifiability, caching, and supply-chain trust.

open as a page

What are shade resource transformers, and why are ServicesResourceTransformer and ManifestResourceTransformer often required?

level: middleimportance: must knowfreq 60%

basics

~10 s

Transformers control how shade merges resource files that exist in multiple dependency JARs. ServicesResourceTransformer concatenates META-INF/services files so SPI lookups still work; ManifestResourceTransformer builds the merged manifest, e.g. setting Main-Class.

open as a page

How does project.build.outputTimestamp make a Maven archive reproducible, and what values can it take?

level: seniorimportance: must knowfreq 45%

basics

~10 s

Setting project.build.outputTimestamp gives Maven Archiver a fixed timestamp to stamp on every archive entry instead of the current time, and it sorts entries. It accepts an ISO-8601 instant or Unix epoch seconds.

open as a page

What is package relocation (shading) in maven-shade-plugin and what problem does it solve?

level: seniorimportance: must knowfreq 65%

basics

~10 s

Relocation rewrites a dependency's package names (and the bytecode references to them) to a new prefix inside your uber-JAR. It prevents version conflicts when consumers also use a different version of that same library.

open as a page

How does the maven-war-plugin assemble a war, and how do dependency scopes affect what ends up inside it?

level: middleimportance: should knowfreq 50%

basics

~10 s

The war plugin copies your classes to WEB-INF/classes and your compile/runtime dependencies to WEB-INF/lib, plus web resources at the root. provided and test scoped dependencies are left out so the container supplies them.

open as a page

How do you build a runnable executable fat jar with the assembly plugin, and what's needed to make `java -jar` work?

level: middleimportance: should knowfreq 50%

basics

~10 s

Use the jar-with-dependencies descriptorRef so all dependencies are merged into one jar, and set a Main-Class in the manifest via <archive><manifest><mainClass>. Then java -jar can find both your code and its dependencies.

open as a page

What do addDefaultImplementationEntries / addDefaultSpecificationEntries do, and what Implementation-* headers result?

level: middleimportance: should knowfreq 40%

basics

~10 s

Setting <addDefaultImplementationEntries>true</addDefaultImplementationEntries> tells maven-jar-plugin to write Implementation-Title/Version/Vendor headers from your pom's name, version, and organization, so code can read its own version at runtime.

open as a page

You inherit an existing Spring Boot Maven project that is not reproducible. Walk through the minimal steps to make and verify it reproducible.

level: middleimportance: should knowfreq 28%

basics

~10 s

Add project.build.outputTimestamp to the POM (often derived from the commit), make sure packaging plugin versions are current, then run mvn artifact:check-buildplan and rebuild twice to confirm the JAR hashes match.

open as a page

Compare the ways to produce a runnable Java distribution with Maven: shade/assembly uber-jars, Spring Boot repackage, and OS-native distributions via appassembler, jlink, or jpackage. When would you pick each?

level: seniorimportance: should knowfreq 40%

basics

~20 s

Uber-jars (shade/assembly) and Spring Boot repackage bundle everything into one runnable jar needing only a JRE. appassembler generates start scripts plus a lib folder. jlink builds a trimmed custom runtime image, and jpackage produces a native OS installer or app bundle that includes a runtime, so users need no separate Java install.

open as a page

Walk me through writing a custom assembly.xml descriptor to produce a tar.gz distribution with a bin/lib/conf layout.

level: seniorimportance: should knowfreq 35%

basics

~20 s

Write an assembly.xml with an <id>, one or more <formats> (like tar.gz), <fileSets> to copy your scripts/config into bin/ and conf/, and a <dependencySets> to drop dependency jars into lib/. Reference it from the plugin's <descriptors> and run assembly:single.

open as a page

How do you add arbitrary custom manifest headers, and what happens when they collide with generated or hand-written ones?

level: seniorimportance: should knowfreq 28%

basics

~10 s

Add free-form headers under <archive><manifestEntries>, each child element name becoming a header. You can also merge a hand-written file via <manifestFile>. manifestEntries values take precedence over generated defaults.

open as a page

What is a Multi-Release JAR, how do you build one with Maven, and what does the manifest contain?

level: seniorimportance: should knowfreq 30%

basics

~10 s

A Multi-Release JAR ships one base set of classes plus version-specific overrides under META-INF/versions/<N>/. Its manifest has Multi-Release: true, so a JDK 17 runtime prefers versions/17 classes over the base.

open as a page

What does mvn artifact:check-buildplan do, and how does it fit into verifying a reproducible build?

level: seniorimportance: should knowfreq 30%

basics

~10 s

artifact:check-buildplan (from the maven-artifact-plugin) inspects your effective build plan and warns or fails if plugins are configured in a way that breaks reproducibility — for example if project.build.outputTimestamp is missing.

open as a page

What does minimizeJar do in maven-shade-plugin, and what are its risks?

level: seniorimportance: should knowfreq 45%

basics

~10 s

minimizeJar makes shade strip out dependency classes that aren't reachable from your code, shrinking the uber-JAR. The risk is it may remove classes only loaded via reflection or SPI, causing ClassNotFoundException at runtime.

open as a page

What is the dependency-reduced-pom.xml that maven-shade-plugin generates, and why does it matter?

level: seniorimportance: should knowfreq 40%

basics

~10 s

It's a rewritten POM shade installs/deploys instead of the original, with the bundled dependencies removed from <dependencies>. This stops consumers of your uber-JAR from transitively pulling those same dependencies again.

open as a page

Compare the assembly plugin with the shade plugin and spring-boot-maven-plugin for producing distributable artifacts. When do you pick each?

level: principalimportance: should knowfreq 30%

basics

~20 s

Assembly = flexible distribution layouts (zip/tar.gz, bin/lib/conf) and simple fat jars. Shade = uber-jars that need package relocation and proper merging of service files. spring-boot-maven-plugin = runnable Spring Boot jars with nested-jar layout. Pick by what you're shipping.

open as a page

Beyond the build timestamp, what other sources of non-determinism can break a reproducible Maven build, and how do you address them?

level: principalimportance: should knowfreq 22%

basics

~20 s

Besides timestamps, watch out for entry ordering, the JDK version baked into the manifest, locale/timezone effects, absolute paths, SNAPSHOT dependencies, and code generators that embed times. Pin the toolchain, avoid SNAPSHOTs, and normalize generated content.

open as a page

When would you choose maven-shade-plugin over the spring-boot-maven-plugin or maven-assembly-plugin for packaging?

level: principalimportance: should knowfreq 35%

basics

~20 s

Use shade when you need a flattened uber-JAR with package relocation and smart resource merging — typically for libraries, Maven plugins, or big-data jobs. Use spring-boot-maven-plugin for Spring Boot apps, and assembly only for simple bundles or non-JAR archives.

open as a page

What is the maven-ear-plugin used for, how is an EAR project structured, and why has it largely fallen out of favor?

level: seniorimportance: nice to knowfreq 20%

basics

~20 s

maven-ear-plugin builds an EAR — an enterprise archive that groups several modules (wars, EJB jars, libraries) and generates application.xml for deployment to a full Jakarta EE application server. It's faded because Spring Boot executable jars and microservices replaced the monolithic app-server model.

open as a page

When the assembly plugin runs, what artifact does it produce relative to the main jar, and how does it get installed and deployed?

level: seniorimportance: nice to knowfreq 22%

basics

~20 s

By default the assembly is attached as a secondary artifact with a classifier (the assembly id, e.g. -dist), alongside the main jar. Because it's attached, mvn install and deploy will install/upload it to the repository too.

open as a page