Browse Source

GroovyScriptFactory supports CompilationCustomizer next to GroovyObjectCustomizer

Issue: SPR-14585
pull/1136/head
Juergen Hoeller 9 years ago
parent
commit
433764d217
  1. 49
      spring-context/src/main/java/org/springframework/scripting/groovy/GroovyScriptFactory.java
  2. 30
      spring-context/src/test/java/org/springframework/scripting/groovy/MyImportCustomizer.java
  3. 16
      spring-context/src/test/resources/org/springframework/scripting/groovy/groovy-with-xsd.xml
  4. 13
      src/asciidoc/integration.adoc

49
spring-context/src/main/java/org/springframework/scripting/groovy/GroovyScriptFactory.java

@ -24,6 +24,8 @@ import groovy.lang.GroovyObject; @@ -24,6 +24,8 @@ import groovy.lang.GroovyObject;
import groovy.lang.MetaClass;
import groovy.lang.Script;
import org.codehaus.groovy.control.CompilationFailedException;
import org.codehaus.groovy.control.CompilerConfiguration;
import org.codehaus.groovy.control.customizers.CompilationCustomizer;
import org.springframework.beans.factory.BeanClassLoaderAware;
import org.springframework.beans.factory.BeanFactory;
@ -57,7 +59,9 @@ public class GroovyScriptFactory implements ScriptFactory, BeanFactoryAware, Bea @@ -57,7 +59,9 @@ public class GroovyScriptFactory implements ScriptFactory, BeanFactoryAware, Bea
private final String scriptSourceLocator;
private final GroovyObjectCustomizer groovyObjectCustomizer;
private GroovyObjectCustomizer groovyObjectCustomizer;
private CompilerConfiguration compilerConfiguration;
private GroovyClassLoader groovyClassLoader;
@ -80,27 +84,46 @@ public class GroovyScriptFactory implements ScriptFactory, BeanFactoryAware, Bea @@ -80,27 +84,46 @@ public class GroovyScriptFactory implements ScriptFactory, BeanFactoryAware, Bea
* Interpreted by the post-processor that actually creates the script.
*/
public GroovyScriptFactory(String scriptSourceLocator) {
this(scriptSourceLocator, null);
Assert.hasText(scriptSourceLocator, "'scriptSourceLocator' must not be empty");
this.scriptSourceLocator = scriptSourceLocator;
}
/**
* Create a new GroovyScriptFactory for the given script source,
* specifying a strategy interface that can create a custom MetaClass
* to supply missing methods and otherwise change the behavior of the object.
* <p>We don't need to specify script interfaces here, since
* a Groovy script defines its Java interfaces itself.
* @param scriptSourceLocator a locator that points to the source of the script.
* Interpreted by the post-processor that actually creates the script.
* @param groovyObjectCustomizer a customizer that can set a custom metaclass
* or make other changes to the GroovyObject created by this factory
* (may be {@code null})
* @see GroovyObjectCustomizer#customize
*/
public GroovyScriptFactory(String scriptSourceLocator, GroovyObjectCustomizer groovyObjectCustomizer) {
Assert.hasText(scriptSourceLocator, "'scriptSourceLocator' must not be empty");
this.scriptSourceLocator = scriptSourceLocator;
this(scriptSourceLocator);
this.groovyObjectCustomizer = groovyObjectCustomizer;
}
/**
* Create a new GroovyScriptFactory for the given script source,
* specifying a strategy interface that can customize Groovy's compilation
* process within the underlying GroovyClassLoader.
* @param scriptSourceLocator a locator that points to the source of the script.
* Interpreted by the post-processor that actually creates the script.
* @param compilationCustomizer a customizer to be applied to the GroovyClassLoader
* compiler configuration (may be {@code null})
* @since 4.3.3
* @see CompilerConfiguration#addCompilationCustomizers
* @see org.codehaus.groovy.control.customizers.ImportCustomizer
*/
public GroovyScriptFactory(String scriptSourceLocator, CompilationCustomizer compilationCustomizer) {
this(scriptSourceLocator);
if (compilationCustomizer != null) {
this.compilerConfiguration = new CompilerConfiguration();
this.compilerConfiguration.addCompilationCustomizers(compilationCustomizer);
}
}
@Override
public void setBeanFactory(BeanFactory beanFactory) {
@ -111,7 +134,7 @@ public class GroovyScriptFactory implements ScriptFactory, BeanFactoryAware, Bea @@ -111,7 +134,7 @@ public class GroovyScriptFactory implements ScriptFactory, BeanFactoryAware, Bea
@Override
public void setBeanClassLoader(ClassLoader classLoader) {
this.groovyClassLoader = new GroovyClassLoader(classLoader);
this.groovyClassLoader = buildGroovyClassLoader(classLoader);
}
/**
@ -120,12 +143,22 @@ public class GroovyScriptFactory implements ScriptFactory, BeanFactoryAware, Bea @@ -120,12 +143,22 @@ public class GroovyScriptFactory implements ScriptFactory, BeanFactoryAware, Bea
public GroovyClassLoader getGroovyClassLoader() {
synchronized (this.scriptClassMonitor) {
if (this.groovyClassLoader == null) {
this.groovyClassLoader = new GroovyClassLoader(ClassUtils.getDefaultClassLoader());
this.groovyClassLoader = buildGroovyClassLoader(ClassUtils.getDefaultClassLoader());
}
return this.groovyClassLoader;
}
}
/**
* Build a {@link GroovyClassLoader} for the given {@code ClassLoader}.
* @param classLoader the ClassLoader to build a GroovyClassLoader for
* @since 4.3.3
*/
protected GroovyClassLoader buildGroovyClassLoader(ClassLoader classLoader) {
return (this.compilerConfiguration != null ?
new GroovyClassLoader(classLoader, this.compilerConfiguration) : new GroovyClassLoader(classLoader));
}
@Override
public String getScriptSourceLocator() {

30
spring-context/src/test/java/org/springframework/scripting/groovy/MyImportCustomizer.java

@ -0,0 +1,30 @@ @@ -0,0 +1,30 @@
/*
* 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.scripting.groovy;
import org.codehaus.groovy.control.customizers.ImportCustomizer;
/**
* @author Juergen Hoeller
*/
public class MyImportCustomizer extends ImportCustomizer {
public MyImportCustomizer() {
addStarImports("org.springframework.scripting.groovy");
}
}

16
spring-context/src/test/resources/org/springframework/scripting/groovy/groovy-with-xsd.xml

@ -2,7 +2,7 @@ @@ -2,7 +2,7 @@
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:lang="http://www.springframework.org/schema/lang"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
http://www.springframework.org/schema/lang http://www.springframework.org/schema/lang/spring-lang-2.5.xsd">
@ -24,7 +24,7 @@ @@ -24,7 +24,7 @@
<lang:property name="message" value="Hello World!"/>
</lang:groovy>
<lang:groovy id="calculator" depends-on="messenger" customizer-ref="customizer">
<lang:groovy id="calculator" depends-on="messenger" customizer-ref="groovyObjectCustomizer">
<lang:inline-script>
package org.springframework.scripting.groovy;
import org.springframework.scripting.Calculator
@ -36,10 +36,8 @@ class GroovyCalculator implements Calculator { @@ -36,10 +36,8 @@ class GroovyCalculator implements Calculator {
</lang:inline-script>
</lang:groovy>
<lang:groovy id="customizer">
<lang:groovy id="groovyObjectCustomizer" customizer-ref="importCustomizer">
<lang:inline-script><![CDATA[
import org.springframework.scripting.groovy.GroovyObjectCustomizer;
public class TestCustomizer implements GroovyObjectCustomizer {
public void customize(GroovyObject o) {
println "customizing ${o}.."
@ -48,13 +46,15 @@ public class TestCustomizer implements GroovyObjectCustomizer { @@ -48,13 +46,15 @@ public class TestCustomizer implements GroovyObjectCustomizer {
</lang:inline-script>
</lang:groovy>
<bean id="importCustomizer" class="org.springframework.scripting.groovy.MyImportCustomizer"/>
<lang:groovy id="refreshableMessenger" refresh-check-delay="5000"
script-source="classpath:org/springframework/scripting/groovy/Messenger.groovy">
<lang:property name="message" value="Hello World!"/>
</lang:groovy>
<lang:groovy script-source="classpath:org/springframework/scripting/groovy/Messenger.groovy">
<lang:property name="message" value="Hello World!"/>
</lang:groovy>
<lang:groovy script-source="classpath:org/springframework/scripting/groovy/Messenger.groovy">
<lang:property name="message" value="Hello World!"/>
</lang:groovy>
</beans>

13
src/asciidoc/integration.adoc

@ -7639,7 +7639,6 @@ set some default property values, or specify a custom `MetaClass`. @@ -7639,7 +7639,6 @@ set some default property values, or specify a custom `MetaClass`.
public interface GroovyObjectCustomizer {
void customize(GroovyObject goo);
}
----
@ -7678,12 +7677,12 @@ of a `GroovyObjectCustomizer` is easy if you are using the Spring namespace supp @@ -7678,12 +7677,12 @@ of a `GroovyObjectCustomizer` is easy if you are using the Spring namespace supp
[subs="verbatim,quotes"]
----
<!-- define the GroovyObjectCustomizer just like any other bean -->
<bean id="tracingCustomizer" class="example.SimpleMethodTracingCustomizer" />
<bean id="tracingCustomizer" class="example.SimpleMethodTracingCustomizer"/>
<!-- ... and plug it into the desired Groovy bean via the 'customizer-ref' attribute -->
<lang:groovy id="calculator"
script-source="classpath:org/springframework/scripting/groovy/Calculator.groovy"
customizer-ref="tracingCustomizer" />
customizer-ref="tracingCustomizer"/>
----
If you are not using the Spring namespace support, you can still use the
@ -7696,13 +7695,19 @@ If you are not using the Spring namespace support, you can still use the @@ -7696,13 +7695,19 @@ If you are not using the Spring namespace support, you can still use the
<constructor-arg value="classpath:org/springframework/scripting/groovy/Calculator.groovy"/>
<!-- define the GroovyObjectCustomizer (as an inner bean) -->
<constructor-arg>
<bean id="tracingCustomizer" class="example.SimpleMethodTracingCustomizer" />
<bean id="tracingCustomizer" class="example.SimpleMethodTracingCustomizer"/>
</constructor-arg>
</bean>
<bean class="org.springframework.scripting.support.ScriptFactoryPostProcessor"/>
----
[NOTE]
====
As of Spring Framework 4.3.3, you may also specify a Groovy `CompilationCustomizer` type
such as an `ImportCustomizer` in the same place as Spring's `GroovyObjectCustomizer`.
====
[[dynamic-language-beans-bsh]]

Loading…
Cancel
Save