Reputation:
I have two asm
dependencies that have exactly the same class names and project structures included by different dependencies. Although these libraries have the same project structure, they have different Maven coordinates. Therefore, a dependency override won't work.
A one of my dependencies (jnr-ffi
) uses a the org.objectweb.asm.ClassVisitor
class. In "org.objectweb" % "asm" % "3.3.1"
, org.objectweb.asm.ClassVisitor
is an Interface, and this throws an error. I need to use "org.ow2.asm" % "asm" % "5.0.3"
's implementation of org.objectweb.asm.ClassVisitor
because it is an actual class. Jars of both implementations are downloaded into ~/.ivy2/cache
. Unfortunately the one I need isn't used given my merge strategies.
The following error is thrown:
Exception in thread "main" java.lang.IncompatibleClassChangeError: Found interface org.objectweb.asm.ClassVisitor, but class was expected
at jnr.ffi.provider.jffi.AsmLibraryLoader.generateInterfaceImpl(AsmLibraryLoader.java:104)
at jnr.ffi.provider.jffi.AsmLibraryLoader.loadLibrary(AsmLibraryLoader.java:89)
at jnr.ffi.provider.jffi.NativeLibraryLoader.loadLibrary(NativeLibraryLoader.java:43)
at jnr.ffi.LibraryLoader.load(LibraryLoader.java:325)
at jnr.unixsocket.Native.<clinit>(Native.java:80)
at jnr.unixsocket.UnixSocketChannel.<init>(UnixSocketChannel.java:101)
at jnr.unixsocket.UnixSocketChannel.open(UnixSocketChannel.java:65)
I'm using sbt
0.13.5 and sbt assembly
0.14.2 .
I've attempted exclude "org.objectweb" % "asm" % "3.3.1"
. This did not work:
libraryDependencies ++= Seq(. . .).map(_.exclude("org.objectweb" % "asm" % "3.3.1"))
I've also attempted to use the following merge strategies
assemblyMergeStrategy in assembly := {
case PathList("asm-3.2.jar") => MergeStrategy.discard
case PathList(ps @ _*) if ps.last endsWith ".asm-3.2.jar" => MergeStrategy.discard
case PathList("asm-5.0.3.jar") => MergeStrategy.first
case PathList(ps @ _*) if ps.last endsWith ".asm-5.0.3.jar" => MergeStrategy.first
case PathList("META-INF", xs @ _*) => MergeStrategy.discard
case x => MergeStrategy.first
}
I've also tried excluding the jar:
assemblyExcludedJars in assembly := {
val cp = (fullClasspath in assembly).value
cp filter {_.data.getName == "asm-3.2.jar"}
}
I've also tried to implement the custom merge strategy project/IncludeFromJar.scala
from "How can a duplicate class be excluded from sbt assembly?". But IncludeFromJar.scala
won't compile, and I believe its because I'm using the wrong version of sbt assembly
for their example.
case PathList("org", "objectweb", "asm", "ClassVisitor.class") => new IncludeFromJar("asm-5.0.3.jar")
Hence the question: How can I force the usage of a class from a particular jar and exclude same class of another jar in build.sbt?
Upvotes: 1
Views: 986
Reputation: 21
I've lately faced a similar issue. The solution I've found was to use dependencies shading for assembly. Here are the settings I've used within my build.sbt
file.
assemblyShadeRules in assembly := Seq(
ShadeRule.rename("org.objectweb.asm.**" -> "asm503.@1").inLibrary(
"org.ow2.asm" % "asm" % "5.0.3"
).inLibrary(
"org.ow2.asm" % "asm-tree" % "5.0.3"
).inLibrary(
"org.ow2.asm" % "asm-analysis" % "5.0.3"
).inLibrary(
"org.ow2.asm" % "asm-commons" % "5.0.3"
).inLibrary(
"org.ow2.asm" % "asm-util" % "5.0.3"
).inLibrary(
"com.github.jnr" % "jnr-ffi" % "2.1.9"
).inProject // For your own code
)
The .inProject
statement will shade your own imports as well (if needed).
I know the thread is old but this might help someone.
Upvotes: 2