June 1, 2011

Groovy Goodness: Add Imports Transparently to Scripts with ImportCustomizer

Since Groovy 1.8.0 we can easily setup import statements for a Groovy compilation unit (for example a Groovy script file) without adding the imports to the script source. For example we have created domain classes in our own package. The script authors shouldn't know about the packages and just pretend the classes are accessible from the 'default' package.

We define an ImportCustomizer and use the addImport methods to add packages, classes, aliases to our script. The configured ImportCustomizer is added to a CompilerConfiguration object. We will see in future blog posts how we can even add more customizers to the CompilerConfiguration. We use the configuration when we create a GroovyShell and the information is applied to scripts we run with the created shell.

First we create a class and enum in the com.mrhaki.blog package. We compile the code so we have class files we can add to a classpath of another application.

// File: Post.groovy
// Compile with groovyc Post.groovy
package com.mrhaki.blog

class Post {
    String title
    Type type = Type.BLOG

enum Type {

Next we create a Groovy script that will execute the following code:

// File: sample.groovy
// Article is imported as alias for com.mrhaki.blog.Post
def article = new Article(title: 'Groovy Goodness')

assert article.title == 'Groovy Goodness'
// BLOG is statically imported from com.mrhaki.blog.Type.*
assert article.type == BLOG
assert article.class.name == 'com.mrhaki.blog.Post'

Now we are ready to create a small application that will execute sample.groovy. We must add the com.mrhaki.blog.Post and com.mrhaki.blog.Type compiled classes to the classpath if we run the following script:

// File: RunScript.groovy
// Run with groovy -cp . RunScript
import org.codehaus.groovy.control.customizers.ImportCustomizer
import org.codehaus.groovy.control.CompilerConfiguration

// Add imports for script.
def importCustomizer = new ImportCustomizer()
// import static com.mrhaki.blog.Type.*
importCustomizer.addStaticStars 'com.mrhaki.blog.Type'
// import com.mrhaki.blog.Post as Article
importCustomizer.addImport 'Article', 'com.mrhaki.blog.Post'

def configuration = new CompilerConfiguration()

// Create shell and execute script.
def shell = new GroovyShell(configuration)
shell.evaluate new File('sample.groovy')