diff --git a/spring-context/src/main/java/org/springframework/scripting/ScriptCompilationException.java b/spring-context/src/main/java/org/springframework/scripting/ScriptCompilationException.java index ccb8674500..2064ae9080 100644 --- a/spring-context/src/main/java/org/springframework/scripting/ScriptCompilationException.java +++ b/spring-context/src/main/java/org/springframework/scripting/ScriptCompilationException.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2012 the original author or authors. + * Copyright 2002-2015 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. @@ -41,8 +41,7 @@ public class ScriptCompilationException extends NestedRuntimeException { /** * Constructor for ScriptCompilationException. * @param msg the detail message - * @param cause the root cause (usually from using an underlying - * script compiler API) + * @param cause the root cause (usually from using an underlying script compiler API) */ public ScriptCompilationException(String msg, Throwable cause) { super(msg, cause); @@ -51,23 +50,32 @@ public class ScriptCompilationException extends NestedRuntimeException { /** * Constructor for ScriptCompilationException. * @param scriptSource the source for the offending script - * @param cause the root cause (usually from using an underlying - * script compiler API) + * @param msg the detail message + * @since 4.2 + */ + public ScriptCompilationException(ScriptSource scriptSource, String msg) { + super("Could not compile " + scriptSource + ": " + msg); + this.scriptSource = scriptSource; + } + + /** + * Constructor for ScriptCompilationException. + * @param scriptSource the source for the offending script + * @param cause the root cause (usually from using an underlying script compiler API) */ public ScriptCompilationException(ScriptSource scriptSource, Throwable cause) { - super("Could not compile script", cause); + super("Could not compile " + scriptSource, cause); this.scriptSource = scriptSource; } /** * Constructor for ScriptCompilationException. - * @param msg the detail message * @param scriptSource the source for the offending script - * @param cause the root cause (usually from using an underlying - * script compiler API) + * @param msg the detail message + * @param cause the root cause (usually from using an underlying script compiler API) */ public ScriptCompilationException(ScriptSource scriptSource, String msg, Throwable cause) { - super("Could not compile script [" + scriptSource + "]: " + msg, cause); + super("Could not compile " + scriptSource + ": " + msg, cause); this.scriptSource = scriptSource; } diff --git a/spring-context/src/main/java/org/springframework/scripting/config/LangNamespaceHandler.java b/spring-context/src/main/java/org/springframework/scripting/config/LangNamespaceHandler.java index b7888faa78..8a113e9905 100644 --- a/spring-context/src/main/java/org/springframework/scripting/config/LangNamespaceHandler.java +++ b/spring-context/src/main/java/org/springframework/scripting/config/LangNamespaceHandler.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2012 the original author or authors. + * Copyright 2002-2015 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. @@ -44,6 +44,7 @@ public class LangNamespaceHandler extends NamespaceHandlerSupport { registerScriptBeanDefinitionParser("groovy", "org.springframework.scripting.groovy.GroovyScriptFactory"); registerScriptBeanDefinitionParser("jruby", "org.springframework.scripting.jruby.JRubyScriptFactory"); registerScriptBeanDefinitionParser("bsh", "org.springframework.scripting.bsh.BshScriptFactory"); + registerScriptBeanDefinitionParser("std", "org.springframework.scripting.support.StandardScriptFactory"); registerBeanDefinitionParser("defaults", new ScriptingDefaultsParser()); } diff --git a/spring-context/src/main/java/org/springframework/scripting/config/ScriptBeanDefinitionParser.java b/spring-context/src/main/java/org/springframework/scripting/config/ScriptBeanDefinitionParser.java index de5aa7ea9d..67c9a3fe0b 100644 --- a/spring-context/src/main/java/org/springframework/scripting/config/ScriptBeanDefinitionParser.java +++ b/spring-context/src/main/java/org/springframework/scripting/config/ScriptBeanDefinitionParser.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2013 the original author or authors. + * Copyright 2002-2015 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. @@ -55,6 +55,8 @@ import org.springframework.util.xml.DomUtils; */ class ScriptBeanDefinitionParser extends AbstractBeanDefinitionParser { + private static final String ENGINE_ATTRIBUTE = "engine"; + private static final String SCRIPT_SOURCE_ATTRIBUTE = "script-source"; private static final String INLINE_SCRIPT_ELEMENT = "inline-script"; @@ -104,6 +106,9 @@ class ScriptBeanDefinitionParser extends AbstractBeanDefinitionParser { @Override @SuppressWarnings("deprecation") protected AbstractBeanDefinition parseInternal(Element element, ParserContext parserContext) { + // Engine attribute only supported for + String engine = element.getAttribute(ENGINE_ATTRIBUTE); + // Resolve the script source. String value = resolveScriptSource(element, parserContext.getReaderContext()); if (value == null) { @@ -184,9 +189,13 @@ class ScriptBeanDefinitionParser extends AbstractBeanDefinitionParser { // Add constructor arguments. ConstructorArgumentValues cav = bd.getConstructorArgumentValues(); int constructorArgNum = 0; + if (StringUtils.hasLength(engine)) { + cav.addIndexedArgumentValue(constructorArgNum++, engine); + } cav.addIndexedArgumentValue(constructorArgNum++, value); if (element.hasAttribute(SCRIPT_INTERFACES_ATTRIBUTE)) { - cav.addIndexedArgumentValue(constructorArgNum++, element.getAttribute(SCRIPT_INTERFACES_ATTRIBUTE)); + cav.addIndexedArgumentValue( + constructorArgNum++, element.getAttribute(SCRIPT_INTERFACES_ATTRIBUTE), "java.lang.Class[]"); } // This is used for Groovy. It's a bean reference to a customizer bean. diff --git a/spring-context/src/main/java/org/springframework/scripting/support/StandardScriptFactory.java b/spring-context/src/main/java/org/springframework/scripting/support/StandardScriptFactory.java new file mode 100644 index 0000000000..8c6b8c9793 --- /dev/null +++ b/spring-context/src/main/java/org/springframework/scripting/support/StandardScriptFactory.java @@ -0,0 +1,248 @@ +/* + * Copyright 2002-2015 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.support; + +import java.io.IOException; +import javax.script.Invocable; +import javax.script.ScriptEngine; +import javax.script.ScriptEngineManager; + +import org.springframework.beans.BeanUtils; +import org.springframework.beans.factory.BeanClassLoaderAware; +import org.springframework.scripting.ScriptCompilationException; +import org.springframework.scripting.ScriptFactory; +import org.springframework.scripting.ScriptSource; +import org.springframework.util.Assert; +import org.springframework.util.ClassUtils; +import org.springframework.util.ObjectUtils; +import org.springframework.util.StringUtils; + +/** + * {@link org.springframework.scripting.ScriptFactory} implementation based + * on the JSR-223 script engine abstraction (as included in Java 6+). + * Supports JavaScript, Groovy, JRuby and other JSR-223 compliant engines. + * + *

Typically used in combination with a + * {@link org.springframework.scripting.support.ScriptFactoryPostProcessor}; + * see the latter's javadoc for a configuration example. + * + * @author Juergen Hoeller + * @since 4.2 + * @see ScriptFactoryPostProcessor + */ +public class StandardScriptFactory implements ScriptFactory, BeanClassLoaderAware { + + private final String scriptEngineName; + + private final String scriptSourceLocator; + + private final Class[] scriptInterfaces; + + private ClassLoader beanClassLoader = ClassUtils.getDefaultClassLoader(); + + private volatile ScriptEngine scriptEngine; + + + /** + * Create a new StandardScriptFactory for the given script source. + * @param scriptSourceLocator a locator that points to the source of the script. + * Interpreted by the post-processor that actually creates the script. + */ + public StandardScriptFactory(String scriptSourceLocator) { + this(null, scriptSourceLocator, (Class[]) null); + } + + /** + * Create a new StandardScriptFactory for the given script source. + * @param scriptSourceLocator a locator that points to the source of the script. + * Interpreted by the post-processor that actually creates the script. + * @param scriptInterfaces the Java interfaces that the scripted object + * is supposed to implement + */ + public StandardScriptFactory(String scriptSourceLocator, Class... scriptInterfaces) { + this(null, scriptSourceLocator, scriptInterfaces); + } + + /** + * Create a new StandardScriptFactory for the given script source. + * @param scriptEngineName the name of the JSR-223 ScriptEngine to use + * (explicitly given instead of inferred from the script source) + * @param scriptSourceLocator a locator that points to the source of the script. + * Interpreted by the post-processor that actually creates the script. + */ + public StandardScriptFactory(String scriptEngineName, String scriptSourceLocator) { + this(scriptEngineName, scriptSourceLocator, (Class[]) null); + } + + /** + * Create a new StandardScriptFactory for the given script source. + * @param scriptEngineName the name of the JSR-223 ScriptEngine to use + * (explicitly given instead of inferred from the script source) + * @param scriptSourceLocator a locator that points to the source of the script. + * Interpreted by the post-processor that actually creates the script. + * @param scriptInterfaces the Java interfaces that the scripted object + * is supposed to implement + */ + public StandardScriptFactory(String scriptEngineName, String scriptSourceLocator, Class... scriptInterfaces) { + Assert.hasText(scriptSourceLocator, "'scriptSourceLocator' must not be empty"); + this.scriptEngineName = scriptEngineName; + this.scriptSourceLocator = scriptSourceLocator; + this.scriptInterfaces = scriptInterfaces; + } + + + @Override + public void setBeanClassLoader(ClassLoader classLoader) { + this.beanClassLoader = classLoader; + } + + protected ScriptEngine retrieveScriptEngine(ScriptSource scriptSource) { + ScriptEngineManager scriptEngineManager = new ScriptEngineManager(this.beanClassLoader); + if (this.scriptEngineName != null) { + ScriptEngine engine = scriptEngineManager.getEngineByName(this.scriptEngineName); + if (engine == null) { + throw new IllegalStateException("Script engine named '" + this.scriptEngineName + "' not found"); + } + return engine; + } + if (scriptSource instanceof ResourceScriptSource) { + String filename = ((ResourceScriptSource) scriptSource).getResource().getFilename(); + if (filename != null) { + String extension = StringUtils.getFilenameExtension(filename); + if (extension != null) { + ScriptEngine engine = scriptEngineManager.getEngineByExtension(extension); + if (engine != null) { + return engine; + } + } + } + } + return null; + } + + + @Override + public String getScriptSourceLocator() { + return this.scriptSourceLocator; + } + + @Override + public Class[] getScriptInterfaces() { + return this.scriptInterfaces; + } + + @Override + public boolean requiresConfigInterface() { + return false; + } + + + /** + * Load and parse the script via JSR-223's ScriptEngine. + */ + @Override + public Object getScriptedObject(ScriptSource scriptSource, Class... actualInterfaces) + throws IOException, ScriptCompilationException { + + Object script; + + try { + if (this.scriptEngine == null) { + this.scriptEngine = retrieveScriptEngine(scriptSource); + if (this.scriptEngine == null) { + throw new IllegalStateException("Could not determine script engine for " + scriptSource); + } + } + script = this.scriptEngine.eval(scriptSource.getScriptAsString()); + } + catch (Exception ex) { + throw new ScriptCompilationException(scriptSource, ex); + } + + if (!ObjectUtils.isEmpty(actualInterfaces)) { + boolean adaptationRequired = false; + for (Class requestedIfc : actualInterfaces) { + if (!requestedIfc.isInstance(script)) { + adaptationRequired = true; + } + } + if (adaptationRequired) { + Class adaptedIfc; + if (actualInterfaces.length == 1) { + adaptedIfc = actualInterfaces[0]; + } + else { + adaptedIfc = ClassUtils.createCompositeInterface(actualInterfaces, this.beanClassLoader); + } + if (adaptedIfc != null) { + if (!(this.scriptEngine instanceof Invocable)) { + throw new ScriptCompilationException(scriptSource, + "ScriptEngine must implement Invocable in order to adapt it to an interface: " + + this.scriptEngine); + } + Invocable invocable = (Invocable) this.scriptEngine; + if (script != null) { + script = invocable.getInterface(script, adaptedIfc); + } + if (script == null) { + script = invocable.getInterface(adaptedIfc); + if (script == null) { + throw new ScriptCompilationException(scriptSource, + "Could not adapt script to interface [" + adaptedIfc.getName() + "]"); + } + } + } + } + } + + if (script instanceof Class) { + Class scriptClass = (Class) script; + try { + return scriptClass.newInstance(); + } + catch (InstantiationException ex) { + throw new ScriptCompilationException( + scriptSource, "Could not instantiate script class: " + scriptClass.getName(), ex); + } + catch (IllegalAccessException ex) { + throw new ScriptCompilationException( + scriptSource, "Could not access script constructor: " + scriptClass.getName(), ex); + } + } + + return script; + } + + @Override + public Class getScriptedObjectType(ScriptSource scriptSource) + throws IOException, ScriptCompilationException { + + return null; + } + + @Override + public boolean requiresScriptedObjectRefresh(ScriptSource scriptSource) { + return scriptSource.isModified(); + } + + + @Override + public String toString() { + return "StandardScriptFactory: script source locator [" + this.scriptSourceLocator + "]"; + } + +} diff --git a/spring-context/src/main/resources/META-INF/spring.schemas b/spring-context/src/main/resources/META-INF/spring.schemas index 26ff291eed..3cac0ddd79 100644 --- a/spring-context/src/main/resources/META-INF/spring.schemas +++ b/spring-context/src/main/resources/META-INF/spring.schemas @@ -4,7 +4,8 @@ http\://www.springframework.org/schema/context/spring-context-3.1.xsd=org/spring http\://www.springframework.org/schema/context/spring-context-3.2.xsd=org/springframework/context/config/spring-context-3.2.xsd http\://www.springframework.org/schema/context/spring-context-4.0.xsd=org/springframework/context/config/spring-context-4.0.xsd http\://www.springframework.org/schema/context/spring-context-4.1.xsd=org/springframework/context/config/spring-context-4.1.xsd -http\://www.springframework.org/schema/context/spring-context.xsd=org/springframework/context/config/spring-context-4.1.xsd +http\://www.springframework.org/schema/context/spring-context-4.2.xsd=org/springframework/context/config/spring-context-4.2.xsd +http\://www.springframework.org/schema/context/spring-context.xsd=org/springframework/context/config/spring-context-4.2.xsd http\://www.springframework.org/schema/jee/spring-jee-2.0.xsd=org/springframework/ejb/config/spring-jee-2.0.xsd http\://www.springframework.org/schema/jee/spring-jee-2.5.xsd=org/springframework/ejb/config/spring-jee-2.5.xsd http\://www.springframework.org/schema/jee/spring-jee-3.0.xsd=org/springframework/ejb/config/spring-jee-3.0.xsd @@ -12,7 +13,8 @@ http\://www.springframework.org/schema/jee/spring-jee-3.1.xsd=org/springframewor http\://www.springframework.org/schema/jee/spring-jee-3.2.xsd=org/springframework/ejb/config/spring-jee-3.2.xsd http\://www.springframework.org/schema/jee/spring-jee-4.0.xsd=org/springframework/ejb/config/spring-jee-4.0.xsd http\://www.springframework.org/schema/jee/spring-jee-4.1.xsd=org/springframework/ejb/config/spring-jee-4.1.xsd -http\://www.springframework.org/schema/jee/spring-jee.xsd=org/springframework/ejb/config/spring-jee-4.1.xsd +http\://www.springframework.org/schema/jee/spring-jee-4.2.xsd=org/springframework/ejb/config/spring-jee-4.2.xsd +http\://www.springframework.org/schema/jee/spring-jee.xsd=org/springframework/ejb/config/spring-jee-4.2.xsd http\://www.springframework.org/schema/lang/spring-lang-2.0.xsd=org/springframework/scripting/config/spring-lang-2.0.xsd http\://www.springframework.org/schema/lang/spring-lang-2.5.xsd=org/springframework/scripting/config/spring-lang-2.5.xsd http\://www.springframework.org/schema/lang/spring-lang-3.0.xsd=org/springframework/scripting/config/spring-lang-3.0.xsd @@ -20,15 +22,18 @@ http\://www.springframework.org/schema/lang/spring-lang-3.1.xsd=org/springframew http\://www.springframework.org/schema/lang/spring-lang-3.2.xsd=org/springframework/scripting/config/spring-lang-3.2.xsd http\://www.springframework.org/schema/lang/spring-lang-4.0.xsd=org/springframework/scripting/config/spring-lang-4.0.xsd http\://www.springframework.org/schema/lang/spring-lang-4.1.xsd=org/springframework/scripting/config/spring-lang-4.1.xsd -http\://www.springframework.org/schema/lang/spring-lang.xsd=org/springframework/scripting/config/spring-lang-4.1.xsd +http\://www.springframework.org/schema/lang/spring-lang-4.2.xsd=org/springframework/scripting/config/spring-lang-4.2.xsd +http\://www.springframework.org/schema/lang/spring-lang.xsd=org/springframework/scripting/config/spring-lang-4.2.xsd http\://www.springframework.org/schema/task/spring-task-3.0.xsd=org/springframework/scheduling/config/spring-task-3.0.xsd http\://www.springframework.org/schema/task/spring-task-3.1.xsd=org/springframework/scheduling/config/spring-task-3.1.xsd http\://www.springframework.org/schema/task/spring-task-3.2.xsd=org/springframework/scheduling/config/spring-task-3.2.xsd http\://www.springframework.org/schema/task/spring-task-4.0.xsd=org/springframework/scheduling/config/spring-task-4.0.xsd http\://www.springframework.org/schema/task/spring-task-4.1.xsd=org/springframework/scheduling/config/spring-task-4.1.xsd -http\://www.springframework.org/schema/task/spring-task.xsd=org/springframework/scheduling/config/spring-task-4.1.xsd +http\://www.springframework.org/schema/task/spring-task-4.2.xsd=org/springframework/scheduling/config/spring-task-4.2.xsd +http\://www.springframework.org/schema/task/spring-task.xsd=org/springframework/scheduling/config/spring-task-4.2.xsd http\://www.springframework.org/schema/cache/spring-cache-3.1.xsd=org/springframework/cache/config/spring-cache-3.1.xsd http\://www.springframework.org/schema/cache/spring-cache-3.2.xsd=org/springframework/cache/config/spring-cache-3.2.xsd http\://www.springframework.org/schema/cache/spring-cache-4.0.xsd=org/springframework/cache/config/spring-cache-4.0.xsd http\://www.springframework.org/schema/cache/spring-cache-4.1.xsd=org/springframework/cache/config/spring-cache-4.1.xsd -http\://www.springframework.org/schema/cache/spring-cache.xsd=org/springframework/cache/config/spring-cache-4.1.xsd +http\://www.springframework.org/schema/cache/spring-cache-4.2.xsd=org/springframework/cache/config/spring-cache-4.2.xsd +http\://www.springframework.org/schema/cache/spring-cache.xsd=org/springframework/cache/config/spring-cache-4.2.xsd diff --git a/spring-context/src/main/resources/org/springframework/cache/config/spring-cache-4.2.xsd b/spring-context/src/main/resources/org/springframework/cache/config/spring-cache-4.2.xsd new file mode 100644 index 0000000000..66104b98db --- /dev/null +++ b/spring-context/src/main/resources/org/springframework/cache/config/spring-cache-4.2.xsd @@ -0,0 +1,310 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/spring-context/src/main/resources/org/springframework/context/config/spring-context-4.2.xsd b/spring-context/src/main/resources/org/springframework/context/config/spring-context-4.2.xsd new file mode 100644 index 0000000000..d9aeea34c1 --- /dev/null +++ b/spring-context/src/main/resources/org/springframework/context/config/spring-context-4.2.xsd @@ -0,0 +1,520 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + tag for that purpose. + + See javadoc for org.springframework.context.annotation.AnnotationConfigApplicationContext + for information on code-based alternatives to bootstrapping annotation-driven support. + from XML. + ]]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/spring-context/src/main/resources/org/springframework/ejb/config/spring-jee-4.2.xsd b/spring-context/src/main/resources/org/springframework/ejb/config/spring-jee-4.2.xsd new file mode 100644 index 0000000000..3ad80562fb --- /dev/null +++ b/spring-context/src/main/resources/org/springframework/ejb/config/spring-jee-4.2.xsd @@ -0,0 +1,267 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/spring-context/src/main/resources/org/springframework/scheduling/config/spring-task-4.2.xsd b/spring-context/src/main/resources/org/springframework/scheduling/config/spring-task-4.2.xsd new file mode 100644 index 0000000000..c4304fa185 --- /dev/null +++ b/spring-context/src/main/resources/org/springframework/scheduling/config/spring-task-4.2.xsd @@ -0,0 +1,307 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/spring-context/src/main/resources/org/springframework/scripting/config/spring-lang-4.2.xsd b/spring-context/src/main/resources/org/springframework/scripting/config/spring-lang-4.2.xsd new file mode 100644 index 0000000000..061d7c1bad --- /dev/null +++ b/spring-context/src/main/resources/org/springframework/scripting/config/spring-lang-4.2.xsd @@ -0,0 +1,255 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/spring-context/src/test/java/org/springframework/scripting/groovy/GroovyScriptFactoryTests.java b/spring-context/src/test/java/org/springframework/scripting/groovy/GroovyScriptFactoryTests.java index 21044dd9a5..1f5131a51c 100644 --- a/spring-context/src/test/java/org/springframework/scripting/groovy/GroovyScriptFactoryTests.java +++ b/spring-context/src/test/java/org/springframework/scripting/groovy/GroovyScriptFactoryTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2013 the original author or authors. + * Copyright 2002-2015 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. @@ -90,6 +90,35 @@ public class GroovyScriptFactoryTests { assertTrue(ctx.getBeansOfType(Messenger.class).values().contains(messenger)); } + @Test + public void testStaticScriptUsingJsr223() throws Exception { + ApplicationContext ctx = new ClassPathXmlApplicationContext("groovyContextWithJsr223.xml", getClass()); + + assertTrue(Arrays.asList(ctx.getBeanNamesForType(Calculator.class)).contains("calculator")); + assertTrue(Arrays.asList(ctx.getBeanNamesForType(Messenger.class)).contains("messenger")); + + Calculator calc = (Calculator) ctx.getBean("calculator"); + Messenger messenger = (Messenger) ctx.getBean("messenger"); + + assertFalse("Shouldn't get proxy when refresh is disabled", AopUtils.isAopProxy(calc)); + assertFalse("Shouldn't get proxy when refresh is disabled", AopUtils.isAopProxy(messenger)); + + assertFalse("Scripted object should not be instance of Refreshable", calc instanceof Refreshable); + assertFalse("Scripted object should not be instance of Refreshable", messenger instanceof Refreshable); + + assertEquals(calc, calc); + assertEquals(messenger, messenger); + assertTrue(!messenger.equals(calc)); + assertTrue(messenger.hashCode() != calc.hashCode()); + assertTrue(!messenger.toString().equals(calc.toString())); + + String desiredMessage = "Hello World!"; + assertEquals("Message is incorrect", desiredMessage, messenger.getMessage()); + + assertTrue(ctx.getBeansOfType(Calculator.class).values().contains(calc)); + assertTrue(ctx.getBeansOfType(Messenger.class).values().contains(messenger)); + } + @Test public void testStaticPrototypeScript() throws Exception { ApplicationContext ctx = new ClassPathXmlApplicationContext("groovyContext.xml", getClass()); @@ -109,6 +138,25 @@ public class GroovyScriptFactoryTests { assertEquals("Byebye World!", messenger2.getMessage()); } + @Test + public void testStaticPrototypeScriptUsingJsr223() throws Exception { + ApplicationContext ctx = new ClassPathXmlApplicationContext("groovyContextWithJsr223.xml", getClass()); + ConfigurableMessenger messenger = (ConfigurableMessenger) ctx.getBean("messengerPrototype"); + ConfigurableMessenger messenger2 = (ConfigurableMessenger) ctx.getBean("messengerPrototype"); + + assertFalse("Shouldn't get proxy when refresh is disabled", AopUtils.isAopProxy(messenger)); + assertFalse("Scripted object should not be instance of Refreshable", messenger instanceof Refreshable); + + assertNotSame(messenger, messenger2); + assertSame(messenger.getClass(), messenger2.getClass()); + assertEquals("Hello World!", messenger.getMessage()); + assertEquals("Hello World!", messenger2.getMessage()); + messenger.setMessage("Bye World!"); + messenger2.setMessage("Byebye World!"); + assertEquals("Bye World!", messenger.getMessage()); + assertEquals("Byebye World!", messenger2.getMessage()); + } + @Test public void testStaticScriptWithInstance() throws Exception { ApplicationContext ctx = new ClassPathXmlApplicationContext("groovyContext.xml", getClass()); @@ -123,6 +171,20 @@ public class GroovyScriptFactoryTests { assertTrue(ctx.getBeansOfType(Messenger.class).values().contains(messenger)); } + @Test + public void testStaticScriptWithInstanceUsingJsr223() throws Exception { + ApplicationContext ctx = new ClassPathXmlApplicationContext("groovyContextWithJsr223.xml", getClass()); + assertTrue(Arrays.asList(ctx.getBeanNamesForType(Messenger.class)).contains("messengerInstance")); + Messenger messenger = (Messenger) ctx.getBean("messengerInstance"); + + assertFalse("Shouldn't get proxy when refresh is disabled", AopUtils.isAopProxy(messenger)); + assertFalse("Scripted object should not be instance of Refreshable", messenger instanceof Refreshable); + + String desiredMessage = "Hello World!"; + assertEquals("Message is incorrect", desiredMessage, messenger.getMessage()); + assertTrue(ctx.getBeansOfType(Messenger.class).values().contains(messenger)); + } + @Test public void testStaticScriptWithInlineDefinedInstance() throws Exception { ApplicationContext ctx = new ClassPathXmlApplicationContext("groovyContext.xml", getClass()); @@ -137,6 +199,20 @@ public class GroovyScriptFactoryTests { assertTrue(ctx.getBeansOfType(Messenger.class).values().contains(messenger)); } + @Test + public void testStaticScriptWithInlineDefinedInstanceUsingJsr223() throws Exception { + ApplicationContext ctx = new ClassPathXmlApplicationContext("groovyContextWithJsr223.xml", getClass()); + assertTrue(Arrays.asList(ctx.getBeanNamesForType(Messenger.class)).contains("messengerInstanceInline")); + Messenger messenger = (Messenger) ctx.getBean("messengerInstanceInline"); + + assertFalse("Shouldn't get proxy when refresh is disabled", AopUtils.isAopProxy(messenger)); + assertFalse("Scripted object should not be instance of Refreshable", messenger instanceof Refreshable); + + String desiredMessage = "Hello World!"; + assertEquals("Message is incorrect", desiredMessage, messenger.getMessage()); + assertTrue(ctx.getBeansOfType(Messenger.class).values().contains(messenger)); + } + @Test public void testNonStaticScript() throws Exception { ApplicationContext ctx = new ClassPathXmlApplicationContext("groovyRefreshableContext.xml", getClass()); @@ -311,8 +387,6 @@ public class GroovyScriptFactoryTests { } } - @Ignore - // see http://build.springframework.org/browse/SPR-TRUNKQUICK-908 @Test public void testResourceScriptFromTag() throws Exception { ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("groovy-with-xsd.xml", getClass()); @@ -409,6 +483,49 @@ public class GroovyScriptFactoryTests { assertEquals(4, beans.size()); } + @Test + public void testJsr223FromTag() throws Exception { + ApplicationContext ctx = new ClassPathXmlApplicationContext("groovy-with-xsd-jsr223.xml", getClass()); + assertTrue(Arrays.asList(ctx.getBeanNamesForType(Messenger.class)).contains("messenger")); + Messenger messenger = (Messenger) ctx.getBean("messenger"); + assertFalse(AopUtils.isAopProxy(messenger)); + assertEquals("Hello World!", messenger.getMessage()); + } + + @Test + public void testJsr223FromTagWithInterface() throws Exception { + ApplicationContext ctx = new ClassPathXmlApplicationContext("groovy-with-xsd-jsr223.xml", getClass()); + assertTrue(Arrays.asList(ctx.getBeanNamesForType(Messenger.class)).contains("messengerWithInterface")); + Messenger messenger = (Messenger) ctx.getBean("messengerWithInterface"); + assertFalse(AopUtils.isAopProxy(messenger)); + } + + @Test + public void testRefreshableJsr223FromTag() throws Exception { + ApplicationContext ctx = new ClassPathXmlApplicationContext("groovy-with-xsd-jsr223.xml", getClass()); + assertTrue(Arrays.asList(ctx.getBeanNamesForType(Messenger.class)).contains("refreshableMessenger")); + Messenger messenger = (Messenger) ctx.getBean("refreshableMessenger"); + assertTrue(AopUtils.isAopProxy(messenger)); + assertTrue(messenger instanceof Refreshable); + assertEquals("Hello World!", messenger.getMessage()); + } + + @Test + public void testInlineJsr223FromTag() throws Exception { + ApplicationContext ctx = new ClassPathXmlApplicationContext("groovy-with-xsd-jsr223.xml", getClass()); + assertTrue(Arrays.asList(ctx.getBeanNamesForType(Messenger.class)).contains("inlineMessenger")); + Messenger messenger = (Messenger) ctx.getBean("inlineMessenger"); + assertFalse(AopUtils.isAopProxy(messenger)); + } + + @Test + public void testInlineJsr223FromTagWithInterface() throws Exception { + ApplicationContext ctx = new ClassPathXmlApplicationContext("groovy-with-xsd-jsr223.xml", getClass()); + assertTrue(Arrays.asList(ctx.getBeanNamesForType(Messenger.class)).contains("inlineMessengerWithInterface")); + Messenger messenger = (Messenger) ctx.getBean("inlineMessengerWithInterface"); + assertFalse(AopUtils.isAopProxy(messenger)); + } + /** * Tests the SPR-2098 bug whereby no more than 1 property element could be * passed to a scripted bean :( diff --git a/spring-context/src/test/java/org/springframework/scripting/jruby/JRubyScriptFactoryTests.java b/spring-context/src/test/java/org/springframework/scripting/jruby/JRubyScriptFactoryTests.java index 0c45266dbf..95c6de6f48 100644 --- a/spring-context/src/test/java/org/springframework/scripting/jruby/JRubyScriptFactoryTests.java +++ b/spring-context/src/test/java/org/springframework/scripting/jruby/JRubyScriptFactoryTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2013 the original author or authors. + * Copyright 2002-2015 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. @@ -64,6 +64,27 @@ public class JRubyScriptFactoryTests { assertNotSame(messenger.hashCode(), calc.hashCode()); assertTrue(!messenger.toString().equals(calc.toString())); + assertEquals(3, calc.add(1, 2)); + String desiredMessage = "Hello World!"; + assertEquals("Message is incorrect", desiredMessage, messenger.getMessage()); + } + + @Test + public void testStaticScriptUsingJsr223() throws Exception { + ApplicationContext ctx = new ClassPathXmlApplicationContext("jrubyContextWithJsr223.xml", getClass()); + Calculator calc = (Calculator) ctx.getBean("calculator"); + Messenger messenger = (Messenger) ctx.getBean("messenger"); + + assertFalse("Scripted object should not be instance of Refreshable", calc instanceof Refreshable); + assertFalse("Scripted object should not be instance of Refreshable", messenger instanceof Refreshable); + + assertEquals(calc, calc); + assertEquals(messenger, messenger); + assertTrue(!messenger.equals(calc)); + assertNotSame(messenger.hashCode(), calc.hashCode()); + assertTrue(!messenger.toString().equals(calc.toString())); + + assertEquals(3, calc.add(1, 2)); String desiredMessage = "Hello World!"; assertEquals("Message is incorrect", desiredMessage, messenger.getMessage()); } @@ -163,6 +184,15 @@ public class JRubyScriptFactoryTests { assertEquals(testBean, messengerByName.getTestBean()); } + @Test + public void testResourceScriptFromTagUsingJsr223() throws Exception { + ApplicationContext ctx = new ClassPathXmlApplicationContext("jruby-with-xsd-jsr223.xml", getClass()); + + Messenger messenger = (Messenger) ctx.getBean("messenger"); + assertEquals("Hello World!", messenger.getMessage()); + assertFalse(messenger instanceof Refreshable); + } + @Test public void testPrototypeScriptFromTag() throws Exception { ApplicationContext ctx = new ClassPathXmlApplicationContext("jruby-with-xsd.xml", getClass()); @@ -185,6 +215,16 @@ public class JRubyScriptFactoryTests { Calculator calculator = (Calculator) ctx.getBean("calculator"); assertNotNull(calculator); assertFalse(calculator instanceof Refreshable); + assertEquals(3, calculator.add(1, 2)); + } + + @Test + public void testInlineScriptFromTagUsingJsr223() throws Exception { + ApplicationContext ctx = new ClassPathXmlApplicationContext("jruby-with-xsd-jsr223.xml", getClass()); + Calculator calculator = (Calculator) ctx.getBean("calculator"); + assertNotNull(calculator); + assertFalse(calculator instanceof Refreshable); + assertEquals(3, calculator.add(1, 2)); } @Test @@ -195,6 +235,15 @@ public class JRubyScriptFactoryTests { assertTrue("Messenger should be Refreshable", messenger instanceof Refreshable); } + @Test + public void testRefreshableFromTagUsingJsr223() throws Exception { + ApplicationContext ctx = new ClassPathXmlApplicationContext("jruby-with-xsd-jsr223.xml", getClass()); + Messenger messenger = (Messenger) ctx.getBean("refreshableMessenger"); + assertEquals("Hello World!", messenger.getMessage()); + assertTrue("Messenger should be Refreshable", messenger instanceof Refreshable); + } + + @Test public void testThatMultipleScriptInterfacesAreSupported() throws Exception { ApplicationContext ctx = new ClassPathXmlApplicationContext("jruby-with-xsd.xml", getClass()); Messenger messenger = (Messenger) ctx.getBean("calculatingMessenger"); @@ -214,6 +263,15 @@ public class JRubyScriptFactoryTests { assertEquals(1, printable.count); } + @Test + public void testWithComplexArgUsingJsr223() throws Exception { + ApplicationContext ctx = new ClassPathXmlApplicationContext("jrubyContextWithJsr223.xml", getClass()); + Printer printer = (Printer) ctx.getBean("printer"); + CountingPrintable printable = new CountingPrintable(); + printer.print(printable); + assertEquals(1, printable.count); + } + @Test public void testWithPrimitiveArgsInReturnTypeAndParameters() throws Exception { ApplicationContext ctx = new ClassPathXmlApplicationContext("jrubyContextForPrimitives.xml", getClass()); diff --git a/spring-context/src/test/java/org/springframework/scripting/support/StandardScriptFactoryTests.java b/spring-context/src/test/java/org/springframework/scripting/support/StandardScriptFactoryTests.java new file mode 100644 index 0000000000..fdd33ad842 --- /dev/null +++ b/spring-context/src/test/java/org/springframework/scripting/support/StandardScriptFactoryTests.java @@ -0,0 +1,67 @@ +/* + * Copyright 2002-2015 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.support; + +import java.util.Arrays; + +import org.junit.Test; + +import org.springframework.aop.support.AopUtils; +import org.springframework.aop.target.dynamic.Refreshable; +import org.springframework.context.ApplicationContext; +import org.springframework.context.support.ClassPathXmlApplicationContext; +import org.springframework.scripting.Messenger; + +import static org.junit.Assert.*; + +/** + * {@link StandardScriptFactory} (lang:std) tests for JavaScript. + * + * @author Juergen Hoeller + * @since 4.2 + */ +public class StandardScriptFactoryTests { + + @Test + public void testJsr223FromTagWithInterface() throws Exception { + ApplicationContext ctx = new ClassPathXmlApplicationContext("jsr223-with-xsd.xml", getClass()); + assertTrue(Arrays.asList(ctx.getBeanNamesForType(Messenger.class)).contains("messengerWithInterface")); + Messenger messenger = (Messenger) ctx.getBean("messengerWithInterface"); + assertFalse(AopUtils.isAopProxy(messenger)); + assertEquals("Hello World!", messenger.getMessage()); + } + + @Test + public void testRefreshableJsr223FromTagWithInterface() throws Exception { + ApplicationContext ctx = new ClassPathXmlApplicationContext("jsr223-with-xsd.xml", getClass()); + assertTrue(Arrays.asList(ctx.getBeanNamesForType(Messenger.class)).contains("refreshableMessengerWithInterface")); + Messenger messenger = (Messenger) ctx.getBean("refreshableMessengerWithInterface"); + assertTrue(AopUtils.isAopProxy(messenger)); + assertTrue(messenger instanceof Refreshable); + assertEquals("Hello World!", messenger.getMessage()); + } + + @Test + public void testInlineJsr223FromTagWithInterface() throws Exception { + ApplicationContext ctx = new ClassPathXmlApplicationContext("jsr223-with-xsd.xml", getClass()); + assertTrue(Arrays.asList(ctx.getBeanNamesForType(Messenger.class)).contains("inlineMessengerWithInterface")); + Messenger messenger = (Messenger) ctx.getBean("inlineMessengerWithInterface"); + assertFalse(AopUtils.isAopProxy(messenger)); + assertEquals("Hello World!", messenger.getMessage()); + } + +} diff --git a/spring-context/src/test/resources/org/springframework/scripting/groovy/groovy-with-xsd-jsr223.xml b/spring-context/src/test/resources/org/springframework/scripting/groovy/groovy-with-xsd-jsr223.xml new file mode 100644 index 0000000000..5d7f273990 --- /dev/null +++ b/spring-context/src/test/resources/org/springframework/scripting/groovy/groovy-with-xsd-jsr223.xml @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + package org.springframework.scripting.groovy; + import org.springframework.scripting.Messenger + class GroovyMessenger implements Messenger { + def String message; + } + return new GroovyMessenger(); + + + + + + package org.springframework.scripting.groovy; + import org.springframework.scripting.Messenger + class GroovyMessenger implements Messenger { + def String message; + } + return new GroovyMessenger(); + + + + diff --git a/spring-context/src/test/resources/org/springframework/scripting/groovy/groovy-with-xsd-proxy-target-class.xml b/spring-context/src/test/resources/org/springframework/scripting/groovy/groovy-with-xsd-proxy-target-class.xml index 822ad89a06..44a4333940 100644 --- a/spring-context/src/test/resources/org/springframework/scripting/groovy/groovy-with-xsd-proxy-target-class.xml +++ b/spring-context/src/test/resources/org/springframework/scripting/groovy/groovy-with-xsd-proxy-target-class.xml @@ -3,12 +3,11 @@ 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-2.0.xsd - http://www.springframework.org/schema/lang http://www.springframework.org/schema/lang/spring-lang-3.1.xsd"> - + script-source="classpath:org/springframework/scripting/groovy/Messenger.groovy"> + diff --git a/spring-context/src/test/resources/org/springframework/scripting/groovy/groovy-with-xsd.xml b/spring-context/src/test/resources/org/springframework/scripting/groovy/groovy-with-xsd.xml index 8de3522ab6..a573d6a2e0 100644 --- a/spring-context/src/test/resources/org/springframework/scripting/groovy/groovy-with-xsd.xml +++ b/spring-context/src/test/resources/org/springframework/scripting/groovy/groovy-with-xsd.xml @@ -33,7 +33,7 @@ class GroovyCalculator implements Calculator { return x + y; } } - + diff --git a/spring-context/src/test/resources/org/springframework/scripting/groovy/groovyContext.xml b/spring-context/src/test/resources/org/springframework/scripting/groovy/groovyContext.xml index a159b1791e..e9c674b959 100644 --- a/spring-context/src/test/resources/org/springframework/scripting/groovy/groovyContext.xml +++ b/spring-context/src/test/resources/org/springframework/scripting/groovy/groovyContext.xml @@ -10,8 +10,7 @@ - + inline: package org.springframework.scripting.groovy; @@ -25,28 +24,24 @@ class GroovyCalculator implements Calculator { - + - - + - - + + inline: package org.springframework.scripting.groovy; import org.springframework.scripting.Messenger diff --git a/spring-context/src/test/resources/org/springframework/scripting/groovy/groovyContextWithJsr223.xml b/spring-context/src/test/resources/org/springframework/scripting/groovy/groovyContextWithJsr223.xml new file mode 100644 index 0000000000..c5f69cd7ea --- /dev/null +++ b/spring-context/src/test/resources/org/springframework/scripting/groovy/groovyContextWithJsr223.xml @@ -0,0 +1,61 @@ + + + + + + + + + inline: +package org.springframework.scripting.groovy; +import org.springframework.scripting.Calculator +class GroovyCalculator implements Calculator { + int add(int x, int y) { + return x + y; + } +} + + + + + + + + + + + + + + + + + + + + + + + inline: +package org.springframework.scripting.groovy; +import org.springframework.scripting.Messenger +class GroovyMessenger implements Messenger { + def String message; +} +return new GroovyMessenger(); + + + + + + + + + + diff --git a/spring-context/src/test/resources/org/springframework/scripting/jruby/MessengerWithInstance.rb b/spring-context/src/test/resources/org/springframework/scripting/jruby/MessengerWithInstance.rb new file mode 100644 index 0000000000..3bdb75e3c9 --- /dev/null +++ b/spring-context/src/test/resources/org/springframework/scripting/jruby/MessengerWithInstance.rb @@ -0,0 +1,25 @@ +require 'java' + +class RubyMessenger + include org.springframework.scripting.ConfigurableMessenger + + @@message = "Hello World!" + + def setMessage(message) + @@message = message + end + + def getMessage + @@message + end + + def setTestBean(testBean) + @@testBean = testBean + end + + def getTestBean + @@testBean + end +end + +RubyMessenger.new diff --git a/spring-context/src/test/resources/org/springframework/scripting/jruby/PrinterWithInstance.rb b/spring-context/src/test/resources/org/springframework/scripting/jruby/PrinterWithInstance.rb new file mode 100644 index 0000000000..58f8a7b512 --- /dev/null +++ b/spring-context/src/test/resources/org/springframework/scripting/jruby/PrinterWithInstance.rb @@ -0,0 +1,11 @@ +require 'java' + +class RubyPrinter + include org.springframework.scripting.jruby.Printer + + def print(obj) + puts obj.getContent + end +end + +RubyPrinter.new diff --git a/spring-context/src/test/resources/org/springframework/scripting/jruby/jruby-with-xsd-jsr223.xml b/spring-context/src/test/resources/org/springframework/scripting/jruby/jruby-with-xsd-jsr223.xml new file mode 100644 index 0000000000..c07e66dc45 --- /dev/null +++ b/spring-context/src/test/resources/org/springframework/scripting/jruby/jruby-with-xsd-jsr223.xml @@ -0,0 +1,32 @@ + + + + + + + + + require 'java' + + class RubyCalculator + include org.springframework.scripting.Calculator + + def add(x, y) + x + y + end + end + + RubyCalculator.new + + + + + + + \ No newline at end of file diff --git a/spring-context/src/test/resources/org/springframework/scripting/jruby/jrubyContextWithJsr223.xml b/spring-context/src/test/resources/org/springframework/scripting/jruby/jrubyContextWithJsr223.xml new file mode 100644 index 0000000000..f552bc90c2 --- /dev/null +++ b/spring-context/src/test/resources/org/springframework/scripting/jruby/jrubyContextWithJsr223.xml @@ -0,0 +1,40 @@ + + + + + + + + + + + inline: +require 'java' + +class RubyCalculator + include org.springframework.scripting.Calculator + + def add(x, y) + x + y + end +end + +RubyCalculator.new + + + + + + + + + + + + + + + + + + diff --git a/spring-context/src/test/resources/org/springframework/scripting/support/Messenger.js b/spring-context/src/test/resources/org/springframework/scripting/support/Messenger.js new file mode 100644 index 0000000000..5277c3c73a --- /dev/null +++ b/spring-context/src/test/resources/org/springframework/scripting/support/Messenger.js @@ -0,0 +1 @@ +function getMessage() { return "Hello World!" } diff --git a/spring-context/src/test/resources/org/springframework/scripting/support/jsr223-with-xsd.xml b/spring-context/src/test/resources/org/springframework/scripting/support/jsr223-with-xsd.xml new file mode 100644 index 0000000000..b88c93bcab --- /dev/null +++ b/spring-context/src/test/resources/org/springframework/scripting/support/jsr223-with-xsd.xml @@ -0,0 +1,23 @@ + + + + + + + + + + + function getMessage() { return "Hello World!" } + + + +