Executing Groovy Programs in-memory

Now that we've gone over some Groovy[2]basics[3], it's time to switch back to writing in the Java language, and talk about how to run Groovy programs inside your Java programs. Like most general purpose programming languages, there's more than one way to do things in Groovy, and that's never more true when it comes to executing Scripts - I once counted 7 ways to use the String "System.exit(0)" to shut down the VM, and I'm quite sure that I missed a few. For this example, we'll use the method I consider to be the best and most extensible, which uses the class GroovyShell.

Before we get started, be sure to include the Groovy libraries in your Java class path, so that you can use the same classes as Groovy. In the current distro, it's the file named groovy-all.jar. Once that's there, you should be able to execute the following code:

I won't bother including the surrounding cruft in the future, but wanted to illustrate that this is just a (very) simple Java program. We create a GroovyShell object, and call the evaluate method on it, passing a String. That String, in turn, is evaluated by the Groovy parser, a class is (invisibly) created, and the class is run - the end result is that "hello world" is printed to std out.

There's a problem with this code though - it's kinda slow. About 10ms on my machine (for a warm run, where all the required classes are already loaded and initialized - the initialization is actually 300ms, but that's a one time hit). Now, that might be perfectly acceptable for your application - but if you're going to be executing this thing multiple times, that could really add up in a multiuser environment. One of the things that's happening here is a full compile of the generated script code. And while compiler technology has certainly gotten faster in the last few years, it'd be nice to skip that step on occasion. The GroovyShell API offers a way to separate out the compilation and execution steps.

Here, we've separated out the compile phase from the run phase. The compile phase still takes 10ms, but the run phase only takes whatever the Java class run time is. In this case, it's a sub 1ms run time. This separation also opens things up for us to use other APIs as well, and we're going to use this technique going forward.

Under the hood, here's what's happening: Groovy is taking your input String, and converting it into a class, of type Script. Script contains a method, run. The contents of that run method are populated with the parsed contents of the String you pass in as an argument. So, when we call script.run(), the println method is called, which prints out the message. One last important note is that the run method actually returns Object - so we can also use these scripts to compute values. And if you don't specify a return, the final statement executed in the script will be automatically returned as the value. Thus, if the final line in your script is "x < y", the run method will return a Boolean equal to whatever the result of the comparison is. You can also define inline methods (as we did in the intro post I did[2]), and those methods will be placed on the generated Script - you can even access those methods via reflection.