How can a duplicate class be excluded from sbt assembly?

蹲街弑〆低调 提交于 2019-11-29 08:37:18

问题


We have a situation in which two dependencies have exactly the same class (because one of the dependencies copied it and included in their own source).

This is causing sbt assembly to fail its deduplication checks.

How can I exclude a class from a particular jar?


回答1:


You need a mergeStrategy, which will take one of the files.

mergeStrategy in assembly := {
    case PathList("path", "to", "your", "DuplicatedClass.class") => MergeStrategy.first
    case x => (mergeStrategy in assembly).value(x)
}

Update

If you want to handle the file depending on the JAR which it came from, I don't think you can with the merge strategies that assembly plugin defines. What you could do you could define your own strategy.

I would invert your condition though. I think the question should be "How can I include a class from a particular JAR?". The reason is that there can be more than two JARs having the same class, and you can only include one in the end.

You can tell from where the file comes by using AssemblyUtils.sourceOfFileForMerge.

project/IncludeFromJar.scala

import sbtassembly._
import java.io.File
import sbtassembly.Plugin.MergeStrategy

class IncludeFromJar(val jarName: String) extends MergeStrategy {

  val name = "includeFromJar"

  def apply(args: (File, String, Seq[File])): Either[String, Seq[(File, String)]] = {
    val (tmp, path, files) = args
    val includedFiles = files.flatMap { f =>
      val (source, _, _, isFromJar) = sbtassembly.AssemblyUtils.sourceOfFileForMerge(tmp, f)
      if(isFromJar && source.getName == jarName) Some(f -> path) else None
    }
    Right(includedFiles)
  }

}

build.sbt

mergeStrategy in assembly := {
    case PathList("path", "to", "your", "DuplicatedClass.class") => new IncludeFromJar("jarname.jar")
    case x => (mergeStrategy in assembly).value(x)
}



回答2:


What version of sbtassembly are yall using? I believe Im using using a different version (0.14.2) because Im getting an error using use project/IncludeFromJar.scala.

When compiling I get the following error:

method apply cannot override final member
def apply(args: (File, String, Seq[File])): Either[String, Seq[(File, String)]] = {
^  

Upon further investigation I found out that sbtassembly.MergeStrategy's apply method is final. Therefore, IncludeFromJar's apply method cannot override sbtassembly.MergeStrategy's even with specifying override def apply in IncludeFromJar

Thanks :)




回答3:


Probably a bit late to the discussion but to help others that find this:

when you extend MergeStrategy you want to override the method apply with the signature:

 def apply(tempDir: File, path: String, files: Seq[File]): Either[String, Seq[(File, String)]]

The apply method that is final with the tuple argument, calls the apply with the parameters split out as above

https://github.com/sbt/sbt-assembly/blob/edd35cfbaf05c3465371b63d38fda8ac579d766c/src/main/scala/sbtassembly/MergeStrategy.scala#L19

So the example becomes:

def includeFromJar(val jarName: String): sbtassembly.MergeStrategy = new sbtassembly.MergeStrategy {

  val name = "includeFromJar"

  def apply(tmp: File, path: String, files: Seq[File]): Either[String, Seq[(File, String)]] = {
    val includedFiles = files.flatMap { f =>
      val (source, _, _, isFromJar) = sbtassembly.AssemblyUtils.sourceOfFileForMerge(tmp, f)
      if(isFromJar && source.getName == jarName) Some(f -> path) else None
    }
    Right(includedFiles)
  }
}

mergeStrategy in assembly := {
    case PathList("path", "to", "your", "DuplicatedClass.class") => includeFromJar("jarname.jar")
    case x => (mergeStrategy in assembly).value(x)
}


来源:https://stackoverflow.com/questions/24363363/how-can-a-duplicate-class-be-excluded-from-sbt-assembly

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!