Jak zbudować Uber JAR (Fat JAR) za pomocą SBT w IntelliJ IDEA?

92

Używam SBT (w IntelliJ IDEA) do zbudowania prostego projektu Scala.

Chciałbym wiedzieć, jaki jest najprostszy sposób na zbudowanie pliku JAR Ubera (inaczej Fat JAR, Super JAR).

Obecnie używam SBT, ale podczas przesyłania mojego pliku JAR do Apache Spark pojawia się następujący błąd:

Wyjątek w wątku „main” java.lang.SecurityException: Nieprawidłowe podsumowanie pliku podpisu dla głównych atrybutów manifestu

Lub ten błąd podczas kompilacji:

java.lang.RuntimeException: deduplicate: inna zawartość pliku znaleziona w następującym:
PATH \ DEPENDENCY.jar: META-INF / DEPENDENCIES
PATH \ DEPENDENCY.jar: META-INF / MANIFEST.MF

To wygląda to dlatego, że niektóre z moich uzależnień zawierać pliki sygnatur (meta-inf), która musi być usunięta w końcowym Uber pliku JAR.

Próbowałem użyć wtyczki sbt-assembly w następujący sposób :

/project/assembly.sbt

addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "0.12.0")

/project/plugins.sbt

logLevel := Level.Warn

/build.sbt

lazy val commonSettings = Seq(
  name := "Spark-Test"
  version := "1.0"
  scalaVersion := "2.11.4"
)

lazy val app = (project in file("app")).
  settings(commonSettings: _*).
  settings(
    libraryDependencies ++= Seq(
      "org.apache.spark" %% "spark-core" % "1.2.0",
      "org.apache.spark" %% "spark-streaming" % "1.2.0",
      "org.apache.spark" % "spark-streaming-twitter_2.10" % "1.2.0"
    )
  )

Kiedy klikam „ Build Artifact ... ” w IntelliJ IDEA, otrzymuję plik JAR. Ale kończy się z tym samym błędem ...

Jestem nowy w SBT i niezbyt eksperymentowałem z IntelliJ IDE.

Dzięki.

Yves M.
źródło
2
Przez dźwięk rzeczy może trzeba odfiltrować META-INFpliki - jeden blogu, że może pomóc: janschulte.wordpress.com/2014/03/20/...
Sean Vieira

Odpowiedzi:

147

Wreszcie całkowicie pomijam używanie IntelliJ IDEA, aby uniknąć generowania hałasu w moim globalnym rozumieniu :)

Zacząłem czytać oficjalny poradnik SBT .

Stworzyłem swój projekt o następującej strukturze plików:

my-project/project/assembly.sbt
my-project/src/main/scala/myPackage/MyMainObject.scala
my-project/build.sbt

Dodano wtyczkę sbt-assembly w moim pliku assembly.sbt . Pozwalając mi zbudować gruby JAR:

addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "0.12.0")

Mój minimal build.sbt wygląda następująco:

lazy val root = (project in file(".")).
  settings(
    name := "my-project",
    version := "1.0",
    scalaVersion := "2.11.4",
    mainClass in Compile := Some("myPackage.MyMainObject")        
  )

val sparkVersion = "1.2.0"

libraryDependencies ++= Seq(
  "org.apache.spark" %% "spark-core" % sparkVersion % "provided",
  "org.apache.spark" %% "spark-streaming" % sparkVersion % "provided",
  "org.apache.spark" %% "spark-streaming-twitter" % sparkVersion
)

// META-INF discarding
mergeStrategy in assembly <<= (mergeStrategy in assembly) { (old) =>
   {
    case PathList("META-INF", xs @ _*) => MergeStrategy.discard
    case x => MergeStrategy.first
   }
}

Uwaga : % "provided"środki, aby nie uwzględniać zależności w ostatecznym grubym pliku JAR (te biblioteki są już uwzględnione w moich plikach roboczych)

Uwaga : odrzucanie META-INF zainspirowane tą odpowiedzią .

Uwaga : znaczenie %i%%

Teraz mogę zbudować mój gruby JAR za pomocą SBT ( jak go zainstalować ), uruchamiając następujące polecenie w folderze głównym mojego / my-project :

sbt assembly

Mój gruby plik JAR znajduje się teraz w nowym folderze wygenerowanym / docelowym :

/my-project/target/scala-2.11/my-project-assembly-1.0.jar

Mam nadzieję, że to pomoże komuś innemu.


Dla tych, którzy chcą wprowadzić SBT do IntelliJ IDE: Jak uruchamiać zadania składania sbt z poziomu IntelliJ IDEA?

Yves M.
źródło
2
Sugestia Java / Maven dotycząca [problemu z wykluczeniem Sparka z uber-jars z Databricks databricks.gitbooks.io/databricks-spark-knowledge-base/content/…
JimLohse
1
Jaki jest powód odrzucenia starego META-INF?
Qed
2
Uwaga:% „dostarczone” oznacza, że ​​nie uwzględniaj zależności w końcowym pliku JAR z tłustym plikiem, który mi pomógł!
Jayasagar
poważnie zaskoczony, że jest to jedyny plugin dostępny - nawet oficjalne, a nawet nie jest praca całej wersjach SBT
Abhinandan DUBEY
40

3-etapowy proces tworzenia Uber JAR / Fat JAR w IntelliJ Idea:

Uber JAR / Fat JAR : plik JAR zawierający wszystkie zewnętrzne zależności bibliotek.

  1. Dodanie wtyczki SBT Assembly w IntelliJ Idea

    Plugin sbt Path

    Przejdź do pliku ProjectName / project / target / plugins.sbt i dodaj tę linięaddSbtPlugin("com.eed3si9n" % "sbt-assembly" % "0.12.0")

  2. Dodawanie strategii scalania, odrzucania i nie dodawania w pliku build.sbt

    Zbuduj ścieżkę SBT

    Przejdź do pliku ProjectName / build.sbt i dodaj strategię pakowania pliku JAR Uber

    Strategia scalania: Jeśli występuje konflikt między dwoma pakietami dotyczącymi wersji biblioteki, to który z nich należy spakować w Uber JAR.
    Odrzuć strategię: aby usunąć niektóre pliki z biblioteki, których nie chcesz pakować do Uber JAR.
    Nie dodawaj strategii: Nie dodawaj żadnego pakietu do Uber JAR.
    Na przykład: spark-corebędzie już obecny w Twoim Spark Cluster, więc nie powinniśmy tego pakować w Uber JAR

    Podstawowy kod strategii scalania i odrzucania strategii:

    assemblyMergeStrategy in assembly := { case PathList("META-INF", xs @ _*) => MergeStrategy.discard case x => MergeStrategy.first }

    Więc prosisz o odrzucenie plików META-INF za pomocą tego polecenia, MergeStrategy.discarda dla pozostałych plików pobierasz pierwsze wystąpienie pliku biblioteki, jeśli wystąpi konflikt za pomocą tego polecenia MergeStrategy.first.

    Nie dodawaj podstawowego kodu strategii:

    libraryDependencies += "org.apache.spark" %% "spark-core" % "1.4.1" %"provided"

    Jeśli nie chcemy dodawać iskiernika do naszego pliku JAR Ubera, ponieważ będzie on już na naszym sprzęcie, dodajemy % "provided"na końcu zależność od biblioteki.

  3. Tworzenie Uber JAR ze wszystkimi jego zależnościami

    sbtassembly

    W typie terminala sbt assemblydo tworzenia pakietu


Voila !!! Uber JAR jest zbudowany. JAR będzie w ProjectName / target / scala-XX

JarBuilt

Ajay Gupta
źródło
16

Dodaj następujący wiersz do swojego projektu / plugins.sbt

addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "0.12.0")

Dodaj następujące elementy do pliku build.sbt

mainClass in assembly := some("package.MainClass")
assemblyJarName := "desired_jar_name_after_assembly.jar"

val meta = """META.INF(.)*""".r
assemblyMergeStrategy in assembly := {
  case PathList("javax", "servlet", xs @ _*) => MergeStrategy.first
  case PathList(ps @ _*) if ps.last endsWith ".html" => MergeStrategy.first
  case n if n.startsWith("reference.conf") => MergeStrategy.concat
  case n if n.endsWith(".conf") => MergeStrategy.concat
  case meta(_) => MergeStrategy.discard
  case x => MergeStrategy.first
}

Strategia scalania zestawów służy do rozwiązywania konfliktów występujących podczas tworzenia słoika tłuszczu.

ARMV
źródło
1
Możesz stworzyć gruby Jar, uruchamiając "sbt assembly" w konsoli
ARMV
2
dla wersji scala 2.11.8 (wersja SBT: 0.13.12) umieść addSbtPlugin ("com.eed3si9n"% "sbt-assembly"% "0.12.0") w project / assembly.sbt
ARMV