prayformojo
prayformojo

Reputation: 23

Dynamically loading Groovy scripts into app server

I have a Java Spring app running in Tomcat that is meant to perform various processing rules based on incoming files. Because the file types and rules change, I would like to use Groovy to dynamically load new/changed functionality without having to recompile/restart the Java application each time.

Following the "Dynamically loading and running Groovy code inside Java" from the Groovy documentation,

GroovyClassLoader gcl = new GroovyClassLoader();
Class clazz = gcl.parseClass(myStringwithGroovyClassSource, "SomeName.groovy");
Object aScript = clazz.newInstance();
MyInterface myObject = (MyInterface) aScript;
myObject.interfaceMethod();

I created my version of SomeName.groovy that implements MyInterface and modified my Java app to then create an instance of that class as shown above. I know that my Groovy file is being read correctly because if I print out myObject.getClass().toString it shows the correct object type as defined in SomeName.groovy; however, when it gets to point of calling one of the implemented methods (myObject.interfaceMethod()) it doesn't do anything.

I've tested this approach in a Java application outside of Tomcat and it worked so I'm uncertain as to why running this inside of an app server would cause it to break. Also, I've confirmed that groovy-all-2.1.8.jar is included in my project.

Thanks in advance for any information that you can provide that might shed some light on why the dynamic loading might be failing.

Thx.

Upvotes: 1

Views: 2767

Answers (1)

Roger Glover
Roger Glover

Reputation: 3256

The form of the parseClass() method that you are using does not look at any external file at all. Instead it treats the first String argument (myStringwithGroovyClassSource in your case) as if it were the text content of a Groovy source file, and the second String argument (the literal "SomeName.groovy" in your case) as if it were the name of that file. This method does not open or parse any ACTUAL file at all.

To make this code work as is you would have to predefine the variable myStringwithGroovyClassSource. The overall effect would look something like this:

def myStringwithGroovyClassSource = """
class SomeName implements MyInterface {
    def prop1 = 1, prop2 = 2
    def interfaceMethod() { println prop1 }
}
"""

interface MyInterface { def interfaceMethod() }
GroovyClassLoader gcl = new GroovyClassLoader()
Class clazz = gcl.parseClass(myStringwithGroovyClassSource, "SomeName.groovy")
Object aScript = clazz.newInstance()
MyInterface myObject = (MyInterface) aScript
myObject.interfaceMethod()

Now, on the other hand, if, as you say, you already have an external uncompiled Groovy source file named SomeFile.groovy that you wish to bring into your script via the GroovyClassLoader, then you need to change your existing code to something like this:

interface MyInterface { def interfaceMethod() }
GroovyClassLoader gcl = new GroovyClassLoader()
Class clazz = gcl.parseClass("SomeName.groovy" as File)
Object aScript = clazz.newInstance()
MyInterface myObject = (MyInterface) aScript
myObject.interfaceMethod()

If the code in the file is valid-when-compiled, then you should have no trouble getting this to work.

Upvotes: 3

Related Questions