Reputation: 16387
I have an SBT Plugin and in this plugin I want to instantiate classes that were compiled as part of the compile step.
Essentially, think of my plugin as doing this:
classOf[com.skamuel.Dummy].newInstance
where Dummy is a class compiled by the build.
But when I try this, I get class not found exception. I can execute the above code in the console after executing the compile task, just not as part of a plugin.
So, what classpath magic do I need to do to get the above to work?
Upvotes: 1
Views: 291
Reputation: 13749
Your plugin can use runtime class path of the compiled project to which it is added, but it cannot use it at the compile time. This is logical I guess, your plugin exists without knowing of your project.
Given that you could use the mentioned class like this:
import sbt._
import Keys._
import classpath._
object MyPlugin extends Plugin {
val createClass = taskKey[Unit]("Creates new instance of a class")
lazy val myPluginSettings = inConfig(Compile)(Seq(
createClass := {
// we need to make sure the class we want to use is compiled
val analysis = (compile in Compile).value
// create custom class loader from the output of compile plus other deps
val classpath = (fullClasspath in Compile).value.map(_.data)
val loader = ClasspathUtilities.makeLoader(classpath, scalaInstance.value)
val myClass = Class.forName("com.stackoverflow.lpiepiora.MyClass", true, loader).newInstance
println(myClass.asInstanceOf[{def helloWorld(): String}].helloWorld())
}
))
}
The problem is that you cannot do much with the class, as plugin cannot cast it directly to the type - it doesn't know it.
I'm using structural type for the example, as I have my class defined as
package com.stackoverflow.lpiepiora
class MyClass {
def helloWorld(): String = "Hello World"
}
You can also check the complete, working example in my GitHub repository
Upvotes: 2