The title could also be:
What are the differences between Maven and SBT assembly plugins.
I have found this to be an issue, while migrating a project from Maven to SBT.
To describe the problem I have created an example project with dependencies that I found to behave differently, depending on the build tool.
https://github.com/atais/mvn-sbt-assembly
The only dependencies are (sbt style)
"com.netflix.astyanax" % "astyanax-cassandra" % "3.9.0",
"org.apache.cassandra" % "cassandra-all" % "3.4",
and what I do not understand is, why mvn package
creates the fat jar successfully, while sbt assembly
gives conflicts:
[error] 39 errors were encountered during merge
[error] java.lang.RuntimeException: deduplicate: different file contents found in the following:
[error] /home/siatkowskim/.ivy2/cache/org.slf4j/jcl-over-slf4j/jars/jcl-over-slf4j-1.7.7.jar:org/apache/commons/logging/<some classes>
[error] /home/siatkowskim/.ivy2/cache/commons-logging/commons-logging/jars/commons-logging-1.1.1.jar:org/apache/commons/logging/<some classes>
...
[error] /home/siatkowskim/.ivy2/cache/com.github.stephenc.high-scale-lib/high-scale-lib/jars/high-scale-lib-1.1.2.jar:org/cliffc/high_scale_lib/<some classes>
[error] /home/siatkowskim/.ivy2/cache/com.boundary/high-scale-lib/jars/high-scale-lib-1.0.6.jar:org/cliffc/high_scale_lib/<some classes>
...
Extension to Alexey Romanov answer.
I have also updated my project with detailed explanation, so you might want to check it out.
Following the advice
I compared the
fat-jars
produced bymaven
andsbt
withMergeStrategy.first
, that showed some extra filesMergeStrategy.last
, that showed binary differences & extra filesI have taken the next step and checked the
fat-jars
against the dependenciessbt
found conflicts at, specifically:Conclusion
maven-assembly-plugin
resolves conflicts onjar
level. When it finds any conflict, it picks the firstjar
and simply ignores all the content from the other.Whereas
sbt-assembly
mixes all theclass
files, resolving conflicts locally, file by file.My theory would be, that if your
fat-jar
made withmaven-assembly-plugin
works, you can specifyMergeStrategy.first
for all the conflicts insbt
. They only difference would be, that thejar
produced withsbt
will be even bigger, containing extra classes that were ignored bymaven
.It seems
maven-assembly-plugin
resolves conflictsequivalently toby just picking one of the files in an unspecified way whenMergeStrategy.first
(not sure if it's completely equivalent)jar-with-dependencies
is used (since it only has one phase):Even if one of the conflicting files would work for all of your dependencies (which isn't necessarily so), Maven doesn't know which one, so you can just silently get the wrong result. Silently at build-time, I mean; at runtime you can get e.g.
AbstractMethodError
, or again just a wrong result.You can influence which file gets picked by writing your own descriptor, but it's horribly verbose, there's no equivalent to just writing
MergeStrategy.first/last
(andconcat
/discard
are not allowed).The SBT plugin could do the same: default to a strategy when you don't specify one, but then, well, you could silently get the wrong result.
From the build.sbt I can see that their is no Merge-Strategy in you build. Plus there is a Rogue "," in your libraryDependencies Key placed after the dependency of "org.apache.cassandra" % "cassandra-all" % "3.4" in your build.sbt in the project to which the link you have shared above.
A merge strategy is required to handle all the duplicate files and in the jar as well as versions. The following one is an example of how to get one in place in your build.
You could try writing a simple build file if you do not have sub-projects in your project. You can try the following build.sbt.