I have implemented a custom class loader in Scala that serves to isolate plugins from the main application. At present I require a Java interface to act as the shared root object so my main application can use the plugin code.
Interface acting as shared root (I would like this to be Scala):
public interface Handler {
public List<HandlerInfo> getHandlers();
}
Example plugin:
class MyPlugin extends Handler {
def getHandlers: java.util.List[HandlerInfo] = // get some handlers
}
Usage in application:
val jarFile = new File(System.getProperty("user.dir") + "/plugins/" + jarName)
val cl = new PluginLoader(jarFile, this.getClass.getClassLoader) // my custom classloader
val classToLoad = Class.forName(className, true, cl)
val handler = classToLoad.newInstance.asInstanceOf[Handler]
val handlers = handler.getHandlers
This works fine, but my problem is that I have to keep this one Java class around (and the resulting build configuration). I would like instead to use a Scala trait or abstract class, like this:
trait Handler {
def getHandlers : List[HandlerInfo]
}
Then my plugin could look like this:
class MyPlugin extends Handler {
def getHandlers: List[HandlerInfo] = // no more java.util.List
}
But I can’t do this, because this line
val handler = classToLoad.newInstance.asInstanceOf[Handler]
throws a ClassCastException, presumably because the Scala compiler doesn’t generate a nice clean Java interface. Is there any way around this, so I can have a Scala-only project?
The problem is not where you think it is; it’s somewhere in your class loader. The default class loader works just fine, even the Java one. Evidence:
And here we run it:
with the Scala
Listand everything, and the new class loaded by the default Java class loader.