gary f.
gary f.

Reputation: 51

How to setup a java based Spring Boot app to use Groovy scripting

How does one setup a Spring Boot app written mostly in java and be able to refer to Groovy scripts as well?

I read the following articles:

http://www.ibm.com/developerworks/library/j-groovierspring1/ http://www.ibm.com/developerworks/library/j-groovierspring2/

These were written well before Spring Boot's time. I want the runtime dynamic nature of Groovy scripts in my java based Spring Boot application. I don't want to compile my Groovy classes out-of-band and refer to them. I want the scripting ability (as described in the linked web pages).

What I've done so far is just create a bare bones Spring Boot app that really does nothing and tried to get the app to recognize a bean implemented by a Groovy script. I used a modified version of GroovyPdfGenerator that's mentioned in the linked articles.

Here's what I have:

// PdfGenerator.java, lives under demo
package demo;
public interface PdfGenerator {
    String pdfFor(String name);
}

// GroovyPdfGenerator.groovy, lives under demo
package demo
import demo.PdfGenerator
class GroovyPdfGenerator implements PdfGenerator {
    public String pdfFor(String name) {
        return "Hello, World!"
    }
}

// beans.xml, lives under src/main/resources
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:lang="http://www.springframework.org/schema/lang"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-4.1.xsd
    http://www.springframework.org/schema/lang
    http://www.springframework.org/schema/lang/spring-lang-2.0.xsd">
    <lang:groovy id="pdfGenerator" script source="classpath:GroovyPdfGenerator.groovy"/>
</beans>

// DemoGroovyTaskApplication.java, lives under demo
package demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ImportResource;
@SpringBootApplication
@ImportResource(value = { "classpath:beans.xml" })
public class DemoGroovyTaskApplication {
    public static void main(String[] args) {
        SpringApplication.run(DemoGroovyTaskApplication.class, args);
    }
}

I tried moving the Groovy file to under resources/ but that didn't work. Also, I couldn't figure out how to get Spring Boot to load the Groovy bean other than using a XML configuration.

Anyone know how this may work?

Forgot to mention, what I get w/ my code is a ClassNotFoundException. I broke on that exception and Spring is looking scriptFactory.pdfGenerator.

Here's the stack trace w/ debugging enabled (sans Negative Matches):

2015-01-23 05:47:49.646  INFO 56013 --- [          main] demo.DemoGroovyTaskApplication        : Starting DemoGroovyTaskApplication on gary-fong2.local with PID 56013 (/Users/gary.fong/development/spring/experiments/my-workspace/demoGroovyTask/target/classes started by gary.fong in /Users/gary.fong/development/spring/experiments/my-workspace/demoGroovyTask)
2015-01-23 05:47:49.650 DEBUG 56013 --- [          main] o.s.boot.SpringApplication            : Loading source class demo.DemoGroovyTaskApplication
2015-01-23 05:47:49.694 DEBUG 56013 --- [          main] o.s.b.c.c.ConfigFileApplicationListener  : Skipped config file 'file:./config/application.yaml' resource not found
2015-01-23 05:47:49.694 DEBUG 56013 --- [          main] o.s.b.c.c.ConfigFileApplicationListener  : Skipped config file 'file:./config/application.xml' resource not found
2015-01-23 05:47:49.694 DEBUG 56013 --- [          main] o.s.b.c.c.ConfigFileApplicationListener  : Skipped config file 'file:./config/application.properties' resource not found
2015-01-23 05:47:49.694 DEBUG 56013 --- [          main] o.s.b.c.c.ConfigFileApplicationListener  : Skipped config file 'file:./config/application.yml' resource not found
2015-01-23 05:47:49.694 DEBUG 56013 --- [          main] o.s.b.c.c.ConfigFileApplicationListener  : Skipped config file 'file:./application.yaml' resource not found
2015-01-23 05:47:49.694 DEBUG 56013 --- [          main] o.s.b.c.c.ConfigFileApplicationListener  : Skipped config file 'file:./application.xml' resource not found
2015-01-23 05:47:49.694 DEBUG 56013 --- [          main] o.s.b.c.c.ConfigFileApplicationListener  : Skipped config file 'file:./application.properties' resource not found
2015-01-23 05:47:49.695 DEBUG 56013 --- [          main] o.s.b.c.c.ConfigFileApplicationListener  : Skipped config file 'file:./application.yml' resource not found
2015-01-23 05:47:49.695 DEBUG 56013 --- [          main] o.s.b.c.c.ConfigFileApplicationListener  : Skipped config file 'classpath:/config/application.yaml' resource not found
2015-01-23 05:47:49.695 DEBUG 56013 --- [          main] o.s.b.c.c.ConfigFileApplicationListener  : Skipped config file 'classpath:/config/application.xml' resource not found
2015-01-23 05:47:49.695 DEBUG 56013 --- [          main] o.s.b.c.c.ConfigFileApplicationListener  : Skipped config file 'classpath:/config/application.properties' resource not found
2015-01-23 05:47:49.695 DEBUG 56013 --- [          main] o.s.b.c.c.ConfigFileApplicationListener  : Skipped config file 'classpath:/config/application.yml' resource not found
2015-01-23 05:47:49.695 DEBUG 56013 --- [          main] o.s.b.c.c.ConfigFileApplicationListener  : Skipped config file 'classpath:/application.yaml' resource not found
2015-01-23 05:47:49.695 DEBUG 56013 --- [          main] o.s.b.c.c.ConfigFileApplicationListener  : Skipped config file 'classpath:/application.xml' resource not found
2015-01-23 05:47:49.695 DEBUG 56013 --- [          main] o.s.b.c.c.ConfigFileApplicationListener  : Skipped config file 'classpath:/application.properties' 
2015-01-23 05:47:49.695 DEBUG 56013 --- [          main] o.s.b.c.c.ConfigFileApplicationListener  : Skipped config file 'classpath:/application.yml' resource not found
2015-01-23 05:47:49.700  INFO 56013 --- [          main] s.c.a.AnnotationConfigApplicationContext : Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@a39e3dd: startup date [Fri Jan 23 05:47:49 PST 2015]; root of context hierarchy
2015-01-23 05:47:50.014  INFO 56013 --- [          main] o.s.b.f.xml.XmlBeanDefinitionReader      : Loading XML bean definitions from class path resource [beans.xml]
2015-01-23 05:47:50.377  INFO 56013 --- [          main] .b.l.ClasspathLoggingApplicationListener : Application failed to start with classpath: [file:/Users/gary.fong/development/spring/experiments/my-workspace/demoGroovyTask/target/classes/, file:/Users/gary.fong/.m2/repository/org/springframework/boot/spring-boot-starter/1.2.1.RELEASE/spring-boot-starter-1.2.1.RELEASE.jar, file:/Users/gary.fong/.m2/repository/org/springframework/boot/spring-boot/1.2.1.RELEASE/spring-boot-1.2.1.RELEASE.jar, file:/Users/gary.fong/.m2/repository/org/springframework/spring-context/4.1.4.RELEASE/spring-context-4.1.4.RELEASE.jar, file:/Users/gary.fong/.m2/repository/org/springframework/spring-aop/4.1.4.RELEASE/spring-aop-4.1.4.RELEASE.jar, file:/Users/gary.fong/.m2/repository/aopalliance/aopalliance/1.0/aopalliance-1.0.jar, file:/Users/gary.fong/.m2/repository/org/springframework/spring-beans/4.1.4.RELEASE/spring-beans-4.1.4.RELEASE.jar, file:/Users/gary.fong/.m2/repository/org/springframework/spring-expression/4.1.4.RELEASE/spring-expression-4.1.4.RELEASE.jar, file:/Users/gary.fong/.m2/repository/org/springframework/boot/spring-boot-autoconfigure/1.2.1.RELEASE/spring-boot-autoconfigure-1.2.1.RELEASE.jar, file:/Users/gary.fong/.m2/repository/org/springframework/boot/spring-boot-starter-logging/1.2.1.RELEASE/spring-boot-starter-logging-1.2.1.RELEASE.jar, file:/Users/gary.fong/.m2/repository/org/slf4j/jcl-over-slf4j/1.7.8/jcl-over-slf4j-1.7.8.jar, file:/Users/gary.fong/.m2/repository/org/slf4j/slf4j-api/1.7.8/slf4j-api-1.7.8.jar, file:/Users/gary.fong/.m2/repository/org/slf4j/jul-to-slf4j/1.7.8/jul-to-slf4j-1.7.8.jar, file:/Users/gary.fong/.m2/repository/org/slf4j/log4j-over-slf4j/1.7.8/log4j-over-slf4j-1.7.8.jar, file:/Users/gary.fong/.m2/repository/ch/qos/logback/logback-classic/1.1.2/logback-classic-1.1.2.jar, file:/Users/gary.fong/.m2/repository/ch/qos/logback/logback-core/1.1.2/logback-core-1.1.2.jar, file:/Users/gary.fong/.m2/repository/org/springframework/spring-core/4.1.4.RELEASE/spring-core-4.1.4.RELEASE.jar, file:/Users/gary.fong/.m2/repository/org/yaml/snakeyaml/1.14/snakeyaml-1.14.jar]
2015-01-23 05:47:50.378 DEBUG 56013 --- [          main] utoConfigurationReportLoggingInitializer : 
=========================
AUTO-CONFIGURATION REPORT
=========================
Positive matches:
-----------------
   JmxAutoConfiguration
      - @ConditionalOnClass classes found: org.springframework.jmx.export.MBeanExporter (OnClassCondition)
      - matched (OnPropertyCondition)
   JmxAutoConfiguration#mbeanExporter
      - @ConditionalOnMissingBean (types: org.springframework.jmx.export.MBeanExporter; SearchStrategy: current) found no beans (OnBeanCondition)
   JmxAutoConfiguration#mbeanServer
      - @ConditionalOnMissingBean (types: javax.management.MBeanServer; SearchStrategy: all) found no beans (OnBeanCondition)
   JmxAutoConfiguration#objectNamingStrategy
      - @ConditionalOnMissingBean (types: org.springframework.jmx.export.naming.ObjectNamingStrategy; SearchStrategy: current) found no beans (OnBeanCondition)
   PropertyPlaceholderAutoConfiguration#propertySourcesPlaceholderConfigurer
      - @ConditionalOnMissingBean (types: org.springframework.context.support.PropertySourcesPlaceholderConfigurer; SearchStrategy: current) found no beans (OnBeanCondition)
2015-01-23 05:47:50.384 ERROR 56013 --- [          main] o.s.boot.SpringApplication            : Application startup failed
java.lang.NoClassDefFoundError: org/codehaus/groovy/control/CompilationFailedException
    at java.lang.Class.getDeclaredMethods0(Native Method)
    at java.lang.Class.privateGetDeclaredMethods(Class.java:2615)
    at java.lang.Class.getDeclaredMethods(Class.java:1860)
    at org.springframework.util.ReflectionUtils.getDeclaredMethods(ReflectionUtils.java:571)
    at org.springframework.util.ReflectionUtils.doWithMethods(ReflectionUtils.java:490)
    at org.springframework.util.ReflectionUtils.doWithMethods(ReflectionUtils.java:474)
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.determineCandidateConstructors(AutowiredAnnotationBeanPostProcessor.java:241)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.determineConstructorsFromBeanPostProcessors(AbstractAutowireCapableBeanFactory.java:1057)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1030)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:504)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:476)
    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:303)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:299)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199)
    at org.springframework.scripting.support.ScriptFactoryPostProcessor.prepareScriptBeans(ScriptFactoryPostProcessor.java:357)
    at org.springframework.scripting.support.ScriptFactoryPostProcessor.predictBeanType(ScriptFactoryPostProcessor.java:251)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.predictBeanType(AbstractAutowireCapableBeanFactory.java:599)
    at org.springframework.beans.factory.support.AbstractBeanFactory.isFactoryBean(AbstractBeanFactory.java:1397)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.doGetBeanNamesForType(DefaultListableBeanFactory.java:434)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeanNamesForType(DefaultListableBeanFactory.java:404)
    at org.springframework.context.support.AbstractApplicationContext.getBeanNamesForType(AbstractApplicationContext.java:1046)
    at org.springframework.context.support.AbstractApplicationContext.registerListeners(AbstractApplicationContext.java:726)
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:477)
    at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:691)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:321)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:961)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:950)
    at demo.DemoGroovyTaskApplication.main(DemoGroovyTaskApplication.java:11)
Caused by: java.lang.ClassNotFoundException: org.codehaus.groovy.control.CompilationFailedException
    at java.net.URLClassLoader$1.run(URLClassLoader.java:366)
    at java.net.URLClassLoader$1.run(URLClassLoader.java:355)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.net.URLClassLoader.findClass(URLClassLoader.java:354)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:425)
    at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:308)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:358)
    ... 29 common frames omitted
2015-01-23 05:47:50.384  INFO 56013 --- [          main] s.c.a.AnnotationConfigApplicationContext : Closing org.springframework.context.annotation.AnnotationConfigApplicationContext@a39e3dd: startup date [Fri Jan 23 05:47:49 PST 2015]; root of context hierarchy
2015-01-23 05:47:50.386  WARN 56013 --- [          main] s.c.a.AnnotationConfigApplicationContext : Exception thrown from LifecycleProcessor on context close
java.lang.IllegalStateException: LifecycleProcessor not initialized - call 'refresh' before invoking lifecycle methods via the context: org.springframework.context.annotation.AnnotationConfigApplicationContext@a39e3dd: startup date [Fri Jan 23 05:47:49 PST 2015]; root of context hierarchy
    at org.springframework.context.support.AbstractApplicationContext.getLifecycleProcessor(AbstractApplicationContext.java:357)
    at org.springframework.context.support.AbstractApplicationContext.doClose(AbstractApplicationContext.java:877)
    at org.springframework.context.support.AbstractApplicationContext.close(AbstractApplicationContext.java:836)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:343)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:961)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:950)
    at demo.DemoGroovyTaskApplication.main(DemoGroovyTaskApplication.java:11)
Exception in thread "main" java.lang.NoClassDefFoundError: org/codehaus/groovy/control/CompilationFailedException
    at java.lang.Class.getDeclaredMethods0(Native Method)
    at java.lang.Class.privateGetDeclaredMethods(Class.java:2615)
    at java.lang.Class.getDeclaredMethods(Class.java:1860)
    at org.springframework.util.ReflectionUtils.getDeclaredMethods(ReflectionUtils.java:571)
    at org.springframework.util.ReflectionUtils.doWithMethods(ReflectionUtils.java:490)
    at org.springframework.util.ReflectionUtils.doWithMethods(ReflectionUtils.java:474)
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.determineCandidateConstructors(AutowiredAnnotationBeanPostProcessor.java:241)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.determineConstructorsFromBeanPostProcessors(AbstractAutowireCapableBeanFactory.java:1057)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1030)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:504)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:476)
    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:303)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:299)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199)
    at org.springframework.scripting.support.ScriptFactoryPostProcessor.prepareScriptBeans(ScriptFactoryPostProcessor.java:357)
    at org.springframework.scripting.support.ScriptFactoryPostProcessor.predictBeanType(ScriptFactoryPostProcessor.java:251)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.predictBeanType(AbstractAutowireCapableBeanFactory.java:599)
    at org.springframework.beans.factory.support.AbstractBeanFactory.isFactoryBean(AbstractBeanFactory.java:1397)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.doGetBeanNamesForType(DefaultListableBeanFactory.java:434)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeanNamesForType(DefaultListableBeanFactory.java:404)
    at org.springframework.context.support.AbstractApplicationContext.getBeanNamesForType(AbstractApplicationContext.java:1046)
    at org.springframework.context.support.AbstractApplicationContext.registerListeners(AbstractApplicationContext.java:726)
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:477)
    at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:691)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:321)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:961)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:950)
    at demo.DemoGroovyTaskApplication.main(DemoGroovyTaskApplication.java:11)
Caused by: java.lang.ClassNotFoundException: org.codehaus.groovy.control.CompilationFailedException
    at java.net.URLClassLoader$1.run(URLClassLoader.java:366)
    at java.net.URLClassLoader$1.run(URLClassLoader.java:355)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.net.URLClassLoader.findClass(URLClassLoader.java:354)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:425)
    at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:308)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:358)
    ... 29 more

Upvotes: 2

Views: 4391

Answers (1)

gary f.
gary f.

Reputation: 51

I was able to resolve my issue.

I had to 1) install Groovy-Eclipse, 2) add the Groovy libraries to the build path. For good measure, I also enabled [Enable script folder support] so that my script isn't compiled at build time.

Once I got all of this in, Eclipse reported an error with my "import" statement in the Groovy script. And once I removed that, it all worked. Very cool.

Thanks all

Upvotes: 3

Related Questions