The maven-shade-plugin offers a great feature: to unpack all your dependencies (and repack) into a single über-jar that is self-contained for running a Java program.
The idea isn’t new and the approach is employed by several frameworks, such as Spring Boot.
There are however some things to watch out for, especially if you depend on the shaded artifact. As part of its transformation, the shade plugin will strip away the <dependencies>
of your POM.
A POM before shading:
<project>
<groupId>org.example</groupId>
<artifactId>artifact</artifactId>
<version>1.10</version>
<dependencies>
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>2.6</version>
</dependency>
</dependencies>
</project>
The POM after shading:
<project>
<groupId>org.example</groupId>
<artifactId>artifact</artifactId>
<version>1.10</version>
</project>
From the plugin’s standpoint, it makes sense since all dependencies are already included in the jar, so transitively saying that you have a dependency to (say)
commons-lang:commons-lang:2.6 will just clutter up the classpath of the dependent.
The real problem occurs when you have shaded a dependency of a certain version and start depending on the shaded artifact and include another version of the same artifact:

But since the dependency version is stripped away, myproject doesn’t necessarily know that artifact even includes commons-lang:2.6,
but its packages are nevertheless still in front of the classpath, enclosed in the jar of artifact.
Is there a way out of this?
Fortunately, yes. The authors of maven-shade-plugin thought of this and included a way to deploy two jars with the same POM:
- One unshaded jar (the main artifact)
- The shaded jar (now called an attachment)
The shaded jar will use a classifier to distinguish between the two.
<project>
...
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<shadedArtifactAttached>true</shadedArtifactAttached>
<!-- Any classifier name that makes sense -->
<shadedClassifierName>shaded</shadedClassifierName>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
...
</project>
The resulting POM will now include the <dependencies> section so any dependent can now choose which version it wants.
It also makes it clearer when you are depending on a regular artifact and when you are depending on a shaded artifact.
<project>
<groupId>org.example</groupId>
<artifactId>myproject</artifactId>
<version>4.2</version>
<dependencies>
<dependency>
<groupId>org.example</groupId>
<artifactId>artifact</artifactId>
<version>1.10</version>
<classifier>shaded</classifier>
</dependency>
</dependencies>
</project>
or
<project>
<groupId>org.example</groupId>
<artifactId>myproject</artifactId>
<version>4.2</version>
<dependencies>
<dependency>
<groupId>org.example</groupId>
<artifactId>artifact</artifactId>
<version>1.10</version>
</dependency>
</dependencies>
</project>
You still might end up with weird classpath issues if you depend on a shaded artifact (you really shouldn’t, the shader’s purpose is to produce a self-contained jar with everything inside to run it, not to be a dependency to other artifacts), but hopefully it should be more obvious when you do so.