I'm using maven shade plugin in order to create an uber jar while relocating all classes. That's because I'm getting an external jar and I don't want to have classpath collisions. So the idea is to create a new uber (relocated) jar and use it in my application. So the shade plugin takes all the classes and relocates them to the new package prefix. My issue is that a far as I understand, it also does that for dependencies which the classes they depend on, aren't in the scope [*].
Let's say I'm relocating all com
to shade.com
:
<executions>
<execution>
<id>rename-all</id>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<shadedArtifactAttached>true</shadedArtifactAttached>
<keepDependenciesWithProvidedScope>false</keepDependenciesWithProvidedScope>
<relocations>
<relocation>
<pattern>com</pattern>
<shadedPattern>shade/com</shadedPattern>
</relocation>
</relocations>
</configuration>
</execution>
</executions>
So if one of my dependencies, A, has a <optional>
dependency on B (which package com.B
), the plugin would change the imports within A to point to shade.com.B
. But com.B is optional, which means those classes won't be available in shade.com.B
, because they didn't get into the relocation process. The actual classes available when using this jar would be the "normal" ones - com.B
.
And then I get class not found exceptions on shade.com.B
classes when I try to use the shaded jar in my application.
Am I missing something in my understanding? Is there any solution to this?
[*] Some examples: I'm not sure yet about the exact cases where this happens. In my case, I depend on spark-sql
dependency. I dig into 3 of the classes which I saw this issue (there are many more):
org/apache/html/dom/HTMLIsIndexElementImpl
importsorg.w3c.dom.html.HTMLIsIndexElement
which is inrt.jar
- the import was relocated so now it points toshade.org.w3c.dom.html.HTMLIsIndexElement
and can't be found.io/netty/handler/codec/marshalling/ChannelBufferByteOutput
importsorg.jboss.marshalling.ByteOutput
. Hence the relocation change this toimport shade.org.jboss.marshalling.ByteOutput
. But as can be seen here, the import forjboss-marshalling
is marked as<optional>true</optional>
, so it's not in the jar andByteOutput
itself won't be relocated, hence won't be available.jasper-runtime
is included here but excluded in the upper one, here. So the outcome is that the files in Hadoop-hdfs are getting relocation to their dependencies, even though these classes would never be available in the relocated path since they aren’t in the jar at all. e.g.org/apache/hadoop/hdfs/server/datanode/browseBlock_jsp
now has a reference to “shade/org/apache/jasper/runtime/JspSourceDependent”.