I know I have to be doing something just brain-dead stupid for this not to work, but I'm in a situation where I want to dynamically load behavior into a running server. I chose groovy as my tool to do this. The behavior will need to reference classes on the server's classpath, such as my model objects as well as third party libraries like Freemarker.
I threw together this silly POC to show feasibility. I can't get the groovy script to resolve the Java classes "ThingyDoodle" and "Fooable", in spite of the fact that I am setting the parent classpath of the GroovyClassPath to be my current.
public class GroovyTest
{
public static void main ( String [ ] argv ) throws Throwable
{
// Setting parent classloader!
// also tried plain old "GroovyTest.class.getClassLoader()" as well
GroovyClassLoader gcl = new GroovyClassLoader ( Thread.currentThread().getContextClassLoader() ) ;
String src =
"class Arf implements Fooable {
public String foo ( ) {
return new ThingyDoodle().doStuff('Arf');}}" ;
Class clazz = gcl.parseClass(src, "AppleSauce.groovy");
Object aScript = clazz.newInstance();
Fooable myObject = (Fooable) aScript;
System.out.println ( myObject.foo() ) ;
}
public static interface Fooable { public String foo ( ) ; }
public static class ThingyDoodle
{
public String doStuff ( String input )
{
return "Hi Worlds" ;
}
}
}
What the heck am I doing wrong here?
Exception in thread "main" org.codehaus.groovy.control.MultipleCompilationErrorsException: startup failed:
AppleSauce.groovy: 1: unable to resolve class Fooable
@ line 1, column 1.
class Arf implements Fooable { public String foo ( ) { return new ThingyDoodle().doStuff('Arf');}}
^
AppleSauce.groovy: 1: unable to resolve class ThingyDoodle
@ line 1, column 63.
ublic String foo ( ) { return new Thingy
^
解决方案
The problem in your code is that the Fooable interface and ThingyDoodle class cannot be found because they're both internal classes and need to be qualified with the containing class name, i.e. GroovyTest. I qualified both names in the embedded script (and fixed the quotes around the script) and it ran as expected.
import groovy.lang.GroovyClassLoader;
public class GroovyTest
{
public static void main ( String [ ] argv ) throws Throwable
{
// Setting parent classloader!
// also tried plain old "GroovyTest.class.getClassLoader()" as well
GroovyClassLoader gcl = new GroovyClassLoader ( Thread.currentThread().getContextClassLoader() ) ;
String src =
"class Arf implements GroovyTest.Fooable { " +
"public String foo ( ) { " +
"return new GroovyTest.ThingyDoodle().doStuff('Arf');}}" ;
Class clazz = gcl.parseClass(src, "AppleSauce.groovy");
Object aScript = clazz.newInstance();
Fooable myObject = (Fooable) aScript;
System.out.println ( myObject.foo() ) ;
}
public static interface Fooable { public String foo ( ) ; }
public static class ThingyDoodle
{
public String doStuff ( String input )
{
return "Hi Worlds" ;
}
}
}