驱逐sbt中的特定传递依赖

时间:2015-06-02 10:46:03

标签: scala sbt sbt-assembly

假设一个小型测试项目(sbt 0.13.8,完整项目为gist):

name := "test"

organization := "org.example"

version := "0.1.0-SNAPSHOT"

scalaVersion := "2.11.6"

libraryDependencies ++= Seq (
  "com.lowagie"              %  "itext"         % "4.2.1",
  "com.github.wookietreiber" %% "scala-chart"   % "0.4.2"
)

依赖关系树如下所示:

dependencyTree
[info] org.example:test_2.11:0.1.0-SNAPSHOT [S]
[info]   +-com.github.wookietreiber:scala-chart_2.11:0.4.2 [S]
[info]   | +-org.jfree:jfreechart:1.0.17
[info]   | | +-org.jfree:jcommon:1.0.21
[info]   | | +-xml-apis:xml-apis:1.3.04
[info]   | | 
[info]   | +-org.scala-lang.modules:scala-swing_2.11:1.0.1 [S]
[info]   | 
[info]   +-com.lowagie:itext:4.2.1
[info]     +-bouncycastle:bctsp-jdk14:138
[info]     | +-org.bouncycastle:bctsp-jdk14:1.38
[info]     |   +-org.bouncycastle:bcmail-jdk14:1.38
[info]     |   | +-org.bouncycastle:bcprov-jdk14:1.38
[info]     |   | 
[info]     |   +-org.bouncycastle:bcprov-jdk14:1.38
[info]     |   
[info]     +-dom4j:dom4j:1.6.1
[info]     | +-xml-apis:xml-apis:1.0.b2 (evicted by: 1.3.04)
[info]     | +-xml-apis:xml-apis:1.3.04
[info]     | 
[info]     +-jfree:jfreechart:1.0.12
[info]     | +-jfree:jcommon:1.0.15
[info]     | 
[info]     +-org.swinglabs:pdf-renderer:1.0.5
[info]     
[success] Total time: 0 s, completed Jun 2, 2015 12:16:14 PM

问题是依赖jfreechartscala-chartitext引入(同样适用于jcommon,但我会关注{{} 1}})。但是,jfreechart引入的较旧版本使用其他组织名称(itextjfree)。

通常情况下,如果这些组织使用相同的组织,那么较旧的组织将被驱逐(如org.jfree示例中所做的那样)并且只要存在二进制兼容性就不存在冲突。

现在真正的冲突是依赖xml-apisjfree:jfreechart都在类路径上并提供相同的类。编译工作正常,sbt甚至没有抱怨。以此为例以下示例org.jfree:jfreechart

App

这个编译得很好!我不知道sbt如何选择使用哪种依赖。如果你试图真正运行这件事,那一切都会爆发:

package org.example

import scalax.chart.api._

object Main extends App {
  val data = for {
    i <- 1 to 5
    category = i.toString
    date = new org.jfree.data.time.Day(i, 2, 1998)
    value = i * 2
  } yield category -> Map(date -> value)

  val chart = XYAreaChart.stacked(data.toTimeTable)

  chart.saveAsPDF("/tmp/my-chart.pdf")
}

要解决这个问题,我需要从依赖项列表/类路径中专门逐出/删除较旧的sbt @ test $ compile [info] Updating {file:/home/wookietreiber/projects/scala/jfree-itext-test/}jfree-itext-test... [info] Resolving jline#jline;2.12.1 ... [info] Done updating. [info] Compiling 1 Scala source to /tmp/sbt/test/scala-2.11/classes... [success] Total time: 1 s, completed Jun 2, 2015 1:18:36 PM sbt @ test $ run [info] Running org.example.Main [error] (run-main-1) java.lang.NoSuchMethodError: org.jfree.data.time.TimeTableXYDataset.add(Lorg/jfree/data/time/TimePeriod;Ljava/lang/Number;Ljava/lang/Comparable;Z)V java.lang.NoSuchMethodError: org.jfree.data.time.TimeTableXYDataset.add(Lorg/jfree/data/time/TimePeriod;Ljava/lang/Number;Ljava/lang/Comparable;Z)V at scalax.chart.module.RichChartingCollections$RichCategorizedTuple2s$$anonfun$toTimeTable$1$$anonfun$apply$4.apply(RichChartingCollections.scala:300) ... jfree:jfreechart版本。这是可能的,如果是这样的话?

我发现的另一个问题是jfree:jcommon出现如下错误(对于每个重复文件):

sbt-assembly

1 个答案:

答案 0 :(得分:2)

您需要在* .sbt或* .scala项目定义中定义mergeStragey in assembly以使用sbt-assembly命令。以下是一个示例。

mergeStrategy in assembly <<= (mergeStrategy in assembly) { (old) =>
  {
    case PathList("javax", "servlet", xs @ _*) => MergeStrategy.last
    case PathList("javax", "activation", xs @ _*) => MergeStrategy.last
    case PathList("org", "apache", xs @ _*) => MergeStrategy.last
    case PathList("com", "google", xs @ _*) => MergeStrategy.last
    case PathList("com", "esotericsoftware", xs @ _*) => MergeStrategy.last
    case PathList("com", "codahale", xs @ _*) => MergeStrategy.last
    case PathList("com", "yammer", xs @ _*) => MergeStrategy.last
    case "about.html" => MergeStrategy.rename
    case "META-INF/ECLIPSEF.RSA" => MergeStrategy.last
    case "META-INF/mailcap" => MergeStrategy.last
    case "META-INF/mimetypes.default" => MergeStrategy.last
    case "plugin.properties" => MergeStrategy.last
    case "log4j.properties" => MergeStrategy.last
    case x => old(x)
  }
}

如果您清楚知道导致问题的传递jar是什么,可以在libraryDependencies中将其排除。例如,我排除了httpclient jar直接依赖于play 2.3.6,这取决于更高版本的httpclient,这不是我想要的。

 "com.typesafe.play" %% "play" % "2.3.6" exclude("org.apache.httpcomponents", "httpclient") 

在您的情况下,您可以对引入此旧jar的直接依赖项exclude("jfree", "jfreechart")执行操作。