I have a maven project with both Java and Scala components, but when I use maven-shade-plugin, it relocates package names for both Java and Scala files, but ONLY renames packages inside Java files, Scala files still contain the older package names, what am I missing?
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.2.1</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<!--<minimizeJar>true</minimizeJar>-->
<artifactSet>
<includes>
<include>ml.dmlc:xgboost4j-spark</include>
<include>ml.dmlc:xgboost4j</include>
</includes>
</artifactSet>
<filters>
<filter>
<artifact>*:*</artifact>
<excludes>
<exclude>META-INF/*.SF</exclude>
<exclude>META-INF/*.DSA</exclude>
<exclude>META-INF/*.RSA</exclude>
</excludes>
</filter>
</filters>
<relocations>
<relocation>
<pattern>ml.dmlc.xgboost4j</pattern>
<shadedPattern>ml.dmlc.xgboost4j.shaded</shadedPattern>
</relocation>
</relocations>
<transformers>
</transformers>
</configuration>
</execution>
</executions>
</plugin>```
If you're familiar with Maven, you can go ahead with the Scala Maven Plugin.
This plugin provides the capability to package the artifact in an uber-jar, including its dependencies and to shade - i.e. rename - the packages of some of the dependencies.
The scala-maven-plugin is used for compiling/testing/running/documenting scala code in maven.
In Java, to “shade” a dependency is to include all its classes and the classes from its transitive dependencies in your project, often renaming the packages and rewriting all affected bytecode.
Short Answer. The dependency-reduced-pom. xml removes transitive dependencies which are already in your shaded jar. This prevents consumers from pulling them in twice.
Sadly, I believe that Maven is intended to have this functionality but, currently (Dec 2020), it does not.
This can be seen with this bug ticket: https://issues.apache.org/jira/browse/MSHADE-345
workaround
I have personally done a silly workaround for this. I make a new empty mvn project that has the dependency:
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>28.0-jre</version>
</dependency>
And the plugin:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.1.1</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<relocations>
<relocation>
<pattern>com.google.</pattern>
<shadedPattern>shader.com.google.</shadedPattern>
</relocation>
</relocations>
</configuration>
</execution>
</executions>
</plugin>
Then in the project with code that requires a low version of guava and a new version of guava, include the empty project as a dependency.
<dependency>
<groupId>com.yoursite.yourwork</groupId>
<artifactId>shader</artifactId>
<version>0.0.1</version>
</dependency>
Then in a .scala file you import the new (version 28) guava classes like this:
import shader.com.google.common.graph.Network
Why this works
Since the error only occurs in scala projects where you refer to your own class that uses the dependency, or as said in the question "Scala files still contain the older package names", shading a project that does not refer to its own dependencies bypasses the bug.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With