INT-3958: Groovy Compiler Customization Support
JIRA: https://jira.spring.io/browse/INT-3958 * Introduce `compileStatic` and `compilerConfiguration` properties for the `GroovyScriptExecutingMessageProcessor`, to allow to customize the Groovy Script compilation * Introduce `compile-static` and `compiler-configuration` options on the `<int-groovy:script>` component * Change `RefreshableResourceScriptSource.suggestedClassName()` to return the **full** file name together with the extension. That may be useful during the filtering phase for Compiler customization * Modify tests to demonstrate different Compiler customization tricks * Since Spring Boot 1.4 is already based on the SF-4.3, make an appropriate upgrade, too Doc Polishing More Docs Polishing
This commit is contained in:
committed by
Gary Russell
parent
82c2da8dc4
commit
15026062ac
@@ -139,7 +139,7 @@ subprojects { subproject ->
|
||||
springSecurityVersion = project.hasProperty('springSecurityVersion') ? project.springSecurityVersion : '4.0.3.RELEASE'
|
||||
springSocialTwitterVersion = '1.1.1.RELEASE'
|
||||
springRetryVersion = '1.1.2.RELEASE'
|
||||
springVersion = project.hasProperty('springVersion') ? project.springVersion : '4.2.4.RELEASE'
|
||||
springVersion = project.hasProperty('springVersion') ? project.springVersion : '4.3.0.BUILD-SNAPSHOT'
|
||||
springWsVersion = '2.2.4.RELEASE'
|
||||
xmlUnitVersion = '1.6'
|
||||
xstreamVersion = '1.4.7'
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -20,8 +20,10 @@ import java.util.Map;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.codehaus.groovy.control.CompilerConfiguration;
|
||||
import org.codehaus.groovy.control.customizers.ASTTransformationCustomizer;
|
||||
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
|
||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||
import org.springframework.integration.scripting.AbstractScriptExecutingMessageProcessor;
|
||||
@@ -40,6 +42,7 @@ import groovy.lang.GroovyObject;
|
||||
import groovy.lang.MetaClass;
|
||||
import groovy.lang.MissingPropertyException;
|
||||
import groovy.lang.Script;
|
||||
import groovy.transform.CompileStatic;
|
||||
|
||||
/**
|
||||
* The {@link org.springframework.integration.handler.MessageProcessor} implementation
|
||||
@@ -52,7 +55,8 @@ import groovy.lang.Script;
|
||||
* @author Artem Bilan
|
||||
* @since 2.0
|
||||
*/
|
||||
public class GroovyScriptExecutingMessageProcessor extends AbstractScriptExecutingMessageProcessor<Object> {
|
||||
public class GroovyScriptExecutingMessageProcessor extends AbstractScriptExecutingMessageProcessor<Object>
|
||||
implements InitializingBean {
|
||||
|
||||
private final VariableBindingGroovyObjectCustomizerDecorator customizerDecorator =
|
||||
new VariableBindingGroovyObjectCustomizerDecorator();
|
||||
@@ -65,10 +69,13 @@ public class GroovyScriptExecutingMessageProcessor extends AbstractScriptExecuti
|
||||
|
||||
private volatile Class<?> scriptClass;
|
||||
|
||||
private boolean compileStatic;
|
||||
|
||||
private CompilerConfiguration compilerConfiguration;
|
||||
|
||||
/**
|
||||
* Create a processor for the given {@link ScriptSource} that will use a
|
||||
* DefaultScriptVariableGenerator.
|
||||
*
|
||||
* @param scriptSource The script source.
|
||||
*/
|
||||
public GroovyScriptExecutingMessageProcessor(ScriptSource scriptSource) {
|
||||
@@ -79,43 +86,69 @@ public class GroovyScriptExecutingMessageProcessor extends AbstractScriptExecuti
|
||||
/**
|
||||
* Create a processor for the given {@link ScriptSource} that will use the provided
|
||||
* ScriptVariableGenerator.
|
||||
*
|
||||
* @param scriptSource The script source.
|
||||
* @param scriptVariableGenerator The variable generator.
|
||||
*/
|
||||
public GroovyScriptExecutingMessageProcessor(ScriptSource scriptSource, ScriptVariableGenerator scriptVariableGenerator) {
|
||||
public GroovyScriptExecutingMessageProcessor(ScriptSource scriptSource,
|
||||
ScriptVariableGenerator scriptVariableGenerator) {
|
||||
super(scriptVariableGenerator);
|
||||
this.scriptSource = scriptSource;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBeanClassLoader(ClassLoader classLoader) {
|
||||
super.setBeanClassLoader(classLoader);
|
||||
this.groovyClassLoader = new GroovyClassLoader(classLoader);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
|
||||
super.setBeanFactory(beanFactory);
|
||||
if (beanFactory != null && beanFactory instanceof ConfigurableListableBeanFactory) {
|
||||
((ConfigurableListableBeanFactory) beanFactory).ignoreDependencyType(MetaClass.class);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a {@link GroovyObjectCustomizer} for this processor.
|
||||
*
|
||||
* @param customizer The customizer.
|
||||
*/
|
||||
public void setCustomizer(GroovyObjectCustomizer customizer) {
|
||||
this.customizerDecorator.setCustomizer(customizer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify the {@code boolean} flag to indicate if the {@link GroovyClassLoader}'s compiler
|
||||
* should be customised for the {@link CompileStatic} hint for the provided script.
|
||||
* <p> More compiler options can be provided via {@link #setCompilerConfiguration(CompilerConfiguration)}
|
||||
* overriding this flag.
|
||||
* @param compileStatic the compile static {@code boolean} flag.
|
||||
* @since 4.3
|
||||
* @see CompileStatic
|
||||
*/
|
||||
public void setCompileStatic(boolean compileStatic) {
|
||||
this.compileStatic = compileStatic;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify the {@link CompilerConfiguration} options to customize the Groovy script compilation.
|
||||
* For example the {@link CompileStatic} and {@link org.codehaus.groovy.control.customizers.ImportCustomizer}
|
||||
* are the most popular options.
|
||||
* @param compilerConfiguration the Groovy script compiler options to use.
|
||||
* @since 4.3
|
||||
* @see CompileStatic
|
||||
* @see GroovyClassLoader
|
||||
*/
|
||||
public void setCompilerConfiguration(CompilerConfiguration compilerConfiguration) {
|
||||
this.compilerConfiguration = compilerConfiguration;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ScriptSource getScriptSource(Message<?> message) {
|
||||
return this.scriptSource;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
if (this.beanFactory != null && this.beanFactory instanceof ConfigurableListableBeanFactory) {
|
||||
((ConfigurableListableBeanFactory) this.beanFactory).ignoreDependencyType(MetaClass.class);
|
||||
}
|
||||
|
||||
CompilerConfiguration compilerConfiguration = this.compilerConfiguration;
|
||||
if (compilerConfiguration == null && this.compileStatic) {
|
||||
compilerConfiguration = new CompilerConfiguration();
|
||||
compilerConfiguration.addCompilationCustomizers(new ASTTransformationCustomizer(CompileStatic.class));
|
||||
}
|
||||
|
||||
this.groovyClassLoader = new GroovyClassLoader(this.beanClassLoader, compilerConfiguration);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object executeScript(ScriptSource scriptSource, Map<String, Object> variables) throws Exception {
|
||||
Assert.notNull(scriptSource, "scriptSource must not be null");
|
||||
@@ -182,8 +215,8 @@ public class GroovyScriptExecutingMessageProcessor extends AbstractScriptExecuti
|
||||
return super.getVariable(name);
|
||||
}
|
||||
catch (MissingPropertyException e) {
|
||||
// Original {@link Binding} doesn't have 'variable' for the given 'name'.
|
||||
// Try to resolve it as 'bean' from the given <code>beanFactory</code>.
|
||||
// Original {@link Binding} doesn't have 'variable' for the given 'name'.
|
||||
// Try to resolve it as 'bean' from the given <code>beanFactory</code>.
|
||||
}
|
||||
|
||||
if (GroovyScriptExecutingMessageProcessor.this.beanFactory == null) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -16,13 +16,15 @@
|
||||
|
||||
package org.springframework.integration.groovy.config;
|
||||
|
||||
import groovy.lang.Script;
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.springframework.integration.config.xml.IntegrationNamespaceUtils;
|
||||
import org.springframework.integration.groovy.GroovyScriptExecutingMessageProcessor;
|
||||
import org.springframework.integration.scripting.config.AbstractScriptParser;
|
||||
import org.springframework.integration.config.xml.IntegrationNamespaceUtils;
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
import groovy.lang.Script;
|
||||
|
||||
/**
|
||||
* Parser for the <groovy:script/> element.
|
||||
@@ -51,6 +53,8 @@ public class GroovyScriptParser extends AbstractScriptParser {
|
||||
|
||||
protected void postProcess(BeanDefinitionBuilder builder, Element element, ParserContext parserContext) {
|
||||
IntegrationNamespaceUtils.setReferenceIfAttributeDefined(builder, element, "customizer");
|
||||
IntegrationNamespaceUtils.setReferenceIfAttributeDefined(builder, element, "compiler-configuration");
|
||||
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "compile-static");
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -36,6 +36,30 @@
|
||||
</xsd:appinfo>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="compile-static" default="false">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
Indicates if the target Groovy script should be compiled statically.
|
||||
The @CompileStatic hint is applied for the Groovy compiler.
|
||||
This attribute is ignored if the 'compiler-configuration' reference is specified.
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
<xsd:simpleType>
|
||||
<xsd:union memberTypes="xsd:boolean xsd:string" />
|
||||
</xsd:simpleType>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="compiler-configuration">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
Reference to a CompilerConfiguration bean to be applied to the underlying GroovyClassLoader
|
||||
for this script compilation.
|
||||
</xsd:documentation>
|
||||
<xsd:appinfo>
|
||||
<tool:expected-type
|
||||
type="org.codehaus.groovy.control.CompilerConfiguration" />
|
||||
</xsd:appinfo>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
</xsd:extension>
|
||||
</xsd:complexContent>
|
||||
</xsd:complexType>
|
||||
|
||||
@@ -1,20 +1,29 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans:beans xmlns="http://www.springframework.org/schema/integration"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:beans="http://www.springframework.org/schema/beans"
|
||||
xmlns:groovy="http://www.springframework.org/schema/integration/groovy"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration.xsd
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:beans="http://www.springframework.org/schema/beans"
|
||||
xmlns:groovy="http://www.springframework.org/schema/integration/groovy"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration.xsd
|
||||
http://www.springframework.org/schema/integration/groovy http://www.springframework.org/schema/integration/groovy/spring-integration-groovy.xsd
|
||||
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
|
||||
|
||||
<beans:bean class="org.springframework.integration.groovy.config.GroovyFilterTests.TestConfig"/>
|
||||
|
||||
<filter id="groovyFilter" input-channel="referencedScriptInput">
|
||||
<groovy:script location="org/springframework/integration/groovy/config/GroovyFilterTests.groovy"/>
|
||||
<groovy:script location="org/springframework/integration/groovy/config/GroovyFilterTests.groovy"
|
||||
compiler-configuration="compilerConfiguration"/>
|
||||
</filter>
|
||||
|
||||
<filter input-channel="inlineScriptInput">
|
||||
<groovy:script><![CDATA[
|
||||
return payload == 'good'
|
||||
]]></groovy:script>
|
||||
return payload == 'good'
|
||||
]]></groovy:script>
|
||||
</filter>
|
||||
|
||||
<filter input-channel="compileStaticFailScriptInput">
|
||||
<groovy:script compile-static="true"><![CDATA[
|
||||
payload == 'good'
|
||||
]]></groovy:script>
|
||||
</filter>
|
||||
|
||||
</beans:beans>
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
headers.type == 'good'
|
||||
// org.springframework.integration.groovy.config.GroovyFilterTests.TestConfig
|
||||
headers.type == pi
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -16,16 +16,25 @@
|
||||
|
||||
package org.springframework.integration.groovy.config;
|
||||
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.hamcrest.Matchers.instanceOf;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import org.codehaus.groovy.control.CompilerConfiguration;
|
||||
import org.codehaus.groovy.control.MultipleCompilationErrorsException;
|
||||
import org.codehaus.groovy.control.customizers.ASTTransformationCustomizer;
|
||||
import org.codehaus.groovy.control.customizers.ImportCustomizer;
|
||||
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.context.annotation.Bean;
|
||||
import org.springframework.integration.channel.QueueChannel;
|
||||
import org.springframework.integration.core.MessageSelector;
|
||||
import org.springframework.integration.filter.MessageFilter;
|
||||
@@ -37,9 +46,14 @@ import org.springframework.integration.test.util.TestUtils;
|
||||
import org.springframework.messaging.Message;
|
||||
import org.springframework.messaging.MessageChannel;
|
||||
import org.springframework.messaging.MessageHandler;
|
||||
import org.springframework.messaging.MessageHandlingException;
|
||||
import org.springframework.messaging.support.GenericMessage;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
|
||||
import groovy.transform.CompileStatic;
|
||||
|
||||
/**
|
||||
* @author Mark Fisher
|
||||
* @author Artem Bilan
|
||||
@@ -55,6 +69,9 @@ public class GroovyFilterTests {
|
||||
@Autowired
|
||||
private MessageChannel inlineScriptInput;
|
||||
|
||||
@Autowired
|
||||
private MessageChannel compileStaticFailScriptInput;
|
||||
|
||||
@Autowired
|
||||
@Qualifier("groovyFilter.handler")
|
||||
private MessageHandler groovyFilterMessageHandler;
|
||||
@@ -69,7 +86,7 @@ public class GroovyFilterTests {
|
||||
.build();
|
||||
Message<?> message2 = MessageBuilder.withPayload("test-2")
|
||||
.setReplyChannel(replyChannel)
|
||||
.setHeader("type", "good")
|
||||
.setHeader("type", Math.PI)
|
||||
.build();
|
||||
this.referencedScriptInput.send(message1);
|
||||
this.referencedScriptInput.send(message2);
|
||||
@@ -103,4 +120,31 @@ public class GroovyFilterTests {
|
||||
assertTrue(messageProcessor instanceof GroovyScriptExecutingMessageProcessor);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCompileStaticIsApplied() {
|
||||
try {
|
||||
this.compileStaticFailScriptInput.send(new GenericMessage<Object>("foo"));
|
||||
fail("MultipleCompilationErrorsException expected");
|
||||
}
|
||||
catch (Exception e) {
|
||||
assertThat(e, instanceOf(MessageHandlingException.class));
|
||||
assertThat(e.getCause(), instanceOf(MultipleCompilationErrorsException.class));
|
||||
assertThat(e.getMessage(), containsString("[Static type checking] - The variable [payload] is undeclared."));
|
||||
}
|
||||
}
|
||||
|
||||
@Component
|
||||
public static class TestConfig {
|
||||
|
||||
@Bean
|
||||
public CompilerConfiguration compilerConfiguration() {
|
||||
CompilerConfiguration compilerConfiguration = new CompilerConfiguration();
|
||||
ImportCustomizer importCustomizer = new ImportCustomizer();
|
||||
importCustomizer.addStaticImport("pi", "java.lang.Math", "PI"); // import static java.lang.Math.PI as pi
|
||||
compilerConfiguration.addCompilationCustomizers(importCustomizer);
|
||||
return compilerConfiguration;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration.xsd
|
||||
http://www.springframework.org/schema/integration/groovy http://www.springframework.org/schema/integration/groovy/spring-integration-groovy.xsd
|
||||
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
|
||||
|
||||
|
||||
<bean class="org.springframework.beans.factory.config.CustomEditorConfigurer" xmlns="http://www.springframework.org/schema/beans">
|
||||
<property name="customEditors">
|
||||
<map>
|
||||
@@ -16,7 +16,7 @@
|
||||
</bean>
|
||||
|
||||
<transformer input-channel="referencedScriptInput">
|
||||
<groovy:script location="GroovyRefreshTests.groovy" refresh-check-delay="0"/>
|
||||
<groovy:script location="GroovyRefreshTests.groovy" refresh-check-delay="0" compile-static="true"/>
|
||||
</transformer>
|
||||
|
||||
</beans:beans>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2010 the original author or authors.
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -36,6 +36,7 @@ import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
|
||||
/**
|
||||
* @author Mark Fisher
|
||||
* @author Artem Bilan
|
||||
* @since 2.0
|
||||
*/
|
||||
@ContextConfiguration
|
||||
@@ -66,7 +67,8 @@ public class GroovyRefreshTests {
|
||||
private static class CycleResource extends AbstractResource {
|
||||
|
||||
private int count = -1;
|
||||
private String[] scripts = {"\"groovy-$payload-0\"", "\"groovy-$payload-1\""};
|
||||
private String[] scripts = {"\"groovy-${binding.variables['payload']}-0\"",
|
||||
"\"groovy-${binding.variables['payload']}-1\""};
|
||||
|
||||
public String getDescription() {
|
||||
return "CycleResource";
|
||||
|
||||
@@ -12,8 +12,8 @@
|
||||
</splitter>
|
||||
|
||||
<splitter input-channel="inlineScriptInput">
|
||||
<groovy:script><![CDATA[
|
||||
return payload.split('\\s+')
|
||||
<groovy:script compile-static="true"><![CDATA[
|
||||
((String) binding.variables.payload).split('\\s+')
|
||||
]]></groovy:script>
|
||||
</splitter>
|
||||
|
||||
|
||||
@@ -1 +1,6 @@
|
||||
"groovy-$payload"
|
||||
@groovy.transform.CompileStatic
|
||||
String transform(Object payload) {
|
||||
"groovy-$payload"
|
||||
}
|
||||
|
||||
transform(payload)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -60,7 +60,7 @@ public class RefreshableResourceScriptSource implements ScriptSource {
|
||||
}
|
||||
|
||||
public String suggestedClassName() {
|
||||
return this.source.suggestedClassName();
|
||||
return this.source.getResource().getFilename();
|
||||
}
|
||||
|
||||
public boolean isModified() {
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
=== Groovy support
|
||||
|
||||
In Spring Integration 2.0 we added Groovy support allowing you to use the Groovy scripting language to provide the logic for various integration components similar to the way the Spring Expression Language (SpEL) is supported for routing, transformation and other integration concerns.
|
||||
For more information about Groovy please refer to the Groovy documentation which you can find on the http://groovy.codehaus.org[project website]
|
||||
For more information about Groovy please refer to the Groovy documentation which you can find on the http://www.groovy-lang.org/[project website].
|
||||
|
||||
[[groovy-config]]
|
||||
==== Groovy configuration
|
||||
@@ -32,7 +32,7 @@ Also note that the `lang` attribute on the `<script>` tag is not valid in this n
|
||||
_Groovy object customization_
|
||||
|
||||
If you need to customize the Groovy object itself, beyond setting variables, you can reference a bean that implements `org.springframework.scripting.groovy.GroovyObjectCustomizer` via the `customizer` attribute.
|
||||
For example, this might be useful if you want to implement a domain-specific language (DSL) by modifying the MetaClass and registering functions to be available within the script:
|
||||
For example, this might be useful if you want to implement a domain-specific language (DSL) by modifying the `MetaClass` and registering functions to be available within the script:
|
||||
[source,xml]
|
||||
----
|
||||
<int:service-activator input-channel="groovyChannel">
|
||||
@@ -42,11 +42,11 @@ For example, this might be useful if you want to implement a domain-specific lan
|
||||
<beans:bean id="groovyCustomizer" class="org.foo.MyGroovyObjectCustomizer"/>
|
||||
----
|
||||
|
||||
Setting a custom GroovyObjectCustomizer is not mutually exclusive with `<variable>` sub-elements or the `script-variable-generator` attribute.
|
||||
Setting a custom `GroovyObjectCustomizer` is not mutually exclusive with `<variable>` sub-elements or the `script-variable-generator` attribute.
|
||||
It can also be provided when defining an inline script.
|
||||
|
||||
With _Spring Integration 3.0_, in addition to the `variable` sub-element, the `variables` attribute has been introduced.
|
||||
Also, groovy scripts have the ability to resolve a variable to a bean in the`BeanFactory`, if a binding variable was not provided with the name:
|
||||
Also, groovy scripts have the ability to resolve a variable to a bean in the `BeanFactory`, if a binding variable was not provided with the name:
|
||||
[source,xml]
|
||||
----
|
||||
<int-groovy:script>
|
||||
@@ -61,6 +61,63 @@ where variable `entityManager` is an appropriate bean in the application context
|
||||
|
||||
For more information regarding `<variable>`, `variables`, and `script-variable-generator`, see the paragraph '_Script variable bindings_' of <<scripting-config>>.
|
||||
|
||||
_Groovy Script Compiler Customization_
|
||||
|
||||
The `@CompileStatic` hint is the most popular Groovy compiler customization option,
|
||||
which can be used on the class or method level.
|
||||
See more information in the Groovy
|
||||
http://docs.groovy-lang.org/latest/html/documentation/index.html#_static_compilation[Reference Manual] and,
|
||||
specifically, http://docs.groovy-lang.org/latest/html/documentation/index.html#compilestatic-annotation[@CompileStatic].
|
||||
To utilize this feature for short scripts (in integration scenarios), we are forced to change a simple script like this
|
||||
(a `<filter>` script):
|
||||
|
||||
[source,groovy]
|
||||
----
|
||||
headers.type == 'good'
|
||||
----
|
||||
|
||||
to more Java-like code:
|
||||
|
||||
[source,groovy]
|
||||
----
|
||||
@groovy.transform.CompileStatic
|
||||
String filter(Map headers) {
|
||||
headers.type == 'good'
|
||||
}
|
||||
|
||||
filter(headers)
|
||||
----
|
||||
|
||||
With that, the `filter()` method will be transformed and compiled to static Java code, bypassing the Groovy
|
||||
dynamic phases of invocation, like `getProperty()` factories and `CallSite` proxies.
|
||||
|
||||
Starting with _version 4.3_, Spring Integration Groovy components can be configured with the `compile-static` `boolean`
|
||||
option, specifying that `ASTTransformationCustomizer` for `@CompileStatic` should be added to the internal
|
||||
`CompilerConfiguration`.
|
||||
With that in place, we can omit the method declaration with `@CompileStatic` in our script code and still get compiled
|
||||
plain Java code.
|
||||
In this case our script can still be short but still needs to be a little more verbose than interpreted script:
|
||||
|
||||
[source,groovy]
|
||||
----
|
||||
binding.variables.headers.type == 'good'
|
||||
----
|
||||
Where we can access the `headers` and `payload` (or any other) variables only through the `groovy.lang.Script`
|
||||
`binding` property since, with `@CompileStatic`, we don't have the dynamic `GroovyObject.getProperty()` capability.
|
||||
|
||||
In addition, the `compiler-configuration` bean reference has been introduced.
|
||||
With this attribute, you can provide any other required Groovy compiler customizations, e.g. `ImportCustomizer`.
|
||||
For more information about this feature, please, refer to the Groovy Documentation:
|
||||
http://groovy.jmiguel.eu/groovy.codehaus.org/Advanced+compiler+configuration.html[Advanced compiler configuration].
|
||||
|
||||
NOTE: Using `compilerConfiguration` does not automatically add a `ASTTransformationCustomizer` for `@CompileStatic`
|
||||
and overrides the `compileStatic` option.
|
||||
If `CompileStatic` is still requirement, a `new ASTTransformationCustomizer(CompileStatic.class)` should be manually
|
||||
added into the `CompilationCustomizers` of that custom `compilerConfiguration`.
|
||||
|
||||
NOTE: The Groovy compiler customization does not have any effect to the `refresh-check-delay` option
|
||||
and reloadable scripts can be statically compiled, too.
|
||||
|
||||
[[groovy-control-bus]]
|
||||
==== Control Bus
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ Sun developed a JSR223 reference implementation which works with Java 5 but it i
|
||||
|
||||
In order to use a JVM scripting language, a JSR223 implementation for that language must be included in your class path.
|
||||
Java 6 natively supports Javascript.
|
||||
The http://groovy.codehaus.org[Groovy] and http://jruby.org/[JRuby] projects provide JSR233 support in their standard distribution.
|
||||
The http://www.groovy-lang.org/[Groovy] and http://jruby.org/[JRuby] projects provide JSR233 support in their standard distribution.
|
||||
Other language implementations may be available or under development.
|
||||
Please refer to the appropriate project website for more information.
|
||||
|
||||
|
||||
@@ -136,3 +136,8 @@ See <<router>> for more information.
|
||||
AMQP, WS and XMPP header mappings (e.g. `request-header-mapping`, `reply-header-mapping`) now support negated
|
||||
patterns.
|
||||
See <<amqp-message-headers>>, <<ws-message-headers>>, and <<xmpp-message-headers>> for more information.
|
||||
|
||||
==== Groovy Scripts
|
||||
|
||||
Groovy scripts can now be configured with the `compile-static` hint or any other `CompilerConfiguration` options.
|
||||
See <<groovy-config>> for more information.
|
||||
|
||||
Reference in New Issue
Block a user