简体   繁体   中英

How can I force the usage of a class from a particular jar and exclude same class of another jar in build.sbt?

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?

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM