spring

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.

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:

  1. Add a Groovy dependency in the pom.xml
  2. Add a Groovy source folder
  3. 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

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
<?xml version="1.0" encoding="UTF-8"?>
    <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.

spring framework groovy - Project Structure
Figure 1 Project Structure

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

01
02
03
04
05
06
07
08
09
10
11
12
13
14
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

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
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

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
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

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
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

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
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

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
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

01
02
03
04
05
06
07
08
09
10
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

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
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

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
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

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
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

1
2
3
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

1
2
3
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

1
2
3
4
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 namealpha2_code, and alpha3_code.

GCountry.groovy

01
02
03
04
05
06
07
08
09
10
11
package jcg.zheng.demo.groovyspring.model;
 
import groovy.transform.*
 
@Canonical
class GCountry {
 
    String name
    String alpha2_code
    String alpha3_code
}

GState class contains nameabbr, and capital, etc.

GState.groovy

01
02
03
04
05
06
07
08
09
10
11
12
13
14
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

1
2
3
4
5
6
7
8
9
package jcg.zheng.demo.groovyspring.model;
import groovy.transform.*
 
@Canonical
class GResponse {
    List<String> messages
 
    List<Object> result
}

GResponseWrapper class contains RestResponse.

Want to master Spring Framework ?
Subscribe to our newsletter and download the Spring Framework Cookbook right now!
In order to help you master the leading and innovative Java framework, we have compiled a kick-ass guide with all its major features and use cases! Besides studying them online you may download the eBook in PDF format!

GResponseWrapper.groovy

1
2
3
4
5
6
7
8
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

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
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

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
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

1
2
3
4
5
6
7
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

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
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

1
2
3
4
5
6
7
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

10. Download the Source Code

This example consists of a Spring boot application which developed in Groovy.

Download
You can download the full source code of this example here: Spring Framework Groovy Tutorial

Last updated on Apr. 29th, 2021

Do you want to know how to develop your skillset to become a Java Rockstar?
Subscribe to our newsletter to start Rocking right now!
To get you started we give you our best selling eBooks for FREE!
1. JPA Mini Book
2. JVM Troubleshooting Guide
3. JUnit Tutorial for Unit Testing
4. Java Annotations Tutorial
5. Java Interview Questions
6. Spring Interview Questions
7. Android UI Design
and many more ....
I agree to the Terms and Privacy Policy

Mary Zheng

Mary has graduated from Mechanical Engineering department at ShangHai JiaoTong University. She also holds a Master degree in Computer Science from Webster University. During her studies she has been involved with a large number of projects ranging from programming and software engineering. She works as a senior Software Engineer in the telecommunications sector where she acts as a leader and works with others to design, implement, and monitor the software solution.
Subscribe
Notify of
guest


This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Back to top button