summaryrefslogtreecommitdiff
path: root/spring-context
diff options
context:
space:
mode:
authorEmmanuel Bourg <ebourg@apache.org>2016-09-26 09:12:32 +0200
committerEmmanuel Bourg <ebourg@apache.org>2016-09-26 09:12:32 +0200
commitc3df6b7858afaef71fbe0b42cd62f7f12e595bf0 (patch)
treec724137b4083c01dd5e4a830803f291ee76a2de8 /spring-context
parent75a721d1019da2a2fa86e24ff439df4a224e5b19 (diff)
New upstream version 4.3.3
Diffstat (limited to 'spring-context')
-rw-r--r--spring-context/src/main/java/org/springframework/cache/annotation/CacheEvict.java4
-rw-r--r--spring-context/src/main/java/org/springframework/cache/annotation/CachePut.java12
-rw-r--r--spring-context/src/main/java/org/springframework/cache/annotation/Cacheable.java8
-rw-r--r--spring-context/src/main/java/org/springframework/cache/interceptor/AbstractCacheInvoker.java29
-rw-r--r--spring-context/src/main/java/org/springframework/cache/interceptor/CacheAspectSupport.java2
-rw-r--r--spring-context/src/main/java/org/springframework/cache/interceptor/CacheEvaluationContext.java28
-rw-r--r--spring-context/src/main/java/org/springframework/context/annotation/Bean.java37
-rw-r--r--spring-context/src/main/java/org/springframework/context/annotation/ComponentScanAnnotationParser.java43
-rw-r--r--spring-context/src/main/java/org/springframework/context/annotation/Configuration.java37
-rw-r--r--spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassParser.java32
-rw-r--r--spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassPostProcessor.java3
-rw-r--r--spring-context/src/main/java/org/springframework/context/annotation/ParserStrategyUtils.java65
-rw-r--r--spring-context/src/main/java/org/springframework/context/event/ApplicationListenerMethodAdapter.java93
-rw-r--r--spring-context/src/main/java/org/springframework/context/expression/MethodBasedEvaluationContext.java53
-rw-r--r--spring-context/src/main/java/org/springframework/context/support/GenericApplicationContext.java22
-rw-r--r--spring-context/src/main/java/org/springframework/context/support/LiveBeansView.java30
-rw-r--r--spring-context/src/main/java/org/springframework/format/annotation/DateTimeFormat.java2
-rw-r--r--spring-context/src/main/java/org/springframework/format/datetime/DateFormatter.java4
-rw-r--r--spring-context/src/main/java/org/springframework/format/support/FormatterPropertyEditorAdapter.java6
-rw-r--r--spring-context/src/main/java/org/springframework/format/support/FormattingConversionService.java8
-rw-r--r--spring-context/src/main/java/org/springframework/scheduling/annotation/ScheduledAnnotationBeanPostProcessor.java44
-rw-r--r--spring-context/src/main/java/org/springframework/scheduling/support/CronSequenceGenerator.java7
-rw-r--r--spring-context/src/main/java/org/springframework/scripting/config/ScriptBeanDefinitionParser.java21
-rw-r--r--spring-context/src/main/java/org/springframework/scripting/groovy/GroovyScriptEvaluator.java38
-rw-r--r--spring-context/src/main/java/org/springframework/scripting/groovy/GroovyScriptFactory.java68
-rw-r--r--spring-context/src/test/java/org/springframework/context/annotation/configuration/ConfigurationClassProcessingTests.java112
-rw-r--r--spring-context/src/test/java/org/springframework/context/event/AnnotationDrivenEventListenerTests.java10
-rw-r--r--spring-context/src/test/java/org/springframework/context/event/test/EventCollector.java14
-rw-r--r--spring-context/src/test/java/org/springframework/context/expression/MethodBasedEvaluationContextTests.java53
-rw-r--r--spring-context/src/test/java/org/springframework/jmx/export/annotation/EnableMBeanExportConfigurationTests.java4
-rw-r--r--spring-context/src/test/java/org/springframework/scheduling/annotation/AsyncExecutionTests.java1
-rw-r--r--spring-context/src/test/java/org/springframework/scripting/groovy/GroovyScriptEvaluatorTests.java21
-rw-r--r--spring-context/src/test/java/org/springframework/scripting/groovy/GroovyScriptFactoryTests.java2
-rw-r--r--spring-context/src/test/java/org/springframework/scripting/groovy/MyBytecodeProcessor.java37
-rw-r--r--spring-context/src/test/java/org/springframework/scripting/groovy/MyImportCustomizer.java30
-rw-r--r--spring-context/src/test/resources/org/springframework/scripting/groovy/groovy-with-xsd.xml27
36 files changed, 693 insertions, 314 deletions
diff --git a/spring-context/src/main/java/org/springframework/cache/annotation/CacheEvict.java b/spring-context/src/main/java/org/springframework/cache/annotation/CacheEvict.java
index f12d2119..9364e800 100644
--- a/spring-context/src/main/java/org/springframework/cache/annotation/CacheEvict.java
+++ b/spring-context/src/main/java/org/springframework/cache/annotation/CacheEvict.java
@@ -69,7 +69,9 @@ public @interface CacheEvict {
* following meta-data:
* <ul>
* <li>{@code #result} for a reference to the result of the method invocation, which
- * can only be used if {@link #beforeInvocation()} is {@code false}.</li>
+ * can only be used if {@link #beforeInvocation()} is {@code false}. For supported
+ * wrappers such as {@code Optional}, {@code #result} refers to the actual object,
+ * not the wrapper</li>
* <li>{@code #root.method}, {@code #root.target}, and {@code #root.caches} for
* references to the {@link java.lang.reflect.Method method}, target object, and
* affected cache(s) respectively.</li>
diff --git a/spring-context/src/main/java/org/springframework/cache/annotation/CachePut.java b/spring-context/src/main/java/org/springframework/cache/annotation/CachePut.java
index cd48e410..72d41be0 100644
--- a/spring-context/src/main/java/org/springframework/cache/annotation/CachePut.java
+++ b/spring-context/src/main/java/org/springframework/cache/annotation/CachePut.java
@@ -31,7 +31,9 @@ import org.springframework.core.annotation.AliasFor;
*
* <p>In contrast to the {@link Cacheable @Cacheable} annotation, this annotation
* does not cause the advised method to be skipped. Rather, it always causes the
- * method to be invoked and its result to be stored in the associated cache.
+ * method to be invoked and its result to be stored in the associated cache. Note
+ * that Java8's {@code Optional} return types are automatically handled and its
+ * content is stored in the cache if present.
*
* <p>This annotation may be used as a <em>meta-annotation</em> to create custom
* <em>composed annotations</em> with attribute overrides.
@@ -73,7 +75,9 @@ public @interface CachePut {
* <p>The SpEL expression evaluates against a dedicated context that provides the
* following meta-data:
* <ul>
- * <li>{@code #result} for a reference to the result of the method invocation.</li>
+ * <li>{@code #result} for a reference to the result of the method invocation. For
+ * supported wrappers such as {@code Optional}, {@code #result} refers to the actual
+ * object, not the wrapper</li>
* <li>{@code #root.method}, {@code #root.target}, and {@code #root.caches} for
* references to the {@link java.lang.reflect.Method method}, target object, and
* affected cache(s) respectively.</li>
@@ -138,7 +142,9 @@ public @interface CachePut {
* <p>The SpEL expression evaluates against a dedicated context that provides the
* following meta-data:
* <ul>
- * <li>{@code #result} for a reference to the result of the method invocation.</li>
+ * <li>{@code #result} for a reference to the result of the method invocation. For
+ * supported wrappers such as {@code Optional}, {@code #result} refers to the actual
+ * object, not the wrapper</li>
* <li>{@code #root.method}, {@code #root.target}, and {@code #root.caches} for
* references to the {@link java.lang.reflect.Method method}, target object, and
* affected cache(s) respectively.</li>
diff --git a/spring-context/src/main/java/org/springframework/cache/annotation/Cacheable.java b/spring-context/src/main/java/org/springframework/cache/annotation/Cacheable.java
index 225ada51..9defd955 100644
--- a/spring-context/src/main/java/org/springframework/cache/annotation/Cacheable.java
+++ b/spring-context/src/main/java/org/springframework/cache/annotation/Cacheable.java
@@ -38,7 +38,9 @@ import org.springframework.core.annotation.AliasFor;
* replace the default one (see {@link #keyGenerator}).
*
* <p>If no value is found in the cache for the computed key, the target method
- * will be invoked and the returned value stored in the associated cache.
+ * will be invoked and the returned value stored in the associated cache. Note
+ * that Java8's {@code Optional} return types are automatically handled and its
+ * content is stored in the cache if present.
*
* <p>This annotation may be used as a <em>meta-annotation</em> to create custom
* <em>composed annotations</em> with attribute overrides.
@@ -144,7 +146,9 @@ public @interface Cacheable {
* <p>The SpEL expression evaluates against a dedicated context that provides the
* following meta-data:
* <ul>
- * <li>{@code #result} for a reference to the result of the method invocation.</li>
+ * <li>{@code #result} for a reference to the result of the method invocation. For
+ * supported wrappers such as {@code Optional}, {@code #result} refers to the actual
+ * object, not the wrapper</li>
* <li>{@code #root.method}, {@code #root.target}, and {@code #root.caches} for
* references to the {@link java.lang.reflect.Method method}, target object, and
* affected cache(s) respectively.</li>
diff --git a/spring-context/src/main/java/org/springframework/cache/interceptor/AbstractCacheInvoker.java b/spring-context/src/main/java/org/springframework/cache/interceptor/AbstractCacheInvoker.java
index 70ab3a5f..4d3da400 100644
--- a/spring-context/src/main/java/org/springframework/cache/interceptor/AbstractCacheInvoker.java
+++ b/spring-context/src/main/java/org/springframework/cache/interceptor/AbstractCacheInvoker.java
@@ -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.
@@ -31,14 +31,16 @@ public abstract class AbstractCacheInvoker {
private CacheErrorHandler errorHandler;
+
+ protected AbstractCacheInvoker() {
+ this(new SimpleCacheErrorHandler());
+ }
+
protected AbstractCacheInvoker(CacheErrorHandler errorHandler) {
Assert.notNull("ErrorHandler must not be null");
this.errorHandler = errorHandler;
}
- protected AbstractCacheInvoker() {
- this(new SimpleCacheErrorHandler());
- }
/**
* Set the {@link CacheErrorHandler} instance to use to handle errors
@@ -56,6 +58,7 @@ public abstract class AbstractCacheInvoker {
return this.errorHandler;
}
+
/**
* Execute {@link Cache#get(Object)} on the specified {@link Cache} and
* invoke the error handler if an exception occurs. Return {@code null}
@@ -67,9 +70,9 @@ public abstract class AbstractCacheInvoker {
try {
return cache.get(key);
}
- catch (RuntimeException e) {
- getErrorHandler().handleCacheGetError(e, cache, key);
- return null; // If the exception is handled, return a cache miss
+ catch (RuntimeException ex) {
+ getErrorHandler().handleCacheGetError(ex, cache, key);
+ return null; // If the exception is handled, return a cache miss
}
}
@@ -81,8 +84,8 @@ public abstract class AbstractCacheInvoker {
try {
cache.put(key, result);
}
- catch (RuntimeException e) {
- getErrorHandler().handleCachePutError(e, cache, key, result);
+ catch (RuntimeException ex) {
+ getErrorHandler().handleCachePutError(ex, cache, key, result);
}
}
@@ -94,8 +97,8 @@ public abstract class AbstractCacheInvoker {
try {
cache.evict(key);
}
- catch (RuntimeException e) {
- getErrorHandler().handleCacheEvictError(e, cache, key);
+ catch (RuntimeException ex) {
+ getErrorHandler().handleCacheEvictError(ex, cache, key);
}
}
@@ -107,8 +110,8 @@ public abstract class AbstractCacheInvoker {
try {
cache.clear();
}
- catch (RuntimeException e) {
- getErrorHandler().handleCacheClearError(e, cache);
+ catch (RuntimeException ex) {
+ getErrorHandler().handleCacheClearError(ex, cache);
}
}
diff --git a/spring-context/src/main/java/org/springframework/cache/interceptor/CacheAspectSupport.java b/spring-context/src/main/java/org/springframework/cache/interceptor/CacheAspectSupport.java
index 2de8bd8f..7cfb76d9 100644
--- a/spring-context/src/main/java/org/springframework/cache/interceptor/CacheAspectSupport.java
+++ b/spring-context/src/main/java/org/springframework/cache/interceptor/CacheAspectSupport.java
@@ -444,7 +444,7 @@ public abstract class CacheAspectSupport extends AbstractCacheInvoker
excluded.add(context);
}
}
- catch (VariableNotAvailableException e) {
+ catch (VariableNotAvailableException ex) {
// Ignoring failure due to missing result, consider the cache put has to proceed
}
}
diff --git a/spring-context/src/main/java/org/springframework/cache/interceptor/CacheEvaluationContext.java b/spring-context/src/main/java/org/springframework/cache/interceptor/CacheEvaluationContext.java
index 8d65e15e..213bcd06 100644
--- a/spring-context/src/main/java/org/springframework/cache/interceptor/CacheEvaluationContext.java
+++ b/spring-context/src/main/java/org/springframework/cache/interceptor/CacheEvaluationContext.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2015 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.
@@ -17,8 +17,8 @@
package org.springframework.cache.interceptor;
import java.lang.reflect.Method;
-import java.util.ArrayList;
-import java.util.List;
+import java.util.HashSet;
+import java.util.Set;
import org.springframework.context.expression.MethodBasedEvaluationContext;
import org.springframework.core.ParameterNameDiscoverer;
@@ -38,25 +38,27 @@ import org.springframework.core.ParameterNameDiscoverer;
*
* @author Costin Leau
* @author Stephane Nicoll
+ * @author Juergen Hoeller
* @since 3.1
*/
class CacheEvaluationContext extends MethodBasedEvaluationContext {
- private final List<String> unavailableVariables;
+ private final Set<String> unavailableVariables = new HashSet<String>(1);
- CacheEvaluationContext(Object rootObject, Method method, Object[] args,
- ParameterNameDiscoverer paramDiscoverer) {
- super(rootObject, method, args, paramDiscoverer);
- this.unavailableVariables = new ArrayList<String>();
+ CacheEvaluationContext(Object rootObject, Method method, Object[] arguments,
+ ParameterNameDiscoverer parameterNameDiscoverer) {
+
+ super(rootObject, method, arguments, parameterNameDiscoverer);
}
+
/**
- * Add the specified variable name as unavailable for that context. Any expression trying
- * to access this variable should lead to an exception.
- * <p>This permits the validation of expressions that could potentially a variable even
- * when such variable isn't available yet. Any expression trying to use that variable should
- * therefore fail to evaluate.
+ * Add the specified variable name as unavailable for that context.
+ * Any expression trying to access this variable should lead to an exception.
+ * <p>This permits the validation of expressions that could potentially a
+ * variable even when such variable isn't available yet. Any expression
+ * trying to use that variable should therefore fail to evaluate.
*/
public void addUnavailableVariable(String name) {
this.unavailableVariables.add(name);
diff --git a/spring-context/src/main/java/org/springframework/context/annotation/Bean.java b/spring-context/src/main/java/org/springframework/context/annotation/Bean.java
index 8cbaa0da..b15b7c8e 100644
--- a/spring-context/src/main/java/org/springframework/context/annotation/Bean.java
+++ b/spring-context/src/main/java/org/springframework/context/annotation/Bean.java
@@ -24,6 +24,7 @@ import java.lang.annotation.Target;
import org.springframework.beans.factory.annotation.Autowire;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
+import org.springframework.core.annotation.AliasFor;
/**
* Indicates that a method produces a bean to be managed by the Spring container.
@@ -44,15 +45,15 @@ import org.springframework.beans.factory.support.AbstractBeanDefinition;
*
* <h3>Bean Names</h3>
*
- * <p>While a {@link #name() name} attribute is available, the default strategy for
+ * <p>While a {@link #name} attribute is available, the default strategy for
* determining the name of a bean is to use the name of the {@code @Bean} method.
* This is convenient and intuitive, but if explicit naming is desired, the
- * {@code name} attribute may be used. Also note that {@code name} accepts an array
- * of Strings. This is in order to allow for specifying multiple names (i.e., aliases)
- * for a single bean.
+ * {@code name} attribute (or its alias {@code value}) may be used. Also note
+ * that {@code name} accepts an array of Strings, allowing for multiple names
+ * (i.e. a primary bean name plus one or more aliases) for a single bean.
*
* <pre class="code">
- * &#064;Bean(name={"b1","b2"}) // bean available as 'b1' and 'b2', but not 'myBean'
+ * &#064;Bean({"b1", "b2"}) // bean available as 'b1' and 'b2', but not 'myBean'
* public MyBean myBean() {
* // instantiate and configure MyBean obj
* return obj;
@@ -78,9 +79,9 @@ import org.springframework.beans.factory.support.AbstractBeanDefinition;
* <h3>{@code @Bean} Methods in {@code @Configuration} Classes</h3>
*
* <p>Typically, {@code @Bean} methods are declared within {@code @Configuration}
- * classes. In this case, bean methods may reference other {@code @Bean} methods
- * in the same class by calling them <i>directly</i>. This ensures that references between
- * beans are strongly typed and navigable. Such so-called <em>'inter-bean references'</em> are
+ * classes. In this case, bean methods may reference other {@code @Bean} methods in the
+ * same class by calling them <i>directly</i>. This ensures that references between beans
+ * are strongly typed and navigable. Such so-called <em>'inter-bean references'</em> are
* guaranteed to respect scoping and AOP semantics, just like {@code getBean()} lookups
* would. These are the semantics known from the original 'Spring JavaConfig' project
* which require CGLIB subclassing of each such configuration class at runtime. As a
@@ -190,10 +191,24 @@ import org.springframework.beans.factory.support.AbstractBeanDefinition;
public @interface Bean {
/**
- * The name of this bean, or if plural, aliases for this bean. If left unspecified
- * the name of the bean is the name of the annotated method. If specified, the method
- * name is ignored.
+ * Alias for {@link #name}.
+ * <p>Intended to be used when no other attributes are needed, for example:
+ * {@code @Bean("customBeanName")}.
+ * @since 4.3.3
+ * @see #name
*/
+ @AliasFor("name")
+ String[] value() default {};
+
+ /**
+ * The name of this bean, or if several names, a primary bean name plus aliases.
+ * <p>If left unspecified, the name of the bean is the name of the annotated method.
+ * If specified, the method name is ignored.
+ * <p>The bean name and aliases may also be configured via the {@link #value}
+ * attribute if no other attributes are declared.
+ * @see #value
+ */
+ @AliasFor("value")
String[] name() default {};
/**
diff --git a/spring-context/src/main/java/org/springframework/context/annotation/ComponentScanAnnotationParser.java b/spring-context/src/main/java/org/springframework/context/annotation/ComponentScanAnnotationParser.java
index 247c5838..6a8fba7b 100644
--- a/spring-context/src/main/java/org/springframework/context/annotation/ComponentScanAnnotationParser.java
+++ b/spring-context/src/main/java/org/springframework/context/annotation/ComponentScanAnnotationParser.java
@@ -25,17 +25,10 @@ import java.util.Set;
import java.util.regex.Pattern;
import org.springframework.beans.BeanUtils;
-import org.springframework.beans.factory.Aware;
-import org.springframework.beans.factory.BeanClassLoaderAware;
-import org.springframework.beans.factory.BeanFactory;
-import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.config.BeanDefinitionHolder;
-import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanNameGenerator;
import org.springframework.context.ConfigurableApplicationContext;
-import org.springframework.context.EnvironmentAware;
-import org.springframework.context.ResourceLoaderAware;
import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.core.env.Environment;
import org.springframework.core.io.ResourceLoader;
@@ -61,16 +54,16 @@ import org.springframework.util.StringUtils;
*/
class ComponentScanAnnotationParser {
- private final ResourceLoader resourceLoader;
-
private final Environment environment;
- private final BeanDefinitionRegistry registry;
+ private final ResourceLoader resourceLoader;
private final BeanNameGenerator beanNameGenerator;
+ private final BeanDefinitionRegistry registry;
+
- public ComponentScanAnnotationParser(ResourceLoader resourceLoader, Environment environment,
+ public ComponentScanAnnotationParser(Environment environment, ResourceLoader resourceLoader,
BeanNameGenerator beanNameGenerator, BeanDefinitionRegistry registry) {
this.resourceLoader = resourceLoader;
@@ -90,7 +83,7 @@ class ComponentScanAnnotationParser {
scanner.setResourceLoader(this.resourceLoader);
Class<? extends BeanNameGenerator> generatorClass = componentScan.getClass("nameGenerator");
- boolean useInheritedGenerator = BeanNameGenerator.class == generatorClass;
+ boolean useInheritedGenerator = (BeanNameGenerator.class == generatorClass);
scanner.setBeanNameGenerator(useInheritedGenerator ? this.beanNameGenerator :
BeanUtils.instantiateClass(generatorClass));
@@ -164,7 +157,8 @@ class ComponentScanAnnotationParser {
Assert.isAssignable(TypeFilter.class, filterClass,
"An error occurred while processing a @ComponentScan CUSTOM type filter: ");
TypeFilter filter = BeanUtils.instantiateClass(filterClass, TypeFilter.class);
- invokeAwareMethods(filter);
+ ParserStrategyUtils.invokeAwareMethods(
+ filter, this.environment, this.resourceLoader, this.registry);
typeFilters.add(filter);
break;
default:
@@ -188,27 +182,4 @@ class ComponentScanAnnotationParser {
return typeFilters;
}
- /**
- * Invoke {@link ResourceLoaderAware}, {@link BeanClassLoaderAware} and
- * {@link BeanFactoryAware} contracts if implemented by the given {@code filter}.
- */
- private void invokeAwareMethods(TypeFilter filter) {
- if (filter instanceof Aware) {
- if (filter instanceof EnvironmentAware) {
- ((EnvironmentAware) filter).setEnvironment(this.environment);
- }
- if (filter instanceof ResourceLoaderAware) {
- ((ResourceLoaderAware) filter).setResourceLoader(this.resourceLoader);
- }
- if (filter instanceof BeanClassLoaderAware) {
- ClassLoader classLoader = (this.registry instanceof ConfigurableBeanFactory ?
- ((ConfigurableBeanFactory) this.registry).getBeanClassLoader() :
- this.resourceLoader.getClassLoader());
- ((BeanClassLoaderAware) filter).setBeanClassLoader(classLoader);
- }
- if (filter instanceof BeanFactoryAware && this.registry instanceof BeanFactory) {
- ((BeanFactoryAware) filter).setBeanFactory((BeanFactory) this.registry);
- }
- }
- }
}
diff --git a/spring-context/src/main/java/org/springframework/context/annotation/Configuration.java b/spring-context/src/main/java/org/springframework/context/annotation/Configuration.java
index 5d3b6777..9cb02b7d 100644
--- a/spring-context/src/main/java/org/springframework/context/annotation/Configuration.java
+++ b/spring-context/src/main/java/org/springframework/context/annotation/Configuration.java
@@ -84,7 +84,22 @@ import org.springframework.stereotype.Component;
* {@code @Configuration} classes are candidates for component scanning (typically using
* Spring XML's {@code <context:component-scan/>} element) and therefore may also take
* advantage of {@link Autowired @Autowired}/{@link javax.inject.Inject @Inject}
- * at the field and method level (but not at the constructor level).
+ * like any regular {@code @Component}. In particular, if a single constructor is present
+ * autowiring semantics will be applied transparently:
+ *
+ * <pre class="code">
+ * &#064;Configuration
+ * public class AppConfig {
+ * private final SomeBean someBean;
+ *
+ * public AppConfig(SomeBean someBean) {
+ * this.someBean = someBean;
+ * }
+ *
+ * // &#064;Bean definition using "SomeBean"
+ *
+ * }</pre>
+ *
* <p>{@code @Configuration} classes may not only be bootstrapped using
* component scanning, but may also themselves <em>configure</em> component scanning using
* the {@link ComponentScan @ComponentScan} annotation:
@@ -104,13 +119,13 @@ import org.springframework.stereotype.Component;
*
* Externalized values may be looked up by injecting the Spring
* {@link org.springframework.core.env.Environment} into a {@code @Configuration}
- * class using the {@code @Autowired} or the {@code @Inject} annotation:
+ * class the usual (e.g. using the {@code @Autowired} annotation):
*
* <pre class="code">
* &#064;Configuration
* public class AppConfig {
*
- * &#064Inject Environment env;
+ * &#064Autowired Environment env;
*
* &#064;Bean
* public MyBean myBean() {
@@ -175,7 +190,7 @@ import org.springframework.stereotype.Component;
* <p>{@code @Configuration} classes may be composed using the {@link Import @Import} annotation,
* not unlike the way that {@code <import>} works in Spring XML. Because
* {@code @Configuration} objects are managed as Spring beans within the container,
- * imported configurations may be injected using {@code @Autowired} or {@code @Inject}:
+ * imported configurations may be injected the usual way (e.g. via constructor injection):
*
* <pre class="code">
* &#064;Configuration
@@ -191,7 +206,11 @@ import org.springframework.stereotype.Component;
* &#064;Import(DatabaseConfig.class)
* public class AppConfig {
*
- * &#064Inject DatabaseConfig dataConfig;
+ * private final DatabaseConfig dataConfig;
+ *
+ * public AppConfig(DatabaseConfig dataConfig) {
+ * this.dataConfig = dataConfig;
+ * }
*
* &#064;Bean
* public MyBean myBean() {
@@ -240,8 +259,8 @@ import org.springframework.stereotype.Component;
* As mentioned above, {@code @Configuration} classes may be declared as regular Spring
* {@code <bean>} definitions within Spring XML files. It is also possible to
* import Spring XML configuration files into {@code @Configuration} classes using
- * the {@link ImportResource @ImportResource} annotation. Bean definitions imported from XML can be
- * injected using {@code @Autowired} or {@code @Inject}:
+ * the {@link ImportResource @ImportResource} annotation. Bean definitions imported from
+ * XML can be injected the usual way (e.g. using the {@code Inject} annotation):
*
* <pre class="code">
* &#064;Configuration
@@ -340,9 +359,7 @@ import org.springframework.stereotype.Component;
* <ul>
* <li>&#064;Configuration classes must be non-final
* <li>&#064;Configuration classes must be non-local (may not be declared within a method)
- * <li>&#064;Configuration classes must have a default/no-arg constructor and may not use
- * {@link Autowired @Autowired} constructor parameters. Any nested configuration classes
- * must be {@code static}.
+ * <li>Any nested configuration classes must be {@code static}.
* </ul>
*
* @author Rod Johnson
diff --git a/spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassParser.java b/spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassParser.java
index 46d98634..c4c54832 100644
--- a/spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassParser.java
+++ b/spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassParser.java
@@ -158,7 +158,7 @@ class ConfigurationClassParser {
this.resourceLoader = resourceLoader;
this.registry = registry;
this.componentScanParser = new ComponentScanAnnotationParser(
- resourceLoader, environment, componentScanBeanNameGenerator, registry);
+ environment, resourceLoader, componentScanBeanNameGenerator, registry);
this.conditionEvaluator = new ConditionEvaluator(registry, environment, resourceLoader);
}
@@ -509,7 +509,8 @@ class ConfigurationClassParser {
// Candidate class is an ImportSelector -> delegate to it to determine imports
Class<?> candidateClass = candidate.loadClass();
ImportSelector selector = BeanUtils.instantiateClass(candidateClass, ImportSelector.class);
- invokeAwareMethods(selector);
+ ParserStrategyUtils.invokeAwareMethods(
+ selector, this.environment, this.resourceLoader, this.registry);
if (this.deferredImportSelectors != null && selector instanceof DeferredImportSelector) {
this.deferredImportSelectors.add(
new DeferredImportSelectorHolder(configClass, (DeferredImportSelector) selector));
@@ -526,7 +527,8 @@ class ConfigurationClassParser {
Class<?> candidateClass = candidate.loadClass();
ImportBeanDefinitionRegistrar registrar =
BeanUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class);
- invokeAwareMethods(registrar);
+ ParserStrategyUtils.invokeAwareMethods(
+ registrar, this.environment, this.resourceLoader, this.registry);
configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata());
}
else {
@@ -565,30 +567,6 @@ class ConfigurationClassParser {
return false;
}
- /**
- * Invoke {@link ResourceLoaderAware}, {@link BeanClassLoaderAware} and
- * {@link BeanFactoryAware} contracts if implemented by the given {@code bean}.
- */
- private void invokeAwareMethods(Object importStrategyBean) {
- if (importStrategyBean instanceof Aware) {
- if (importStrategyBean instanceof EnvironmentAware) {
- ((EnvironmentAware) importStrategyBean).setEnvironment(this.environment);
- }
- if (importStrategyBean instanceof ResourceLoaderAware) {
- ((ResourceLoaderAware) importStrategyBean).setResourceLoader(this.resourceLoader);
- }
- if (importStrategyBean instanceof BeanClassLoaderAware) {
- ClassLoader classLoader = (this.registry instanceof ConfigurableBeanFactory ?
- ((ConfigurableBeanFactory) this.registry).getBeanClassLoader() :
- this.resourceLoader.getClassLoader());
- ((BeanClassLoaderAware) importStrategyBean).setBeanClassLoader(classLoader);
- }
- if (importStrategyBean instanceof BeanFactoryAware && this.registry instanceof BeanFactory) {
- ((BeanFactoryAware) importStrategyBean).setBeanFactory((BeanFactory) this.registry);
- }
- }
- }
-
/**
* Validate each {@link ConfigurationClass} object.
diff --git a/spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassPostProcessor.java b/spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassPostProcessor.java
index 301256a6..d86ac32f 100644
--- a/spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassPostProcessor.java
+++ b/spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassPostProcessor.java
@@ -205,6 +205,9 @@ public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPo
public void setResourceLoader(ResourceLoader resourceLoader) {
Assert.notNull(resourceLoader, "ResourceLoader must not be null");
this.resourceLoader = resourceLoader;
+ if (!this.setMetadataReaderFactoryCalled) {
+ this.metadataReaderFactory = new CachingMetadataReaderFactory(resourceLoader);
+ }
}
@Override
diff --git a/spring-context/src/main/java/org/springframework/context/annotation/ParserStrategyUtils.java b/spring-context/src/main/java/org/springframework/context/annotation/ParserStrategyUtils.java
new file mode 100644
index 00000000..f1ced515
--- /dev/null
+++ b/spring-context/src/main/java/org/springframework/context/annotation/ParserStrategyUtils.java
@@ -0,0 +1,65 @@
+/*
+ * 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.context.annotation;
+
+import org.springframework.beans.factory.Aware;
+import org.springframework.beans.factory.BeanClassLoaderAware;
+import org.springframework.beans.factory.BeanFactory;
+import org.springframework.beans.factory.BeanFactoryAware;
+import org.springframework.beans.factory.config.ConfigurableBeanFactory;
+import org.springframework.beans.factory.support.BeanDefinitionRegistry;
+import org.springframework.context.EnvironmentAware;
+import org.springframework.context.ResourceLoaderAware;
+import org.springframework.core.env.Environment;
+import org.springframework.core.io.ResourceLoader;
+
+/**
+ * Common delegate code for the handling of parser strategies, e.g.
+ * {@code TypeFilter}, {@code ImportSelector}, {@code ImportBeanDefinitionRegistrar}
+ *
+ * @author Juergen Hoeller
+ * @since 4.3.3
+ */
+abstract class ParserStrategyUtils {
+
+ /**
+ * Invoke {@link BeanClassLoaderAware}, {@link BeanFactoryAware},
+ * {@link EnvironmentAware}, and {@link ResourceLoaderAware} contracts
+ * if implemented by the given object.
+ */
+ public static void invokeAwareMethods(Object parserStrategyBean, Environment environment,
+ ResourceLoader resourceLoader, BeanDefinitionRegistry registry) {
+
+ if (parserStrategyBean instanceof Aware) {
+ if (parserStrategyBean instanceof BeanClassLoaderAware) {
+ ClassLoader classLoader = (registry instanceof ConfigurableBeanFactory ?
+ ((ConfigurableBeanFactory) registry).getBeanClassLoader() : resourceLoader.getClassLoader());
+ ((BeanClassLoaderAware) parserStrategyBean).setBeanClassLoader(classLoader);
+ }
+ if (parserStrategyBean instanceof BeanFactoryAware && registry instanceof BeanFactory) {
+ ((BeanFactoryAware) parserStrategyBean).setBeanFactory((BeanFactory) registry);
+ }
+ if (parserStrategyBean instanceof EnvironmentAware) {
+ ((EnvironmentAware) parserStrategyBean).setEnvironment(environment);
+ }
+ if (parserStrategyBean instanceof ResourceLoaderAware) {
+ ((ResourceLoaderAware) parserStrategyBean).setResourceLoader(resourceLoader);
+ }
+ }
+ }
+
+}
diff --git a/spring-context/src/main/java/org/springframework/context/event/ApplicationListenerMethodAdapter.java b/spring-context/src/main/java/org/springframework/context/event/ApplicationListenerMethodAdapter.java
index a57eb0c6..48de2bff 100644
--- a/spring-context/src/main/java/org/springframework/context/event/ApplicationListenerMethodAdapter.java
+++ b/spring-context/src/main/java/org/springframework/context/event/ApplicationListenerMethodAdapter.java
@@ -16,7 +16,6 @@
package org.springframework.context.event;
-import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.UndeclaredThrowableException;
@@ -53,6 +52,7 @@ import org.springframework.util.StringUtils;
* evaluated prior to invoking the underlying method.
*
* @author Stephane Nicoll
+ * @author Juergen Hoeller
* @author Sam Brannen
* @since 4.2
*/
@@ -70,26 +70,58 @@ public class ApplicationListenerMethodAdapter implements GenericApplicationListe
private final List<ResolvableType> declaredEventTypes;
+ private final String condition;
+
+ private final int order;
+
private final AnnotatedElementKey methodKey;
private ApplicationContext applicationContext;
private EventExpressionEvaluator evaluator;
- private String condition;
-
- private EventListener eventListener;
-
public ApplicationListenerMethodAdapter(String beanName, Class<?> targetClass, Method method) {
this.beanName = beanName;
this.method = method;
this.targetClass = targetClass;
this.bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
- this.declaredEventTypes = resolveDeclaredEventTypes();
- this.methodKey = new AnnotatedElementKey(this.method, this.targetClass);
+
+ EventListener ann = AnnotatedElementUtils.findMergedAnnotation(method, EventListener.class);
+ this.declaredEventTypes = resolveDeclaredEventTypes(method, ann);
+ this.condition = (ann != null ? ann.condition() : null);
+ this.order = resolveOrder(method);
+
+ this.methodKey = new AnnotatedElementKey(method, targetClass);
+ }
+
+
+ private List<ResolvableType> resolveDeclaredEventTypes(Method method, EventListener ann) {
+ int count = method.getParameterTypes().length;
+ if (count > 1) {
+ throw new IllegalStateException(
+ "Maximum one parameter is allowed for event listener method: " + method);
+ }
+ if (ann != null && ann.classes().length > 0) {
+ List<ResolvableType> types = new ArrayList<ResolvableType>(ann.classes().length);
+ for (Class<?> eventType : ann.classes()) {
+ types.add(ResolvableType.forClass(eventType));
+ }
+ return types;
+ }
+ else {
+ if (count == 0) {
+ throw new IllegalStateException(
+ "Event parameter is mandatory for event listener method: " + method);
+ }
+ return Collections.singletonList(ResolvableType.forMethodParameter(method, 0));
+ }
}
+ private int resolveOrder(Method method) {
+ Order ann = AnnotatedElementUtils.findMergedAnnotation(method, Order.class);
+ return (ann != null ? ann.value() : 0);
+ }
/**
* Initialize this instance.
@@ -128,8 +160,7 @@ public class ApplicationListenerMethodAdapter implements GenericApplicationListe
@Override
public int getOrder() {
- Order order = getMethodAnnotation(Order.class);
- return (order != null ? order.value() : 0);
+ return this.order;
}
@@ -164,8 +195,8 @@ public class ApplicationListenerMethodAdapter implements GenericApplicationListe
if (this.method.getParameterTypes().length == 0) {
return new Object[0];
}
- if (!ApplicationEvent.class.isAssignableFrom(declaredEventType.getRawClass())
- && event instanceof PayloadApplicationEvent) {
+ if (!ApplicationEvent.class.isAssignableFrom(declaredEventType.getRawClass()) &&
+ event instanceof PayloadApplicationEvent) {
return new Object[] {((PayloadApplicationEvent) event).getPayload()};
}
else {
@@ -212,10 +243,6 @@ public class ApplicationListenerMethodAdapter implements GenericApplicationListe
return true;
}
- protected <A extends Annotation> A getMethodAnnotation(Class<A> annotationType) {
- return AnnotatedElementUtils.findMergedAnnotation(this.method, annotationType);
- }
-
/**
* Invoke the event listener method with the given argument values.
*/
@@ -253,13 +280,6 @@ public class ApplicationListenerMethodAdapter implements GenericApplicationListe
return this.applicationContext.getBean(this.beanName);
}
- protected EventListener getEventListener() {
- if (this.eventListener == null) {
- this.eventListener = AnnotatedElementUtils.findMergedAnnotation(this.method, EventListener.class);
- }
- return this.eventListener;
- }
-
/**
* Return the condition to use.
* <p>Matches the {@code condition} attribute of the {@link EventListener}
@@ -267,12 +287,6 @@ public class ApplicationListenerMethodAdapter implements GenericApplicationListe
* is meta-annotated with {@code @EventListener}.
*/
protected String getCondition() {
- if (this.condition == null) {
- EventListener eventListener = AnnotatedElementUtils.findMergedAnnotation(this.method, EventListener.class);
- if (eventListener != null) {
- this.condition = eventListener.condition();
- }
- }
return this.condition;
}
@@ -346,29 +360,6 @@ public class ApplicationListenerMethodAdapter implements GenericApplicationListe
return null;
}
- private List<ResolvableType> resolveDeclaredEventTypes() {
- int count = this.method.getParameterTypes().length;
- if (count > 1) {
- throw new IllegalStateException(
- "Maximum one parameter is allowed for event listener method: " + this.method);
- }
- EventListener ann = getEventListener();
- if (ann != null && ann.classes().length > 0) {
- List<ResolvableType> types = new ArrayList<ResolvableType>();
- for (Class<?> eventType : ann.classes()) {
- types.add(ResolvableType.forClass(eventType));
- }
- return types;
- }
- else {
- if (count == 0) {
- throw new IllegalStateException(
- "Event parameter is mandatory for event listener method: " + this.method);
- }
- return Collections.singletonList(ResolvableType.forMethodParameter(this.method, 0));
- }
- }
-
@Override
public String toString() {
diff --git a/spring-context/src/main/java/org/springframework/context/expression/MethodBasedEvaluationContext.java b/spring-context/src/main/java/org/springframework/context/expression/MethodBasedEvaluationContext.java
index 6c564535..816069f9 100644
--- a/spring-context/src/main/java/org/springframework/context/expression/MethodBasedEvaluationContext.java
+++ b/spring-context/src/main/java/org/springframework/context/expression/MethodBasedEvaluationContext.java
@@ -17,6 +17,7 @@
package org.springframework.context.expression;
import java.lang.reflect.Method;
+import java.util.Arrays;
import org.springframework.core.ParameterNameDiscoverer;
import org.springframework.expression.spel.support.StandardEvaluationContext;
@@ -34,27 +35,27 @@ import org.springframework.util.ObjectUtils;
* </ol>
*
* @author Stephane Nicoll
- * @author Sergey Podgurskiy
+ * @author Juergen Hoeller
* @since 4.2
*/
public class MethodBasedEvaluationContext extends StandardEvaluationContext {
private final Method method;
- private final Object[] args;
+ private final Object[] arguments;
- private final ParameterNameDiscoverer paramDiscoverer;
+ private final ParameterNameDiscoverer parameterNameDiscoverer;
- private boolean paramLoaded = false;
+ private boolean argumentsLoaded = false;
- public MethodBasedEvaluationContext(Object rootObject, Method method, Object[] args,
- ParameterNameDiscoverer paramDiscoverer) {
+ public MethodBasedEvaluationContext(Object rootObject, Method method, Object[] arguments,
+ ParameterNameDiscoverer parameterNameDiscoverer) {
super(rootObject);
this.method = method;
- this.args = args;
- this.paramDiscoverer = paramDiscoverer;
+ this.arguments = arguments;
+ this.parameterNameDiscoverer = parameterNameDiscoverer;
}
@@ -64,9 +65,9 @@ public class MethodBasedEvaluationContext extends StandardEvaluationContext {
if (variable != null) {
return variable;
}
- if (!this.paramLoaded) {
+ if (!this.argumentsLoaded) {
lazyLoadArguments();
- this.paramLoaded = true;
+ this.argumentsLoaded = true;
variable = super.lookupVariable(name);
}
return variable;
@@ -76,22 +77,30 @@ public class MethodBasedEvaluationContext extends StandardEvaluationContext {
* Load the param information only when needed.
*/
protected void lazyLoadArguments() {
- // shortcut if no args need to be loaded
- if (ObjectUtils.isEmpty(this.args)) {
+ // Shortcut if no args need to be loaded
+ if (ObjectUtils.isEmpty(this.arguments)) {
return;
}
- // save arguments as indexed variables
- for (int i = 0; i < this.args.length; i++) {
- setVariable("a" + i, this.args[i]);
- setVariable("p" + i, this.args[i]);
- }
+ // Expose indexed variables as well as parameter names (if discoverable)
+ String[] paramNames = this.parameterNameDiscoverer.getParameterNames(this.method);
+ int paramCount = (paramNames != null ? paramNames.length : this.method.getParameterTypes().length);
+ int argsCount = this.arguments.length;
- String[] parameterNames = this.paramDiscoverer.getParameterNames(this.method);
- // save parameter names (if discovered)
- if (parameterNames != null) {
- for (int i = 0; i < this.args.length; i++) {
- setVariable(parameterNames[i], this.args[i]);
+ for (int i = 0; i < paramCount; i++) {
+ Object value = null;
+ if (argsCount > paramCount && i == paramCount - 1) {
+ // Expose remaining arguments as vararg array for last parameter
+ value = Arrays.copyOfRange(this.arguments, i, argsCount);
+ }
+ else if (argsCount > i) {
+ // Actual argument found - otherwise left as null
+ value = this.arguments[i];
+ }
+ setVariable("a" + i, value);
+ setVariable("p" + i, value);
+ if (paramNames != null) {
+ setVariable(paramNames[i], value);
}
}
}
diff --git a/spring-context/src/main/java/org/springframework/context/support/GenericApplicationContext.java b/spring-context/src/main/java/org/springframework/context/support/GenericApplicationContext.java
index aff0017e..754ceafe 100644
--- a/spring-context/src/main/java/org/springframework/context/support/GenericApplicationContext.java
+++ b/spring-context/src/main/java/org/springframework/context/support/GenericApplicationContext.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2015 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.
@@ -91,6 +91,8 @@ public class GenericApplicationContext extends AbstractApplicationContext implem
private ResourceLoader resourceLoader;
+ private boolean customClassLoader = false;
+
private final AtomicBoolean refreshed = new AtomicBoolean();
@@ -198,6 +200,10 @@ public class GenericApplicationContext extends AbstractApplicationContext implem
}
+ //---------------------------------------------------------------------
+ // ResourceLoader / ResourcePatternResolver override if necessary
+ //---------------------------------------------------------------------
+
/**
* This implementation delegates to this context's ResourceLoader if set,
* falling back to the default superclass behavior else.
@@ -225,6 +231,20 @@ public class GenericApplicationContext extends AbstractApplicationContext implem
return super.getResources(locationPattern);
}
+ @Override
+ public void setClassLoader(ClassLoader classLoader) {
+ super.setClassLoader(classLoader);
+ this.customClassLoader = true;
+ }
+
+ @Override
+ public ClassLoader getClassLoader() {
+ if (this.resourceLoader != null && !this.customClassLoader) {
+ return this.resourceLoader.getClassLoader();
+ }
+ return super.getClassLoader();
+ }
+
//---------------------------------------------------------------------
// Implementations of AbstractApplicationContext's template methods
diff --git a/spring-context/src/main/java/org/springframework/context/support/LiveBeansView.java b/spring-context/src/main/java/org/springframework/context/support/LiveBeansView.java
index b77e6046..abac5b27 100644
--- a/spring-context/src/main/java/org/springframework/context/support/LiveBeansView.java
+++ b/spring-context/src/main/java/org/springframework/context/support/LiveBeansView.java
@@ -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.
@@ -165,6 +165,9 @@ public class LiveBeansView implements LiveBeansViewMBean, ApplicationContextAwar
result.append(",\n");
}
result.append("{\n\"bean\": \"").append(beanName).append("\",\n");
+ result.append("\"aliases\": ");
+ appendArray(result, bf.getAliases(beanName));
+ result.append(",\n");
String scope = bd.getScope();
if (!StringUtils.hasText(scope)) {
scope = BeanDefinition.SCOPE_SINGLETON;
@@ -178,16 +181,9 @@ public class LiveBeansView implements LiveBeansViewMBean, ApplicationContextAwar
result.append("\"type\": null,\n");
}
result.append("\"resource\": \"").append(getEscapedResourceDescription(bd)).append("\",\n");
- result.append("\"dependencies\": [");
- String[] dependencies = bf.getDependenciesForBean(beanName);
- if (dependencies.length > 0) {
- result.append("\"");
- }
- result.append(StringUtils.arrayToDelimitedString(dependencies, "\", \""));
- if (dependencies.length > 0) {
- result.append("\"");
- }
- result.append("]\n}");
+ result.append("\"dependencies\": ");
+ appendArray(result, bf.getDependenciesForBean(beanName));
+ result.append("\n}");
elementAppended = true;
}
}
@@ -241,4 +237,16 @@ public class LiveBeansView implements LiveBeansViewMBean, ApplicationContextAwar
return result.toString();
}
+ private void appendArray(StringBuilder result, String[] arr) {
+ result.append('[');
+ if (arr.length > 0) {
+ result.append('\"');
+ }
+ result.append(StringUtils.arrayToDelimitedString(arr, "\", \""));
+ if (arr.length > 0) {
+ result.append('\"');
+ }
+ result.append(']');
+ }
+
}
diff --git a/spring-context/src/main/java/org/springframework/format/annotation/DateTimeFormat.java b/spring-context/src/main/java/org/springframework/format/annotation/DateTimeFormat.java
index 3c84ff39..e52d5d4f 100644
--- a/spring-context/src/main/java/org/springframework/format/annotation/DateTimeFormat.java
+++ b/spring-context/src/main/java/org/springframework/format/annotation/DateTimeFormat.java
@@ -104,7 +104,7 @@ public @interface DateTimeFormat {
/**
* The most common ISO DateTime Format {@code yyyy-MM-dd'T'HH:mm:ss.SSSZ},
- * e.g. "2000-10-31 01:30:00.000-05:00".
+ * e.g. "2000-10-31T01:30:00.000-05:00".
* <p>This is the default if no annotation value is specified.
*/
DATE_TIME,
diff --git a/spring-context/src/main/java/org/springframework/format/datetime/DateFormatter.java b/spring-context/src/main/java/org/springframework/format/datetime/DateFormatter.java
index b1115366..6806628b 100644
--- a/spring-context/src/main/java/org/springframework/format/datetime/DateFormatter.java
+++ b/spring-context/src/main/java/org/springframework/format/datetime/DateFormatter.java
@@ -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.
@@ -191,7 +191,7 @@ public class DateFormatter implements Formatter<Date> {
if (timeStyle != -1) {
return DateFormat.getTimeInstance(timeStyle, locale);
}
- throw new IllegalStateException("Unsupported style pattern '"+ this.stylePattern+ "'");
+ throw new IllegalStateException("Unsupported style pattern '" + this.stylePattern + "'");
}
return DateFormat.getDateInstance(this.style, locale);
diff --git a/spring-context/src/main/java/org/springframework/format/support/FormatterPropertyEditorAdapter.java b/spring-context/src/main/java/org/springframework/format/support/FormatterPropertyEditorAdapter.java
index 7d490f5d..c3812473 100644
--- a/spring-context/src/main/java/org/springframework/format/support/FormatterPropertyEditorAdapter.java
+++ b/spring-context/src/main/java/org/springframework/format/support/FormatterPropertyEditorAdapter.java
@@ -18,7 +18,6 @@ package org.springframework.format.support;
import java.beans.PropertyEditor;
import java.beans.PropertyEditorSupport;
-import java.text.ParseException;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.format.Formatter;
@@ -65,7 +64,10 @@ public class FormatterPropertyEditorAdapter extends PropertyEditorSupport {
try {
setValue(this.formatter.parse(text, LocaleContextHolder.getLocale()));
}
- catch (ParseException ex) {
+ catch (IllegalArgumentException ex) {
+ throw ex;
+ }
+ catch (Throwable ex) {
throw new IllegalArgumentException("Parse attempt failed for value [" + text + "]", ex);
}
}
diff --git a/spring-context/src/main/java/org/springframework/format/support/FormattingConversionService.java b/spring-context/src/main/java/org/springframework/format/support/FormattingConversionService.java
index e65e4fbd..342607ed 100644
--- a/spring-context/src/main/java/org/springframework/format/support/FormattingConversionService.java
+++ b/spring-context/src/main/java/org/springframework/format/support/FormattingConversionService.java
@@ -17,7 +17,6 @@
package org.springframework.format.support;
import java.lang.annotation.Annotation;
-import java.text.ParseException;
import java.util.Collections;
import java.util.Map;
import java.util.Set;
@@ -193,11 +192,14 @@ public class FormattingConversionService extends GenericConversionService
try {
result = this.parser.parse(text, LocaleContextHolder.getLocale());
}
- catch (ParseException ex) {
+ catch (IllegalArgumentException ex) {
+ throw ex;
+ }
+ catch (Throwable ex) {
throw new IllegalArgumentException("Parse attempt failed for value [" + text + "]", ex);
}
if (result == null) {
- throw new IllegalStateException("Parsers are not allowed to return null");
+ throw new IllegalStateException("Parsers are not allowed to return null: " + this.parser);
}
TypeDescriptor resultType = TypeDescriptor.valueOf(result.getClass());
if (!resultType.isAssignableTo(targetType)) {
diff --git a/spring-context/src/main/java/org/springframework/scheduling/annotation/ScheduledAnnotationBeanPostProcessor.java b/spring-context/src/main/java/org/springframework/scheduling/annotation/ScheduledAnnotationBeanPostProcessor.java
index 89d35299..7b5cb34f 100644
--- a/spring-context/src/main/java/org/springframework/scheduling/annotation/ScheduledAnnotationBeanPostProcessor.java
+++ b/spring-context/src/main/java/org/springframework/scheduling/annotation/ScheduledAnnotationBeanPostProcessor.java
@@ -19,6 +19,7 @@ package org.springframework.scheduling.annotation;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.Collections;
+import java.util.IdentityHashMap;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
@@ -113,7 +114,7 @@ public class ScheduledAnnotationBeanPostProcessor implements DestructionAwareBea
Collections.newSetFromMap(new ConcurrentHashMap<Class<?>, Boolean>(64));
private final Map<Object, Set<ScheduledTask>> scheduledTasks =
- new ConcurrentHashMap<Object, Set<ScheduledTask>>(16);
+ new IdentityHashMap<Object, Set<ScheduledTask>>(16);
@Override
@@ -263,8 +264,8 @@ public class ScheduledAnnotationBeanPostProcessor implements DestructionAwareBea
new MethodIntrospector.MetadataLookup<Set<Scheduled>>() {
@Override
public Set<Scheduled> inspect(Method method) {
- Set<Scheduled> scheduledMethods =
- AnnotatedElementUtils.getMergedRepeatableAnnotations(method, Scheduled.class, Schedules.class);
+ Set<Scheduled> scheduledMethods = AnnotatedElementUtils.getMergedRepeatableAnnotations(
+ method, Scheduled.class, Schedules.class);
return (!scheduledMethods.isEmpty() ? scheduledMethods : null);
}
});
@@ -302,11 +303,7 @@ public class ScheduledAnnotationBeanPostProcessor implements DestructionAwareBea
String errorMessage =
"Exactly one of the 'cron', 'fixedDelay(String)', or 'fixedRate(String)' attributes is required";
- Set<ScheduledTask> tasks = this.scheduledTasks.get(bean);
- if (tasks == null) {
- tasks = new LinkedHashSet<ScheduledTask>(4);
- this.scheduledTasks.put(bean, tasks);
- }
+ Set<ScheduledTask> tasks = new LinkedHashSet<ScheduledTask>(4);
// Determine initial delay
long initialDelay = scheduled.initialDelay();
@@ -400,6 +397,16 @@ public class ScheduledAnnotationBeanPostProcessor implements DestructionAwareBea
// Check whether we had any attribute set
Assert.isTrue(processedSchedule, errorMessage);
+
+ // Finally register the scheduled tasks
+ synchronized (this.scheduledTasks) {
+ Set<ScheduledTask> registeredTasks = this.scheduledTasks.get(bean);
+ if (registeredTasks == null) {
+ registeredTasks = new LinkedHashSet<ScheduledTask>(4);
+ this.scheduledTasks.put(bean, registeredTasks);
+ }
+ registeredTasks.addAll(tasks);
+ }
}
catch (IllegalArgumentException ex) {
throw new IllegalStateException(
@@ -410,7 +417,10 @@ public class ScheduledAnnotationBeanPostProcessor implements DestructionAwareBea
@Override
public void postProcessBeforeDestruction(Object bean, String beanName) {
- Set<ScheduledTask> tasks = this.scheduledTasks.remove(bean);
+ Set<ScheduledTask> tasks;
+ synchronized (this.scheduledTasks) {
+ tasks = this.scheduledTasks.remove(bean);
+ }
if (tasks != null) {
for (ScheduledTask task : tasks) {
task.cancel();
@@ -420,18 +430,22 @@ public class ScheduledAnnotationBeanPostProcessor implements DestructionAwareBea
@Override
public boolean requiresDestruction(Object bean) {
- return this.scheduledTasks.containsKey(bean);
+ synchronized (this.scheduledTasks) {
+ return this.scheduledTasks.containsKey(bean);
+ }
}
@Override
public void destroy() {
- Collection<Set<ScheduledTask>> allTasks = this.scheduledTasks.values();
- for (Set<ScheduledTask> tasks : allTasks) {
- for (ScheduledTask task : tasks) {
- task.cancel();
+ synchronized (this.scheduledTasks) {
+ Collection<Set<ScheduledTask>> allTasks = this.scheduledTasks.values();
+ for (Set<ScheduledTask> tasks : allTasks) {
+ for (ScheduledTask task : tasks) {
+ task.cancel();
+ }
}
+ this.scheduledTasks.clear();
}
- this.scheduledTasks.clear();
this.registrar.destroy();
}
diff --git a/spring-context/src/main/java/org/springframework/scheduling/support/CronSequenceGenerator.java b/spring-context/src/main/java/org/springframework/scheduling/support/CronSequenceGenerator.java
index c7b356fd..09d14360 100644
--- a/spring-context/src/main/java/org/springframework/scheduling/support/CronSequenceGenerator.java
+++ b/spring-context/src/main/java/org/springframework/scheduling/support/CronSequenceGenerator.java
@@ -42,6 +42,7 @@ import org.springframework.util.StringUtils;
* <li>"0 0 * * * *" = the top of every hour of every day.</li>
* <li>"*&#47;10 * * * * *" = every ten seconds.</li>
* <li>"0 0 8-10 * * *" = 8, 9 and 10 o'clock of every day.</li>
+ * <li>"0 * 6,19 * * *" = 6:00 AM and 7:00 PM every day.</li>
* <li>"0 0/30 8-10 * * *" = 8:00, 8:30, 9:00, 9:30 and 10 o'clock every day.</li>
* <li>"0 0 9-17 * * MON-FRI" = on the hour nine-to-five weekdays</li>
* <li>"0 0 0 25 12 ?" = every Christmas Day at midnight</li>
@@ -115,7 +116,7 @@ public class CronSequenceGenerator {
/*
The plan:
- 1 Round up to the next whole second
+ 1 Start with whole second (rounding up if necessary)
2 If seconds match move on, otherwise find the next match:
2.1 If next match is in the next minute then roll forwards
@@ -127,8 +128,6 @@ public class CronSequenceGenerator {
4 If hour matches move on, otherwise find the next match
4.1 If next match is in the next day then roll forwards,
4.2 Reset the minutes and seconds and go to 2
-
- ...
*/
Calendar calendar = new GregorianCalendar();
@@ -427,7 +426,7 @@ public class CronSequenceGenerator {
@Override
public String toString() {
- return (getClass().getSimpleName() + ": " + this.expression);
+ return getClass().getSimpleName() + ": " + this.expression;
}
}
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 83d72a9d..bd4aa553 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-2015 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.
@@ -35,17 +35,17 @@ import org.springframework.util.xml.DomUtils;
/**
* BeanDefinitionParser implementation for the '{@code <lang:groovy/>}',
- * '{@code <lang:jruby/>}' and '{@code <lang:bsh/>}' tags.
+ * '{@code <lang:std/>}' and '{@code <lang:bsh/>}' tags.
* Allows for objects written using dynamic languages to be easily exposed with
* the {@link org.springframework.beans.factory.BeanFactory}.
*
- * <p>The script for each object can be specified either as a reference to the Resource
- * containing it (using the '{@code script-source}' attribute) or inline in the XML configuration
- * itself (using the '{@code inline-script}' attribute.
+ * <p>The script for each object can be specified either as a reference to the
+ * resource containing it (using the '{@code script-source}' attribute) or inline
+ * in the XML configuration itself (using the '{@code inline-script}' attribute.
*
- * <p>By default, dynamic objects created with these tags are <strong>not</strong> refreshable.
- * To enable refreshing, specify the refresh check delay for each object (in milliseconds) using the
- * '{@code refresh-check-delay}' attribute.
+ * <p>By default, dynamic objects created with these tags are <strong>not</strong>
+ * refreshable. To enable refreshing, specify the refresh check delay for each
+ * object (in milliseconds) using the '{@code refresh-check-delay}' attribute.
*
* @author Rob Harrop
* @author Rod Johnson
@@ -176,14 +176,13 @@ class ScriptBeanDefinitionParser extends AbstractBeanDefinitionParser {
// Attach any refresh metadata.
String refreshCheckDelay = element.getAttribute(REFRESH_CHECK_DELAY_ATTRIBUTE);
if (StringUtils.hasText(refreshCheckDelay)) {
- bd.setAttribute(ScriptFactoryPostProcessor.REFRESH_CHECK_DELAY_ATTRIBUTE, new Long(refreshCheckDelay));
+ bd.setAttribute(ScriptFactoryPostProcessor.REFRESH_CHECK_DELAY_ATTRIBUTE, Long.valueOf(refreshCheckDelay));
}
// Attach any proxy target class metadata.
String proxyTargetClass = element.getAttribute(PROXY_TARGET_CLASS_ATTRIBUTE);
if (StringUtils.hasText(proxyTargetClass)) {
- Boolean flag = new Boolean(proxyTargetClass);
- bd.setAttribute(ScriptFactoryPostProcessor.PROXY_TARGET_CLASS_ATTRIBUTE, flag);
+ bd.setAttribute(ScriptFactoryPostProcessor.PROXY_TARGET_CLASS_ATTRIBUTE, Boolean.valueOf(proxyTargetClass));
}
// Add constructor arguments.
diff --git a/spring-context/src/main/java/org/springframework/scripting/groovy/GroovyScriptEvaluator.java b/spring-context/src/main/java/org/springframework/scripting/groovy/GroovyScriptEvaluator.java
index 3bcf53f0..e94b9d40 100644
--- a/spring-context/src/main/java/org/springframework/scripting/groovy/GroovyScriptEvaluator.java
+++ b/spring-context/src/main/java/org/springframework/scripting/groovy/GroovyScriptEvaluator.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2015 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.
@@ -22,6 +22,8 @@ import java.util.Map;
import groovy.lang.Binding;
import groovy.lang.GroovyRuntimeException;
import groovy.lang.GroovyShell;
+import org.codehaus.groovy.control.CompilerConfiguration;
+import org.codehaus.groovy.control.customizers.CompilationCustomizer;
import org.springframework.beans.factory.BeanClassLoaderAware;
import org.springframework.scripting.ScriptCompilationException;
@@ -40,6 +42,8 @@ public class GroovyScriptEvaluator implements ScriptEvaluator, BeanClassLoaderAw
private ClassLoader classLoader;
+ private CompilerConfiguration compilerConfiguration = new CompilerConfiguration();
+
/**
* Construct a new GroovyScriptEvaluator.
@@ -56,6 +60,35 @@ public class GroovyScriptEvaluator implements ScriptEvaluator, BeanClassLoaderAw
}
+ /**
+ * Set a custom compiler configuration for this evaluator.
+ * @since 4.3.3
+ * @see #setCompilationCustomizers
+ */
+ public void setCompilerConfiguration(CompilerConfiguration compilerConfiguration) {
+ this.compilerConfiguration =
+ (compilerConfiguration != null ? compilerConfiguration : new CompilerConfiguration());
+ }
+
+ /**
+ * Return this evaluator's compiler configuration (never {@code null}).
+ * @since 4.3.3
+ * @see #setCompilerConfiguration
+ */
+ public CompilerConfiguration getCompilerConfiguration() {
+ return this.compilerConfiguration;
+ }
+
+ /**
+ * Set one or more customizers to be applied to this evaluator's compiler configuration.
+ * <p>Note that this modifies the shared compiler configuration held by this evaluator.
+ * @since 4.3.3
+ * @see #setCompilerConfiguration
+ */
+ public void setCompilationCustomizers(CompilationCustomizer... compilationCustomizers) {
+ this.compilerConfiguration.addCompilationCustomizers(compilationCustomizers);
+ }
+
@Override
public void setBeanClassLoader(ClassLoader classLoader) {
this.classLoader = classLoader;
@@ -69,7 +102,8 @@ public class GroovyScriptEvaluator implements ScriptEvaluator, BeanClassLoaderAw
@Override
public Object evaluate(ScriptSource script, Map<String, Object> arguments) {
- GroovyShell groovyShell = new GroovyShell(this.classLoader, new Binding(arguments));
+ GroovyShell groovyShell = new GroovyShell(
+ this.classLoader, new Binding(arguments), this.compilerConfiguration);
try {
String filename = (script instanceof ResourceScriptSource ?
((ResourceScriptSource) script).getResource().getFilename() : null);
diff --git a/spring-context/src/main/java/org/springframework/scripting/groovy/GroovyScriptFactory.java b/spring-context/src/main/java/org/springframework/scripting/groovy/GroovyScriptFactory.java
index fdc2bb83..6e84456d 100644
--- a/spring-context/src/main/java/org/springframework/scripting/groovy/GroovyScriptFactory.java
+++ b/spring-context/src/main/java/org/springframework/scripting/groovy/GroovyScriptFactory.java
@@ -17,12 +17,15 @@
package org.springframework.scripting.groovy;
import java.io.IOException;
+import java.lang.reflect.InvocationTargetException;
import groovy.lang.GroovyClassLoader;
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;
@@ -33,6 +36,8 @@ 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.ReflectionUtils;
/**
* {@link org.springframework.scripting.ScriptFactory} implementation
@@ -55,7 +60,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;
@@ -78,27 +85,62 @@ 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 create a custom MetaClass
+ * to supply missing methods and otherwise change the behavior of the object.
+ * @param scriptSourceLocator a locator that points to the source of the script.
+ * Interpreted by the post-processor that actually creates the script.
+ * @param compilerConfiguration a custom compiler configuration to be applied
+ * to the GroovyClassLoader (may be {@code null})
+ * @since 4.3.3
+ * @see GroovyClassLoader#GroovyClassLoader(ClassLoader, CompilerConfiguration)
+ */
+ public GroovyScriptFactory(String scriptSourceLocator, CompilerConfiguration compilerConfiguration) {
+ this(scriptSourceLocator);
+ this.compilerConfiguration = compilerConfiguration;
+ }
+
+ /**
+ * 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 compilationCustomizers one or more customizers to be applied to the
+ * GroovyClassLoader compiler configuration
+ * @since 4.3.3
+ * @see CompilerConfiguration#addCompilationCustomizers
+ * @see org.codehaus.groovy.control.customizers.ImportCustomizer
+ */
+ public GroovyScriptFactory(String scriptSourceLocator, CompilationCustomizer... compilationCustomizers) {
+ this(scriptSourceLocator);
+ if (!ObjectUtils.isEmpty(compilationCustomizers)) {
+ this.compilerConfiguration = new CompilerConfiguration();
+ this.compilerConfiguration.addCompilationCustomizers(compilationCustomizers);
+ }
+ }
+
@Override
public void setBeanFactory(BeanFactory beanFactory) {
@@ -109,7 +151,7 @@ public class GroovyScriptFactory implements ScriptFactory, BeanFactoryAware, Bea
@Override
public void setBeanClassLoader(ClassLoader classLoader) {
- this.groovyClassLoader = new GroovyClassLoader(classLoader);
+ this.groovyClassLoader = buildGroovyClassLoader(classLoader);
}
/**
@@ -118,12 +160,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() {
diff --git a/spring-context/src/test/java/org/springframework/context/annotation/configuration/ConfigurationClassProcessingTests.java b/spring-context/src/test/java/org/springframework/context/annotation/configuration/ConfigurationClassProcessingTests.java
index bf4c9e6a..88d27eac 100644
--- a/spring-context/src/test/java/org/springframework/context/annotation/configuration/ConfigurationClassProcessingTests.java
+++ b/spring-context/src/test/java/org/springframework/context/annotation/configuration/ConfigurationClassProcessingTests.java
@@ -20,9 +20,12 @@ import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Set;
+import java.util.function.Supplier;
import javax.inject.Provider;
+import org.junit.Rule;
import org.junit.Test;
+import org.junit.rules.ExpectedException;
import org.springframework.beans.factory.BeanClassLoaderAware;
import org.springframework.beans.factory.BeanFactory;
@@ -65,6 +68,7 @@ import static org.junit.Assert.*;
*
* @author Chris Beams
* @author Juergen Hoeller
+ * @author Sam Brannen
*/
public class ConfigurationClassProcessingTests {
@@ -92,40 +96,57 @@ public class ConfigurationClassProcessingTests {
}
+ @Rule
+ public final ExpectedException exception = ExpectedException.none();
+
+
+ @Test
+ public void customBeanNameIsRespectedWhenConfiguredViaNameAttribute() {
+ customBeanNameIsRespected(ConfigWithBeanWithCustomName.class,
+ () -> ConfigWithBeanWithCustomName.testBean, "customName");
+ }
+
@Test
- public void customBeanNameIsRespected() {
+ public void customBeanNameIsRespectedWhenConfiguredViaValueAttribute() {
+ customBeanNameIsRespected(ConfigWithBeanWithCustomNameConfiguredViaValueAttribute.class,
+ () -> ConfigWithBeanWithCustomNameConfiguredViaValueAttribute.testBean, "enigma");
+ }
+
+ private void customBeanNameIsRespected(Class<?> testClass, Supplier<TestBean> testBeanSupplier, String beanName) {
GenericApplicationContext ac = new GenericApplicationContext();
AnnotationConfigUtils.registerAnnotationConfigProcessors(ac);
- ac.registerBeanDefinition("config", new RootBeanDefinition(ConfigWithBeanWithCustomName.class));
+ ac.registerBeanDefinition("config", new RootBeanDefinition(testClass));
ac.refresh();
- assertSame(ac.getBean("customName"), ConfigWithBeanWithCustomName.testBean);
+
+ assertSame(testBeanSupplier.get(), ac.getBean(beanName));
// method name should not be registered
- try {
- ac.getBean("methodName");
- fail("bean should not have been registered with 'methodName'");
- }
- catch (NoSuchBeanDefinitionException ex) {
- // expected
- }
+ exception.expect(NoSuchBeanDefinitionException.class);
+ ac.getBean("methodName");
}
@Test
- public void aliasesAreRespected() {
- BeanFactory factory = initBeanFactory(ConfigWithBeanWithAliases.class);
- assertSame(factory.getBean("name1"), ConfigWithBeanWithAliases.testBean);
- String[] aliases = factory.getAliases("name1");
- for (String alias : aliases)
- assertSame(factory.getBean(alias), ConfigWithBeanWithAliases.testBean);
+ public void aliasesAreRespectedWhenConfiguredViaNameAttribute() {
+ aliasesAreRespected(ConfigWithBeanWithAliases.class,
+ () -> ConfigWithBeanWithAliases.testBean, "name1");
+ }
+
+ @Test
+ public void aliasesAreRespectedWhenConfiguredViaValueAttribute() {
+ aliasesAreRespected(ConfigWithBeanWithAliasesConfiguredViaValueAttribute.class,
+ () -> ConfigWithBeanWithAliasesConfiguredViaValueAttribute.testBean, "enigma");
+ }
+
+ private void aliasesAreRespected(Class<?> testClass, Supplier<TestBean> testBeanSupplier, String beanName) {
+ TestBean testBean = testBeanSupplier.get();
+ BeanFactory factory = initBeanFactory(testClass);
+
+ assertSame(testBean, factory.getBean(beanName));
+ Arrays.stream(factory.getAliases(beanName)).map(factory::getBean).forEach(alias -> assertSame(testBean, alias));
// method name should not be registered
- try {
- factory.getBean("methodName");
- fail("bean should not have been registered with 'methodName'");
- }
- catch (NoSuchBeanDefinitionException ex) {
- // expected
- }
+ exception.expect(NoSuchBeanDefinitionException.class);
+ factory.getBean("methodName");
}
@Test // SPR-11830
@@ -146,8 +167,9 @@ public class ConfigurationClassProcessingTests {
assertSame(ac.getBean("customName"), ConfigWithSetWithProviderImplementation.set);
}
- @Test(expected=BeanDefinitionParsingException.class)
+ @Test
public void testFinalBeanMethod() {
+ exception.expect(BeanDefinitionParsingException.class);
initBeanFactory(ConfigWithFinalBean.class);
}
@@ -219,6 +241,7 @@ public class ConfigurationClassProcessingTests {
adaptive = factory.getBean(AdaptiveInjectionPoints.class);
assertEquals("adaptiveInjectionPoint1", adaptive.adaptiveInjectionPoint1.getName());
assertEquals("setAdaptiveInjectionPoint2", adaptive.adaptiveInjectionPoint2.getName());
+ factory.close();
}
@Test
@@ -240,15 +263,28 @@ public class ConfigurationClassProcessingTests {
SpousyTestBean listener = factory.getBean("listenerTestBean", SpousyTestBean.class);
assertTrue(listener.refreshed);
+ factory.close();
}
@Configuration
static class ConfigWithBeanWithCustomName {
- static TestBean testBean = new TestBean();
+ static TestBean testBean = new TestBean(ConfigWithBeanWithCustomName.class.getSimpleName());
- @Bean(name="customName")
+ @Bean(name = "customName")
+ public TestBean methodName() {
+ return testBean;
+ }
+ }
+
+
+ @Configuration
+ static class ConfigWithBeanWithCustomNameConfiguredViaValueAttribute {
+
+ static TestBean testBean = new TestBean(ConfigWithBeanWithCustomNameConfiguredViaValueAttribute.class.getSimpleName());
+
+ @Bean("enigma")
public TestBean methodName() {
return testBean;
}
@@ -258,9 +294,21 @@ public class ConfigurationClassProcessingTests {
@Configuration
static class ConfigWithBeanWithAliases {
- static TestBean testBean = new TestBean();
+ static TestBean testBean = new TestBean(ConfigWithBeanWithAliases.class.getSimpleName());
+
+ @Bean(name = { "name1", "alias1", "alias2", "alias3" })
+ public TestBean methodName() {
+ return testBean;
+ }
+ }
+
+
+ @Configuration
+ static class ConfigWithBeanWithAliasesConfiguredViaValueAttribute {
+
+ static TestBean testBean = new TestBean(ConfigWithBeanWithAliasesConfiguredViaValueAttribute.class.getSimpleName());
- @Bean(name={"name1", "alias1", "alias2", "alias3"})
+ @Bean({ "enigma", "alias1", "alias2", "alias3" })
public TestBean methodName() {
return testBean;
}
@@ -270,9 +318,9 @@ public class ConfigurationClassProcessingTests {
@Configuration
static class ConfigWithBeanWithProviderImplementation implements Provider<TestBean> {
- static TestBean testBean = new TestBean();
+ static TestBean testBean = new TestBean(ConfigWithBeanWithProviderImplementation.class.getSimpleName());
- @Bean(name="customName")
+ @Bean(name = "customName")
public TestBean get() {
return testBean;
}
@@ -284,7 +332,7 @@ public class ConfigurationClassProcessingTests {
static Set<String> set = Collections.singleton("value");
- @Bean(name="customName")
+ @Bean(name = "customName")
public Set<String> get() {
return set;
}
@@ -406,7 +454,7 @@ public class ConfigurationClassProcessingTests {
};
}
- //@Bean
+ // @Bean
public BeanFactoryPostProcessor beanFactoryPostProcessor() {
return new BeanFactoryPostProcessor() {
@Override
diff --git a/spring-context/src/test/java/org/springframework/context/event/AnnotationDrivenEventListenerTests.java b/spring-context/src/test/java/org/springframework/context/event/AnnotationDrivenEventListenerTests.java
index 89738660..438c126f 100644
--- a/spring-context/src/test/java/org/springframework/context/event/AnnotationDrivenEventListenerTests.java
+++ b/spring-context/src/test/java/org/springframework/context/event/AnnotationDrivenEventListenerTests.java
@@ -77,7 +77,7 @@ public class AnnotationDrivenEventListenerTests {
private EventCollector eventCollector;
- private CountDownLatch countDownLatch; // 1 call by default
+ private CountDownLatch countDownLatch; // 1 call by default
@After
@@ -93,16 +93,23 @@ public class AnnotationDrivenEventListenerTests {
load(TestEventListener.class);
TestEvent event = new TestEvent(this, "test");
TestEventListener listener = this.context.getBean(TestEventListener.class);
+
this.eventCollector.assertNoEventReceived(listener);
this.context.publishEvent(event);
this.eventCollector.assertEvent(listener, event);
this.eventCollector.assertTotalEventsCount(1);
+
+ this.eventCollector.clear();
+ this.context.publishEvent(event);
+ this.eventCollector.assertEvent(listener, event);
+ this.eventCollector.assertTotalEventsCount(1);
}
@Test
public void simpleEventXmlConfig() {
this.context = new ClassPathXmlApplicationContext(
"org/springframework/context/event/simple-event-configuration.xml");
+
TestEvent event = new TestEvent(this, "test");
TestEventListener listener = this.context.getBean(TestEventListener.class);
this.eventCollector = getEventCollector(this.context);
@@ -116,7 +123,6 @@ public class AnnotationDrivenEventListenerTests {
@Test
public void metaAnnotationIsDiscovered() {
load(MetaAnnotationListenerTestBean.class);
-
MetaAnnotationListenerTestBean bean = this.context.getBean(MetaAnnotationListenerTestBean.class);
this.eventCollector.assertNoEventReceived(bean);
diff --git a/spring-context/src/test/java/org/springframework/context/event/test/EventCollector.java b/spring-context/src/test/java/org/springframework/context/event/test/EventCollector.java
index 9df254c2..cbbee976 100644
--- a/spring-context/src/test/java/org/springframework/context/event/test/EventCollector.java
+++ b/spring-context/src/test/java/org/springframework/context/event/test/EventCollector.java
@@ -30,6 +30,7 @@ import static org.junit.Assert.*;
* Test utility to collect and assert events.
*
* @author Stephane Nicoll
+ * @author Juergen Hoeller
*/
@Component
public class EventCollector {
@@ -73,7 +74,7 @@ public class EventCollector {
*/
public void assertEvent(String listenerId, Object... events) {
List<Object> actual = this.content.getOrDefault(listenerId, Collections.emptyList());
- assertEquals("wrong number of events", events.length, actual.size());
+ assertEquals("Wrong number of events", events.length, actual.size());
for (int i = 0; i < events.length; i++) {
assertEquals("Wrong event at index " + i, events[i], actual.get(i));
}
@@ -97,8 +98,15 @@ public class EventCollector {
for (Map.Entry<String, List<Object>> entry : this.content.entrySet()) {
actual += entry.getValue().size();
}
- assertEquals("Wrong number of total events (" + this.content.size() + ") " +
- "registered listener(s)", number, actual);
+ assertEquals("Wrong number of total events (" + this.content.size() +
+ ") registered listener(s)", number, actual);
+ }
+
+ /**
+ * Clear the collected events, allowing for reuse of the collector.
+ */
+ public void clear() {
+ this.content.clear();
}
}
diff --git a/spring-context/src/test/java/org/springframework/context/expression/MethodBasedEvaluationContextTests.java b/spring-context/src/test/java/org/springframework/context/expression/MethodBasedEvaluationContextTests.java
index 2711b006..cdb05632 100644
--- a/spring-context/src/test/java/org/springframework/context/expression/MethodBasedEvaluationContextTests.java
+++ b/spring-context/src/test/java/org/springframework/context/expression/MethodBasedEvaluationContextTests.java
@@ -30,17 +30,18 @@ import static org.junit.Assert.*;
* Unit tests for {@link MethodBasedEvaluationContext}.
*
* @author Stephane Nicoll
+ * @author Juergen Hoeller
* @author Sergey Podgurskiy
*/
public class MethodBasedEvaluationContextTests {
private final ParameterNameDiscoverer paramDiscover = new DefaultParameterNameDiscoverer();
+
@Test
public void simpleArguments() {
- Method method = ReflectionUtils.findMethod(SampleMethods.class, "hello",
- String.class, Boolean.class);
- MethodBasedEvaluationContext context = createEvaluationContext(method, new Object[] {"test", true});
+ Method method = ReflectionUtils.findMethod(SampleMethods.class, "hello", String.class, Boolean.class);
+ MethodBasedEvaluationContext context = createEvaluationContext(method, "test", true);
assertEquals("test", context.lookupVariable("a0"));
assertEquals("test", context.lookupVariable("p0"));
@@ -51,16 +52,21 @@ public class MethodBasedEvaluationContextTests {
assertEquals(true, context.lookupVariable("flag"));
assertNull(context.lookupVariable("a2"));
+ assertNull(context.lookupVariable("p2"));
}
@Test
public void nullArgument() {
- Method method = ReflectionUtils.findMethod(SampleMethods.class, "hello",
- String.class, Boolean.class);
- MethodBasedEvaluationContext context = createEvaluationContext(method, new Object[] {null, null});
+ Method method = ReflectionUtils.findMethod(SampleMethods.class, "hello", String.class, Boolean.class);
+ MethodBasedEvaluationContext context = createEvaluationContext(method, null, null);
assertNull(context.lookupVariable("a0"));
assertNull(context.lookupVariable("p0"));
+ assertNull(context.lookupVariable("foo"));
+
+ assertNull(context.lookupVariable("a1"));
+ assertNull(context.lookupVariable("p1"));
+ assertNull(context.lookupVariable("flag"));
}
@Test
@@ -68,39 +74,58 @@ public class MethodBasedEvaluationContextTests {
Method method = ReflectionUtils.findMethod(SampleMethods.class, "hello", Boolean.class, String[].class);
MethodBasedEvaluationContext context = createEvaluationContext(method, new Object[] {null});
+ assertNull(context.lookupVariable("a0"));
assertNull(context.lookupVariable("p0"));
+ assertNull(context.lookupVariable("flag"));
+
+ assertNull(context.lookupVariable("a1"));
assertNull(context.lookupVariable("p1"));
+ assertNull(context.lookupVariable("vararg"));
}
@Test
public void varArgNull() {
Method method = ReflectionUtils.findMethod(SampleMethods.class, "hello", Boolean.class, String[].class);
- MethodBasedEvaluationContext context = createEvaluationContext(method, new Object[] {null, null});
+ MethodBasedEvaluationContext context = createEvaluationContext(method, null, null);
+ assertNull(context.lookupVariable("a0"));
assertNull(context.lookupVariable("p0"));
+ assertNull(context.lookupVariable("flag"));
+
+ assertNull(context.lookupVariable("a1"));
assertNull(context.lookupVariable("p1"));
+ assertNull(context.lookupVariable("vararg"));
}
@Test
public void varArgSingle() {
Method method = ReflectionUtils.findMethod(SampleMethods.class, "hello", Boolean.class, String[].class);
- MethodBasedEvaluationContext context = createEvaluationContext(method, new Object[] {null, "hello"});
+ MethodBasedEvaluationContext context = createEvaluationContext(method, null, "hello");
+ assertNull(context.lookupVariable("a0"));
assertNull(context.lookupVariable("p0"));
+ assertNull(context.lookupVariable("flag"));
+
+ assertEquals("hello", context.lookupVariable("a1"));
assertEquals("hello", context.lookupVariable("p1"));
+ assertEquals("hello", context.lookupVariable("vararg"));
}
@Test
public void varArgMultiple() {
Method method = ReflectionUtils.findMethod(SampleMethods.class, "hello", Boolean.class, String[].class);
- MethodBasedEvaluationContext context = createEvaluationContext(method,
- new Object[] {null, new String[]{"hello", "hi"}});
+ MethodBasedEvaluationContext context = createEvaluationContext(method, null, "hello", "hi");
+ assertNull(context.lookupVariable("a0"));
assertNull(context.lookupVariable("p0"));
- assertArrayEquals(new String[]{"hello", "hi"}, (String[]) context.lookupVariable("p1"));
+ assertNull(context.lookupVariable("flag"));
+
+ assertArrayEquals(new Object[] {"hello", "hi"}, (Object[]) context.lookupVariable("a1"));
+ assertArrayEquals(new Object[] {"hello", "hi"}, (Object[]) context.lookupVariable("p1"));
+ assertArrayEquals(new Object[] {"hello", "hi"}, (Object[]) context.lookupVariable("vararg"));
}
- private MethodBasedEvaluationContext createEvaluationContext(Method method, Object[] args) {
+ private MethodBasedEvaluationContext createEvaluationContext(Method method, Object... args) {
return new MethodBasedEvaluationContext(this, method, args, this.paramDiscover);
}
@@ -112,9 +137,7 @@ public class MethodBasedEvaluationContextTests {
}
private void hello(Boolean flag, String... vararg){
-
}
-
}
-} \ No newline at end of file
+}
diff --git a/spring-context/src/test/java/org/springframework/jmx/export/annotation/EnableMBeanExportConfigurationTests.java b/spring-context/src/test/java/org/springframework/jmx/export/annotation/EnableMBeanExportConfigurationTests.java
index 90488829..d9d93306 100644
--- a/spring-context/src/test/java/org/springframework/jmx/export/annotation/EnableMBeanExportConfigurationTests.java
+++ b/spring-context/src/test/java/org/springframework/jmx/export/annotation/EnableMBeanExportConfigurationTests.java
@@ -228,7 +228,7 @@ public class EnableMBeanExportConfigurationTests {
return new MBeanServerFactoryBean();
}
- @Bean(name="bean:name=testBean4")
+ @Bean("bean:name=testBean4")
@Lazy
public AnnotationTestBean testBean4() {
AnnotationTestBean bean = new AnnotationTestBean();
@@ -237,7 +237,7 @@ public class EnableMBeanExportConfigurationTests {
return bean;
}
- @Bean(name="bean:name=testBean5")
+ @Bean("bean:name=testBean5")
public AnnotationTestBeanFactory testBean5() throws Exception {
return new AnnotationTestBeanFactory();
}
diff --git a/spring-context/src/test/java/org/springframework/scheduling/annotation/AsyncExecutionTests.java b/spring-context/src/test/java/org/springframework/scheduling/annotation/AsyncExecutionTests.java
index 0d55ec7a..afc56975 100644
--- a/spring-context/src/test/java/org/springframework/scheduling/annotation/AsyncExecutionTests.java
+++ b/spring-context/src/test/java/org/springframework/scheduling/annotation/AsyncExecutionTests.java
@@ -124,6 +124,7 @@ public class AsyncExecutionTests {
context.registerBeanDefinition("autoProxyCreator", new RootBeanDefinition(DefaultAdvisorAutoProxyCreator.class));
context.registerBeanDefinition("asyncAdvisor", new RootBeanDefinition(AsyncAnnotationAdvisor.class));
context.refresh();
+
SimpleInterface asyncTest = context.getBean("asyncTest", SimpleInterface.class);
asyncTest.doNothing(5);
asyncTest.doSomething(10);
diff --git a/spring-context/src/test/java/org/springframework/scripting/groovy/GroovyScriptEvaluatorTests.java b/spring-context/src/test/java/org/springframework/scripting/groovy/GroovyScriptEvaluatorTests.java
index 14ab7aa3..7921a081 100644
--- a/spring-context/src/test/java/org/springframework/scripting/groovy/GroovyScriptEvaluatorTests.java
+++ b/spring-context/src/test/java/org/springframework/scripting/groovy/GroovyScriptEvaluatorTests.java
@@ -19,6 +19,7 @@ package org.springframework.scripting.groovy;
import java.util.HashMap;
import java.util.Map;
+import org.codehaus.groovy.control.customizers.ImportCustomizer;
import org.junit.Test;
import org.springframework.core.io.ClassPathResource;
@@ -59,6 +60,26 @@ public class GroovyScriptEvaluatorTests {
}
@Test
+ public void testGroovyScriptWithCompilerConfiguration() {
+ GroovyScriptEvaluator evaluator = new GroovyScriptEvaluator();
+ MyBytecodeProcessor processor = new MyBytecodeProcessor();
+ evaluator.getCompilerConfiguration().setBytecodePostprocessor(processor);
+ Object result = evaluator.evaluate(new StaticScriptSource("return 3 * 2"));
+ assertEquals(6, result);
+ assertTrue(processor.processed.contains("Script1"));
+ }
+
+ @Test
+ public void testGroovyScriptWithImportCustomizer() {
+ GroovyScriptEvaluator evaluator = new GroovyScriptEvaluator();
+ ImportCustomizer importCustomizer = new ImportCustomizer();
+ importCustomizer.addStarImports("org.springframework.util");
+ evaluator.setCompilationCustomizers(importCustomizer);
+ Object result = evaluator.evaluate(new StaticScriptSource("return ResourceUtils.CLASSPATH_URL_PREFIX"));
+ assertEquals("classpath:", result);
+ }
+
+ @Test
public void testGroovyScriptFromStringUsingJsr223() {
StandardScriptEvaluator evaluator = new StandardScriptEvaluator();
evaluator.setLanguage("Groovy");
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 c8abcc42..65bec6c9 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
@@ -477,6 +477,8 @@ public class GroovyScriptFactoryTests {
ApplicationContext ctx = new ClassPathXmlApplicationContext("groovy-with-xsd.xml", getClass());
Map<?, Messenger> beans = ctx.getBeansOfType(Messenger.class);
assertEquals(4, beans.size());
+ assertTrue(ctx.getBean(MyBytecodeProcessor.class).processed.contains(
+ "org.springframework.scripting.groovy.GroovyMessenger2"));
}
@Test
diff --git a/spring-context/src/test/java/org/springframework/scripting/groovy/MyBytecodeProcessor.java b/spring-context/src/test/java/org/springframework/scripting/groovy/MyBytecodeProcessor.java
new file mode 100644
index 00000000..12a99139
--- /dev/null
+++ b/spring-context/src/test/java/org/springframework/scripting/groovy/MyBytecodeProcessor.java
@@ -0,0 +1,37 @@
+/*
+ * 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 java.util.HashSet;
+import java.util.Set;
+
+import org.codehaus.groovy.control.BytecodeProcessor;
+
+/**
+ * @author Juergen Hoeller
+ */
+public class MyBytecodeProcessor implements BytecodeProcessor {
+
+ public final Set<String> processed = new HashSet<String>();
+
+ @Override
+ public byte[] processBytecode(String name, byte[] original) {
+ this.processed.add(name);
+ return original;
+ }
+
+}
diff --git a/spring-context/src/test/java/org/springframework/scripting/groovy/MyImportCustomizer.java b/spring-context/src/test/java/org/springframework/scripting/groovy/MyImportCustomizer.java
new file mode 100644
index 00000000..24160f50
--- /dev/null
+++ b/spring-context/src/test/java/org/springframework/scripting/groovy/MyImportCustomizer.java
@@ -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");
+ }
+
+}
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 a573d6a2..070a64d0 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
@@ -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 @@
<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,25 +36,32 @@ 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}.."
+ public void customize(GroovyObject go) {
+ println "customizing ${go}..."
}
}]]>
</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"
+ customizer-ref="compilerConfiguration">
+ <lang:property name="message" value="Hello World!"/>
+ </lang:groovy>
+
+ <bean id="compilerConfiguration" class="org.codehaus.groovy.control.CompilerConfiguration">
+ <property name="bytecodePostprocessor" ref="bytecodeProcessor"/>
+ </bean>
+
+ <bean id="bytecodeProcessor" class="org.springframework.scripting.groovy.MyBytecodeProcessor"/>
</beans>