'Customizing scripts execution in Groovy Shell' post illustration

Customizing scripts execution in Groovy Shell

avatar

When Groovy has grown up to version 2, it has gained a lot of brand new features and improvements in areas of productivity and security. Groovy now provides the ability to statically type check and statically compile your Groovy code for robustness and performance. This is very useful when you don't need Groovy's dynamic features, or simply want to speed up performance of your scripts.

Let's say, you're invoking Groovy scripts via GroovyShell within your application. You may want your scripts to be statically compiled in order to prevent any missing properties or methods passing to runtime, or may just want to speed up your system. For such purpose, you can make your own extension for groovy script files, and tell GroovyShell that you want it to statically compile all scripts with that extension.

Take a look at these lines of code:

StaticScript.sgroovy
1
2
3
4
5
6
7
8
class Greeter {
    // no methods
}

// Will result in MultipleCompilationException
Greeter.metaClass.greet = { String name -> println "Hello $name!" }
def greeter = new Greeter()
greeter.greet('John')
Main.groovy
1
2
3
4
5
6
7
8
9
10
11
12
13
...
def compilerConfiguration = new CompilerConfiguration()
CompilerCustomizationBuilder.withConfig(compilerConfiguration) {
    source(extensions: ['sgroovy']) {
        ast(CompileStatic)
    }
}
compilerConfiguration.setScriptExtensions(['groovy', 'sgroovy'] as Set<String>)
def groovyShell = new GroovyShell(compilerConfiguration)
...
def script = groovyShell.parse(scriptFile) // parsing script file StaticScript.sgroovy extension
script.run()  // running script
...

The following lines of code configure GroovyShell's behavior for files with *.sgroovy extension, so that these scripts will be compiled statically. This means that when you run your scripts with *.sgroovy extension using this modified GroovyShell – any undeclared variable, method or metaClass extending, etc. will result in MultipleCompilationException at compilation time!

Sometimes you may want your executed scripts to have some predefined methods, properties, classes or annotations. This can be done by creating an abstract class inherited from Script class. Assume, you want your script to return null instead of throwing MissingProperty/MissingMethod exception in situations when property or method doesn't exist. All you need is to set your custom Script class as a script base superclass in CompilerConfiguration and then apply it to GroovyShell.

Here's an example of how you can achieve this:

CustomScript.groovy
1
2
3
4
5
6
7
8
9
10
package org.sysgears.script

abstract class CustomScript extends Script {

    // here can go any other stuff (properties, methods, classes, etc.)

    def propertyMissing(String name) {
        null
    }
}
Main.groovy
1
2
3
4
5
6
7
...
def compilerConfiguration = new CompilerConfiguration()
compilerConfiguration.setScriptBaseClass('org.sysgears.script.CustomScript')
def groovyShell = new GroovyShell(compilerConfiguration)
...
Script script = groovyShell.parse(scriptFile) // scriptFile is a Script.groovy script
script.run()  // running script
Script.groovy
1
println person == null // prints true instead of throwing MissingPropertyException

Besides these features, you can do even more: customize imports, secure AST (allow/disallow closures creations, imports, package definition, definition of methods, etc.), and more.

Check out Groovy Official Documentation to stay in touch!

Cheers!

If you're looking for a developer or considering starting a new project,
we are always ready to help!