What exactly does the spring-boot-maven-plugin `repackage` goal do, and how does it relate to Gradle's `bootJar` task?
answer
- repackage rewrites the plain jar in place
- BOOT-INF/lib nested deps, BOOT-INF/classes your code
- Main-Class=JarLauncher, Start-Class=your main
- plain jar saved as *.jar.original
- Gradle bootJar builds it directly, no repackage step
basics
~20 srepackage takes the plain jar Maven already built and rewrites it into an executable 'fat' jar: dependencies nested under BOOT-INF/lib, your classes under BOOT-INF/classes, plus a launcher in the manifest. Gradle's bootJar task builds the same executable jar directly.
solid answer
~40 sIn Maven, `maven-jar-plugin` first builds an ordinary jar of your classes. The `repackage` goal (bound to the `package` phase) then transforms it in place into an *executable* archive: it nests each dependency jar under `BOOT-INF/lib/`, moves your classes to `BOOT-INF/classes/`, adds Spring Boot's loader classes, and sets the manifest `Main-Class` to a launcher (`JarLauncher`) with `Start-Class` pointing at your `@SpringBootApplication`. The original plain jar is preserved as `*.jar.original`. At runtime the launcher's custom classloader reads the nested jars. Gradle skips the two-step dance: the `bootJar` task builds the executable jar directly from your classes and runtime classpath — there's no separate 'repackage' step because Gradle's `jar` task and `bootJar` task are distinct. Both approaches yield the same nested-jar layout so `java -jar` runs standalone.
code
java · 15 lines// pom.xml: repackage runs by default when the plugin is present.
// (equivalent XML shown as a Java-style comment for clarity)
//
// <build><plugins><plugin>
// <groupId>org.springframework.boot</groupId>
// <artifactId>spring-boot-maven-plugin</artifactId>
// <executions><execution><goals>
// <goal>repackage</goal> <!-- bound to the package phase -->
// </goals></execution></executions>
// </plugin></plugins></build>
//
// After `mvn package`:
// target/app.jar -> executable fat jar (java -jar this)
// target/app.jar.original -> the plain library jar kept as backup
public class PackagingNotes { }go deeper
Knows repackage/bootJar produce a runnable fat jar.
Must describe the two-step Maven flow, BOOT-INF layout, and Main-Class vs Start-Class.
Explains the custom classloader, nested-vs-shaded rationale, and the .original artifact.
Reasons about when fat jars hurt (libraries, layered images) and drives packaging strategy across modules.
**The Maven two-step.** Maven's lifecycle already has `maven-jar-plugin` produce a jar during the `package` phase containing just your compiled classes and resources. Spring Boot's `spring-boot-maven-plugin` binds its `repackage` goal to that same `package` phase, running *after* the plain jar exists. `repackage` reads that jar and rewrites it into an *executable jar* — sometimes called a 'fat jar' or 'uber jar' because it's self-contained. **The executable-jar layout.** The repackaged archive has a specific internal structure: - `BOOT-INF/classes/` — your application's compiled classes and resources. - `BOOT-INF/lib/` — every runtime dependency, kept as intact nested jar files (not exploded/merged). - `org/springframework/boot/loader/...` — Spring Boot's loader classes, at the archive root so the JVM can find them immediately. - `META-INF/MANIFEST.MF` — with `Main-Class` set to a Spring Boot launcher (`org.springframework.boot.loader.launch.JarLauncher` in Boot 3.2+, `org.springframework.boot.loader.JarLauncher` in earlier versions) and `Start-Class` set to your `@SpringBootApplication` main class. **How it runs.** When you `java -jar app.jar`, the JVM reads `Main-Class` and starts the launcher. The launcher installs a custom classloader (`LaunchedClassLoader`) that can load classes directly from the *nested* jars in `BOOT-INF/lib/` — standard Java can't load a jar-inside-a-jar, which is why Boot needs its own loader. The launcher then reflectively calls the `main` of your `Start-Class`. **Nested vs shaded.** Boot deliberately nests dependency jars intact rather than 'shading' (exploding all classes into one flat jar). Shading risks file collisions (e.g., two libs each shipping `META-INF/spring.factories` or `application.properties`) and breaks signed jars. Nesting preserves each library's boundary. **The `.original` file.** After `repackage`, the executable jar *replaces* the plain jar under the same name, and the plain jar is saved as `target/<name>.jar.original`. This matters if another tool expects the library-style jar. **Gradle's model.** Gradle applies the `org.springframework.boot` plugin, which registers a `bootJar` task (type `BootJar`) that builds the executable jar directly from `main` source-set output and the `runtimeClasspath` configuration. There's no 'repackage' concept because Gradle has separate tasks: the standard `jar` task produces a plain library jar, and `bootJar` produces the executable one — they don't rewrite each other. `assemble`/`build` run `bootJar`. **When to use.** The executable jar is your deployable artifact. If instead you need a traditional library jar (e.g., you're publishing a shared module), you want the plain `jar`/`maven-jar-plugin` output, not the repackaged fat jar. **Gotchas.** - Running `mvn jar:jar` alone won't give you a runnable app; you need `package` so `repackage` fires. - `repackage` only makes sense for applications, not libraries — a fat jar is a poor library dependency. - The manifest `Main-Class` is the launcher, *not* your class; your class is `Start-Class`. Candidates often confuse these.
- After `mvn package`, what is the file `target/myapp.jar.original`?It's the plain, non-executable jar that `maven-jar-plugin` produced before `repackage` overwrote `myapp.jar` with the executable version. Boot keeps it as a backup of the original library-style artifact.
- Why does Spring Boot nest dependency jars instead of merging all classes into one flat jar?Nesting keeps each library intact, avoiding resource-file collisions (duplicate `META-INF` entries, config files) and preserving signed jars. A custom `LaunchedClassLoader` loads classes from the nested jars at runtime.
saying these in an interview costs you the question
- Saying the manifest Main-Class is your @SpringBootApplication class
- Describing repackage as merging/shading all classes into one flat jar
- Thinking Gradle has a separate 'repackage' step like Maven