How to solve transitive dependencies version conflicts (scala/sbt) - scala

I have a project with several utility classes. Let's name it Utils.
I have a proj1 which depends on Utils. And another proj2 that depends on proj1 and Utils.
The problem is if both proj1 and proj2 depend on different Utils version this will lead to problems.
What's the best solution?
This situation occurs in Scala/SBT projects, but I guess other languages have the same problems.
Edit:
Just to be clear, proj2 is the project that will run, that uses some code from proj1 and Utils.

This is classic Jar Hell, and it is a problem on any JVM based project not just scala with sbt.
There are 4 common solutions
Get rid of conflict by changing code, consolidate your multiple version dependency into a single dependency.
Shading (as mentioned above by #Sean Viera)
Multiple ClassLoader component architecture like OSGI (as mentioned by #tuxdna)
Run in separate JVMs like a microservice architecture (also mentioned by #tuxdna)

You have three different projects:
Utils
proj1 <- depends on Utils v1
proj2 <- depends on Utils v2
The only way you can be 100% sure that there are no conflicts between proj1 and proj2 is to run them in isolation.
As soon as you will mix proj1 and proj2 with different versions of Utils on the same classpath, you will end up override one or the other project.
You can achive isolation using:
run them in separate JVMs, with appropriate version of Utils
run them in same JVM but in different class loaders

Related

Dependency conflicts in scala multi moduled projects

I have below structure for the project.
project
|_build.properties
|_plugins.sbt
Core
Module1
Module2
build.sbt
In Module1 and Module2, I use the same dependency in different versions. Then I aggregate the 2 modules with Core module. Then one dependency is getting evicted by another version. How do I keep both dependency versions?
Update: The expected dependency tree is as follows:
core_1.0-SNAPSHOT
-module1_1.0
--org.milyn:milyn-smooks-core:1.1
-module2_1.0
--org.milyn:milyn-smooks-core:1.5.2
module1_1.0-SNAPSHOT
-org.milyn:milyn-smooks-core:1.1
module2_1.0-SNAPSHOT
-org.milyn:milyn-smooks-core:1.5.2
And, what I getting is as follows:
core_1.0-SNAPSHOT
-module1_1.0
--org.milyn:milyn-smooks-core:1.1 (evicted by 1.5.2)
-module2_1.0
--org.milyn:milyn-smooks-core:1.5.2
module1_1.0-SNAPSHOT
-org.milyn:milyn-smooks-core:1.1
module2_1.0-SNAPSHOT
-org.milyn:milyn-smooks-core:1.5.2
How can I disregard the eviction?
In 99% of cases you don't want to have two versions of the same dependency. Assuming they contain same classes (as in the same name), it will cause runtime errors as only one version will be loaded (first come, first loaded).
What you likely want to do is:
either let the eviction do its work (it should pick up most recent version)
or, define the same version across all your modules
or, define some dependencyOverrides in your "Core" module to force a version (which can be the one of "Module1", "Module2", or even another one)

sbt-assembly multimodule project?

My project is separated on multiple parts:
* core project
* utils (as example) project
Both of them have some unit-tests, and "core project" relies on code in "utils" project by "dependsOn" mechanism of sbt.
I am using sbt-assembly plugin for building "uber-jar"/"fat-jar", but sbt assembly task does`t run test on utils project - which is what I am trying to achieve (I can not see any tests from "utils project" in logs)
Changing "dependsOn" to "aggregate" introduce new problem:
sbt assembly aggregate deduplicate
something similar to this issue-on-github
So my question is how to organize multimodule project which can be assembled by sbt-assembly and all of the tests are executed during assembly task?
My guess is that you should have both dependsOn and aggregate relationships between your subprojects. They are not mutually exclusive, only serve different purposes.
DependsOn introduces code dependency, so if core depends on utils it means that you can reference types from utils in core.
Aggregate introduces task dependency. That means if you execute compile or test on core and it aggregates utils then the task will be executed on both subprojects.
Problems with deduplicate are another beast - it means, that there are duplicates in resources or classes when attempting to create one jar. The reasons for this may be various and you can tackle them by verifying the library dependencies in the build or creating MergeStrategy - https://github.com/sbt/sbt-assembly#merge-strategy

Unit testing SBT code within the local project

I have an SBT project, within which I have defined a source generator that parses some DB migration scripts in order to make the current DB version available to the application at compile-time.
For example, I might have the following resources:
subproject1/src/main/resources/db/migration/
|- V1__Baseline.sql
|- V2__AddCustomerTable.sql
|- V2_1__Refactor.sql
And I would require my source generator to create a scala object with the field val version = "2.1".
The SBT project is structured as:
project/
|- build.sbt
|- SchemaVersionParser.scala
Where SchemaVersionParser defines the utility functions that are used by build.sbt in order to parse the resources and generate the appropriate file.
Now since this is a key component of my app, I'd like to ensure that the functions in SchemaVersionParser which extract and sort the versions are unit tested.
Is there any supported means of unit testing SBT code residing locally in the one project? I know I can do this if I create a separate SBT plugin, however it'd be nice if I could avoid this.
SBT build definitions are SBT projects. So put test code in project/src/test/scala should be able to access SchemaVersionParser, and to launch the tests you just do sbt test in project directory.

How to find unused sbt dependencies?

My build.sbt has a lot of dependencies now. How do I know which dependencies are actually being used?
Maven seems to have dependency:analyse http://maven.apache.org/plugins/maven-dependency-plugin/
Is there something similar for sbt?
There is the sbt-explicit-dependencies plugin, which has been developed recently. It has direct commands in the SBT console to:
Enforce explicit direct declaration of dependencies, thus disallowing transitive dependencies.
Detect and remove unneeded dependencies.
you can use sbt-dependency-graph plugin. it shows dependencies in different graphical representations. also you can try to use tattletale, but it's not integrated with sbt. it'll require you to copy managed dependencies (retrieveManaged := true). this tool not only shows dependency graph, but analyzes class usage and can display unused dependencies (including transitive)

How do I use shared configurations across SBT (Play) multi-projects?

I have several SBT 0.13 / Play 2.2 projects (websites). They are all multi-module as they share some common functionality. This makes their project configuration files both complex and almost identical, but not quite.
I would like to be able to share as much as possible of these configuration files across the projects (frequent play updates makes keeping 5+ websites up to date a royal pain, not to mention all the almost-identical-but-evolving dependency lists across the projects).
build.properties and plugins.sbt are identical across projects and can be overwritten by a simple script. Great.
Build.scala is trickier - I would like to introduce a shared base class like so:
abstract class MyBuildBase extends Build { ... }
that in Build.scala do:
object ApplicationBuild extends MyBuildBuild { ... }
In order for this to make any sense at all, MyBuildBase.scala needs to be shared across projects. This can be done with svn:external, which operates on directories. Which means I need to somehow make this shared directory accessible when Build.scala is compiled (otherwise sbt complains loudly).
Reading http://www.scala-sbt.org/0.13.0/docs/Detailed-Topics/Classpaths.html and http://www.scala-sbt.org/0.13.0/docs/Getting-Started/Full-Def.html it seems like this should be possible.
However, it is exceptionally unclear to me what to actually put in the project/project/Build.scala file to actually achieve this - I can't find an example of "an sbt build file that's intended to build an sbt build file and include some extra source files in the build".
Any suggestions?
What you probably want to do is create a plugin, or shared library.
You can make an sbt project with a build like follows:
build.sbt
sbtPlugin := true
organization := "you"
name := "common-build"
version := "1.0"
Then create in src/main/scala your abstract class "MyBuildBase". Release this project as an sbt plugin.
Then in your other projects, you can use this as a library/plugin. In project/plugins.sbt add:
addSbtPlugin("you" % "common-build" % "1.0")
And this will resolve your common build library when building your build.
If you need more information, look up more about sbt plugins and ignore the part about making something that extends a Plugin. Plugins are just libraries versioned with sbt's version number and your own. You should be able to put whatever code you want in there to share between builds.
Note: in 2016, Build.scala is deprecated for Build.sbt.
Here is the new (Dec. 2016) multi-module with App Scala sbt template by Michael Lewis.
Usage
sbt new lewismj/sbt-template.g8
You can then run:
sbt compile
sbt publish-local
sbt assembly
It is based on Scala SBT template (Library)
This giter8 template will write SBT build files for a Scala library.