Reputation: 51
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
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