Create über-jar containing dependent libraries with sbt-assembly
scalasbt-assembly is a sbt plugin to create über-jar (fat-jar) containing dependent libraries.
$ cat peojcts/plugins.sbt
addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "2.1.1")
$ sbt assembly
$ java -jar ./target/scala-2.13/sbt-assembly-test-0.1.0-SNAPSHOT.jar
Hello world!
If multiple JARs, including the dependencies of the dependent library, contain files with the same path and the contents are different, “Deduplicate found different file contents” errors occur. In that case, set how to resolve it in assemblyMergeStrategy.
$ cat build.sbt
...
libraryDependencies += "software.amazon.awssdk" % "s3" % "2.20.14"
ThisBuild / assemblyMergeStrategy := {
case PathList("META-INF", xs @ _*) => MergeStrategy.discard
case x =>
val oldStrategy = (ThisBuild / assemblyMergeStrategy).value
oldStrategy(x)
}
If the number of conflicted files is too large to resolve, you can exclude them from the über-jar with assemblyExcludedJars and place them to the classpath and load them at runtime, but there is a possibility that it will cause errors for compatibility.
assembly / assemblyExcludedJars := {
(assembly / fullClasspath).value.filter { _.data.getName.contains("testlib") }
}
val outputExcludedJar = taskKey[Seq[File]]("Output jars that is excluded from the uber jar")
outputExcludedJar := {
val targetDir = (assembly / Keys.target).value
val assemblyJAR = (assembly / assemblyOutputPath).value
val libraryJARs = (assembly / update).value matching configurationFilter(Runtime.name)
val exludedJARs = libraryJARs.filter { jar => (assembly / assemblyExcludedJars).value.map(_.data).contains(jar) }
IO.createDirectory(targetDir)
exludedJARs.foreach { jar =>
IO.copyFile(jar, targetDir / jar.getName)
}
Seq(assemblyJAR) ++ (targetDir ** "*.jar").get
}
assembly := assembly.dependsOn(outputExcludedJar).value
Besides, if some libraries exist in the execution environment, you can avoid them being contained in the JAR with “provided”, and when running it locally, you can contain them in the following way.
$ cat build.sbt
...
libraryDependencies += "software.amazon.awssdk" % "s3" % "2.20.14" % "provided"
Compile / run := Defaults.runTask(Compile / fullClasspath, Compile / run / mainClass, Compile / run / runner).evaluated
$ sbt run