【问题标题】:How can a duplicate class be excluded from sbt assembly?如何从 sbt 程序集中排除重复的类?
【发布时间】:2014-08-13 08:12:39
【问题描述】:

我们有一种情况,其中两个依赖项具有完全相同的类(因为其中一个依赖项复制了它并包含在它们自己的源中)。

这导致sbt assembly 的重复数据删除检查失败。

如何从特定 jar 中排除一个类?

【问题讨论】:

    标签: sbt sbt-assembly


    【解决方案1】:

    您需要一个mergeStrategy,它将获取其中一个文件。

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

    更新

    如果你想根据它来自的 JAR 来处理文件,我认为你不能使用程序集插件定义的合并策略。你能做什么,你可以定义自己的策略。

    不过,我会颠倒你的情况。我认为问题应该是“如何包含来自特定 JAR 的类?”。原因是同一类的 JAR 可以有两个以上,最后只能包含一个。

    您可以使用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)
    }
    

    【讨论】:

    • 确实如此,但现在好多了。谢谢你的改变!人们会更快地适应新的运营商。
    • 这个解决方案不知道它是从哪里来的吗?我想排除一个不应该在我依赖的 jar 中的类,因此我需要在该 jar 中指定该类。
    • @ChanningWalton 我认为您必须编写自定义的MergeStrategy 才能做到这一点。请检查我的更新答案。
    • 我得到“project\IncludeFromJar.scala:1: not found: object sbtassembly”
    • 在项目/plugins.sbt addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "0.11.2")。 AFA 导入:我将您的代码逐字复制到 project/IncludeFromJar.scala 中,intellij 没有显示错误,但从 sbt 命令行失败。
    【解决方案2】:

    你们使用的是什么版本的sbtassembly? 我相信我使用的是不同的版本(0.14.2),因为我在使用 use project/IncludeFromJar.scala 时遇到了错误。

    编译时出现以下错误:

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

    经过进一步调查,我发现sbtassembly.MergeStrategyapply 方法是最终的。因此,IncludeFromJarapply 方法不能覆盖sbtassembly.MergeStrategy 的即使在IncludeFromJar 中指定了override def apply

    谢谢:)

    【讨论】:

      【解决方案3】:

      讨论可能有点晚了,但为了帮助其他发现此问题的人:

      当你扩展 MergeStrategy 时,你想用签名覆盖方法 apply:

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

      以元组参数结尾的apply方法,调用apply,参数如上拆分

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

      所以例子变成了:

      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)
      }
      

      【讨论】:

        猜你喜欢
        • 2014-05-10
        • 2015-01-27
        • 2013-12-06
        • 1970-01-01
        • 2021-10-08
        • 2011-12-10
        • 2021-10-24
        • 2014-11-02
        • 2013-12-21
        相关资源
        最近更新 更多