Spring Dynamic Language Support with Groovy
Groovy is a dynamic and object-oriented programming language running on JVM. It uses a syntax like Java, can be embedded in Java and is compiled to byte-code. Java code can be called from Groovy, and vice versa. Some of Groovy features are Meta and Functional programming, Dynamic typing (with the def keyword), Closures, GroovyBeans, Groovlets, integration with Bean Scripting Framework(BSF), Generics, Anotation and Collection Support.
This article explains fundamental Spring Dynamic Language Support for Groovy via the following ways :
- By using Java syntax and Spring Stereotype,
- By using Groovy syntax and Spring Stereotype,
- By using inline-script feature,
- By using Spring Groovy language support(lang:groovy).
Used Technologies :
- JDK 1.7.0_09
- Spring 3.2.0
- Groovy 2.0.4
- Maven 3.0.4
STEP 1 : CREATE MAVEN PROJECT
A maven project is created as below. (It can be created by using Maven or IDE Plug-in).
STEP 2 : LIBRARIES
Firstly, dependencies are added to Maven’ s pom.xml.
<properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <spring.version>3.2.0.RELEASE</spring.version> </properties> <!-- Spring 3 dependencies --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.codehaus.groovy</groupId> <artifactId>groovy-all</artifactId> <version>2.0.4</version> </dependency>
maven-compiler-plugin(Maven Plugin) is used to compile the project with JDK 1.7
<plugin> <artifactId>maven-compiler-plugin</artifactId> <version>2.3.2</version> <configuration> <compilerId>groovy-eclipse-compiler</compilerId> <verbose>true</verbose> <source>1.7</source> <target>1.7</target> <encoding>${project.build.sourceEncoding}</encoding> </configuration> <dependencies> <dependency> <groupId>org.codehaus.groovy</groupId> <artifactId>groovy-eclipse-compiler</artifactId> <version>2.6.0-01</version> </dependency> </dependencies> </plugin>
maven-shade-plugin(Maven Plugin) can be used to create runnable-jar
<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-shade-plugin</artifactId> <version>2.0</version> <executions> <execution> <phase>package</phase> <goals> <goal>shade</goal> </goals> <configuration> <createDependencyReducedPom>false</createDependencyReducedPom> <configuration> <source>1.7</source> <target>1.7</target> </configuration> <transformers> <transformer implementation='org.apache.maven.plugins.shade.resource.ManifestResourceTransformer'> <mainClass>com.onlinetechvision.exe.Application</mainClass> </transformer> <transformer implementation='org.apache.maven.plugins.shade.resource.AppendingTransformer'> <resource>META-INF/spring.handlers</resource> </transformer> <transformer implementation='org.apache.maven.plugins.shade.resource.AppendingTransformer'> <resource>META-INF/spring.schemas</resource> </transformer> </transformers> </configuration> </execution> </executions> </plugin>
STEP 3 : CREATE Employee CLASS
Employee Bean is created.
package com.onlinetechvision.employee; /** * Employee Bean * * @author onlinetechvision.com * @since 24 Dec 2012 * @version 1.0.0 * */ public class Employee { private String id; private String name; private String surname; public Employee(String id, String name, String surname) { this.id = id; this.name = name; this.surname = surname; } public String getId() { return id; } public void setId(String id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getSurname() { return surname; } public void setSurname(String surname) { this.surname = surname; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((id == null) ? 0 : id.hashCode()); result = prime * result + ((name == null) ? 0 : name.hashCode()); result = prime * result + ((surname == null) ? 0 : surname.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; Employee other = (Employee) obj; if (id == null) { if (other.id != null) return false; } else if (!id.equals(other.id)) return false; if (name == null) { if (other.name != null) return false; } else if (!name.equals(other.name)) return false; if (surname == null) { if (other.surname != null) return false; } else if (!surname.equals(other.surname)) return false; return true; } @Override public String toString() { return 'Employee [id=' + id + ', name=' + name + ', surname=' + surname + ']'; } }
METHOD 1 : USING JAVA SYNTAX
STEP 4 : CREATE IGroovyEmployeeCacheService INTERFACE
IGroovyEmployeeCacheService Interface is created to expose Groovy Cache functionality.
package com.onlinetechvision.groovy.srv import com.onlinetechvision.employee.Employee /** * IGroovyEmployeeCacheService Interface exposes cache functionality. * * @author onlinetechvision.com * @since 24 Dec 2012 * @version 1.0.0 * */ interface IGroovyEmployeeCacheService { /** * Adds employee entry to cache * * @param Employee employee * */ void addToEmployeeCache(Employee employee); /** * Gets employee entry from cache * * @param String id * @return Employee employee */ Employee getFromEmployeeCache(String id); /** * Removes employee entry from cache * * @param Employee employee * */ void removeFromEmployeeCache(Employee employee); }
STEP 5 : CREATE GroovyEmployeeCacheService IMPL
GroovyEmployeeCacheService Class is created by implementing IGroovyEmployeeCacheService Interface.
package com.onlinetechvision.groovy.srv import com.onlinetechvision.employee.Employee; import org.springframework.stereotype.Service; /** * GroovyEmployeeCacheService Class is implementation of IGroovyEmployeeCacheService Interface. * * @author onlinetechvision.com * @since 24 Dec 2012 * @version 1.0.0 * */ @Service class GroovyEmployeeCacheService implements IGroovyEmployeeCacheService { private Map<String, Employee> cache = new HashMap(); /** * Adds employee entry to cache * * @param Employee employee * */ public void addToEmployeeCache(Employee employee) { getCache().put(employee.getId(), employee); println print(employee, 'added to cache...'); } /** * Gets employee entry from cache * * @param String id * @return Employee employee */ public Employee getFromEmployeeCache(String id) { Employee employee = getCache().get(id); println print(employee, 'gotten from cache...'); return employee; } /** * Removes employee entry from cache * * @param Employee employee * */ public void removeFromEmployeeCache(Employee employee) { getCache().remove(employee.getId()); println print(employee, 'removed from cache...'); println 'Groovy Cache Entries :' + getCache(); } public Map<String, Employee> getCache() { return cache; } public void setCache(Map<String, Employee> map) { cache = map; } /** * Prints operation information * * @param Employee employee * @param String description * */ private String print(Employee employee, String desc) { StringBuilder strBldr = new StringBuilder(); strBldr.append(employee) strBldr.append(' '); strBldr.append(desc); return strBldr.toString(); } }
STEP 6 : CREATE IEmployeeService INTERFACE
IUserService Interface is created for Spring service layer and shows how to integrate Spring and Groovy Service layers.
package com.onlinetechvision.spring.srv; import com.onlinetechvision.employee.Employee; /** * IEmployeeService Interface is created to represent Spring Service layer. * * @author onlinetechvision.com * @since 24 Dec 2012 * @version 1.0.0 * */ public interface IEmployeeService { /** * Adds Employee entry to cache * * @param Employee employee * */ void addToGroovyEmployeeCache(Employee employee); /** * Gets Employee entry from cache * * @param String id * @return Employee employee */ Employee getFromGroovyEmployeeCache(String id); /** * Removes Employee entry from cache * * @param Employee employee * */ void removeFromGroovyEmployeeCache(Employee employee); }
STEP 7 : CREATE EmployeeService IMPL
EmployeeService Class is created by implementing IUserService Interface.
package com.onlinetechvision.spring.srv; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import com.onlinetechvision.employee.Employee; import com.onlinetechvision.groovy.srv.IGroovyEmployeeCacheService; /** * EmployeeService Class is implementation of IEmployeeService interface. * * @author onlinetechvision.com * @since 24 Dec 2012 * @version 1.0.0 * */ @Service public class EmployeeService implements IEmployeeService { @Autowired private IGroovyEmployeeCacheService groovyEmployeeCacheService ; /** * Adds Employee entry to cache * * @param Employee employee * */ public void addToGroovyEmployeeCache(Employee employee) { getGroovyEmployeeCacheService().addToEmployeeCache(employee); } /** * Gets Employee entry from cache * * @param String id * @return Employee employee */ public Employee getFromGroovyEmployeeCache(String id) { return getGroovyEmployeeCacheService().getFromEmployeeCache(id); } /** * Removes Employee entry from cache * * @param Employee employee * */ public void removeFromGroovyEmployeeCache(Employee employee) { getGroovyEmployeeCacheService().removeFromEmployeeCache(employee); } public IGroovyEmployeeCacheService getGroovyEmployeeCacheService() { return groovyEmployeeCacheService; } public void setGroovyEmployeeCacheService(IGroovyEmployeeCacheService groovyEmployeeCacheService) { this.groovyEmployeeCacheService = groovyEmployeeCacheService; } }
STEP 8 : CREATE applicationContext.xml
Spring Configuration file, applicationContext.xml, is created.
<beans xmlns='http://www.springframework.org/schema/beans' xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' xmlns:context='http://www.springframework.org/schema/context' xsi:schemaLocation='http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd'> <context:component-scan base-package='com.onlinetechvision.spring.srv, com.onlinetechvision.groovy.srv'/> </beans>
STEP 9 : CREATE Application CLASS
Application Class is created to run the application.
package com.onlinetechvision.exe; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import com.onlinetechvision.spring.srv.EmployeeService; import com.onlinetechvision.spring.srv.IEmployeeService; import com.onlinetechvision.employee.Employee; /** * Application Class starts the application * * @author onlinetechvision.com * @since 24 Dec 2012 * @version 1.0.0 * */ public class Application { /** * Starts the application * * @param String[] args * */ public static void main(String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext('applicationContext.xml'); IEmployeeService employeeService = (IEmployeeService) context.getBean(EmployeeService.class); Employee firstEmployee = new Employee('1', 'Jake', 'Gyllenhaal'); Employee secondEmployee = new Employee('2', 'Woody', 'Harrelson'); employeeService.addToGroovyEmployeeCache(firstEmployee); employeeService.getFromGroovyEmployeeCache(firstEmployee.getId()); employeeService.removeFromGroovyEmployeeCache(firstEmployee); employeeService.addToGroovyEmployeeCache(secondEmployee); employeeService.getFromGroovyEmployeeCache(secondEmployee.getId()); } }
STEP 10 : BUILD PROJECT
After OTV_Spring_Groovy Project is build, OTV_Spring_Groovy-0.0.1-SNAPSHOT.jar is created.
STEP 11 : RUN PROJECT
After created OTV_Spring_Groovy-0.0.1-SNAPSHOT.jar file is run, output logs are shown as the followwing :
Employee [id=1, name=Jake, surname=Gyllenhaal] added to cache... Employee [id=1, name=Jake, surname=Gyllenhaal] gotten from cache... Employee [id=1, name=Jake, surname=Gyllenhaal] removed from cache... Groovy Cache Entries :[:] Employee [id=2, name=Woody, surname=Harrelson] added to cache... Employee [id=2, name=Woody, surname=Harrelson] gotten from cache...
So far, first way has been explained. Let us take a look to the other ways :
METHOD 2 : USING GROOVY SYNTAX
IGroovyEmployeeCacheService Interface and GroovyEmployeeCacheService Impl can be also designed by using Groovy syntax as the following :
STEP 12.1 : CREATE IGroovyEmployeeCacheService INTERFACE
IGroovyEmployeeCacheService Interface is created by using Groovy syntax.
package com.onlinetechvision.groovy.srv import com.onlinetechvision.employee.Employee /** * IGroovyEmployeeCacheService Interface exposes cache functionality. * * @author onlinetechvision.com * @since 24 Dec 2012 * @version 1.0.0 * */ interface IGroovyEmployeeCacheService { /** * Adds employee entry to cache * * @param Employee employee * */ def addToEmployeeCache(Employee employee); /** * Gets employee entry from cache * * @param String id * @return Employee employee */ def getFromEmployeeCache(String id); /** * Removes employee entry from cache * * @param Employee employee * */ def removeFromEmployeeCache(Employee employee); }
STEP 12.2 : CREATE GroovyEmployeeCacheService IMPL
GroovyEmployeeCacheService Class is created by using Groovy syntax.
package com.onlinetechvision.groovy.srv import com.onlinetechvision.employee.Employee; import org.springframework.stereotype.Service; /** * GroovyEmployeeCacheService Class is implementation of IGroovyEmployeeCacheService Interface. * * @author onlinetechvision.com * @since 24 Dec 2012 * @version 1.0.0 * */ @Service class GroovyEmployeeCacheService implements IGroovyEmployeeCacheService { def cache = new HashMap(); /** * Adds employee entry to cache * * @param Employee employee * */ def addToEmployeeCache(Employee employee) { getCache().put(employee.getId(), employee); println print(employee, 'added to cache...'); } /** * Gets employee entry from cache * * @param String id * @return Employee employee */ def getFromEmployeeCache(String id) { Employee employee = getCache().get(id); println print(employee, 'gotten from cache...'); return employee; } /** * Removes employee entry from cache * * @param Employee employee * */ def removeFromEmployeeCache(Employee employee) { getCache().remove(employee.getId()); println print(employee, 'removed from cache...'); println 'Groovy Cache Entries :' + getCache(); } def getCache() { return cache; } def setCache(Map<String, Employee> map) { cache = map; } /** * Prints operation information * * @param Employee employee * @param String description * */ def print(Employee employee, String desc) { StringBuilder strBldr = new StringBuilder(); strBldr.append(employee) strBldr.append(' '); strBldr.append(desc); } }
METHOD 3 : USING INLINE-SCRIPT FEATURE
GroovyEmployeeCacheService Impl can be also defined by using inline-script feature as the following :
STEP 13.1 : DEFINE GroovyEmployeeCacheService IMPL via applicationContext.xml
GroovyEmployeeCacheService Impl Class can be defined in applicationContext.xml.
<beans xmlns='http://www.springframework.org/schema/beans' xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' xmlns:context='http://www.springframework.org/schema/context' xmlns:lang='http://www.springframework.org/schema/lang' xsi:schemaLocation='http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd http://www.springframework.org/schema/lang http://www.springframework.org/schema/lang/spring-lang-3.0.xsd'> <context:component-scan base-package='com.onlinetechvision.spring.srv'/> <lang:groovy id='groovyEmployeeCacheService'> <lang:inline-script> package com.onlinetechvision.groovy.srv import com.onlinetechvision.employee.Employee; import org.springframework.stereotype.Service; class GroovyEmployeeCacheService implements IGroovyEmployeeCacheService { def cache = new HashMap(); def addToEmployeeCache(Employee employee) { getCache().put(employee.getId(), employee); println print(employee, 'added to cache...'); } def getFromEmployeeCache(String id) { Employee employee = getCache().get(id); println print(employee, 'gotten from cache...'); return employee; } def removeFromEmployeeCache(Employee employee) { getCache().remove(employee.getId()); println print(employee, 'removed from cache...'); println 'Groovy Cache Entities :' + getCache(); } def getCache() { return cache; } def setCache(Map map) { cache = map; } def print(Employee employee, String desc) { StringBuilder strBldr = new StringBuilder(); strBldr.append(employee) strBldr.append(' '); strBldr.append(desc); } } </lang:inline-script> </lang:groovy> </beans>
METHOD 4 : USING SPRING GROOVY LANGUAGE SUPPORT
GroovyEmployeeCacheService Impl can be also defined to Spring application-context without using stereotype(@Service) as the following :
STEP 14.1 : DEFINE GroovyEmployeeCacheService IMPL via applicationContext.xml
GroovyEmployeeCacheService Impl Class can be defined in applicationContext.xml.
<beans xmlns='http://www.springframework.org/schema/beans' xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' xmlns:context='http://www.springframework.org/schema/context' xmlns:lang='http://www.springframework.org/schema/lang' xsi:schemaLocation='http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd http://www.springframework.org/schema/lang http://www.springframework.org/schema/lang/spring-lang-3.0.xsd'> <context:component-scan base-package='com.onlinetechvision.spring.srv'/> <lang:groovy id='groovyEmployeeCacheService' script-source='classpath:com/onlinetechvision/groovy/srv/GroovyEmployeeCacheService.groovy'/> </beans>
STEP 15 : DOWNLOAD
https://github.com/erenavsarogullari/OTV_Spring_Groovy
RESOURCES :
Groovy User Guide
Spring Dynamic Language Support
Reference: Spring Dynamic Language Support with Groovy from our JCG partner Eren Avsarogullari at the Online Technology Vision blog.