Spring and Groovy Integration

SHARE & COMMENT :

1) Introduction

Spring makes it easier to provide integration support for scripting languages. The currently supported scripting languages are Groovy, JRuby and BeanShell. However, this article concentrates only on Spring’s support for the Groovy language. Plenty of code samples are given in each section for much clarity. The article assumes that the reader is comfortable in both Spring and Groovy concepts. If you are new to Spring and Groovy frameworks, please read the introduction articles that have been published in javabeat for Spring Introduction to Spring Web Framework and Introduction to Groovy – Scripting Language

also read:

2) Groovy Objects in Spring’s Environment

2.1) Introduction

Let us see a sample Application that will illustrate the integration of Groovy in Spring’s Environment. It will discuss how a Groovy file (the file with extension as ‘.groovy’) can be integrated with Spring to take the power of a dynamic language. In this sample, a Java Application tries to access Groovy code with the help of the configuration information provided by Spring.

2.2) Server interface

Let us define a common interface called Server which is to be given implementation by both Java and Groovy. This interface has three methods start(), restart() and stop(). The following code illustrates for the same.
Server.java

package javabeat.net.articles.spring.groovy.integration.simple;

public interface Server {

    public void start();
    public void restart();
    public void stop();

}

2.3) Groovy Server

The following code presents the Groovy implementation for the above Server interface. The syntax of Groovy resembles almost the same as the Java language. However, Groovy enjoys the benefits of a scripting language like loose type checking, lenient syntax etc.. For example, it is not necessary to suffix a statement terminator with a colon (:) in Groovy.
GroovyServer.java

package javabeat.net.articles.spring.groovy.integration.simple

public class GroovyServer implements Server
{
    public void start()
    {
        println ("Groovy Server started...")
    }

    public void restart()
    {
        println ("Groovy Server restarted...")
    }

    public void stop()
    {
        println ("Groovy Server stopped...")
    }
}

2.4) Java Server

Next comes the implementation in the Java language for the Server interface. The implementation class JavaServer contains a reference with name 'groovyServer' to the Server interface. Later on, through the configuration file, we will see that how we populate this 'groovyServer' reference with the implementation given in Groovy. We also have added a test method by name 'testGroovyServer' that will call the Groovy implementation.

JavaServer.java

package javabeat.net.articles.spring.groovy.integration.simple;

public class JavaServer implements Server{

    private Server groovyServer;

    public JavaServer() {
    }

    public void start() {
        System.out.println("Java server started....");
    }

    public void restart() {
        System.out.println("Java server re-started....");
    }

    public void stop() {
        System.out.println("Java server stopped....");
    }

    public void setGroovyServer(Server groovyServer)
    {
        this.groovyServer = groovyServer;
    }

    public void testGroovyServer(){
        groovyServer.start();
        groovyServer.restart();
        groovyServer.stop();
    }
}

2.5) Configuration file

spring-groovy.xml

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

http://www.springframework.org/schema/beans


http://www.springframework.org/schema/beans/spring-beans-2.0.xsd


http://www.springframework.org/schema/lang


http://www.springframework.org/schema/lang/spring-lang-2.0.xsd">

    <lang:groovy id="groovyServer"
        script-source="classpath:javabeat/net/articles/spring/groovy/integration/simple/GroovyServer.groovy">
    </lang:groovy>

    <bean id="javaServer"
       >
        <property name = "groovyServer" ref = "groovyServer" />
    </bean>

</beans>

In the above configuration file, we have added a new element called 'groovy' taken from the xml name-space 'lang' to provide Groovy support. The value for the 'script-source' attribute says that look into the classpath of the application (classpath: ) for a file by name GroovyServer.groovy within the directory (javabeat/net/articles/spring/groovy/integration/simple). By this, we have imported the Groovy code into the Spring Environment and now we have a Groovy bean identified by 'groovyServer'.
In this Xml configuration file, we have also defined a Spring bean called 'javaServer' by making a reference to the previously declared Groovy Bean 'groovyServer'. So now the Java Code can access Groovy Server through the Groovy reference.

2.6) Client Application

The following client application tries to access the configuration file using the Spring Api to get a reference to the javaServer object. Then the javaServer object accesses the Groovy code by calling the method testGroovy() within which an instance of Groovy Server object is already populated and thereby the Groovy code gets executed.
SpringGroovyIntegrationTest.java

package javabeat.net.articles.spring.groovy.integration.simple;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;

public class SpringGroovyIntegrationTest {

    public static void main(String args[]){

        ApplicationContext context = new FileSystemXmlApplicationContext(
            "./src/resources/spring/groovy/spring-groovy.xml");

        JavaServer javaServer = (JavaServer)context.getBean("javaServer");
        javaServer.start();
        javaServer.restart();
        javaServer.stop();

        javaServer.testGroovyServer();
    }
}

3) Inlining Groovy objects

3.1) Introduction

It is also possible to inline Groovy code directly in the Spring’s configuration file rather than having the code in a separate .groovy file. This will be useful at times when the size of the Groovy code is comparatively smaller.

3.2) Spring’s Configuration file

inline.xml

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

    <lang:groovy id="person">
        <lang:inline-script>

        package javabeat.net.articles.spring.groovy.integration.inline

        public class Person
        {
            String name
            int age
            double salary

            public void toString(){
                println (name + "::" + age + "::" + salary);
            }
        }

        </lang:inline-script>

        <lang:property name="name" value="Nicolas" />
        <lang:property name="age" value="43" />
        <lang:property name="salary" value="56789" />

    </lang:groovy>

</beans>

In the above configuration file, the new Groovy type called Person is created within a well-defined package. Note that the Groovy code should be embedded with the tags lang:inline. It is also possible to define an object of type Person as well as to pass parameters to the defined object with the help of the 'property' tags.

4) Reloading Groovy code

4.1) Introduction

This is a handy feature available in Spring-Groovy Integration. It is basically reloading a Groovy file to get the updated information. Note that when a Groovy file is compiled and made to run, any changes made to the Groovy source file wont affect the running code. This is the default behavior. However, this can be overridden by setting a property in the configuration file. This is illustrated with the help of the following sample,

4.2) The Person interface

Person.java

package javabeat.net.articles.spring.groovy.integration.refresh;

public interface Person {

    public String getName();
    public void setName(String name);

}

We have declared a Person interface for manipulating the name of a person through a getter and a setter.

4.3) PersonImpl class

The following code provides a simple implementation in Groovy for the above Person class.

PersonImpl.java

package javabeat.net.articles.spring.groovy.integration.refresh

public class PersonImpl implements Person
{
    String name;

    public String getName(){
        return name;
    }

    public void setName(String name){
        this.name = name;
    }
}

4.4) Person Wrapper class

This is just a wrapper for the above Person class. Since a defined Groovy object in the Spring’s configuration file cannot be directly referenced in the Client Application, this java class is introduced. This Java class will basically wrap the underlying Groovy object.
PersonWrapper.java

package javabeat.net.articles.spring.groovy.integration.refresh;

public class PersonWrapper {

    private Person person;

    public void setPerson(Person person)
    {
        this.person = person;
    }

    public Person getPerson()
    {
        return person;
    }
}

4.5) Configuration file

refresh.xml

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

http://www.springframework.org/schema/beans


http://www.springframework.org/schema/beans/spring-beans-2.0.xsd


http://www.springframework.org/schema/lang


http://www.springframework.org/schema/lang/spring-lang-2.0.xsd">

    <lang:groovy id="personImpl"
        script-source="classpath:javabeat/net/articles/spring/groovy/integration/refresh/PersonImpl.groovy"
        refresh-check-delay="5000">
        <lang:property name = "name" value = "John"/>
    </lang:groovy>

    <bean id = "personWrapper"
        class = "javabeat.net.articles.spring.groovy.integration.refresh.PersonWrapper">
        <property name = "person" ref = "personImpl"/>
    </bean>

</beans>

It is seen that we have defined a Groovy object called ‘personImpl’ for the type PersonImpl.groovy. We find the introduction of the new property ‘refresh-check-delay’, which tells that for every 5 seconds check the Groovy source file (PersonImpl.groovy in our case) and if it updated, compile the file to take the updated information. If the updated source contains syntax errors, then a Run-time Exception will be thrown.

4.6) Client Application

RefreshTest.java

package javabeat.net.articles.spring.groovy.integration.refresh;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;

public class RefreshTest {

    public static void main(String args[]) throws Exception{

        ApplicationContext context = new FileSystemXmlApplicationContext(
            "./src/resources/spring/groovy/refresh.xml");
        PersonWrapper wrapperForPerson = (PersonWrapper)context.getBean(
            "personWrapper");

        System.out.println("Old Name");
        System.out.println(wrapperForPerson.getPerson().getName());

        Thread.sleep(10 * 1000);

        System.out.println("Updated Name");
        System.out.println(wrapperForPerson.getPerson().getName());
    }
}

The Client Application makes a reference to the Person Wrapper object which wraps the underlying Groovy object (PersonImpl). When the program runs, it initially prints the name of the person as 'John' (that is how we have configured in the Xml file). Later the execution is paused for 10 seconds, which gives enough time to modify the Groovy source file. Change the old name John to something like 'Johny' to see the updated output.

5) Customizing Groovy objects creation

5.1) Introduction

In this final section, we will see how it is possible to customize the Groovy object creation process. The solution lies in the hands of GroovyObjectCustomizer interface. All we have to do is to override the interface to provide the custom logic for the object once it is created. Let us look into that.

5.2) Test Class

We have defined a Test Class in Groovy with a single property called strProp. Whenever an object for this class is created the strProp will soon be populated with the value 'A String Value'. Let us see in the subsequent sections how to modify the original value through customization process.
TestClass.java

package javabeat.net.articles.spring.groovy.integration.customization

public class TestClass
{
    String strProp = "A String Value"
}

5.3) Test Wrapper class

Since Spring doesn’t provide direct support for accessing a Groovy object defined in the Configuration file, we provide a Java wrapper object here. Note that this class contains a reference to GroovyObject. All objects in Groovy are of the generic type 'GroovyObject'. So, it means that even the Groovy object of type 'TestClass' is a kind of 'GroovyObject' object.
TestClassWrapper.java

package javabeat.net.articles.spring.groovy.integration.customization;

import groovy.lang.GroovyObject;

public class TestClassWrapper {

    private GroovyObject groovyObject;

    public TestClassWrapper() {
    }

    public void setGroovyObject(GroovyObject groovyObject)
    {
        this.groovyObject = groovyObject;
    }

    public void testIt()
    {
        System.out.println("Str value is ---&gt; " +
            groovyObject.getProperty("strProp"));
    }
}

5.4) Test Class Customizer

Now let us define the customization class for Groovy. As mentioned, the class should conform to the interface GroovyObjectCustomizer and we should over-ride the method customize() which will be called once the Groovy object is created.

TestClassCustomizer.java

package javabeat.net.articles.spring.groovy.integration.customization;

import groovy.lang.GroovyObject;
import org.springframework.scripting.groovy.GroovyObjectCustomizer;

public class TestClassCustomizer implements GroovyObjectCustomizer {

    public void customize(GroovyObject groovyObject) {
        groovyObject.setProperty("strProp",
            "new value for string property");
    }
}

In the above method, we have modified the value of the string property 'strProp' to a new value.

5.5) Configuration file

Let us see how all these classes get wired in a single Xml file. To enable customization, we have defined the customization class 'TestClassCustomizer' that we created just before by giving an identifier 'testClassCustomizer'. Note that the declaration of the Groovy object testClass contains a reference to the Test Customizer class through its 'customizer-ref' attribute.
custom.xml

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

http://www.springframework.org/schema/beans


http://www.springframework.org/schema/beans/spring-beans-2.0.xsd


http://www.springframework.org/schema/lang


http://www.springframework.org/schema/lang/spring-lang-2.0.xsd">

<bean id="testClassCustomizer"
/>

<lang:groovy id="testClass"
script-source="classpath:javabeat/net/articles/spring/groovy/integration/customization/TestClass.groovy"
customizer-ref="testClassCustomizer">
</lang:groovy>

<bean id = "testClassWrapper"
class = "javabeat.net.articles.spring.groovy.integration.customization.TestClassWrapper">
<property name = "groovyObject" ref = "testClass"/>
</bean>

</beans>

5.6) The Client Application

The Client Application is quite simple. It makes a reference to the Test Wrapper class and then calls the testIt() method to ensure that the property for the groovy object is changed.

RunTestClass.java

package javabeat.net.articles.spring.groovy.integration.customization;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;

public class RunTestClass {

    public static void main(String args[]){

        ApplicationContext context = new FileSystemXmlApplicationContext(
            "./src/resources/spring/groovy/custom.xml");

        TestClassWrapper wrapper = (TestClassWrapper)context.getBean(
            "testClassWrapper");
        wrapper.testIt();
    }
}

also read:

6) Conclusion

In this article, we have seen how Spring and Groovy provides Integration support to Groovy through code samples. The initial section of the article showed a simple Application that defines how Integration for Scripting languages are wired through the Configuration information. Then it described the inlining feature where it is possible to code the Groovy logic directly into the Configuration file. Later on, it talked about the Reloading nature of the Groovy source code. Finally the article was concluded by illustrating the Object Creation Customization process.

Comments

comments

About Krishna Srinivasan

He is Founder and Chief Editor of JavaBeat. He has more than 8+ years of experience on developing Web applications. He writes about Spring, DOJO, JSF, Hibernate and many other emerging technologies in this blog.

Trackbacks

  1. […] Spring and Groovy Integration […]

Speak Your Mind

*

Close
Please support the site
By clicking any of these buttons you help our site to get better