исключить конкретную транзитивную зависимость в sbt

Предположим, небольшой тестовый проект (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

Проблема заключается в зависимости jfreechart, которую втягивают как scala-chart, так и itext (то же самое касается jcommon, но я сосредоточусь на jfreechart). Однако немного более старая версия, которую подтягивает itext, использует другое название организации (jfree против org.jfree).

Обычно, если они будут использовать одну и ту же организацию, более старая будет выселена (как это сделано в примере с xml-apis), и конфликтов не будет, пока существует двоичная совместимость.

Настоящий конфликт сейчас заключается в том, что обе зависимости jfree:jfreechart и org.jfree:jfreechart находятся в пути к классам и предоставляют одни и те же классы. Компиляция работает нормально и sbt даже не жалуется. Возьмите, например, следующий пример App:

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 выбирает, какую зависимость использовать. Все взорвется, если вы попытаетесь запустить эту штуку:

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 с ошибками, подобными приведенным ниже (для каждого повторяющегося файла):

[error] deduplicate: different file contents found in the following:
[error] /home/wookietreiber/.ivy2/cache/jfree/jfreechart/jars/jfreechart-1.0.12.jar:org/jfree/data/KeyedValues2D.class
[error] /home/wookietreiber/.ivy2/cache/org.jfree/jfreechart/jars/jfreechart-1.0.17.jar:org/jfree/data/KeyedValues2D.class

person Christian Krause    schedule 02.06.2015    source источник
comment
Я только что воссоздал другую ситуацию, когда она взрывается: я получаю java.lang.NoSuchMethodError, потому что sbt фактически использует старую версию jfree:jfreechart для компиляции, в которой отсутствует метод, который есть в org.jfree:jfreechart, который включается в scala-chart.   -  person Christian Krause    schedule 02.06.2015


Ответы (1)


Для работы с командой sbt-assembly необходимо указать mergeStragey in assembly в определении проекта * .sbt или * .scala. Ниже приведен образец.

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 вызывает проблему, вы можете исключить его в своей библиотекеDependencies. Например, я исключил httpclient jar из моей прямой зависимости от play 2.3.6, которая зависит от более высокой версии httpclient, а это не то, что я хотел.

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

В вашем случае вы можете сделать exclude("jfree", "jfreechart") свою прямую зависимость, которая представила эту старую банку.

person Wesley Miao    schedule 02.06.2015
comment
Спасибо, это определенно поможет с проблемой, связанной с sbt-assembly, но не с более общей проблемой. У вас есть идеи на этот счет? - person Christian Krause; 02.06.2015
comment
Какой у вас общий вопрос? - person Wesley Miao; 03.06.2015
comment
как удалить эту конкретную зависимость глобально в sbt, а не только для sbt-assembly - person Christian Krause; 03.06.2015