Spring Framework Groovy Tutorial
In this article, we will explain Spring Framework using Groovy. Spring is a Java application framework that provides many useful services for building applications. It has supported Apache Groovy fully since version 4. In this tutorial, we will build a Spring boot application in Groovy.
Table Of Contents
1. Introduction
Apache Groovy (Groovy) is an object-oriented dynamic programming language for the Java platform. It is dynamically compiled to the Java Virtual Machine (JVM) bytecode, and inter-operates with other Java source codes and libraries. Groovy is written in Java. The first version 1.0 was released in 2007 to help developers to write a simple, elegant source code instead of the complicated Java code.
Spring Framework (Spring) is a Java application framework that provides many useful services for building applications. Spring 1.0 was released in 2004. Spring has supported Groovy fully since version 4 in 2013.
Spring boot defines a list of starter projects which each project includes a set of default component dependencies and automatic configuration of components.
In this example, I will create a Spring boot application which utilizes Spring’s features in Groovy.
2. Technologies Used
The example code in this article was built and run using:
- Java 1.8.101 (1.8.x will do fine)
- Maven 3.3.9 (3.3.x will do fine)
- Eclipse Mars (Any Java IDE would work)
- Spring boot 1.5.10.RELEASE
- Groovy 2.4
3. Spring-boot Application
The easiest way to generate a Spring-boot application is via the Spring starter tool. Please check my other article here for more details. A maven project will be generated and downloaded to your workstation. Import it into your Eclipse work space. You should have no errors on building it and running it as a Spring Boot Application.
We will change it to a Groovy spring application with three steps:
- Add a Groovy dependency in the
pom.xml
- Add a Groovy source folder
- Change Spring Application to a Groovy class
3.1 Groovy Dependency
The generated pom.xml
does not include the Groovy library. We will add it as a dependency.
pom.xml
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>jcg.zheng.demo</groupId> <artifactId>groovy-spring</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>jar</packaging> <name>groovy-spring</name> <description>Demo project for Spring Boot</description> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.5.10.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.codehaus.groovy</groupId> <artifactId>groovy-all</artifactId> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
3.2 Groovy Folders
The generated project has a Java
source folder. We will add two folders: src/main/groovy
and src/test/groovy
. Then we will include them as the build resources.
3.3 Spring Framework Application in Groovy
The generated GroovySpringApplication
is a Java
class. We will change it to a Groovy
class and move it under the src/main/groovy
folder.
You can execute mvn install
to build it and then run it as a Spring boot application.
4. Java and Groovy
We will define Payroll
interface and implement it with both Java
and Groovy
and compare their performance.
4.1 Payroll Interface
Define Payroll
interface to calculate the department’s budget based on the time period.
Payroll.java
package jcg.zheng.demo.groovyspring.service; import java.math.BigDecimal; import jcg.zheng.demo.groovyspring.model.BudgetType; import jcg.zheng.demo.groovyspring.model.GDepartment; import jcg.zheng.demo.groovyspring.model.JDepartment; public interface Payroll { BigDecimal caculateBudget(JDepartment department, BudgetType type); BigDecimal caculateBudget(GDepartment department, BudgetType type); }
Note: It defines caculateBudget
method for both Java Department and Groovy Department. We use it to demonstrate the method’s performance.
Define BudgetType
enum
for four time periods.
BudgetType.java
package jcg.zheng.demo.groovyspring.model; import java.math.BigDecimal; public enum BudgetType { YEARLY, QUARTERLY, MONTHLY, WEEKLY; public BigDecimal workingHours() { BigDecimal workingHours = new BigDecimal(0); switch (this) { case YEARLY: workingHours = new BigDecimal(2080); case QUARTERLY: workingHours = new BigDecimal(520); case MONTHLY: workingHours = new BigDecimal(173.34); case WEEKLY: workingHours = new BigDecimal(40); } return workingHours; } }
4.2 Java Classes
In this step, we will create three Java classes to implement the Payroll
interface.
Define a department class which contains a list of employees.
JDepartment.java
package jcg.zheng.demo.groovyspring.model; import java.util.List; public class JDepartment { private int id; private List employees; public List getEmployees() { return employees; } public void setEmployees(List employees) { this.employees = employees; } public int getId() { return id; } public void setId(int id) { this.id = id; } }
Define an employee class which contains the employee’s first name, last name, and hourly pay rate.
JEmployee.java
package jcg.zheng.demo.groovyspring.model; import java.math.BigDecimal; public class JEmployee { public JEmployee() { super(); } private String firstName; private String lastName; private int id; private BigDecimal hourlyRate; public BigDecimal caculatePay(BigDecimal hours) { return hourlyRate.multiply(hours); } public String getFirstName() { return firstName; } public void setFirstName(String firstName) { this.firstName = firstName; } public String getLastName() { return lastName; } public void setLastName(String lastName) { this.lastName = lastName; } public int getId() { return id; } public void setId(int id) { this.id = id; } public BigDecimal getHourlyRate() { return hourlyRate; } public void setHourlyRate(BigDecimal hourlyRate) { this.hourlyRate = hourlyRate; } }
Implement the Payroll
interface’s two methods to calculate a given department’s budget.
JPayrollImpl.java
package jcg.zheng.demo.groovyspring.service.impl; import java.math.BigDecimal; import java.time.Duration; import java.time.Instant; import java.util.ArrayList; import java.util.List; import org.springframework.stereotype.Component; import jcg.zheng.demo.groovyspring.model.BudgetType; import jcg.zheng.demo.groovyspring.model.GDepartment; import jcg.zheng.demo.groovyspring.model.JDepartment; import jcg.zheng.demo.groovyspring.service.Payroll; @Component("javaPayroll") public class JPayrollImp implements Payroll { @Override public BigDecimal caculateBudget(JDepartment department, BudgetType type) { Instant start = Instant.now(); List values = new ArrayList(); department.getEmployees().forEach(emp -> values.add(emp.caculatePay(type.workingHours()))); BigDecimal result = values.stream().reduce(BigDecimal::add).get(); Instant end = Instant.now(); System.out.println("Java caculateBudget for JDepartment took " + Duration.between(start, end)); return result; } @Override public BigDecimal caculateBudget(GDepartment department, BudgetType type) { Instant start = Instant.now(); List values = new ArrayList(); department.getEmployees().forEach(emp -> values.add(emp.caculatePay(type.workingHours()))); BigDecimal result = values.stream().reduce(BigDecimal::add).get(); Instant end = Instant.now(); System.out.println("Java caculateBudget for GDepartment took " + Duration.between(start, end)); return result; } }
Create a Junit test class for JPayrollImp
.
JPayrollImpTest.java
package jcg.zheng.demo.groovyspring.service.impl; import static org.junit.Assert.*; import java.math.BigDecimal; import java.util.ArrayList; import java.util.List; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringRunner; import jcg.zheng.demo.groovyspring.model.BudgetType; import jcg.zheng.demo.groovyspring.model.GDepartment; import jcg.zheng.demo.groovyspring.model.GEmployee; import jcg.zheng.demo.groovyspring.model.JDepartment; import jcg.zheng.demo.groovyspring.model.JEmployee; import jcg.zheng.demo.groovyspring.service.Payroll; @RunWith(SpringRunner.class) @SpringBootTest public class JPayrollImpTest { @Autowired @Qualifier("javaPayroll") private Payroll javaPayroll; @Test public void test_JavaPayroll_caculateBudget_for_JDepartment_yearly() { JDepartment dept = new JDepartment(); List reports = new ArrayList(); reports.add(buildJEmployee("Mary", "Zheng", new BigDecimal(20))); reports.add(buildJEmployee("Alex", "Zheng", new BigDecimal(10))); reports.add(buildJEmployee("Allen", "Zheng", new BigDecimal(8))); dept.setEmployees(reports); BigDecimal budget = javaPayroll.caculateBudget(dept, BudgetType.YEARLY); assertTrue(budget.compareTo(new BigDecimal(1520)) == 0); } @Test public void test_JavaPayroll_caculateBudget_for_GDepartment_yearly() { GDepartment dept = new GDepartment(); List reports = new ArrayList(); reports.add(buildGEmployee("Mary", "Zheng", new BigDecimal(20))); reports.add(buildGEmployee("Alex", "Zheng", new BigDecimal(10))); reports.add(buildGEmployee("Allen", "Zheng", new BigDecimal(8))); dept.setEmployees(reports); BigDecimal budget = javaPayroll.caculateBudget(dept, BudgetType.YEARLY); assertTrue(budget.compareTo(new BigDecimal(1520)) == 0); } private JEmployee buildJEmployee(String fname, String lname, BigDecimal money) { JEmployee mary = new JEmployee(); mary.setFirstName(fname); mary.setLastName(lname); mary.setHourlyRate(money); return mary; } private GEmployee buildGEmployee(String fname, String lname, BigDecimal money) { GEmployee mary = new GEmployee(); mary.setFirstName(fname); mary.setLastName(lname); mary.setHourlyRate(money); return mary; } }
4.3 Groovy Classes
Groovy was introduced to ease the Java syntax’s complexity. The @Canonical
annotation assists Groovy developers to write shorter code. In this step, we will create three Groovy classes to implement the Payroll
interface.
Define a department class which contains a list of employees. It’s much shorter and cleaner comparing to the Java class created in step 4.2.
GDepartment.groovy
package jcg.zheng.demo.groovyspring.model import groovy.transform.* @Canonical class GDepartment { int id List employees }
Define an employee class which contains the employee’s first name, last name, and hourly pay rate.
GEmployee.groovy
package jcg.zheng.demo.groovyspring.model import groovy.transform.* @Canonical class GEmployee { String firstName String lastName int id BigDecimal hourlyRate public BigDecimal caculatePay(BigDecimal hours) { hourlyRate.multiply(hours) } }
Implement the Payroll
interface’s two methods to calculate a given department’s budget.
We can use Spring @Component
annotation to name it groovyPayroll
as a Spring bean. We also add time tracking to calculate the performance time.
GPayrollImpl.groovy
package jcg.zheng.demo.groovyspring.component import java.time.Duration import java.util.ArrayList import java.util.List import org.springframework.stereotype.Component import groovy.time.TimeCategory import groovy.time.TimeDuration import jcg.zheng.demo.groovyspring.model.BudgetType import jcg.zheng.demo.groovyspring.model.GDepartment import jcg.zheng.demo.groovyspring.model.JDepartment import jcg.zheng.demo.groovyspring.service.Payroll @Component("groovyPayroll") class GPayrollImpl implements Payroll{ @Override public BigDecimal caculateBudget(JDepartment department, BudgetType type) { def timeStart = new Date() List values = new ArrayList() department.getEmployees().each { values.add(it.caculatePay(type.workingHours()))} def timeStop = new Date() TimeDuration duration = TimeCategory.minus(timeStop, timeStart) println "Groovy caculateBudget for JDepartment took " + duration values.sum(); } @Override public BigDecimal caculateBudget(GDepartment department, BudgetType type) { def timeStart = new Date() List values = new ArrayList() department.getEmployees().each { values.add(it.caculatePay(type.workingHours()))} def timeStop = new Date() TimeDuration duration = TimeCategory.minus(timeStop, timeStart) println "Groovy caculateBudget for GDepartment took " + duration values.sum(); } }
Create a Junit test class for GPayrollImp
. We use Spring @Autowired
annotation along with @Qualifier
to find the Groovy Payroll
bean.
GPayrollImpTest.groovy
package jcg.zheng.demo.groovyspring.component import static org.junit.Assert.assertTrue import org.junit.Test import org.junit.runner.RunWith import org.springframework.beans.factory.annotation.Autowired import org.springframework.beans.factory.annotation.Qualifier import org.springframework.boot.test.context.SpringBootTest import org.springframework.test.context.junit4.SpringRunner import jcg.zheng.demo.groovyspring.model.BudgetType import jcg.zheng.demo.groovyspring.model.GDepartment import jcg.zheng.demo.groovyspring.model.GEmployee import jcg.zheng.demo.groovyspring.model.JDepartment import jcg.zheng.demo.groovyspring.model.JEmployee import jcg.zheng.demo.groovyspring.service.Payroll @RunWith(SpringRunner.class) @SpringBootTest class GroovyPayrollTest { @Autowired @Qualifier("groovyPayroll") private Payroll groovyPayroll @Test public void test_GroovyPayroll_caculateBudget_for_GDepartment_yearly() { GDepartment department = new GDepartment() List reports = [ new GEmployee(firstName:"Mary", lastName:"Zheng", hourlyRate:new BigDecimal(20)), new GEmployee(firstName:"Alex", lastName:"Zheng", hourlyRate:new BigDecimal(10)), new GEmployee(firstName:"Allen", lastName:"Zheng", hourlyRate:new BigDecimal(8)) ] department.setEmployees(reports); def ret = groovyPayroll.caculateBudget(department, BudgetType.YEARLY) assertTrue(ret.compareTo(new BigDecimal(1520)) == 0); } @Test public void test_GroovyPayroll_caculateBudget_for_JDepartment_yearly() { JDepartment department = new JDepartment() List reports = [ new JEmployee(firstName:"Mary", lastName:"Zheng", hourlyRate:new BigDecimal(20)), new JEmployee(firstName:"Alex", lastName:"Zheng", hourlyRate:new BigDecimal(10)), new JEmployee(firstName:"Allen", lastName:"Zheng", hourlyRate:new BigDecimal(8)) ] department.setEmployees(reports); def ret = groovyPayroll.caculateBudget(department, BudgetType.YEARLY) assertTrue(ret.compareTo(new BigDecimal(1520)) == 0); } }
5. Demo Java vs Groovy
Execute mvn install
to build and run JPayrollImpTest
and GPayrollImpTest
and see the output below.
JPayrollImpTest output
2018-03-28 21:16:58.299 INFO 10460 --- [ main] j.z.d.g.service.impl.JPayrollImpTest : Started JPayrollImpTest in 8.053 seconds (JVM running for 9.671) Java caculateBudget for GDepartment took PT0.039S Java caculateBudget for JDepartment took PT0.003S
GPayrollImpTest output
2018-03-28 21:18:37.369 INFO 7588 --- [ main] j.z.d.g.component.GroovyPayrollTest : Started GroovyPayrollTest in 5.96 seconds (JVM running for 7.935) Groovy caculateBudget for GDepartment took 0.036 seconds Groovy caculateBudget for JDepartment took 0.007 seconds
Testing output shows that the Java implementation of the payroll service with the Java POJO class is the fastest of all four tests.
6. Spring Framework and Groovy
In this step, I will demonstrate how to invoke a Rest service and parse the results in Groovy.
6.1 Spring Properties
The Rest service is a public service which gets all the country’s information and gets state’s information for given country.
Add the service host name and logging level in the Spring properties file.
application.properties
AddressService.HostUrl=http://services.groupkt.com logging.level.org.springframework=INFO logging.level.jcg.zheng.demo=DEBUG
6.2 POGOs
Open browser and go to http://services.groupkt.com/country/get/all get all the country’s information. Go to http://services.groupkt.com/state/get/USA/all to get all the state’s information for USA. Both services return a Json
object which contains a List
of String
messages and List of countries or states.
We will create four POGOs to match the Rest service results. Then use JsonSlurper
to parse the results to the expected data type.
GCountry
class contains name
, alpha2_code
, and alpha3_code
.
GCountry.groovy
package jcg.zheng.demo.groovyspring.model; import groovy.transform.* @Canonical class GCountry { String name String alpha2_code String alpha3_code }
GState
class contains name
, abbr
, and capital
, etc.
GState.groovy
package jcg.zheng.demo.groovyspring.model; import groovy.transform.* @Canonical class GState { Long id String country String name String abbr String area String capital String largest_city }
GResponse
class contains messages
and result
.
GResponse.groovy
package jcg.zheng.demo.groovyspring.model; import groovy.transform.* @Canonical class GResponse { List<String> messages List<Object> result }
GResponseWrapper
class contains RestResponse
.
GResponseWrapper.groovy
package jcg.zheng.demo.groovyspring.model; import groovy.json.internal.LazyMap import groovy.transform.* @Canonical class GResponseWrapper { GResponse RestResponse }
6.3 Address Service
Create an address service and annotate it with @Component
. It invokes a REST API service to get all the country’s information. The results is cached into the memory with the @Memoized
annotation.
AddressService
class contains two methods: getCountries
and getStates
.
AddressService.groovy
package jcg.zheng.demo.groovyspring.component import org.slf4j.Logger import org.slf4j.LoggerFactory import org.springframework.beans.factory.annotation.Value import org.springframework.cache.annotation.Cacheable import org.springframework.stereotype.Component import groovy.json.JsonSlurper import groovy.transform.Memoized import jcg.zheng.demo.groovyspring.model.GCountry import jcg.zheng.demo.groovyspring.model.GResponseWrapper import jcg.zheng.demo.groovyspring.model.GState @Component class AddressService { @Value('${AddressService.HostUrl}') private String serviceHostUrl private String countryPath = "/country/get/all" private String statePath = "/state/get/" private static final Logger logger = LoggerFactory.getLogger(AddressService.class) @Memoized List<GState> getStates(String countryCode){ List<GState> states = new ArrayList<>() String getResult = new URL(serviceHostUrl + statePath + countryCode + "/all").text logger.debug( "getStates called rest service.") def jsonMap = new JsonSlurper().parseText(getResult) GResponseWrapper rep = new GResponseWrapper(jsonMap) return rep.getRestResponse().getResult() } @Memoized List<GCountry> getCountries(){ List<GCountry> countryList = new ArrayList<>() String getResult = new URL(serviceHostUrl + countryPath).text logger.debug( "getCountries called rest service.") def jsonMap = new JsonSlurper().parseText(getResult) GResponseWrapper rep = new GResponseWrapper(jsonMap) return rep.getRestResponse().getResult() } }
Create AddressServiceTest
to test both getCountries
and getStates
.
AddressServiceTest.groovy
package jcg.zheng.demo.groovyspring.component import static org.junit.Assert.* import org.junit.Test import org.junit.runner.RunWith import org.springframework.beans.factory.annotation.Autowired import org.springframework.boot.test.context.SpringBootTest import org.springframework.test.context.junit4.SpringRunner import groovy.time.TimeCategory import groovy.time.TimeDuration import jcg.zheng.demo.groovyspring.component.AddressService import jcg.zheng.demo.groovyspring.model.* @RunWith(SpringRunner.class) @SpringBootTest class AddressServiceTest { @Autowired private AddressService addressService @Test public void test_get_allcountries() { def timeStart = new Date() List countries = addressService.getCountries(); def timeStop = new Date() countries = addressService.getCountries(); def timeStop2 = new Date() TimeDuration duration = TimeCategory.minus(timeStop, timeStart) TimeDuration duration2 = TimeCategory.minus(timeStop2, timeStop) println "Groovy first getCountries took " + duration println "Groovy second getCountries took " + duration2 assertTrue(countries.size() == 249) } @Test public void test_get_USA_states() { def timeStart = new Date() List usStates = addressService.getStates("USA"); def timeStop = new Date() usStates = addressService.getStates("USA"); def timeStop2 = new Date() TimeDuration duration = TimeCategory.minus(timeStop, timeStart) TimeDuration duration2 = TimeCategory.minus(timeStop2, timeStop) println "Groovy second getStates took " + duration println "Groovy second getStates took " + duration2 assertTrue(usStates.size() == 55) } }
Run the AddressServiceTest
and confirm data for the countries and states is cached.
AddressServiceTest output
2018-03-28 22:01:06.764 INFO 5060 --- [ main] j.z.d.g.component.AddressServiceTest : Started AddressServiceTest in 4.743 seconds (JVM running for 6.208) 2018-03-28 22:01:07.070 DEBUG 5060 --- [ main] j.z.d.g.component.AddressService : getCountries called rest service. Groovy first getCountries took 0.256 seconds Groovy second getCountries took 0 2018-03-28 22:01:07.210 DEBUG 5060 --- [ main] j.z.d.g.component.AddressService : getStates called rest service. Groovy second getStates took 0.079 seconds Groovy second getStates took 0
6.4 Groovy Spring Application
GroovySpringApplication
is a Groovy class which annotates with Spring annotation driven configuration annotation @SpringBootApplication
. It finds javaPayroll
and invokes its caculateBudget
for a given department. It also finds the AddressService
beans and finds the USA
from the getCountries
returned countries and then gets all the USA states from getStates
service.
GroovySpringApplication.groovy
package jcg.zheng.demo.groovyspring import org.springframework.boot.SpringApplication import org.springframework.boot.autoconfigure.SpringBootApplication import org.springframework.context.ConfigurableApplicationContext import jcg.zheng.demo.groovyspring.component.AddressService import jcg.zheng.demo.groovyspring.model.BudgetType import jcg.zheng.demo.groovyspring.model.GCountry import jcg.zheng.demo.groovyspring.model.GDepartment import jcg.zheng.demo.groovyspring.model.GEmployee import jcg.zheng.demo.groovyspring.model.GState import jcg.zheng.demo.groovyspring.service.Payroll @SpringBootApplication public class GroovySpringApplication { public static void main(String[] args) { ConfigurableApplicationContext context = SpringApplication.run(GroovySpringApplication.class, args) printYearlyBudget(context) printAddress(context) } private static printYearlyBudget(ConfigurableApplicationContext context) { GDepartment department = new GDepartment(id:1) List reports = [ new GEmployee(firstName:"Mary", lastName:"Zheng", hourlyRate:new BigDecimal(20)), new GEmployee(firstName:"Alex", lastName:"Zheng", hourlyRate:new BigDecimal(10)), new GEmployee(firstName:"Allen", lastName:"Zheng", hourlyRate:new BigDecimal(8)) ] department.setEmployees(reports) Payroll payroll = context.getBean("javaPayroll") println "Departement 1 yearly budget: " + payroll.caculateBudget(department, BudgetType.YEARLY) } private static printAddress(ConfigurableApplicationContext context) { AddressService addressService = context.getBean(AddressService.class) List countries = addressService.getCountries() def usa = countries.find{it.get("alpha3_code").equalsIgnoreCase("USA")} println "Found USA " + usa List usStates = addressService.getStates("USA") println "US States :" + usStates } }
7. Demo Spring Groovy Application
Execute the Spring boot application.
Application Output
2018-03-28 21:36:19.045 INFO 9708 --- [ main] j.z.d.g.GroovySpringApplication : Started GroovySpringApplication in 5.715 seconds (JVM running for 7.525) Java caculateBudget for GDepartment took PT0.011S Departement 1 yearly budget: 1520 2018-03-28 21:36:19.358 DEBUG 9708 --- [ main] j.z.d.g.component.AddressService : getCountries called rest service. Found USA [name:United States of America, alpha2_code:US, alpha3_code:USA] 2018-03-28 21:36:19.468 DEBUG 9708 --- [ main] j.z.d.g.component.AddressService : getStates called rest service. US States :[[id:1, country:USA, name:Alabama, abbr:AL, area:135767SKM, largest_city:Birmingham, capital:Montgomery], [id:2, country:USA, name:Alaska, abbr:AK, area:1723337SKM, largest_city:Anchorage, capital:Juneau], [id:3, country:USA, name:Arizona, abbr:AZ, area:113594SKM, largest_city:Phoenix, capital:Phoenix], [id:4, country:USA, name:Arkansas, abbr:AR, area:52035SKM, largest_city:Little Rock, capital:Little Rock], [id:5, country:USA, name:California, abbr:CA, area:423967SKM, largest_city:Los Angeles, capital:Sacramento], [id:6, country:USA, name:Colorado, abbr:CO, area:103642SKM, largest_city:Denver, capital:Denver], [id:7, country:USA, name:Connecticut, abbr:CT, area:14357SKM, largest_city:Bridgeport, capital:Hartford], [id:8, country:USA, name:Delaware, abbr:DE, area:6446SKM, largest_city:Wilmington, capital:Dover], [id:9, country:USA, name:Florida, abbr:FL, area:170312SKM, largest_city:Jacksonville, capital:Tallahassee], [id:10, country:USA, name:Georgia, abbr:GA, area:57513SKM, largest_city:Atlanta, capital:Atlanta], [id:11, country:USA, name:Hawaii, abbr:HI, area:6423SKM, largest_city:Honolulu, capital:Honolulu], [id:12, country:USA, name:Idaho, abbr:ID, area:82643SKM, largest_city:Boise, capital:Boise], [id:13, country:USA, name:Illinois, abbr:IL, area:149995SKM, largest_city:Chicago, capital:Springfield], [id:14, country:USA, name:Indiana, abbr:IN, area:35826SKM, largest_city:Indianapolis, capital:Indianapolis], [id:15, country:USA, name:Iowa, abbr:IA, area:55857SKM, largest_city:Des Moines, capital:Des Moines], [id:16, country:USA, name:Kansas, abbr:KS, area:213100SKM, largest_city:Wichita, capital:Topeka], [id:17, country:USA, name:Kentucky, abbr:KY, area:104656SKM, largest_city:Louisville, capital:Frankfort], [id:18, country:USA, name:Louisiana, abbr:LA, area:135659SKM, largest_city:New Orleans, capital:Baton Rouge], [id:19, country:USA, name:Maine, abbr:ME, area:91633SKM, largest_city:Portland, capital:Augusta], [id:20, country:USA, name:Maryland, abbr:MD, area:32131SKM, largest_city:Baltimore, capital:Annapolis], [id:21, country:USA, name:Massachusetts, abbr:MA, area:7800SKM, largest_city:Boston, capital:Boston], [id:22, country:USA, name:Michigan, abbr:MI, area:250487SKM, largest_city:Detroit, capital:Lansing], [id:23, country:USA, name:Minnesota, abbr:MN, area:225163SKM, largest_city:Minneapolis, capital:St. Paul], [id:24, country:USA, name:Mississippi, abbr:MS, area:46923SKM, largest_city:Jackson, capital:Jackson], [id:25, country:USA, name:Missouri, abbr:MO, area:180540SKM, largest_city:Kansas City, capital:Jefferson City], [id:26, country:USA, name:Montana, abbr:MT, area:380831SKM, largest_city:Billings, capital:Helena], [id:27, country:USA, name:Nebraska, abbr:NE, area:200330SKM, largest_city:Omaha, capital:Lincoln], [id:28, country:USA, name:Nevada, abbr:NV, area:286380SKM, largest_city:Las Vegas, capital:Carson City], [id:29, country:USA, name:New Hampshire, abbr:NH, area:24214SKM, largest_city:Manchester, capital:Concord], [id:30, country:USA, name:New Jersey, abbr:NJ, area:22591SKM, largest_city:Newark, capital:Trenton], [id:31, country:USA, name:New Mexico, abbr:NM, area:314917SKM, largest_city:Albuquerque, capital:Santa Fe], [id:32, country:USA, name:New York, abbr:NY, area:141297SKM, largest_city:New York City, capital:Albany], [id:33, country:USA, name:North Carolina, abbr:NC, area:139391SKM, largest_city:Charlotte, capital:Raleigh], [id:34, country:USA, name:North Dakota, abbr:ND, area:183108SKM, largest_city:Fargo, capital:Bismarck], [id:35, country:USA, name:Ohio, abbr:OH, area:40861SKM, largest_city:Columbus, capital:Columbus], [id:36, country:USA, name:Oklahoma, abbr:OK, area:68595SKM, largest_city:Oklahoma City, capital:Oklahoma City], [id:37, country:USA, name:Oregon, abbr:OR, area:254799SKM, largest_city:Portland, capital:Salem], [id:38, country:USA, name:Pennsylvania, abbr:PA, area:119280SKM, largest_city:Philadelphia, capital:Harrisburg], [id:39, country:USA, name:Rhode Island, abbr:RI, area:1034SKM, largest_city:Providence, capital:Providence], [id:40, country:USA, name:South Carolina, abbr:SC, area:82933SKM, largest_city:Charleston, capital:Columbia], [id:41, country:USA, name:South Dakota, abbr:SD, area:199729SKM, largest_city:Sioux Falls, capital:Pierre], [id:42, country:USA, name:Tennessee, abbr:TN, area:41235SKM, largest_city:Nashville, capital:Nashville], [id:43, country:USA, name:Texas, abbr:TX, area:695662SKM, largest_city:Houston, capital:Austin], [id:44, country:USA, name:Utah, abbr:UT, area:82170SKM, largest_city:Salt Lake City, capital:Salt Lake City], [id:45, country:USA, name:Vermont, abbr:VT, area:24906SKM, largest_city:Burlington, capital:Montpelier], [id:46, country:USA, name:Virginia, abbr:VA, area:110787SKM, largest_city:Virginia Beach, capital:Richmond], [id:47, country:USA, name:Washington, abbr:WA, area:184661SKM, largest_city:Seattle, capital:Olympia], [id:48, country:USA, name:West Virginia, abbr:WV, area:24038SKM, largest_city:Charleston, capital:Charleston], [id:49, country:USA, name:Wisconsin, abbr:WI, area:169635SKM, largest_city:Milwaukee, capital:Madison], [id:50, country:USA, name:Wyoming, abbr:WY, area:97093SKM, largest_city:Cheyenne, capital:Cheyenne], [id:51, country:USA, name:American Samoa, abbr:AS, area:1505SKM, capital:Pago Pago], [id:52, country:USA, name:Guam, abbr:GU, area:1478SKM, capital:Hagåtña], [id:53, country:USA, name:Northern Mariana Islands, abbr:MP, area:5117SKM, capital:Saipan], [id:54, country:USA, name:Puerto Rico, abbr:PR, area:13791SKM, capital:San Juan], [id:55, country:USA, name:U.S. Virgin Islands, abbr:VI, area:1898SKM, capital:Charlotte Amalie]]
8. Summary
In this example, we built a Spring Boot application with Groovy to demonstrate the integration between Spring and Groovy. We also demonstrated that Groovy source code is shorter and cleaner than Java. But Java is faster than Groovy.
9. References
- https://dzone.com/articles/spring-4-groovy
- https://o7planning.org/en/11799/spring-boot-and-groovy-tutorial
- https://objectpartners.com/2016/01/12/using-groovy-based-spring
- https://spring.io/blog/2013/12/12/announcing-spring-framework-4-0-ga-release
- https://www.javacodegeeks.com/2013/01/spring-dynamic-language-support-with-groovy.html
- http://www.groupkt.com/post/f2129b88/free-restful-web-services-to-consume-and-test.htm
10. Download the Source Code
This example consists of a Spring boot application which developed in Groovy.
You can download the full source code of this example here: Spring Framework Groovy Tutorial
Last updated on Apr. 29th, 2021