diff --git a/spring-boot-modules/spring-boot-groovy/pom.xml b/spring-boot-modules/spring-boot-groovy/pom.xml index 820bb0fd7a..ab1fef6865 100644 --- a/spring-boot-modules/spring-boot-groovy/pom.xml +++ b/spring-boot-modules/spring-boot-groovy/pom.xml @@ -27,6 +27,7 @@ org.codehaus.groovy groovy + ${groovy.version} org.springframework.boot @@ -70,6 +71,7 @@ com.baeldung.springwithgroovy.SpringBootGroovyApplication + 3.0.13 \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-groovy/src/main/groovy/com/baeldung/springgroovyconfig/GroovyBeanBuilder.groovy b/spring-boot-modules/spring-boot-groovy/src/main/groovy/com/baeldung/springgroovyconfig/GroovyBeanBuilder.groovy new file mode 100644 index 0000000000..ca4e07d302 --- /dev/null +++ b/spring-boot-modules/spring-boot-groovy/src/main/groovy/com/baeldung/springgroovyconfig/GroovyBeanBuilder.groovy @@ -0,0 +1,23 @@ +package com.baeldung.springgroovyconfig + + +beans { + + // Declares a simple bean with a constructor argument + companyBean(Company, name: 'ABC Inc'); + + // The same bean can be declared using a simpler syntax: beanName(type, constructor-args) + company String, 'XYZ Inc' + + // Declares an employee object with setters referencing the previous bean + employee(Employee) { + firstName = 'Lakshmi' + lastName = 'Priya' + + // References to other beans can be done in both the ways + company = company // or vendor = ref('company') + } + + // Allows import of other configuration files, both XML and Groovy + importBeans('classpath:xml-bean-config.xml') +} diff --git a/spring-boot-modules/spring-boot-groovy/src/main/groovy/com/baeldung/springgroovyconfig/NotificationService.groovy b/spring-boot-modules/spring-boot-groovy/src/main/groovy/com/baeldung/springgroovyconfig/NotificationService.groovy new file mode 100644 index 0000000000..5c4ad09276 --- /dev/null +++ b/spring-boot-modules/spring-boot-groovy/src/main/groovy/com/baeldung/springgroovyconfig/NotificationService.groovy @@ -0,0 +1,7 @@ +package com.baeldung.springgroovyconfig; + +interface NotificationService { + + String getMessage(); + +} diff --git a/spring-boot-modules/spring-boot-groovy/src/main/groovy/com/baeldung/springgroovyconfig/NotificationServiceImpl.groovy b/spring-boot-modules/spring-boot-groovy/src/main/groovy/com/baeldung/springgroovyconfig/NotificationServiceImpl.groovy new file mode 100644 index 0000000000..ae3f0a6b58 --- /dev/null +++ b/spring-boot-modules/spring-boot-groovy/src/main/groovy/com/baeldung/springgroovyconfig/NotificationServiceImpl.groovy @@ -0,0 +1,6 @@ +package com.baeldung.springgroovyconfig; + +class NotificationServiceImpl implements NotificationService { + + String message; +} diff --git a/spring-boot-modules/spring-boot-groovy/src/main/groovy/com/baeldung/springgroovyconfig/SpringGroovyConfiguration.groovy b/spring-boot-modules/spring-boot-groovy/src/main/groovy/com/baeldung/springgroovyconfig/SpringGroovyConfiguration.groovy new file mode 100644 index 0000000000..54d40e1692 --- /dev/null +++ b/spring-boot-modules/spring-boot-groovy/src/main/groovy/com/baeldung/springgroovyconfig/SpringGroovyConfiguration.groovy @@ -0,0 +1,25 @@ +package com.baeldung.springgroovyconfig + +import org.springframework.context.annotation.Bean +import org.springframework.context.annotation.Configuration + +@Configuration +class SpringGroovyConfiguration { + + public static void main(String[] args) { } + + @Bean + List fruits() { + [ + 'Apple', + 'Orange', + 'Banana', + 'Grapes' + ] + } + + @Bean + Map rankings() { + [1: 'Gold', 2: 'Silver', 3: 'Bronze'] + } +} diff --git a/spring-boot-modules/spring-boot-groovy/src/main/java/com/baeldung/springgroovyconfig/Company.java b/spring-boot-modules/spring-boot-groovy/src/main/java/com/baeldung/springgroovyconfig/Company.java new file mode 100644 index 0000000000..477c2c13cb --- /dev/null +++ b/spring-boot-modules/spring-boot-groovy/src/main/java/com/baeldung/springgroovyconfig/Company.java @@ -0,0 +1,41 @@ +package com.baeldung.springgroovyconfig; + +public class Company { + + private String name; + private String contact; + private String type; + + public Company() { + } + + public Company(String name) { + super(); + this.name = name; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getContact() { + return contact; + } + + public void setContact(String contact) { + this.contact = contact; + } + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + +} diff --git a/spring-boot-modules/spring-boot-groovy/src/main/java/com/baeldung/springgroovyconfig/Employee.java b/spring-boot-modules/spring-boot-groovy/src/main/java/com/baeldung/springgroovyconfig/Employee.java new file mode 100644 index 0000000000..3a90f98268 --- /dev/null +++ b/spring-boot-modules/spring-boot-groovy/src/main/java/com/baeldung/springgroovyconfig/Employee.java @@ -0,0 +1,32 @@ +package com.baeldung.springgroovyconfig; + +public class Employee { + + private String firstName; + private String lastName; + private Company company; + + 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 Company getCompany() { + return company; + } + + public void setCompany(Company company) { + this.company = company; + } +} diff --git a/spring-boot-modules/spring-boot-groovy/src/main/resources/StringJoiner.groovy b/spring-boot-modules/spring-boot-groovy/src/main/resources/StringJoiner.groovy new file mode 100644 index 0000000000..51afa9bc06 --- /dev/null +++ b/spring-boot-modules/spring-boot-groovy/src/main/resources/StringJoiner.groovy @@ -0,0 +1,7 @@ +class StringJoiner { + + String join(String arg1, String arg2) { + arg1 + arg2; + } + +} diff --git a/spring-boot-modules/spring-boot-groovy/src/main/resources/StringJoinerScript.groovy b/spring-boot-modules/spring-boot-groovy/src/main/resources/StringJoinerScript.groovy new file mode 100644 index 0000000000..224f5fb9a8 --- /dev/null +++ b/spring-boot-modules/spring-boot-groovy/src/main/resources/StringJoinerScript.groovy @@ -0,0 +1 @@ +arg1 + arg2; diff --git a/spring-boot-modules/spring-boot-groovy/src/main/resources/groovy-xml-config.xml b/spring-boot-modules/spring-boot-groovy/src/main/resources/groovy-xml-config.xml new file mode 100644 index 0000000000..475bd582e7 --- /dev/null +++ b/spring-boot-modules/spring-boot-groovy/src/main/resources/groovy-xml-config.xml @@ -0,0 +1,26 @@ + + + + + + + + + + + package com.baeldung.springgroovyconfig; + import com.baeldung.springgroovyconfig.NotificationService; + + class Notifier implements NotificationService { + String message + } + + + + + + \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-groovy/src/test/java/com/baeldung/springgroovyconfig/SpringGroovyConfigUnitTest.java b/spring-boot-modules/spring-boot-groovy/src/test/java/com/baeldung/springgroovyconfig/SpringGroovyConfigUnitTest.java new file mode 100644 index 0000000000..3059773d59 --- /dev/null +++ b/spring-boot-modules/spring-boot-groovy/src/test/java/com/baeldung/springgroovyconfig/SpringGroovyConfigUnitTest.java @@ -0,0 +1,144 @@ +package com.baeldung.springgroovyconfig; + +import static org.assertj.core.api.Assertions.fail; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +import java.io.File; +import java.util.List; + +import org.junit.jupiter.api.Test; +import org.springframework.beans.BeansException; +import org.springframework.context.annotation.AnnotationConfigApplicationContext; +import org.springframework.context.support.ClassPathXmlApplicationContext; +import org.springframework.context.support.GenericGroovyApplicationContext; +import org.springframework.util.ResourceUtils; + +import groovy.lang.Binding; +import groovy.lang.GroovyObject; +import groovy.util.GroovyScriptEngine; + +class SpringGroovyConfigUnitTest { + + private static final String FILE_NAME = "GroovyBeanBuilder.groovy"; + private static final String FILE_PATH = "src/main/groovy/com/baeldung/springgroovyconfig/"; + + @Test + void givenGroovyConfigFile_whenCalledWithBeanName_thenReturnCompanyBean() { + try (GenericGroovyApplicationContext ctx = new GenericGroovyApplicationContext()) { + ctx.load("file:" + getPath(FILE_PATH) + FILE_NAME); + ctx.refresh(); + + Company company = (Company) ctx.getBean("companyBean"); + + assertEquals("ABC Inc", company.getName()); + } catch (BeansException | IllegalStateException e) { + fail(e.getMessage()); + } + } + + @Test + void givenGroovyConfigFile_whenCalledWithRefBean_thenReturnEmployeeBean() { + try (GenericGroovyApplicationContext ctx = new GenericGroovyApplicationContext()) { + ctx.load("file:" + getPath(FILE_PATH) + FILE_NAME); + ctx.refresh(); + + Employee employee = ctx.getBean(Employee.class); + + assertEquals("Lakshmi", employee.getFirstName()); + assertEquals("Priya", employee.getLastName()); + assertEquals("XYZ Inc", employee.getCompany() + .getName()); + } catch (BeansException | IllegalStateException e) { + fail(e.getMessage()); + } + } + + @SuppressWarnings("unchecked") + @Test + void givenGroovyFileWithSpringAnnotations_whenCalledWithBeanName_thenReturnValidBean() { + + try (AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();) { + ctx.register(SpringGroovyConfiguration.class); + ctx.refresh(); + + List fruits = (List) ctx.getBean("fruits"); + + assertNotNull(fruits); + assertTrue(fruits.size() == 4); + assertEquals("Apple", fruits.get(0)); + } catch (BeansException | IllegalStateException e) { + fail(e.getMessage()); + } + } + + @Test + void givenGroovyBeanConfiguredInXml_whenCalledWithBeanName_thenReturnValidBean() { + try (ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("groovy-xml-config.xml")) { + ctx.refresh(); + + NotificationService notifier = (NotificationService) ctx.getBean("notification"); + + assertEquals("Hello", notifier.getMessage()); + } catch (BeansException | IllegalStateException e) { + fail(e.getMessage()); + } + } + + @Test + void givenGroovyBeanConfiguredAsInlineScript_whenCalledWithBeanName_thenReturnValidBean() { + try (ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("groovy-xml-config.xml")) { + ctx.refresh(); + + NotificationService notifier = (NotificationService) ctx.getBean("notifier"); + + assertEquals("Have a nice day!", notifier.getMessage()); + } catch (BeansException | IllegalStateException e) { + fail(e.getMessage()); + } + } + + @SuppressWarnings("unchecked") + @Test + void givenGroovyScript_whenCalledWithScriptEngine_thenReturnsResult() { + try { + GroovyScriptEngine engine = new GroovyScriptEngine(ResourceUtils.getFile("file:src/main/resources/") + .getAbsolutePath(), this.getClass().getClassLoader()); + Class joinerClass = engine.loadScriptByName("StringJoiner.groovy"); + GroovyObject joiner = joinerClass.getDeclaredConstructor() + .newInstance(); + Object result = joiner.invokeMethod("join", new Object[] { "Mr.", "Bob" }); + + assertEquals("Mr.Bob", result.toString()); + } catch (Exception e) { + fail(e.getMessage()); + } + } + + @Test + void givenGroovyScript_whenCalledWithBindingObject_thenReturnsResult() { + try { + GroovyScriptEngine engine = new GroovyScriptEngine(ResourceUtils.getFile("file:src/main/resources/") + .getAbsolutePath(), this.getClass().getClassLoader()); + Binding binding = new Binding(); + binding.setVariable("arg1", "Mr."); + binding.setVariable("arg2", "Bob"); + Object result = engine.run("StringJoinerScript.groovy", binding); + + assertEquals("Mr.Bob", result.toString()); + } catch (Exception e) { + fail(e.getMessage()); + } + } + + private String getPath(String filePath) { + String pathPart = new File(".").getAbsolutePath(); + pathPart = pathPart.replace(".", ""); + pathPart = pathPart.replace("\\", "/"); + pathPart = pathPart + filePath; + + return pathPart; + } + +}