Using Spring DI in your Gaelyk projects

| Comments

Since I started using Gaelyk, one of the features I missed most (coming from a Grails background) is Spring’s dependency injection. Until recently I didn’t even know if it was possible to use Spring in Google App Engine, so I decided to do a little investigation on the subject, and found out that it’s very easy indeed.

Here’s a little tutorial on how to configure Spring in your Gaelyk project. I’m assuming you have basic knowledge of Spring, Gaelyk and Maven.

First, let’s create a Gaelyk project. The easiest way is using the excellent maven-gaelyk archetype:

1
mvn archetype:generate -DarchetypeGroupId=org.codeconsole -DarchetypeArtifactId=gaelyk-archetype -DarchetypeVersion=0.5.5 -DarchetypeRepository=http://maven-gaelyk.googlecode.com/svn/repository/ -DartifactId=gaelyk-spring -DgroupId=com.deluan.gaelyk -DgaeApplicationName=gaelyk-spring

Now open the project in your favorite IDE, so we can edit the configuration files. First, add the Spring dependency to your pom.xml:

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-web</artifactId>
            <version>${spring.version}</version>
        </dependency>

Next we need to configure Spring’s ContextLoaderListener in web.xml:

    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>
            /WEB-INF/spring/*.xml
        </param-value>
    </context-param>

    <listener>
        <listener-class>
            org.springframework.web.context.ContextLoaderListener
        </listener-class>
    </listener>

As you can see from above, we configured Spring to load all context configuration files under the directory WEB-INF/spring.

With these configurations in place, your project is already Spring enabled. Now we need a easy way to access the Spring’s Application Context. One good way to do this is using a singleton that implements the ApplicationContextAware interface. To keep this post as small as possible, I borrowed an implementation from this blog post, where you can learn more about the details. Create the directory src/main/groovy and put the following SpringApplicationContext singleton there (in the correct package):

package com.deluan.gaelyk;

import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

/**
 * Wrapper to always return a reference to the Spring Application Context from
 * within non-Spring enabled beans. Unlike Spring MVC's WebApplicationContextUtils
 * we do not need a reference to the Servlet context for this. All we need is
 * for this bean to be initialized during application startup.
 *
 * Original from http://sujitpal.blogspot.com/2007/03/accessing-spring-beans-from-legacy-code.html
 */
public class SpringApplicationContext implements ApplicationContextAware {

    private static ApplicationContext CONTEXT;

    /**
     * This method is called from within the ApplicationContext once it is
     * done starting up, it will stick a reference to itself into this bean.
     * @param context a reference to the ApplicationContext.
     */
    public void setApplicationContext(ApplicationContext context) throws BeansException {
        CONTEXT = context;
    }

    /**
     * This is about the same as context.getBean("beanName"), except it has its
     * own static handle to the Spring context, so calling this method statically
     * will give access to the beans by name in the Spring application context.
     * As in the context.getBean("beanName") call, the caller must cast to the
     * appropriate target class. If the bean does not exist, then a Runtime error
     * will be thrown.
     * @param beanName the name of the bean to get.
     * @return an Object reference to the named bean.
     */
    public static Object getBean(String beanName) {
        return CONTEXT.getBean(beanName);
    }

    public static ApplicationContext getContext() {
        return CONTEXT;
    }
}

Configure the singleton in your spring context:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="springApplicationContext" class="com.deluan.gaelyk.SpringApplicationContext"/>

    <bean id="dateFormat" class="java.text.SimpleDateFormat">
        <constructor-arg value="yyyy/MM/dd" />
    </bean>

    <bean id="timeFormat" class="java.text.SimpleDateFormat">
        <constructor-arg value="hh:mm:ss" />
    </bean>

    <bean id="dateTimeFormat" class="java.text.SimpleDateFormat">
        <constructor-arg value="yyyy/MM/dd hh:mm:ss" />
    </bean>

</beans>

As you can see, I also declared some SimpleDateFormat instances as beans to be used in our examples.

Now everything is configured and ready to be used. Let’s see how we can obtain a spring bean inside a Groovlet. Create the file WEB-INF/groovy/index.groovy with the following content:

import com.deluan.gaelyk.SpringApplicationContext

def dateFormat = SpringApplicationContext.getBean('dateFormat')
def now = new Date()

println dateFormat.format(now)

Now run your application with the command mvn gae:run, point your browser to http://localhost:8080/index.groovy and you should see something like this:

Well, that’s it! Nothing much different from what you are used to do in a normal Web application, right? But remember: Gaelyk is NOT your normal Web framework so let’s spice things a little bit.

The solution for looking up beans depicted above is a bit cumbersome. Let’s use Gaelyk’s plugin system to make things a little more “groovy”. Using the plugin descriptor bellow, we can provide shortcuts to our SpringApplicationContext’s methods, getContext() and getBean(). Save it in the file WEB-INF/plugins/spring.groovy:

import com.deluan.gaelyk.SpringApplicationContext

binding {
    appCtx = SpringApplicationContext.context

    getBean = {
        SpringApplicationContext.getBean(it)
    }

    autowire = { self, beanNames ->
        beanNames.each {
            self.setProperty(it, SpringApplicationContext.getBean(it))
        }
    }
}

Before you can use these shortcuts, you need to tell Gaelyk about your descriptor by “installing” it in your project. Save the code bellow in the file WEB-INF/plugins.groovy:

install spring

Now you can use the shortcuts in your Groovlets this way:


def now = new Date()

// Simple context lookup
def dateFormat = getBean('dateFormat')

// Resolve a list of bean names and create bindings for each one of them
autowire this, ['timeFormat', 'dateTimeFormat']

html.html {
    body {
        p appCtx.displayName  // Access the ApplicationContext
        p dateFormat.format(now)
        p timeFormat.format(now)
        p dateTimeFormat.format(now)
    }
}

Cool, isn’t it? A note on the autowire binding: It creates bindings “automagically” for each bean you passed as a parameter, as if the beans were declared in your Groovlet.

You can download the sample project used in this post from GitHub: http://github.com/deluan/gaelyk-spring. You can follow each commit to see exactly what was changed in each step of this tutorial.

If you have any suggestion or question, please let me know.

UPDATE: I’ve refactored the autowiremethod into a Category, so now it’s not necessary to pass this as the first parameter. The new version is available at GitHub

Comments