I have a multi-module SBT build consisting of api
, core
and third-party
. The structure is roughly this:
api
|- core
|- third-party
The code for third-party
implements api
and is copied verbatim from somewhere else, so I don't really want to touch it.
Because of the way third-party
is implemented (heavy use of singletons), I can't just have core
depend on third-party
. Specifically, I only need to use it via the api
, but I need to have multiple, isolated copies of third-party
at runtime. (This allows me to have multiple "singletons" at the same time.)
If I'm running outside of my SBT build, I just do this:
def createInstance(): foo.bar.API = {
val loader = new java.net.URLClassLoader("path/to/third-party.jar", parent)
loader.loadClass("foo.bar.Impl").asSubclass(classOf[foo.bar.API]).newInstance()
}
But the problem is that I don't know how to figure out at runtime what I should give as an argument to URLClassLoader
if I'm running via sbt core/run
.
This should work, though I didn't quite tested it with your setup.
The basic idea is to let sbt write the classpath into a file that you can use at runtime. sbt-buildinfo already provides a good basis for this, so I'm gonna use it here, but you might extract just the relevant part and not use this plugin as well.
Add this to your project definition:
lazy val core = project enablePlugins BuildInfoPlugin settings (
buildInfoKeys := Seq(BuildInfoKey.map(exportedProducts in (`third-party`, Runtime)) {
case (_, classFiles) ⇒ ("thirdParty", classFiles.map(_.data.toURI.toURL))
})
...
At runtime, use this:
def createInstance(): foo.bar.API = {
val loader = new java.net.URLClassLoader(buildinfo.BuildInfo.thirdParty.toArray, parent)
loader.loadClass("foo.bar.Impl").asSubclass(classOf[foo.bar.API]).newInstance()
}
exportedProducts
only contains the compiled classes for the project (e.g. .../target/scala-2.10/classes/
). Depending on your setup, you might want to use fullClasspath
instead
(which also contains the libraryDependencies and dependent projects) or any other classpath related key.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With