Groovy Application Utilizing Spring IoC Example

With the latest performance enhancements and great dynamic, functional, and metaprogramming features, Groovy is a very good choice not only for scripting but also for building large, complex applications. Long-term complex application development requires extensive unit testing to enable progress without breaking existing features. Groovy plays nicely with the powerful Spring framework, which can be used to make an application easily extensible and unit-test-friendly.

In this article, we will use the latest approaches to inversion of control with the powerful Spring Framework, unit testing, and build tool usage to show how to build a good architecture for a non-trivial Groovy application.

Let’s take a look at the Main class of the application:

Main.groovy

/**
 * Main class of the application that uses Spring framework
 * and JSR 330 annotations for dependency injection.
 */
class Main
{
    /**
     * Launches the application.
     * 
     * @param args command line arguments
     */
    public static void main(final String[] args) {

        // Use Spring annotation-based dependency injection
        def ctx = new AnnotationConfigApplicationContext()
       
        // Parse command line parameters and push
        // all the external configuration to application environment 
        def appProps = new MapPropertySource("appProps", [
                greetInfo: new GreetInfo(text: "Hello",
                        name: args.length > 0 ? args[0] : "world")
        ] as Map<String, Object>)

        // Push environment properties to Spring application context 
        ctx.getEnvironment().getPropertySources().addFirst(appProps);

        // Point Spring to IoC configuration of the application
        ctx.register(AppConfig.class);
        
        // Wire dependencies 
        ctx.refresh();

        // Register hook to close application context on JVM shutdown
        ctx.registerShutdownHook()

        // Launch the application
        def app = ctx.getBean(Application.class)

        app.run()
    }

}

Here we configure Spring to use XML-less annotation-based dependency injection. The IoC configuration is located in the AppConfig.class. After that, we instantiate the Application bean using Spring and pass control to it by calling the run method.

The most interesting place in the code is the environment initialization. The Environment is a relatively new feature added in Spring 3.1. The environment allows the Spring application context to be configured using values from external sources. Here, we push command-line arguments into the environment so that they will be available in different parts of our application later. We use MapPropertySource for this purpose. It lets pass a dictionary of arbitrary Objects into the environment.

Let’s take a look at our AppConfig now:

/**
 * IoC configuration of application.
 */
@Configuration
@ComponentScan(basePackages = "com.sysgears.example",
        scopeResolver = Jsr330ScopeMetadataResolver.class)
class AppConfig {

    private @Inject Environment env
    
    public @Bean GreetInfo createGreetInfo() {
        env.getProperty("greetInfo", GreetInfo.class)
    }
}

Here we instruct Spring to scan com.sysgears.example for components and also to use JSR 330 annotations. JSR 330 is the standard of dependency injection for Java applications.

Notice how we inject Environment into the configuration using JSR330 @Inject annotation and retrieve objects from it. Note also that the environment could be injected only into Spring @Configuration classes.

The source code for GreetInfo is trivial:

/**
 * Container for the greeting text and person name.
 */
class GreetInfo {

    /** Greeting text */
    def text

    /** Name of the person to greet */
    def name
}

By default, JSR 330 components have prototype scope, which means that a new instance of the component will be created each time it is wired. To mark the component as having prototype-scope one should add @Named-annotation. Below is an example of a trivial Greeter prototype-scoped component that constructs a greeting string. This component has a dependency on the GreeterCounter that holds global counter of the number of times the Greeter was instantiated.

/**
 * Greeter that greets a person with greeting text and output information
 * about instance no of the greeter class.
 */
@Named
class Greeter {

    /** Current greeter instance no */
    private final int instanceNo

    /**
     * Creates an instance of this greater and remembers greeter instance no
     */
    @Inject
    public Greeter(final GreetInstanceCounter greeterCounter) {
        instanceNo = greeterCounter.incrementCounter()
    }

    /**
     * Generates string for greeting {@code subject} with the given {@code text} 
     * 
     * @param text greet text
     * @param name whom to greet
     * 
     * @return greeting string 
     */
    public String greet(String text, String name) {
        "${text}, ${name}! (from greeter ${instanceNo})"
    }
}

The GreeterCounter should be instantiated once for the whole application. For this to happen, we should mark it with @javax.inject.Singleton, an annotation.

/**
 * Counter of greeter instances
 */
@Named
@javax.inject.Singleton
class GreeterCounter {
    
    /** Greeter instance current count */
    private int instanceCount = 1

    /**
     * Returns Greeter current instance count and increments counter 
     * 
     * @return Greeter current instance count 
     */
    public int incrementCounter() {
        instanceCount++
    } 
}

So, @Named and @javax.inject.Singleton are the primary mechanisms to control how many instances of your classes will be created. However, these mechanisms only work during the wiring phase, but what if you want to create class instances at runtime?

JSR 330 provides @javax.inject.Provider – a separate mechanism to create instances at runtime. Here is an example of using this mechanism:

/**
 * Class that uses multiple greeter instances to output several greetings.
 */
@Named
@javax.inject.Singleton
class MultiGreeter {

    /**
     * Object that contains greeting text and name passed through environment
     */
    private @Inject GreetInfo greetInfo

    /**
     * Greeter instance factory 
     */
    private @Inject Provider<Greeter> greeterProvider

    /**
     * Outputs greeting with 2 instances of greeter.
     * 
     * @return greeting text
     */
    public String greet() {
        def greeter1 = greeterProvider.get()
        def greeter2 = greeterProvider.get()
        
        greeter1.greet(greetInfo.text, greetInfo.name) + "\n" +
                greeter2.greet(greetInfo.text, greetInfo.name)
    }
}

In this code, we are using our Greeter code to output greeting text twice, using two Greeter instances.

The instances of Greeter are created with injected @Inject Provider greeterProvider. Note that this is enough to write only this line of code to get a factory of Greeters created for us automatically by the IoC container at runtime.

This is pretty much all the logic of our pet application. Now, how to write unit tests for it? Let’s look for the simple case – a unit test for the Greeter.

@ContextConfiguration(classes = AppConfig.class)
class GreeterSpec extends Specification {
    private @Inject Greeter greeter
    
    def 'check greeting'() {
        expect: 'should generate correct greet string'
        greeter.greet('Hello', 'Test') == 'Hello, Test! (from greeter 1)' 
    }
}

Unit tests are implemented using the Spock framework. The Greeter is pretty much simple and independent class. That’s why its unit test is straightforward as well.

In this code, we point Spring to the IoC configuration of our application, using @ContextConfiguration(classes = AppConfig.class). Also, we let Spring create the instance of Greeter class and wire its dependencies by using just @Inject an annotated field.

The code is very neat and straightforward.

Let’s handle a more complex problem – a unit test for the class that depends on Environment:

@ContextConfiguration(classes = AppConfig.class, initializers = TestContextInitializer.class)
class MultiGreeterSpec extends Specification {
    private @Inject MultiGreeter multiGreeter

    public static class TestContextInitializer implements
            ApplicationContextInitializer<ConfigurableApplicationContext> {
        @Override
        public void initialize(ConfigurableApplicationContext ctx) {
            def appProps = new MapPropertySource("appProps", [
                    greetInfo: new GreetInfo(text: "TestHello", name: "TestWorld")
            ] as Map<String, Object>)

            ctx.getEnvironment().getPropertySources().addFirst(appProps);
        }
    }

    def 'check greeting generation'() {
        expect: 'should generate correct greeting'

        multiGreeter.greet().trim() == '''
TestHello, TestWorld! (from greeter 1)
TestHello, TestWorld! (from greeter 2)
'''.trim()
    }
}

Here, in @ContextConfiguration, we point Spring to the context initializer – e.g., the code that will be executed right before wiring. We use a context initializer to push test environment properties into the application context. This is very similar to the code we had in Main.groovy to pass external properties into the Spring context.

At the end of this post, I would like to share the Gradle script to build and test this application and to create an executable JAR that can be launched on any computer with a Java VM installed.

apply plugin: 'maven'
apply plugin: 'groovy'
group = 'com.sysgears.example'
version = '1.0'

defaultTasks 'clean', 'build', 'test', 'uberJar'

def compatibilityVersion = 1.5
def springVersion = '3.2.2.RELEASE'
def mainClassName = 'com.sysgears.example.Main'
sourceCompatibility = compatibilityVersion
targetCompatibility = compatibilityVersion

repositories {
    mavenCentral()
}

dependencies {
     <em>// Spring Framework Dependenices</em>
     compile "org.springframework:spring-beans:${springVersion}"
     compile "org.springframework:spring-context:${springVersion}"
     compile "org.springframework:spring-core:${springVersion}"
     compile "org.springframework:spring-expression:${springVersion}"

     <em>// JSR 330 annotation support</em>
     compile "javax.inject:javax.inject:1"

     <em>// Spring unit testing support</em>
     testCompile "org.springframework:spring-test:${springVersion}"

     <em>// Spock framework for unit testing</em>
     testCompile("org.spockframework:spock-core:0.7-groovy-2.0") {
         exclude module: 'groovy-all'
     }
     testCompile("org.spockframework:spock-spring:0.7-groovy-2.0") {
         exclude module: 'groovy-all'
     }

     <em>// Groovy</em>
     groovy 'org.codehaus.groovy:groovy:2.1.2'
}

<em>// Creates executable standalone JAR file of the application</em>
task uberJar(type: Jar, dependsOn:[':compileJava',':compileGroovy']) {
    from files(sourceSets.main.output.classesDir)
    from files(sourceSets.main.output.resourcesDir)
    from(configurations.runtime.asFileTree.files.collect { zipTree(it) }) {
        exclude "META-INF/*.SF"
        exclude "META-INF/*.DSA"
        exclude "META-INF/*.RSA"
    }
    manifest {
        attributes 'Implementation-Title': 'Groovy app architecture example',
                'Implementation-Version': version,
                'Built-By': System.getProperty('user.name'),
                'Built-Date': new Date(),
                'Built-JDK': System.getProperty('java.version'),
                'Main-Class': mainClassName
    }

}

This script is pretty much self-explanatory; however, you need to make some magic in order for all things to work as expected. I hope this will be improved in future versions of Gradle and the Spock framework.

The full source code of the project is available at the GitHub repository.

Thanks for reading,