Merge branch '3.2.x' into master

Conflicts:
	gradle.properties
	spring-beans/src/main/java/org/springframework/beans/factory/support/StaticListableBeanFactory.java
	spring-context-support/src/main/java/org/springframework/cache/ehcache/EhCacheManagerFactoryBean.java
	spring-core/src/main/java/org/springframework/core/convert/support/StringToEnumConverterFactory.java
	spring-core/src/main/java/org/springframework/core/env/ReadOnlySystemAttributesMap.java
	spring-jdbc/src/main/java/org/springframework/jdbc/datasource/LazyConnectionDataSourceProxy.java
	spring-jdbc/src/main/java/org/springframework/jdbc/support/lob/AbstractLobHandler.java
	spring-web/src/main/java/org/springframework/http/client/BufferingClientHttpRequestWrapper.java
	spring-web/src/main/java/org/springframework/http/client/SimpleBufferingClientHttpRequest.java
	spring-web/src/main/java/org/springframework/http/converter/BufferedImageHttpMessageConverter.java
	spring-web/src/main/java/org/springframework/http/converter/FormHttpMessageConverter.java
This commit is contained in:
Chris Beams
2013-03-04 15:41:15 +01:00
1450 changed files with 17678 additions and 42998 deletions

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2011 the original author or authors.
* Copyright 2002-2013 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.
@@ -32,6 +32,7 @@ import org.springframework.cache.Cache;
* always causes the method to be invoked and its result to be placed into the cache.
*
* @author Costin Leau
* @author Phillip Webb
* @since 3.1
*/
@Target({ ElementType.METHOD, ElementType.TYPE })
@@ -58,4 +59,13 @@ public @interface CachePut {
* <p>Default is "", meaning the method result is always cached.
*/
String condition() default "";
/**
* Spring Expression Language (SpEL) attribute used to veto the cache update.
* <p>Unlike {@link #condition()}, this expression is evaluated after the method
* has been called and can therefore refer to the {@code result}. Default is "",
* meaning that caching is never vetoed.
* @since 3.2
*/
String unless() default "";
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 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.
@@ -30,6 +30,7 @@ import java.lang.annotation.Target;
* returned instance is used as the cache value.
*
* @author Costin Leau
* @author Phillip Webb
* @since 3.1
*/
@Target({ElementType.METHOD, ElementType.TYPE})
@@ -56,4 +57,13 @@ public @interface Cacheable {
* <p>Default is "", meaning the method is always cached.
*/
String condition() default "";
/**
* Spring Expression Language (SpEL) attribute used to veto method caching.
* <p>Unlike {@link #condition()}, this expression is evaluated after the method
* has been called and can therefore refer to the {@code result}. Default is "",
* meaning that caching is never vetoed.
* @since 3.2
*/
String unless() default "";
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2011 the original author or authors.
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,12 +16,7 @@
package org.springframework.cache.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.annotation.*;
/**
* Group annotation for multiple cache annotations (of different or the same type).
@@ -30,7 +25,7 @@ import java.lang.annotation.Target;
* @author Chris Beams
* @since 3.1
*/
@Target({ ElementType.METHOD, ElementType.TYPE })
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
@@ -41,4 +36,5 @@ public @interface Caching {
CachePut[] put() default {};
CacheEvict[] evict() default {};
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 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,6 +35,7 @@ import org.springframework.util.ObjectUtils;
* @author Costin Leau
* @author Juergen Hoeller
* @author Chris Beams
* @author Phillip Webb
* @since 3.1
*/
@SuppressWarnings("serial")
@@ -82,6 +83,7 @@ public class SpringCacheAnnotationParser implements CacheAnnotationParser, Seria
CacheableOperation cuo = new CacheableOperation();
cuo.setCacheNames(caching.value());
cuo.setCondition(caching.condition());
cuo.setUnless(caching.unless());
cuo.setKey(caching.key());
cuo.setName(ae.toString());
return cuo;
@@ -102,6 +104,7 @@ public class SpringCacheAnnotationParser implements CacheAnnotationParser, Seria
CachePutOperation cuo = new CachePutOperation();
cuo.setCacheNames(caching.value());
cuo.setCondition(caching.condition());
cuo.setUnless(caching.unless());
cuo.setKey(caching.key());
cuo.setName(ae.toString());
return cuo;

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2011 the original author or authors.
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -44,6 +44,7 @@ import org.w3c.dom.Element;
* BeanDefinitionParser} for the {@code <tx:advice/>} tag.
*
* @author Costin Leau
* @author Phillip Webb
*/
class CacheAdviceParser extends AbstractSingleBeanDefinitionParser {
@@ -54,7 +55,9 @@ class CacheAdviceParser extends AbstractSingleBeanDefinitionParser {
*/
private static class Props {
private String key, condition, method;
private String key;
private String condition;
private String method;
private String[] caches = null;
Props(Element root) {
@@ -70,13 +73,9 @@ class CacheAdviceParser extends AbstractSingleBeanDefinitionParser {
<T extends CacheOperation> T merge(Element element, ReaderContext readerCtx, T op) {
String cache = element.getAttribute("cache");
String k = element.getAttribute("key");
String c = element.getAttribute("condition");
String[] localCaches = caches;
String localKey = key, localCondition = condition;
// sanity check
String[] localCaches = caches;
if (StringUtils.hasText(cache)) {
localCaches = StringUtils.commaDelimitedListToStringArray(cache.trim());
} else {
@@ -84,17 +83,10 @@ class CacheAdviceParser extends AbstractSingleBeanDefinitionParser {
readerCtx.error("No cache specified specified for " + element.getNodeName(), element);
}
}
if (StringUtils.hasText(k)) {
localKey = k.trim();
}
if (StringUtils.hasText(c)) {
localCondition = c.trim();
}
op.setCacheNames(localCaches);
op.setKey(localKey);
op.setCondition(localCondition);
op.setKey(getAttributeValue(element, "key", this.key));
op.setCondition(getAttributeValue(element, "condition", this.condition));
return op;
}
@@ -165,7 +157,8 @@ class CacheAdviceParser extends AbstractSingleBeanDefinitionParser {
String name = prop.merge(opElement, parserContext.getReaderContext());
TypedStringValue nameHolder = new TypedStringValue(name);
nameHolder.setSource(parserContext.extractSource(opElement));
CacheOperation op = prop.merge(opElement, parserContext.getReaderContext(), new CacheableOperation());
CacheableOperation op = prop.merge(opElement, parserContext.getReaderContext(), new CacheableOperation());
op.setUnless(getAttributeValue(opElement, "unless", ""));
Collection<CacheOperation> col = cacheOpMap.get(nameHolder);
if (col == null) {
@@ -207,7 +200,8 @@ class CacheAdviceParser extends AbstractSingleBeanDefinitionParser {
String name = prop.merge(opElement, parserContext.getReaderContext());
TypedStringValue nameHolder = new TypedStringValue(name);
nameHolder.setSource(parserContext.extractSource(opElement));
CacheOperation op = prop.merge(opElement, parserContext.getReaderContext(), new CachePutOperation());
CachePutOperation op = prop.merge(opElement, parserContext.getReaderContext(), new CachePutOperation());
op.setUnless(getAttributeValue(opElement, "unless", ""));
Collection<CacheOperation> col = cacheOpMap.get(nameHolder);
if (col == null) {
@@ -222,4 +216,14 @@ class CacheAdviceParser extends AbstractSingleBeanDefinitionParser {
attributeSourceDefinition.getPropertyValues().add("nameMap", cacheOpMap);
return attributeSourceDefinition;
}
private static String getAttributeValue(Element element, String attributeName, String defaultValue) {
String attribute = element.getAttribute(attributeName);
if(StringUtils.hasText(attribute)) {
return attribute.trim();
}
return defaultValue;
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 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.
@@ -56,6 +56,7 @@ import org.springframework.util.StringUtils;
* @author Costin Leau
* @author Juergen Hoeller
* @author Chris Beams
* @author Phillip Webb
* @since 3.1
*/
public abstract class CacheAspectSupport implements InitializingBean {
@@ -212,7 +213,7 @@ public abstract class CacheAspectSupport implements InitializingBean {
retVal = invoker.invoke();
inspectAfterCacheEvicts(ops.get(EVICT));
inspectAfterCacheEvicts(ops.get(EVICT), retVal);
if (!updates.isEmpty()) {
update(updates, retVal);
@@ -225,14 +226,16 @@ public abstract class CacheAspectSupport implements InitializingBean {
}
private void inspectBeforeCacheEvicts(Collection<CacheOperationContext> evictions) {
inspectCacheEvicts(evictions, true);
inspectCacheEvicts(evictions, true, ExpressionEvaluator.NO_RESULT);
}
private void inspectAfterCacheEvicts(Collection<CacheOperationContext> evictions) {
inspectCacheEvicts(evictions, false);
private void inspectAfterCacheEvicts(Collection<CacheOperationContext> evictions,
Object result) {
inspectCacheEvicts(evictions, false, result);
}
private void inspectCacheEvicts(Collection<CacheOperationContext> evictions, boolean beforeInvocation) {
private void inspectCacheEvicts(Collection<CacheOperationContext> evictions,
boolean beforeInvocation, Object result) {
if (!evictions.isEmpty()) {
@@ -242,7 +245,7 @@ public abstract class CacheAspectSupport implements InitializingBean {
CacheEvictOperation evictOp = (CacheEvictOperation) context.operation;
if (beforeInvocation == evictOp.isBeforeInvocation()) {
if (context.isConditionPassing()) {
if (context.isConditionPassing(result)) {
// for each cache
// lazy key initialization
Object key = null;
@@ -278,7 +281,7 @@ public abstract class CacheAspectSupport implements InitializingBean {
private CacheStatus inspectCacheables(Collection<CacheOperationContext> cacheables) {
Map<CacheOperationContext, Object> cUpdates = new LinkedHashMap<CacheOperationContext, Object>(cacheables.size());
boolean updateRequire = false;
boolean updateRequired = false;
Object retVal = null;
if (!cacheables.isEmpty()) {
@@ -305,7 +308,7 @@ public abstract class CacheAspectSupport implements InitializingBean {
boolean localCacheHit = false;
// check whether the cache needs to be inspected or not (the method will be invoked anyway)
if (!updateRequire) {
if (!updateRequired) {
for (Cache cache : context.getCaches()) {
Cache.ValueWrapper wrapper = cache.get(key);
if (wrapper != null) {
@@ -317,7 +320,7 @@ public abstract class CacheAspectSupport implements InitializingBean {
}
if (!localCacheHit) {
updateRequire = true;
updateRequired = true;
}
}
else {
@@ -329,7 +332,7 @@ public abstract class CacheAspectSupport implements InitializingBean {
// return a status only if at least on cacheable matched
if (atLeastOnePassed) {
return new CacheStatus(cUpdates, updateRequire, retVal);
return new CacheStatus(cUpdates, updateRequired, retVal);
}
}
@@ -386,8 +389,11 @@ public abstract class CacheAspectSupport implements InitializingBean {
private void update(Map<CacheOperationContext, Object> updates, Object retVal) {
for (Map.Entry<CacheOperationContext, Object> entry : updates.entrySet()) {
for (Cache cache : entry.getKey().getCaches()) {
cache.put(entry.getValue(), retVal);
CacheOperationContext operationContext = entry.getKey();
if(operationContext.canPutToCache(retVal)) {
for (Cache cache : operationContext.getCaches()) {
cache.put(entry.getValue(), retVal);
}
}
}
}
@@ -427,30 +433,49 @@ public abstract class CacheAspectSupport implements InitializingBean {
private final CacheOperation operation;
private final Collection<Cache> caches;
private final Object target;
private final Method method;
private final Object[] args;
// context passed around to avoid multiple creations
private final EvaluationContext evalContext;
private final Object target;
private final Class<?> targetClass;
private final Collection<Cache> caches;
public CacheOperationContext(CacheOperation operation, Method method, Object[] args, Object target, Class<?> targetClass) {
this.operation = operation;
this.caches = CacheAspectSupport.this.getCaches(operation);
this.target = target;
this.method = method;
this.args = args;
this.evalContext = evaluator.createEvaluationContext(caches, method, args, target, targetClass);
this.target = target;
this.targetClass = targetClass;
this.caches = CacheAspectSupport.this.getCaches(operation);
}
protected boolean isConditionPassing() {
return isConditionPassing(ExpressionEvaluator.NO_RESULT);
}
protected boolean isConditionPassing(Object result) {
if (StringUtils.hasText(this.operation.getCondition())) {
return evaluator.condition(this.operation.getCondition(), this.method, this.evalContext);
EvaluationContext evaluationContext = createEvaluationContext(result);
return evaluator.condition(this.operation.getCondition(), this.method,
evaluationContext);
}
return true;
}
protected boolean canPutToCache(Object value) {
String unless = "";
if (this.operation instanceof CacheableOperation) {
unless = ((CacheableOperation) this.operation).getUnless();
}
else if (this.operation instanceof CachePutOperation) {
unless = ((CachePutOperation) this.operation).getUnless();
}
if(StringUtils.hasText(unless)) {
EvaluationContext evaluationContext = createEvaluationContext(value);
return !evaluator.unless(unless, this.method, evaluationContext);
}
return true;
}
@@ -461,13 +486,19 @@ public abstract class CacheAspectSupport implements InitializingBean {
*/
protected Object generateKey() {
if (StringUtils.hasText(this.operation.getKey())) {
return evaluator.key(this.operation.getKey(), this.method, this.evalContext);
EvaluationContext evaluationContext = createEvaluationContext(ExpressionEvaluator.NO_RESULT);
return evaluator.key(this.operation.getKey(), this.method, evaluationContext);
}
return keyGenerator.generate(this.target, this.method, this.args);
}
private EvaluationContext createEvaluationContext(Object result) {
return evaluator.createEvaluationContext(this.caches, this.method, this.args,
this.target, this.targetClass, result);
}
protected Collection<Cache> getCaches() {
return this.caches;
}
}
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2011 the original author or authors.
* Copyright 2002-2013 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.
@@ -27,6 +27,7 @@ public class CacheEvictOperation extends CacheOperation {
private boolean cacheWide = false;
private boolean beforeInvocation = false;
public void setCacheWide(boolean cacheWide) {
this.cacheWide = cacheWide;
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2011 the original author or authors.
* Copyright 2002-2013 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.
@@ -119,10 +119,10 @@ public abstract class CacheOperation {
result.append(this.name);
result.append("] caches=");
result.append(this.cacheNames);
result.append(" | condition='");
result.append(this.condition);
result.append("' | key='");
result.append(" | key='");
result.append(this.key);
result.append("' | condition='");
result.append(this.condition);
result.append("'");
return result;
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2011 the original author or authors.
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -20,8 +20,28 @@ package org.springframework.cache.interceptor;
* Class describing a cache 'put' operation.
*
* @author Costin Leau
* @author Phillip Webb
* @since 3.1
*/
public class CachePutOperation extends CacheOperation {
private String unless;
public String getUnless() {
return unless;
}
public void setUnless(String unless) {
this.unless = unless;
}
@Override
protected StringBuilder getOperationDescription() {
StringBuilder sb = super.getOperationDescription();
sb.append(" | unless='");
sb.append(this.unless);
sb.append("'");
return sb;
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2011 the original author or authors.
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -20,8 +20,28 @@ package org.springframework.cache.interceptor;
* Class describing a cache 'cacheable' operation.
*
* @author Costin Leau
* @author Phillip Webb
* @since 3.1
*/
public class CacheableOperation extends CacheOperation {
private String unless;
public String getUnless() {
return unless;
}
public void setUnless(String unless) {
this.unless = unless;
}
@Override
protected StringBuilder getOperationDescription() {
StringBuilder sb = super.getOperationDescription();
sb.append(" | unless='");
sb.append(this.unless);
sb.append("'");
return sb;
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 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,49 +35,84 @@ import org.springframework.expression.spel.standard.SpelExpressionParser;
* <p>Performs internal caching for performance reasons.
*
* @author Costin Leau
* @author Phillip Webb
* @since 3.1
*/
class ExpressionEvaluator {
public static final Object NO_RESULT = new Object();
private final SpelExpressionParser parser = new SpelExpressionParser();
// shared param discoverer since it caches data internally
private final ParameterNameDiscoverer paramNameDiscoverer = new LocalVariableTableParameterNameDiscoverer();
private final Map<String, Expression> keyCache = new ConcurrentHashMap<String, Expression>(64);
private final Map<String, Expression> conditionCache = new ConcurrentHashMap<String, Expression>(64);
private final Map<String, Expression> keyCache = new ConcurrentHashMap<String, Expression>(64);
private final Map<String, Expression> unlessCache = new ConcurrentHashMap<String, Expression>(64);
private final Map<String, Method> targetMethodCache = new ConcurrentHashMap<String, Method>(64);
public EvaluationContext createEvaluationContext(
Collection<Cache> caches, Method method, Object[] args, Object target, Class<?> targetClass) {
CacheExpressionRootObject rootObject =
new CacheExpressionRootObject(caches, method, args, target, targetClass);
return new LazyParamAwareEvaluationContext(rootObject,
this.paramNameDiscoverer, method, args, targetClass, this.targetMethodCache);
/**
* Create an {@link EvaluationContext} without a return value.
* @see #createEvaluationContext(Collection, Method, Object[], Object, Class, Object)
*/
public EvaluationContext createEvaluationContext(Collection<Cache> caches,
Method method, Object[] args, Object target, Class<?> targetClass) {
return createEvaluationContext(caches, method, args, target, targetClass,
NO_RESULT);
}
public boolean condition(String conditionExpression, Method method, EvaluationContext evalContext) {
String key = toString(method, conditionExpression);
Expression condExp = this.conditionCache.get(key);
if (condExp == null) {
condExp = this.parser.parseExpression(conditionExpression);
this.conditionCache.put(key, condExp);
/**
* Create an {@link EvaluationContext}.
*
* @param caches the current caches
* @param method the method
* @param args the method arguments
* @param target the target object
* @param targetClass the target class
* @param result the return value (can be {@code null}) or
* {@link #NO_RESULT} if there is no return at this time
* @return the evalulation context
*/
public EvaluationContext createEvaluationContext(Collection<Cache> caches,
Method method, Object[] args, Object target, Class<?> targetClass,
final Object result) {
CacheExpressionRootObject rootObject = new CacheExpressionRootObject(caches,
method, args, target, targetClass);
LazyParamAwareEvaluationContext evaluationContext = new LazyParamAwareEvaluationContext(rootObject,
this.paramNameDiscoverer, method, args, targetClass, this.targetMethodCache);
if(result != NO_RESULT) {
evaluationContext.setVariable("result", result);
}
return condExp.getValue(evalContext, boolean.class);
return evaluationContext;
}
public Object key(String keyExpression, Method method, EvaluationContext evalContext) {
String key = toString(method, keyExpression);
Expression keyExp = this.keyCache.get(key);
if (keyExp == null) {
keyExp = this.parser.parseExpression(keyExpression);
this.keyCache.put(key, keyExp);
return getExpression(this.keyCache, keyExpression, method).getValue(evalContext);
}
public boolean condition(String conditionExpression, Method method, EvaluationContext evalContext) {
return getExpression(this.conditionCache, conditionExpression, method).getValue(
evalContext, boolean.class);
}
public boolean unless(String unlessExpression, Method method, EvaluationContext evalContext) {
return getExpression(this.unlessCache, unlessExpression, method).getValue(
evalContext, boolean.class);
}
private Expression getExpression(Map<String, Expression> cache, String expression, Method method) {
String key = toString(method, expression);
Expression rtn = cache.get(key);
if (rtn == null) {
rtn = this.parser.parseExpression(expression);
cache.put(key, rtn);
}
return keyExp.getValue(evalContext);
return rtn;
}
private String toString(Method method, String expression) {
@@ -89,4 +124,4 @@ class ExpressionEvaluator {
sb.append(expression);
return sb.toString();
}
}
}

View File

@@ -117,4 +117,4 @@ class LazyParamAwareEvaluationContext extends StandardEvaluationContext {
sb.append(m.toString());
return sb.toString();
}
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 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.
@@ -26,7 +26,6 @@ import java.util.concurrent.ConcurrentMap;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager;
import org.springframework.util.Assert;
/**
* Abstract base class implementing the common {@link CacheManager} methods.
@@ -45,10 +44,10 @@ public abstract class AbstractCacheManager implements CacheManager, Initializing
public void afterPropertiesSet() {
Collection<? extends Cache> caches = loadCaches();
Assert.notEmpty(caches, "loadCaches must not return an empty Collection");
this.cacheMap.clear();
// preserve the initial order of the cache names
this.cacheMap.clear();
this.cacheNames.clear();
for (Cache cache : caches) {
this.cacheMap.put(cache.getName(), decorateCache(cache));
this.cacheNames.add(cache.getName());

View File

@@ -29,4 +29,4 @@ package org.springframework.context.annotation;
public enum AdviceMode {
PROXY,
ASPECTJ
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 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.
@@ -39,9 +39,10 @@ import static org.springframework.context.annotation.MetadataUtils.*;
*/
public class AnnotationScopeMetadataResolver implements ScopeMetadataResolver {
private final ScopedProxyMode defaultProxyMode;
protected Class<? extends Annotation> scopeAnnotationType = Scope.class;
private final ScopedProxyMode defaultProxyMode;
/**
* Create a new instance of the {@code AnnotationScopeMetadataResolver} class.
@@ -77,8 +78,7 @@ public class AnnotationScopeMetadataResolver implements ScopeMetadataResolver {
ScopeMetadata metadata = new ScopeMetadata();
if (definition instanceof AnnotatedBeanDefinition) {
AnnotatedBeanDefinition annDef = (AnnotatedBeanDefinition) definition;
AnnotationAttributes attributes =
attributesFor(annDef.getMetadata(), this.scopeAnnotationType);
AnnotationAttributes attributes = attributesFor(annDef.getMetadata(), this.scopeAnnotationType);
if (attributes != null) {
metadata.setScopeName(attributes.getString("value"));
ScopedProxyMode proxyMode = attributes.getEnum("proxyMode");

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 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.
@@ -177,7 +177,7 @@ import org.springframework.beans.factory.support.AbstractBeanDefinition;
* @see org.springframework.beans.factory.annotation.Autowired
* @see org.springframework.beans.factory.annotation.Value
*/
@Target({ ElementType.METHOD, ElementType.ANNOTATION_TYPE })
@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Bean {
@@ -190,7 +190,7 @@ public @interface Bean {
String[] name() default {};
/**
* Are dependencies to be injected via autowiring?
* Are dependencies to be injected via convention-based autowiring by name or type?
*/
Autowire autowire() default Autowire.NO;

View File

@@ -725,4 +725,4 @@ public class CommonAnnotationBeanPostProcessor extends InitDestroyAnnotationBean
}
}
}
}

View File

@@ -68,8 +68,7 @@ import org.springframework.stereotype.Component;
* <beans>
* <context:annotation-config/>
* <bean class="com.acme.AppConfig"/>
* </beans>
* }</pre>
* </beans>}</pre>
*
* In the example above, {@code <context:annotation-config/>} is required in order to
* enable {@link ConfigurationClassPostProcessor} and other annotation-related

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 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.
@@ -256,7 +256,8 @@ class ConfigurationClassBeanDefinitionReader {
if (proxyMode != ScopedProxyMode.NO) {
BeanDefinitionHolder proxyDef = ScopedProxyCreator.createScopedProxy(
new BeanDefinitionHolder(beanDef, beanName), this.registry, proxyMode == ScopedProxyMode.TARGET_CLASS);
beanDefToRegister = proxyDef.getBeanDefinition();
beanDefToRegister =
new ConfigurationClassBeanDefinition((RootBeanDefinition) proxyDef.getBeanDefinition(), configClass);
}
if (logger.isDebugEnabled()) {
@@ -307,12 +308,17 @@ class ConfigurationClassBeanDefinitionReader {
@SuppressWarnings("serial")
private static class ConfigurationClassBeanDefinition extends RootBeanDefinition implements AnnotatedBeanDefinition {
private AnnotationMetadata annotationMetadata;
private final AnnotationMetadata annotationMetadata;
public ConfigurationClassBeanDefinition(ConfigurationClass configClass) {
this.annotationMetadata = configClass.getMetadata();
}
public ConfigurationClassBeanDefinition(RootBeanDefinition original, ConfigurationClass configClass) {
super(original);
this.annotationMetadata = configClass.getMetadata();
}
private ConfigurationClassBeanDefinition(ConfigurationClassBeanDefinition original) {
super(original);
this.annotationMetadata = original.annotationMetadata;

View File

@@ -17,17 +17,11 @@
package org.springframework.context.annotation;
import java.lang.reflect.Method;
import java.util.Arrays;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.cglib.proxy.Callback;
import org.springframework.cglib.proxy.CallbackFilter;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import org.springframework.cglib.proxy.NoOp;
import org.springframework.aop.scope.ScopedProxyFactoryBean;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.DisposableBean;
@@ -35,6 +29,12 @@ import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.beans.factory.support.SimpleInstantiationStrategy;
import org.springframework.cglib.proxy.Callback;
import org.springframework.cglib.proxy.CallbackFilter;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import org.springframework.cglib.proxy.NoOp;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.util.Assert;
@@ -52,8 +52,8 @@ class ConfigurationClassEnhancer {
private static final Log logger = LogFactory.getLog(ConfigurationClassEnhancer.class);
private static final Class<?>[] CALLBACK_TYPES = { BeanMethodInterceptor.class,
DisposableBeanMethodInterceptor.class, NoOp.class };
private static final Class<?>[] CALLBACK_TYPES = {BeanMethodInterceptor.class,
DisposableBeanMethodInterceptor.class, NoOp.class};
private static final CallbackFilter CALLBACK_FILTER = new CallbackFilter() {
public int accept(Method candidateMethod) {
@@ -80,10 +80,8 @@ class ConfigurationClassEnhancer {
public ConfigurationClassEnhancer(ConfigurableBeanFactory beanFactory) {
Assert.notNull(beanFactory, "BeanFactory must not be null");
// Callback instances must be ordered in the same way as CALLBACK_TYPES and CALLBACK_FILTER
this.callbackInstances = new Callback[] {
new BeanMethodInterceptor(beanFactory),
DISPOSABLE_BEAN_METHOD_INTERCEPTOR,
NoOp.INSTANCE };
this.callbackInstances = new Callback[]
{new BeanMethodInterceptor(beanFactory), DISPOSABLE_BEAN_METHOD_INTERCEPTOR, NoOp.INSTANCE};
}
/**
@@ -169,9 +167,8 @@ class ConfigurationClassEnhancer {
}
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
return beanFactory.getBean(beanName);
return this.beanFactory.getBean(this.beanName);
}
}
@@ -209,19 +206,16 @@ class ConfigurationClassEnhancer {
*/
private static class BeanMethodInterceptor implements MethodInterceptor {
private static final Class<?>[] CALLBACK_TYPES = {
GetObjectMethodInterceptor.class, NoOp.class };
private static final Class<?>[] CALLBACK_TYPES = {GetObjectMethodInterceptor.class, NoOp.class};
private static final CallbackFilter CALLBACK_FITLER = new CallbackFilter() {
private static final CallbackFilter CALLBACK_FILTER = new CallbackFilter() {
public int accept(Method method) {
return method.getName().equals("getObject") ? 0 : 1;
return (method.getName().equals("getObject") ? 0 : 1);
}
};
private final ConfigurableBeanFactory beanFactory;
public BeanMethodInterceptor(ConfigurableBeanFactory beanFactory) {
this.beanFactory = beanFactory;
}
@@ -229,7 +223,6 @@ class ConfigurationClassEnhancer {
/**
* Enhance a {@link Bean @Bean} method to check the supplied BeanFactory for the
* existence of this bean object.
*
* @throws Throwable as a catch-all for any exception that may be thrown when
* invoking the super implementation of the proxied method i.e., the actual
* {@code @Bean} method.
@@ -255,8 +248,8 @@ class ConfigurationClassEnhancer {
// proxy that intercepts calls to getObject() and returns any cached bean instance.
// this ensures that the semantics of calling a FactoryBean from within @Bean methods
// is the same as that of referring to a FactoryBean within XML. See SPR-6602.
if (factoryContainsBean('&'+beanName) && factoryContainsBean(beanName)) {
Object factoryBean = this.beanFactory.getBean('&'+beanName);
if (factoryContainsBean(BeanFactory.FACTORY_BEAN_PREFIX + beanName) && factoryContainsBean(beanName)) {
Object factoryBean = this.beanFactory.getBean(BeanFactory.FACTORY_BEAN_PREFIX + beanName);
if (factoryBean instanceof ScopedProxyFactoryBean) {
// pass through - scoped proxy factory beans are a special case and should not
// be further proxied
@@ -267,9 +260,7 @@ class ConfigurationClassEnhancer {
}
}
boolean factoryIsCaller = beanMethod.equals(SimpleInstantiationStrategy.getCurrentlyInvokedFactoryMethod());
boolean factoryAlreadyContainsSingleton = this.beanFactory.containsSingleton(beanName);
if (factoryIsCaller && !factoryAlreadyContainsSingleton) {
if (isCurrentlyInvokedFactoryMethod(beanMethod) && !this.beanFactory.containsSingleton(beanName)) {
// the factory is calling the bean method in order to instantiate and register the bean
// (i.e. via a getBean() call) -> invoke the super implementation of the method to actually
// create the bean instance.
@@ -306,7 +297,7 @@ class ConfigurationClassEnhancer {
}
/**
* Check the beanFactory to see whether the bean named <var>beanName</var> already
* Check the BeanFactory to see whether the bean named <var>beanName</var> already
* exists. Accounts for the fact that the requested bean may be "in creation", i.e.:
* we're in the middle of servicing the initial request for this bean. From an enhanced
* factory method's perspective, this means that the bean does not actually yet exist,
@@ -319,9 +310,19 @@ class ConfigurationClassEnhancer {
* @return whether <var>beanName</var> already exists in the factory
*/
private boolean factoryContainsBean(String beanName) {
boolean containsBean = this.beanFactory.containsBean(beanName);
boolean currentlyInCreation = this.beanFactory.isCurrentlyInCreation(beanName);
return (containsBean && !currentlyInCreation);
return (this.beanFactory.containsBean(beanName) && !this.beanFactory.isCurrentlyInCreation(beanName));
}
/**
* Check whether the given method corresponds to the container's currently invoked
* factory method. Compares method name and parameter types only in order to work
* around a potential problem with covariant return types (currently only known
* to happen on Groovy classes).
*/
private boolean isCurrentlyInvokedFactoryMethod(Method method) {
Method currentlyInvoked = SimpleInstantiationStrategy.getCurrentlyInvokedFactoryMethod();
return (currentlyInvoked != null && method.getName().equals(currentlyInvoked.getName()) &&
Arrays.equals(method.getParameterTypes(), currentlyInvoked.getParameterTypes()));
}
/**
@@ -335,13 +336,12 @@ class ConfigurationClassEnhancer {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(fbClass);
enhancer.setUseFactory(false);
enhancer.setCallbackFilter(CALLBACK_FITLER);
enhancer.setCallbackFilter(CALLBACK_FILTER);
// Callback instances must be ordered in the same way as CALLBACK_TYPES and CALLBACK_FILTER
Callback[] callbackInstances = new Callback[] {
new GetObjectMethodInterceptor(this.beanFactory, beanName),
NoOp.INSTANCE
};
enhancer.setCallbackTypes(CALLBACK_TYPES);
Class<?> fbSubclass = enhancer.createClass();
Enhancer.registerCallbacks(fbSubclass, callbackInstances);

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 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.
@@ -54,6 +54,7 @@ import org.springframework.core.type.StandardAnnotationMetadata;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.classreading.MetadataReaderFactory;
import org.springframework.core.type.filter.AssignableTypeFilter;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import static org.springframework.context.annotation.MetadataUtils.*;
@@ -228,7 +229,7 @@ class ConfigurationClassParser {
// process any @Import annotations
Set<String> imports = getImports(metadata.getClassName(), null, new HashSet<String>());
if (imports != null && !imports.isEmpty()) {
if (!CollectionUtils.isEmpty(imports)) {
processImport(configClass, imports.toArray(new String[imports.size()]), true);
}
@@ -292,9 +293,8 @@ class ConfigurationClassParser {
* @return a set of all {@link Import#value() import values} or {@code null}
* @throws IOException if there is any problem reading metadata from the named class
*/
private Set<String> getImports(String className, Set<String> imports,
Set<String> visited) throws IOException {
if (visited.add(className)) {
private Set<String> getImports(String className, Set<String> imports, Set<String> visited) throws IOException {
if (visited.add(className) && !className.startsWith("java")) {
AnnotationMetadata metadata = metadataReaderFactory.getMetadataReader(className).getAnnotationMetadata();
for (String annotationType : metadata.getAnnotationTypes()) {
imports = getImports(annotationType, imports, visited);
@@ -331,7 +331,7 @@ class ConfigurationClassParser {
throw new IllegalStateException(ex);
}
}
else if (new AssignableTypeFilter(ImportBeanDefinitionRegistrar.class).match(reader, metadataReaderFactory)) {
else if (new AssignableTypeFilter(ImportBeanDefinitionRegistrar.class).match(reader, this.metadataReaderFactory)) {
// the candidate class is an ImportBeanDefinitionRegistrar -> delegate to it to register additional bean definitions
try {
ImportBeanDefinitionRegistrar registrar = BeanUtils.instantiateClass(
@@ -360,17 +360,16 @@ class ConfigurationClassParser {
private void invokeAwareMethods(ImportBeanDefinitionRegistrar registrar) {
if (registrar instanceof Aware) {
if (registrar instanceof ResourceLoaderAware) {
((ResourceLoaderAware) registrar).setResourceLoader(resourceLoader);
((ResourceLoaderAware) registrar).setResourceLoader(this.resourceLoader);
}
if (registrar instanceof BeanClassLoaderAware) {
ClassLoader classLoader =
registry instanceof ConfigurableBeanFactory ?
((ConfigurableBeanFactory) registry).getBeanClassLoader() :
resourceLoader.getClassLoader();
ClassLoader classLoader = (this.registry instanceof ConfigurableBeanFactory ?
((ConfigurableBeanFactory) this.registry).getBeanClassLoader() :
this.resourceLoader.getClassLoader());
((BeanClassLoaderAware) registrar).setBeanClassLoader(classLoader);
}
if (registrar instanceof BeanFactoryAware && registry instanceof BeanFactory) {
((BeanFactoryAware) registrar).setBeanFactory((BeanFactory) registry);
if (registrar instanceof BeanFactoryAware && this.registry instanceof BeanFactory) {
((BeanFactoryAware) registrar).setBeanFactory((BeanFactory) this.registry);
}
}
}
@@ -398,6 +397,7 @@ class ConfigurationClassParser {
return this.importStack;
}
interface ImportRegistry {
String getImportingClassFor(String importedClass);
@@ -470,4 +470,5 @@ class ConfigurationClassParser {
new Location(importStack.peek().getResource(), metadata));
}
}
}

View File

@@ -110,4 +110,4 @@ public @interface EnableAspectJAutoProxy {
*/
boolean proxyTargetClass() default false;
}
}

View File

@@ -60,4 +60,4 @@ public interface ImportBeanDefinitionRegistrar {
public void registerBeanDefinitions(
AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry);
}
}

View File

@@ -44,4 +44,4 @@ class PropertyOverrideBeanDefinitionParser extends AbstractPropertyLoadingBeanDe
}
}
}

View File

@@ -87,7 +87,6 @@ public class SimpleApplicationEventMulticaster extends AbstractApplicationEventM
Executor executor = getTaskExecutor();
if (executor != null) {
executor.execute(new Runnable() {
@SuppressWarnings("unchecked")
public void run() {
listener.onApplicationEvent(event);
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 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,7 +17,6 @@
package org.springframework.context.support;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationContext;
import org.springframework.util.Assert;
@@ -114,12 +113,13 @@ public abstract class AbstractRefreshableConfigApplicationContext extends Abstra
/**
* Resolve the given path, replacing placeholders with corresponding
* system property values if necessary. Applied to config locations.
* environment property values if necessary. Applied to config locations.
* @param path the original file path
* @return the resolved file path
* @see org.springframework.core.env.Environment#resolveRequiredPlaceholders(String)
*/
protected String resolvePath(String path) {
return this.getEnvironment().resolveRequiredPlaceholders(path);
return getEnvironment().resolveRequiredPlaceholders(path);
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 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.
@@ -70,9 +70,9 @@ public class MessageSourceResourceBundle extends ResourceBundle {
* Returns {@code null} if the message could not be resolved.
*/
@Override
protected Object handleGetObject(String code) {
protected Object handleGetObject(String key) {
try {
return this.messageSource.getMessage(code, null, this.locale);
return this.messageSource.getMessage(key, null, this.locale);
}
catch (NoSuchMessageException ex) {
return null;
@@ -80,12 +80,29 @@ public class MessageSourceResourceBundle extends ResourceBundle {
}
/**
* This implementation returns {@code null}, as a MessageSource does
* not allow for enumerating the defined message codes.
* This implementation checks whether the target MessageSource can resolve
* a message for the given key, translating {@code NoSuchMessageException}
* accordingly. In contrast to ResourceBundle's default implementation in
* JDK 1.6, this does not rely on the capability to enumerate message keys.
*/
@Override
public boolean containsKey(String key) {
try {
this.messageSource.getMessage(key, null, this.locale);
return true;
}
catch (NoSuchMessageException ex) {
return false;
}
}
/**
* This implementation throws {@code UnsupportedOperationException},
* as a MessageSource does not allow for enumerating the defined message codes.
*/
@Override
public Enumeration<String> getKeys() {
return null;
throw new UnsupportedOperationException("MessageSourceResourceBundle does not support enumerating its keys");
}
/**

View File

@@ -135,7 +135,7 @@ public class ResourceBundleMessageSource extends AbstractMessageSource implement
* @see #setBasename
* @see java.util.ResourceBundle#getBundle(String)
*/
public void setBasenames(String... basenames) {
public void setBasenames(String... basenames) {
if (basenames != null) {
this.basenames = new String[basenames.length];
for (int i = 0; i < basenames.length; i++) {

View File

@@ -110,7 +110,7 @@ public class SimpleRemoteSlsbInvokerInterceptor extends AbstractRemoteSlsbInvoke
}
else if (targetEx instanceof CreateException) {
throw RmiClientInterceptorUtils.convertRmiAccessException(
invocation.getMethod(), targetEx, "Could not create remote EJB [" + getJndiName() + "]");
invocation.getMethod(), targetEx, "Could not create remote EJB [" + getJndiName() + "]");
}
throw targetEx;
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 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.
@@ -71,8 +71,6 @@ import org.springframework.context.access.ContextSingletonBeanFactoryLocator;
* @see org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor
* @see org.springframework.context.access.ContextSingletonBeanFactoryLocator
* @see #getBeanFactoryLocatorKey
* @see org.springframework.ejb.support.AbstractEnterpriseBean#setBeanFactoryLocator
* @see org.springframework.ejb.support.AbstractEnterpriseBean#setBeanFactoryLocatorKey
*/
public class SpringBeanAutowiringInterceptor {
@@ -99,9 +97,15 @@ public class SpringBeanAutowiringInterceptor {
invocationContext.proceed();
}
catch (RuntimeException ex) {
doReleaseBean(invocationContext.getTarget());
throw ex;
}
catch (Error err) {
doReleaseBean(invocationContext.getTarget());
throw err;
}
catch (Exception ex) {
doReleaseBean(invocationContext.getTarget());
// Cannot declare a checked exception on WebSphere here - so we need to wrap.
throw new EJBException(ex);
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 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.
@@ -40,24 +40,28 @@ import org.springframework.util.Assert;
public class DateFormatterRegistrar implements FormatterRegistrar {
private DateFormatter dateFormatter = new DateFormatter();
private DateFormatter dateFormatter;
public void registerFormatters(FormatterRegistry registry) {
addDateConverters(registry);
registry.addFormatter(dateFormatter);
registry.addFormatterForFieldType(Calendar.class, dateFormatter);
registry.addFormatterForFieldAnnotation(new DateTimeFormatAnnotationFormatterFactory());
// In order to retain back compatibility we only register Date/Calendar
// types when a user defined formatter is specified (see SPR-10105)
if(this.dateFormatter != null) {
registry.addFormatter(this.dateFormatter);
registry.addFormatterForFieldType(Calendar.class, this.dateFormatter);
}
}
/**
* Set the date formatter to register. If not specified the default {@link DateFormatter}
* will be used. This method can be used if additional formatter configuration is
* required.
* Set the date formatter to register. If not specified no formatter is registered.
* This method can be used if global formatter configuration is required.
* @param dateFormatter the date formatter
*/
public void setFormatter(DateFormatter dateFormatter) {
Assert.notNull(dateFormatter,"DateFormatter must not be null");
Assert.notNull(dateFormatter, "DateFormatter must not be null");
this.dateFormatter = dateFormatter;
}
@@ -117,7 +121,7 @@ public class DateFormatterRegistrar implements FormatterRegistrar {
private DateToCalendarConverter dateToCalendarConverter = new DateToCalendarConverter();
public Calendar convert(Long source) {
return dateToCalendarConverter.convert(new Date(source));
return this.dateToCalendarConverter.convert(new Date(source));
}
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 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,6 +35,7 @@ import org.springframework.format.datetime.DateFormatterRegistrar;
* Installs lower-level type converters required to integrate Joda Time support into Spring's field formatting system.
*
* @author Keith Donald
* @author Phillip Webb
* @since 3.0
*/
final class JodaTimeConverters {
@@ -55,6 +56,7 @@ final class JodaTimeConverters {
registry.addConverter(new DateTimeToCalendarConverter());
registry.addConverter(new DateTimeToLongConverter());
registry.addConverter(new CalendarToReadableInstantConverter());
registry.addConverter(new DateToReadableInstantConverter());
}
@@ -159,4 +161,14 @@ final class JodaTimeConverters {
}
}
/**
* Used when printing a java.util.Date field with a ReadableInstantPrinter.
* @see MillisecondInstantPrinter
* @see JodaDateTimeFormatAnnotationFormatterFactory
*/
private static class DateToReadableInstantConverter implements Converter<Date, ReadableInstant> {
public ReadableInstant convert(Date source) {
return new DateTime(source);
}
}
}

View File

@@ -75,7 +75,7 @@ public class JodaTimeFormatterRegistrar implements FormatterRegistrar {
* Default is {@link DateTimeFormat#shortDate()}.
*/
public void setDateStyle(String dateStyle) {
factories.get(Type.DATE).setStyle(dateStyle+"-");
this.factories.get(Type.DATE).setStyle(dateStyle+"-");
}
/**
@@ -83,7 +83,7 @@ public class JodaTimeFormatterRegistrar implements FormatterRegistrar {
* Default is {@link DateTimeFormat#shortTime()}.
*/
public void setTimeStyle(String timeStyle) {
factories.get(Type.TIME).setStyle("-"+timeStyle);
this.factories.get(Type.TIME).setStyle("-"+timeStyle);
}
/**
@@ -92,7 +92,7 @@ public class JodaTimeFormatterRegistrar implements FormatterRegistrar {
* Default is {@link DateTimeFormat#shortDateTime()}.
*/
public void setDateTimeStyle(String dateTimeStyle) {
factories.get(Type.DATE_TIME).setStyle(dateTimeStyle);
this.factories.get(Type.DATE_TIME).setStyle(dateTimeStyle);
}
/**
@@ -101,9 +101,9 @@ public class JodaTimeFormatterRegistrar implements FormatterRegistrar {
* If set to true, the dateStyle, timeStyle, and dateTimeStyle properties are ignored.
*/
public void setUseIsoFormat(boolean useIsoFormat) {
factories.get(Type.DATE).setIso(useIsoFormat ? ISO.DATE : null);
factories.get(Type.TIME).setIso(useIsoFormat ? ISO.TIME : null);
factories.get(Type.DATE_TIME).setIso(useIsoFormat ? ISO.DATE_TIME : null);
this.factories.get(Type.DATE).setIso(useIsoFormat ? ISO.DATE : null);
this.factories.get(Type.TIME).setIso(useIsoFormat ? ISO.TIME : null);
this.factories.get(Type.DATE_TIME).setIso(useIsoFormat ? ISO.DATE_TIME : null);
}
/**
@@ -174,19 +174,28 @@ public class JodaTimeFormatterRegistrar implements FormatterRegistrar {
addFormatterForFields(registry,
new ReadableInstantPrinter(dateTimeFormatter),
new DateTimeParser(dateTimeFormatter),
ReadableInstant.class, Date.class, Calendar.class);
ReadableInstant.class);
// In order to retain back compatibility we only register Date/Calendar
// types when a user defined formatter is specified (see SPR-10105)
if(this.formatters.containsKey(Type.DATE_TIME)) {
addFormatterForFields(registry,
new ReadableInstantPrinter(dateTimeFormatter),
new DateTimeParser(dateTimeFormatter),
Date.class, Calendar.class);
}
registry.addFormatterForFieldAnnotation(
new JodaDateTimeFormatAnnotationFormatterFactory());
}
private DateTimeFormatter getFormatter(Type type) {
DateTimeFormatter formatter = formatters.get(type);
DateTimeFormatter formatter = this.formatters.get(type);
if(formatter != null) {
return formatter;
}
DateTimeFormatter fallbackFormatter = getFallbackFormatter(type);
return factories.get(type).createDateTimeFormatter(fallbackFormatter );
return this.factories.get(type).createDateTimeFormatter(fallbackFormatter );
}
private DateTimeFormatter getFallbackFormatter(Type type) {

View File

@@ -195,7 +195,7 @@ public class FormattingConversionService extends GenericConversionService
private Class<? extends Annotation> annotationType;
private AnnotationFormatterFactory annotationFormatterFactory;
private AnnotationFormatterFactory annotationFormatterFactory;
private Class<?> fieldType;

View File

@@ -116,7 +116,7 @@ public class FormattingConversionServiceFactoryBean
/**
* Indicate whether default formatters should be registered or not.
* <p>By default, built-in formatters are registered. This flag can be used
* to turn that off and rely on explicitly registered formatters only.
* to turn that off and rely on explicitly registered formatters only.
* @see #setFormatters(Set)
* @see #setFormatterRegistrars(Set)
*/

View File

@@ -135,4 +135,4 @@ public class ReflectiveLoadTimeWeaver implements LoadTimeWeaver {
return new SimpleThrowawayClassLoader(this.classLoader);
}
}
}
}

View File

@@ -29,7 +29,7 @@ import org.springframework.core.OverridingClassLoader;
* @author Costin Leau
* @since 2.0
*/
public class SimpleInstrumentableClassLoader extends OverridingClassLoader {
public class SimpleInstrumentableClassLoader extends OverridingClassLoader {
private final WeavingTransformer weavingTransformer;

View File

@@ -142,4 +142,4 @@ class JBossMCAdapter implements JBossClassLoaderAdapter {
public ClassLoader getInstrumentableClassLoader() {
return classLoader;
}
}
}

View File

@@ -79,4 +79,4 @@ class JBossMCTranslatorAdapter implements InvocationHandler {
builder.append(this.transformer);
return builder.toString();
}
}
}

View File

@@ -68,4 +68,4 @@ class JBossModulesAdapter implements JBossClassLoaderAdapter {
public ClassLoader getInstrumentableClassLoader() {
return classLoader;
}
}
}

View File

@@ -85,4 +85,4 @@ class OC4JClassLoaderAdapter {
throw new IllegalStateException("Could not copy OC4J classloader", ex);
}
}
}
}

View File

@@ -92,4 +92,4 @@ class OC4JClassPreprocessorAdapter implements InvocationHandler {
builder.append(this.transformer);
return builder.toString();
}
}
}

View File

@@ -76,5 +76,4 @@ public class OC4JLoadTimeWeaver implements LoadTimeWeaver {
public ClassLoader getThrowawayClassLoader() {
return this.classLoader.getThrowawayClassLoader();
}
}

View File

@@ -110,4 +110,4 @@ class WebLogicClassLoaderAdapter {
throw new IllegalStateException("Could not construct WebLogic GenericClassLoader", ex);
}
}
}
}

View File

@@ -87,4 +87,4 @@ class WebLogicClassPreProcessorAdapter implements InvocationHandler {
builder.append(this.transformer);
return builder.toString();
}
}
}

View File

@@ -69,4 +69,4 @@ public class WebLogicLoadTimeWeaver implements LoadTimeWeaver {
public ClassLoader getThrowawayClassLoader() {
return this.classLoader.getThrowawayClassLoader();
}
}
}

View File

@@ -58,7 +58,7 @@ public class SpringModelMBean extends RequiredModelMBean {
* Construct a new SpringModelMBean instance with the given {@link ModelMBeanInfo}.
* @see javax.management.modelmbean.RequiredModelMBean#RequiredModelMBean(ModelMBeanInfo)
*/
public SpringModelMBean(ModelMBeanInfo mbi) throws MBeanException, RuntimeOperationsException {
public SpringModelMBean(ModelMBeanInfo mbi) throws MBeanException, RuntimeOperationsException {
super(mbi);
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 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.
@@ -30,6 +30,8 @@ import javax.management.modelmbean.ModelMBeanOperationInfo;
import org.springframework.aop.framework.AopProxyUtils;
import org.springframework.aop.support.AopUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
import org.springframework.core.ParameterNameDiscoverer;
import org.springframework.jmx.support.JmxUtils;
/**
@@ -49,6 +51,7 @@ import org.springframework.jmx.support.JmxUtils;
*
* @author Rob Harrop
* @author Juergen Hoeller
* @author David Boden
* @since 1.2
* @see #includeOperation
* @see #includeReadAttribute
@@ -177,6 +180,8 @@ public abstract class AbstractReflectiveMBeanInfoAssembler extends AbstractMBean
private boolean exposeClassDescriptor = false;
private ParameterNameDiscoverer parameterNameDiscoverer = new LocalVariableTableParameterNameDiscoverer();
/**
* Set the default for the JMX field "currencyTimeLimit".
@@ -254,6 +259,23 @@ public abstract class AbstractReflectiveMBeanInfoAssembler extends AbstractMBean
return this.exposeClassDescriptor;
}
/**
* Set the ParameterNameDiscoverer to use for resolving method parameter
* names if needed (e.g. for parameter names of MBean operation methods).
* <p>The default is {@link LocalVariableTableParameterNameDiscoverer}.
*/
public void setParameterNameDiscoverer(ParameterNameDiscoverer parameterNameDiscoverer) {
this.parameterNameDiscoverer = parameterNameDiscoverer;
}
/**
* Return the ParameterNameDiscoverer to use for resolving method parameter
* names if needed (may be {@code null} in order to skip parameter detection).
*/
protected ParameterNameDiscoverer getParameterNameDiscoverer() {
return this.parameterNameDiscoverer;
}
/**
* Iterate through all properties on the MBean class and gives subclasses
@@ -381,7 +403,8 @@ public abstract class AbstractReflectiveMBeanInfoAssembler extends AbstractMBean
* Creates an instance of {@code ModelMBeanOperationInfo} for the
* given method. Populates the parameter info for the operation.
* @param method the {@code Method} to create a {@code ModelMBeanOperationInfo} for
* @param name the name for the operation info
* @param name the logical name for the operation (method name or property name);
* not used by the default implementation but possibly by subclasses
* @param beanKey the key associated with the MBean in the beans map
* of the {@code MBeanExporter}
* @return the {@code ModelMBeanOperationInfo}
@@ -392,7 +415,7 @@ public abstract class AbstractReflectiveMBeanInfoAssembler extends AbstractMBean
return new ModelMBeanOperationInfo(getOperationDescription(method, beanKey), method);
}
else {
return new ModelMBeanOperationInfo(name,
return new ModelMBeanOperationInfo(method.getName(),
getOperationDescription(method, beanKey),
getOperationParameters(method, beanKey),
method.getReturnType().getName(),
@@ -476,16 +499,27 @@ public abstract class AbstractReflectiveMBeanInfoAssembler extends AbstractMBean
/**
* Create parameter info for the given method.
* <p>The default implementation returns an empty arry of {@code MBeanParameterInfo}.
* <p>The default implementation returns an empty array of {@code MBeanParameterInfo}.
* @param method the {@code Method} to get the parameter information for
* @param beanKey the key associated with the MBean in the beans map
* of the {@code MBeanExporter}
* @return the {@code MBeanParameterInfo} array
*/
protected MBeanParameterInfo[] getOperationParameters(Method method, String beanKey) {
return new MBeanParameterInfo[0];
}
ParameterNameDiscoverer paramNameDiscoverer = getParameterNameDiscoverer();
String[] paramNames = (paramNameDiscoverer != null ? paramNameDiscoverer.getParameterNames(method) : null);
if (paramNames == null) {
return new MBeanParameterInfo[0];
}
MBeanParameterInfo[] info = new MBeanParameterInfo[paramNames.length];
Class<?>[] typeParameters = method.getParameterTypes();
for(int i = 0; i < info.length; i++) {
info[i] = new MBeanParameterInfo(paramNames[i], typeParameters[i].getName(), paramNames[i]);
}
return info;
}
/**
* Allows subclasses to add extra fields to the {@code Descriptor} for an MBean.

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -36,6 +36,7 @@ import org.springframework.jmx.export.metadata.ManagedOperationParameter;
import org.springframework.jmx.export.metadata.ManagedResource;
import org.springframework.jmx.support.MetricType;
import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
/**
@@ -255,19 +256,17 @@ public class MetadataMBeanInfoAssembler extends AbstractReflectiveMBeanInfoAssem
@Override
protected MBeanParameterInfo[] getOperationParameters(Method method, String beanKey) {
ManagedOperationParameter[] params = this.attributeSource.getManagedOperationParameters(method);
if (params == null || params.length == 0) {
return new MBeanParameterInfo[0];
if (ObjectUtils.isEmpty(params)) {
return super.getOperationParameters(method, beanKey);
}
MBeanParameterInfo[] parameterInfo = new MBeanParameterInfo[params.length];
Class[] methodParameters = method.getParameterTypes();
for (int i = 0; i < params.length; i++) {
ManagedOperationParameter param = params[i];
parameterInfo[i] =
new MBeanParameterInfo(param.getName(), methodParameters[i].getName(), param.getDescription());
}
return parameterInfo;
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,6 +16,7 @@
package org.springframework.jmx.support;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.Set;
import javax.management.InstanceAlreadyExistsException;
@@ -112,7 +113,7 @@ public class MBeanRegistrationSupport {
/**
* The beans that have been registered by this exporter.
*/
protected final Set<ObjectName> registeredBeans = new LinkedHashSet<ObjectName>();
private final Set<ObjectName> registeredBeans = Collections.synchronizedSet(new LinkedHashSet<ObjectName>());
/**
* The policy used when registering an MBean and finding that it already exists.
@@ -228,10 +229,9 @@ public class MBeanRegistrationSupport {
* Unregisters all beans that have been registered by an instance of this class.
*/
protected void unregisterBeans() {
for (ObjectName objectName : this.registeredBeans) {
for (ObjectName objectName : new LinkedHashSet<ObjectName>(this.registeredBeans)) {
doUnregister(objectName);
}
this.registeredBeans.clear();
}
/**
@@ -257,6 +257,7 @@ public class MBeanRegistrationSupport {
logger.error("Could not unregister MBean [" + objectName + "]", ex);
}
}
this.registeredBeans.remove(objectName);
}
/**

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 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.
@@ -19,7 +19,7 @@ package org.springframework.remoting.rmi;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.rmi.RemoteException;
import javax.naming.Context;
import javax.naming.NamingException;
import javax.rmi.PortableRemoteObject;
@@ -88,6 +88,8 @@ public class JndiRmiClientInterceptor extends JndiObjectLocator implements Metho
private boolean refreshStubOnConnectFailure = false;
private boolean exposeAccessContext = false;
private Object cachedStub;
private final Object stubMonitor = new Object();
@@ -166,6 +168,18 @@ public class JndiRmiClientInterceptor extends JndiObjectLocator implements Metho
this.refreshStubOnConnectFailure = refreshStubOnConnectFailure;
}
/**
* Set whether to expose the JNDI environment context for all access to the target
* RMI stub, i.e. for all method invocations on the exposed object reference.
* <p>Default is "false", i.e. to only expose the JNDI context for object lookup.
* Switch this flag to "true" in order to expose the JNDI environment (including
* the authorization context) for each RMI invocation, as needed by WebLogic
* for RMI stubs with authorization requirements.
*/
public void setExposeAccessContext(boolean exposeAccessContext) {
this.exposeAccessContext = exposeAccessContext;
}
@Override
public void afterPropertiesSet() throws NamingException {
@@ -190,8 +204,8 @@ public class JndiRmiClientInterceptor extends JndiObjectLocator implements Metho
else if (getServiceInterface() != null) {
boolean isImpl = getServiceInterface().isInstance(remoteObj);
logger.debug("Using service interface [" + getServiceInterface().getName() +
"] for JNDI RMI object [" + getJndiName() + "] - " +
(!isImpl ? "not " : "") + "directly implemented");
"] for JNDI RMI object [" + getJndiName() + "] - " +
(!isImpl ? "not " : "") + "directly implemented");
}
}
if (this.cacheStub) {
@@ -268,13 +282,15 @@ public class JndiRmiClientInterceptor extends JndiObjectLocator implements Metho
* @see java.rmi.NoSuchObjectException
*/
public Object invoke(MethodInvocation invocation) throws Throwable {
Object stub = null;
Object stub;
try {
stub = getStub();
}
catch (NamingException ex) {
throw new RemoteLookupFailureException("JNDI lookup for RMI service [" + getJndiName() + "] failed", ex);
}
Context ctx = (this.exposeAccessContext ? getJndiTemplate().getContext() : null);
try {
return doInvoke(invocation, stub);
}
@@ -297,6 +313,9 @@ public class JndiRmiClientInterceptor extends JndiObjectLocator implements Metho
throw ex;
}
}
finally {
getJndiTemplate().releaseContext(ctx);
}
}
/**
@@ -354,7 +373,7 @@ public class JndiRmiClientInterceptor extends JndiObjectLocator implements Metho
* @see #invoke
*/
protected Object refreshAndRetry(MethodInvocation invocation) throws Throwable {
Object freshStub = null;
Object freshStub;
synchronized (this.stubMonitor) {
this.cachedStub = null;
freshStub = lookupStub();
@@ -426,7 +445,7 @@ public class JndiRmiClientInterceptor extends JndiObjectLocator implements Metho
* @see org.springframework.remoting.support.RemoteInvocation
*/
protected Object doInvoke(MethodInvocation methodInvocation, RmiInvocationHandler invocationHandler)
throws RemoteException, NoSuchMethodException, IllegalAccessException, InvocationTargetException {
throws RemoteException, NoSuchMethodException, IllegalAccessException, InvocationTargetException {
if (AopUtils.isToStringMethod(methodInvocation.getMethod())) {
return "RMI invoker proxy for service URL [" + getJndiName() + "]";

View File

@@ -345,7 +345,7 @@ public class RmiClientInterceptor extends RemoteInvocationBasedAccessor
}
catch (RemoteException ex) {
throw RmiClientInterceptorUtils.convertRmiAccessException(
invocation.getMethod(), ex, isConnectFailure(ex), getServiceUrl());
invocation.getMethod(), ex, isConnectFailure(ex), getServiceUrl());
}
catch (InvocationTargetException ex) {
Throwable exToThrow = ex.getTargetException();
@@ -389,7 +389,7 @@ public class RmiClientInterceptor extends RemoteInvocationBasedAccessor
* @see org.springframework.remoting.support.RemoteInvocation
*/
protected Object doInvoke(MethodInvocation methodInvocation, RmiInvocationHandler invocationHandler)
throws RemoteException, NoSuchMethodException, IllegalAccessException, InvocationTargetException {
throws RemoteException, NoSuchMethodException, IllegalAccessException, InvocationTargetException {
if (AopUtils.isToStringMethod(methodInvocation.getMethod())) {
return "RMI invoker proxy for service URL [" + getServiceUrl() + "]";

View File

@@ -456,4 +456,4 @@ public class RmiServiceExporter extends RmiBasedExporter implements Initializing
}
}
}
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 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.
@@ -39,7 +39,7 @@ public class AnnotationAsyncExecutionInterceptor extends AsyncExecutionIntercept
/**
* Create a new {@code AnnotationAsyncExecutionInterceptor} with the given executor.
* @param defaultExecutor the executor to be used by default if no more specific
* executor has been qualified at the method level using {@link Async#value()}.
* executor has been qualified at the method level using {@link Async#value()}
*/
public AnnotationAsyncExecutionInterceptor(Executor defaultExecutor) {
super(defaultExecutor);
@@ -64,7 +64,7 @@ public class AnnotationAsyncExecutionInterceptor extends AsyncExecutionIntercept
if (async == null) {
async = AnnotationUtils.findAnnotation(method.getDeclaringClass(), Async.class);
}
return async == null ? null : async.value();
return (async != null ? async.value() : null);
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 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.
@@ -28,7 +28,6 @@ import org.springframework.aop.Pointcut;
import org.springframework.aop.support.AbstractPointcutAdvisor;
import org.springframework.aop.support.ComposablePointcut;
import org.springframework.aop.support.annotation.AnnotationMatchingPointcut;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.core.task.SimpleAsyncTaskExecutor;
@@ -58,8 +57,6 @@ public class AsyncAnnotationAdvisor extends AbstractPointcutAdvisor implements B
private Pointcut pointcut;
private BeanFactory beanFactory;
/**
* Create a new {@code AsyncAnnotationAdvisor} for bean-style configuration.
@@ -84,30 +81,15 @@ public class AsyncAnnotationAdvisor extends AbstractPointcutAdvisor implements B
// If EJB 3.1 API not present, simply ignore.
}
this.advice = buildAdvice(executor);
this.setTaskExecutor(executor);
this.pointcut = buildPointcut(asyncAnnotationTypes);
}
/**
* Set the {@code BeanFactory} to be used when looking up executors by qualifier.
*/
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
this.beanFactory = beanFactory;
delegateBeanFactory(beanFactory);
}
public void delegateBeanFactory(BeanFactory beanFactory) {
if (this.advice instanceof AnnotationAsyncExecutionInterceptor) {
((AnnotationAsyncExecutionInterceptor)this.advice).setBeanFactory(beanFactory);
}
}
/**
* Specify the task executor to use for asynchronous methods.
* Specify the default task executor to use for asynchronous methods.
*/
public void setTaskExecutor(Executor executor) {
this.advice = buildAdvice(executor);
delegateBeanFactory(this.beanFactory);
}
/**
@@ -126,6 +108,15 @@ public class AsyncAnnotationAdvisor extends AbstractPointcutAdvisor implements B
this.pointcut = buildPointcut(asyncAnnotationTypes);
}
/**
* Set the {@code BeanFactory} to be used when looking up executors by qualifier.
*/
public void setBeanFactory(BeanFactory beanFactory) {
if (this.advice instanceof BeanFactoryAware) {
((BeanFactoryAware) this.advice).setBeanFactory(beanFactory);
}
}
public Advice getAdvice() {
return this.advice;

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -64,18 +64,41 @@ public @interface Scheduled {
*/
long fixedDelay() default -1;
/**
* Execute the annotated method with a fixed period between the end
* of the last invocation and the start of the next.
* @return the delay in milliseconds as a String value, e.g. a placeholder
* @since 3.2.2
*/
String fixedDelayString() default "";
/**
* Execute the annotated method with a fixed period between invocations.
* @return the period in milliseconds
*/
long fixedRate() default -1;
/**
* Execute the annotated method with a fixed period between invocations.
* @return the period in milliseconds as a String value, e.g. a placeholder
* @since 3.2.2
*/
String fixedRateString() default "";
/**
* Number of milliseconds to delay before the first execution of a
* {@link #fixedRate()} or {@link #fixedDelay()} task.
* @return the initial delay in milliseconds
* @since 3.2
*/
long initialDelay() default 0;
long initialDelay() default -1;
/**
* Number of milliseconds to delay before the first execution of a
* {@link #fixedRate()} or {@link #fixedDelay()} task.
* @return the initial delay in milliseconds as a String value, e.g. a placeholder
* @since 3.2.2
*/
String initialDelayString() default "";
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 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,7 +17,6 @@
package org.springframework.scheduling.annotation;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ScheduledExecutorService;
@@ -111,53 +110,115 @@ public class ScheduledAnnotationBeanPostProcessor
public void doWith(Method method) throws IllegalArgumentException, IllegalAccessException {
Scheduled annotation = AnnotationUtils.getAnnotation(method, Scheduled.class);
if (annotation != null) {
Assert.isTrue(void.class.equals(method.getReturnType()),
"Only void-returning methods may be annotated with @Scheduled.");
Assert.isTrue(method.getParameterTypes().length == 0,
"Only no-arg methods may be annotated with @Scheduled.");
if (AopUtils.isJdkDynamicProxy(bean)) {
try {
// found a @Scheduled method on the target class for this JDK proxy -> is it
// also present on the proxy itself?
method = bean.getClass().getMethod(method.getName(), method.getParameterTypes());
try {
Assert.isTrue(void.class.equals(method.getReturnType()),
"Only void-returning methods may be annotated with @Scheduled");
Assert.isTrue(method.getParameterTypes().length == 0,
"Only no-arg methods may be annotated with @Scheduled");
if (AopUtils.isJdkDynamicProxy(bean)) {
try {
// found a @Scheduled method on the target class for this JDK proxy -> is it
// also present on the proxy itself?
method = bean.getClass().getMethod(method.getName(), method.getParameterTypes());
}
catch (SecurityException ex) {
ReflectionUtils.handleReflectionException(ex);
}
catch (NoSuchMethodException ex) {
throw new IllegalStateException(String.format(
"@Scheduled method '%s' found on bean target class '%s', " +
"but not found in any interface(s) for bean JDK proxy. Either " +
"pull the method up to an interface or switch to subclass (CGLIB) " +
"proxies by setting proxy-target-class/proxyTargetClass " +
"attribute to 'true'", method.getName(), targetClass.getSimpleName()));
}
}
catch (SecurityException ex) {
ReflectionUtils.handleReflectionException(ex);
Runnable runnable = new ScheduledMethodRunnable(bean, method);
boolean processedSchedule = false;
String errorMessage = "Exactly one of the 'cron', 'fixedDelay(String)', or 'fixedRate(String)' attributes is required";
// Determine initial delay
long initialDelay = annotation.initialDelay();
String initialDelayString = annotation.initialDelayString();
if (!"".equals(initialDelayString)) {
Assert.isTrue(initialDelay < 0, "Specify 'initialDelay' or 'initialDelayString', not both");
if (embeddedValueResolver != null) {
initialDelayString = embeddedValueResolver.resolveStringValue(initialDelayString);
}
try {
initialDelay = Integer.parseInt(initialDelayString);
}
catch (NumberFormatException ex) {
throw new IllegalArgumentException(
"Invalid initialDelayString value \"" + initialDelayString + "\" - cannot parse into integer");
}
}
catch (NoSuchMethodException ex) {
throw new IllegalStateException(String.format(
"@Scheduled method '%s' found on bean target class '%s', " +
"but not found in any interface(s) for bean JDK proxy. Either " +
"pull the method up to an interface or switch to subclass (CGLIB) " +
"proxies by setting proxy-target-class/proxyTargetClass " +
"attribute to 'true'", method.getName(), targetClass.getSimpleName()));
// Check cron expression
String cron = annotation.cron();
if (!"".equals(cron)) {
Assert.isTrue(initialDelay == -1, "'initialDelay' not supported for cron triggers");
processedSchedule = true;
if (embeddedValueResolver != null) {
cron = embeddedValueResolver.resolveStringValue(cron);
}
registrar.addCronTask(new CronTask(runnable, cron));
}
}
Runnable runnable = new ScheduledMethodRunnable(bean, method);
boolean processedSchedule = false;
String errorMessage = "Exactly one of the 'cron', 'fixedDelay', or 'fixedRate' attributes is required.";
String cron = annotation.cron();
if (!"".equals(cron)) {
processedSchedule = true;
if (embeddedValueResolver != null) {
cron = embeddedValueResolver.resolveStringValue(cron);
// At this point we don't need to differentiate between initial delay set or not anymore
if (initialDelay < 0) {
initialDelay = 0;
}
registrar.addCronTask(new CronTask(runnable, cron));
// Check fixed delay
long fixedDelay = annotation.fixedDelay();
if (fixedDelay >= 0) {
Assert.isTrue(!processedSchedule, errorMessage);
processedSchedule = true;
registrar.addFixedDelayTask(new IntervalTask(runnable, fixedDelay, initialDelay));
}
String fixedDelayString = annotation.fixedDelayString();
if (!"".equals(fixedDelayString)) {
Assert.isTrue(!processedSchedule, errorMessage);
processedSchedule = true;
if (embeddedValueResolver != null) {
fixedDelayString = embeddedValueResolver.resolveStringValue(fixedDelayString);
}
try {
fixedDelay = Integer.parseInt(fixedDelayString);
}
catch (NumberFormatException ex) {
throw new IllegalArgumentException(
"Invalid fixedDelayString value \"" + fixedDelayString + "\" - cannot parse into integer");
}
registrar.addFixedDelayTask(new IntervalTask(runnable, fixedDelay, initialDelay));
}
// Check fixed rate
long fixedRate = annotation.fixedRate();
if (fixedRate >= 0) {
Assert.isTrue(!processedSchedule, errorMessage);
processedSchedule = true;
registrar.addFixedRateTask(new IntervalTask(runnable, fixedRate, initialDelay));
}
String fixedRateString = annotation.fixedRateString();
if (!"".equals(fixedRateString)) {
Assert.isTrue(!processedSchedule, errorMessage);
processedSchedule = true;
if (embeddedValueResolver != null) {
fixedRateString = embeddedValueResolver.resolveStringValue(fixedRateString);
}
try {
fixedRate = Integer.parseInt(fixedRateString);
}
catch (NumberFormatException ex) {
throw new IllegalArgumentException(
"Invalid fixedRateString value \"" + fixedRateString + "\" - cannot parse into integer");
}
registrar.addFixedRateTask(new IntervalTask(runnable, fixedRate, initialDelay));
}
// Check whether we had any attribute set
Assert.isTrue(processedSchedule, errorMessage);
}
long initialDelay = annotation.initialDelay();
long fixedDelay = annotation.fixedDelay();
if (fixedDelay >= 0) {
Assert.isTrue(!processedSchedule, errorMessage);
processedSchedule = true;
registrar.addFixedDelayTask(new IntervalTask(runnable, fixedDelay, initialDelay));
catch (IllegalArgumentException ex) {
throw new IllegalStateException(
"Encountered invalid @Scheduled method '" + method.getName() + "': " + ex.getMessage());
}
long fixedRate = annotation.fixedRate();
if (fixedRate >= 0) {
Assert.isTrue(!processedSchedule, errorMessage);
processedSchedule = true;
registrar.addFixedRateTask(new IntervalTask(runnable, fixedRate, initialDelay));
}
Assert.isTrue(processedSchedule, errorMessage);
}
}
});
@@ -168,18 +229,14 @@ public class ScheduledAnnotationBeanPostProcessor
if (event.getApplicationContext() != this.applicationContext) {
return;
}
Map<String, SchedulingConfigurer> configurers =
this.applicationContext.getBeansOfType(SchedulingConfigurer.class);
if (this.scheduler != null) {
this.registrar.setScheduler(this.scheduler);
}
for (SchedulingConfigurer configurer : configurers.values()) {
configurer.configureTasks(this.registrar);
}
if (this.registrar.hasTasks() && this.registrar.getScheduler() == null) {
Map<String, ? super Object> schedulers = new HashMap<String, Object>();
schedulers.putAll(applicationContext.getBeansOfType(TaskScheduler.class));
@@ -199,7 +256,6 @@ public class ScheduledAnnotationBeanPostProcessor
"configureTasks() callback. Found the following beans: " + schedulers.keySet());
}
}
this.registrar.afterPropertiesSet();
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -20,6 +20,7 @@ import java.util.concurrent.ExecutorService;
import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -54,6 +55,8 @@ public abstract class ExecutorConfigurationSupport extends CustomizableThreadFac
private boolean waitForTasksToCompleteOnShutdown = false;
private int awaitTerminationSeconds = 0;
private String beanName;
private ExecutorService executor;
@@ -85,9 +88,17 @@ public abstract class ExecutorConfigurationSupport extends CustomizableThreadFac
}
/**
* Set whether to wait for scheduled tasks to complete on shutdown.
* <p>Default is "false". Switch this to "true" if you prefer
* fully completed tasks at the expense of a longer shutdown phase.
* Set whether to wait for scheduled tasks to complete on shutdown,
* not interrupting running tasks and executing all tasks in the queue.
* <p>Default is "false", shutting down immediately through interrupting
* ongoing tasks and clearing the queue. Switch this flag to "true" if you
* prefer fully completed tasks at the expense of a longer shutdown phase.
* <p>Note that Spring's container shutdown continues while ongoing tasks
* are being completed. If you want this executor to block and wait for the
* termination of tasks before the rest of the container continues to shut
* down - e.g. in order to keep up other resources that your tasks may need -,
* set the {@link #setAwaitTerminationSeconds "awaitTerminationSeconds"}
* property instead of or in addition to this property.
* @see java.util.concurrent.ExecutorService#shutdown()
* @see java.util.concurrent.ExecutorService#shutdownNow()
*/
@@ -95,6 +106,33 @@ public abstract class ExecutorConfigurationSupport extends CustomizableThreadFac
this.waitForTasksToCompleteOnShutdown = waitForJobsToCompleteOnShutdown;
}
/**
* Set the maximum number of seconds that this executor is supposed to block
* on shutdown in order to wait for remaining tasks to complete their execution
* before the rest of the container continues to shut down. This is particularly
* useful if your remaining tasks are likely to need access to other resources
* that are also managed by the container.
* <p>By default, this executor won't wait for the termination of tasks at all.
* It will either shut down immediately, interrupting ongoing tasks and clearing
* the remaining task queue - or, if the
* {@link #setWaitForTasksToCompleteOnShutdown "waitForTasksToCompleteOnShutdown"}
* flag has been set to {@code true}, it will continue to fully execute all
* ongoing tasks as well as all remaining tasks in the queue, in parallel to
* the rest of the container shutting down.
* <p>In either case, if you specify an await-termination period using this property,
* this executor will wait for the given time (max) for the termination of tasks.
* As a rule of thumb, specify a significantly higher timeout here if you set
* "waitForTasksToCompleteOnShutdown" to {@code true} at the same time,
* since all remaining tasks in the queue will still get executed - in contrast
* to the default shutdown behavior where it's just about waiting for currently
* executing tasks that aren't reacting to thread interruption.
* @see java.util.concurrent.ExecutorService#shutdown()
* @see java.util.concurrent.ExecutorService#awaitTermination
*/
public void setAwaitTerminationSeconds(int awaitTerminationSeconds) {
this.awaitTerminationSeconds = awaitTerminationSeconds;
}
public void setBeanName(String name) {
this.beanName = name;
}
@@ -145,6 +183,8 @@ public abstract class ExecutorConfigurationSupport extends CustomizableThreadFac
/**
* Perform a shutdown on the ThreadPoolExecutor.
* @see java.util.concurrent.ExecutorService#shutdown()
* @see java.util.concurrent.ExecutorService#shutdownNow()
* @see #awaitTerminationIfNecessary()
*/
public void shutdown() {
if (logger.isInfoEnabled()) {
@@ -156,6 +196,31 @@ public abstract class ExecutorConfigurationSupport extends CustomizableThreadFac
else {
this.executor.shutdownNow();
}
awaitTerminationIfNecessary();
}
/**
* Wait for the executor to terminate, according to the value of the
* {@link #setAwaitTerminationSeconds "awaitTerminationSeconds"} property.
*/
private void awaitTerminationIfNecessary() {
if (this.awaitTerminationSeconds > 0) {
try {
if (!this.executor.awaitTermination(this.awaitTerminationSeconds, TimeUnit.SECONDS)) {
if (logger.isWarnEnabled()) {
logger.warn("Timed out while waiting for executor" +
(this.beanName != null ? " '" + this.beanName + "'" : "") + " to terminate");
}
}
}
catch (InterruptedException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Interrupted while waiting for executor" +
(this.beanName != null ? " '" + this.beanName + "'" : "") + " to terminate");
}
Thread.currentThread().interrupt();
}
}
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 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.
@@ -126,7 +126,7 @@ public class ThreadPoolExecutorFactoryBean extends ExecutorConfigurationSupport
* <p>Default is "false", exposing the raw executor as bean reference.
* Switch this flag to "true" to strictly prevent clients from
* modifying the executor's configuration.
* @see java.util.concurrent.Executors#unconfigurableScheduledExecutorService
* @see java.util.concurrent.Executors#unconfigurableExecutorService
*/
public void setExposeUnconfigurableExecutor(boolean exposeUnconfigurableExecutor) {
this.exposeUnconfigurableExecutor = exposeUnconfigurableExecutor;
@@ -137,9 +137,8 @@ public class ThreadPoolExecutorFactoryBean extends ExecutorConfigurationSupport
ThreadFactory threadFactory, RejectedExecutionHandler rejectedExecutionHandler) {
BlockingQueue<Runnable> queue = createQueue(this.queueCapacity);
ThreadPoolExecutor executor = new ThreadPoolExecutor(
this.corePoolSize, this.maxPoolSize, this.keepAliveSeconds, TimeUnit.SECONDS,
queue, threadFactory, rejectedExecutionHandler);
ThreadPoolExecutor executor = createExecutor(this.corePoolSize, this.maxPoolSize,
this.keepAliveSeconds, queue, threadFactory, rejectedExecutionHandler);
if (this.allowCoreThreadTimeOut) {
executor.allowCoreThreadTimeOut(true);
}
@@ -151,6 +150,27 @@ public class ThreadPoolExecutorFactoryBean extends ExecutorConfigurationSupport
return executor;
}
/**
* Create a new instance of {@link ThreadPoolExecutor} or a subclass thereof.
* <p>The default implementation creates a standard {@link ThreadPoolExecutor}.
* Can be overridden to provide custom {@link ThreadPoolExecutor} subclasses.
* @param corePoolSize the specified core pool size
* @param maxPoolSize the specified maximum pool size
* @param keepAliveSeconds the specified keep-alive time in seconds
* @param queue the BlockingQueue to use
* @param threadFactory the ThreadFactory to use
* @param rejectedExecutionHandler the RejectedExecutionHandler to use
* @return a new ThreadPoolExecutor instance
* @see #afterPropertiesSet()
*/
protected ThreadPoolExecutor createExecutor(
int corePoolSize, int maxPoolSize, int keepAliveSeconds, BlockingQueue<Runnable> queue,
ThreadFactory threadFactory, RejectedExecutionHandler rejectedExecutionHandler) {
return new ThreadPoolExecutor(corePoolSize, maxPoolSize,
keepAliveSeconds, TimeUnit.SECONDS, queue, threadFactory, rejectedExecutionHandler);
}
/**
* Create the BlockingQueue to use for the ThreadPoolExecutor.
* <p>A LinkedBlockingQueue instance will be created for a positive

View File

@@ -0,0 +1,65 @@
/*
* Copyright 2002-2013 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.scheduling.config;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
/**
* {@link ScheduledTaskRegistrar} subclass that redirects the actual scheduling
* of tasks to the {@link ContextRefreshedEvent} callback. Falls back to regular
* {@code ScheduledTaskRegistrar} behavior when not running within an ApplicationContext.
*
* @author Juergen Hoeller
* @since 3.2.1
*/
public class ContextLifecycleScheduledTaskRegistrar extends ScheduledTaskRegistrar
implements ApplicationContextAware, ApplicationListener<ContextRefreshedEvent> {
private ApplicationContext applicationContext;
public void setApplicationContext(ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
}
/**
* If we're running within an ApplicationContext, don't schedule the tasks
* right here; wait for this context's ContextRefreshedEvent instead.
*/
@Override
public void afterPropertiesSet() {
if (this.applicationContext == null) {
scheduleTasks();
}
}
/**
* Actually schedule the tasks at the right time of the context lifecycle,
* if we're running within an ApplicationContext.
*/
public void onApplicationEvent(ContextRefreshedEvent event) {
if (event.getApplicationContext() != this.applicationContext) {
return;
}
scheduleTasks();
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -44,8 +44,8 @@ public class IntervalTask extends Task {
*/
public IntervalTask(Runnable runnable, long interval, long initialDelay) {
super(runnable);
this.initialDelay = initialDelay;
this.interval = interval;
this.initialDelay = initialDelay;
}
/**
@@ -59,10 +59,11 @@ public class IntervalTask extends Task {
public long getInterval() {
return interval;
return this.interval;
}
public long getInitialDelay() {
return initialDelay;
return this.initialDelay;
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 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.
@@ -274,11 +274,19 @@ public class ScheduledTaskRegistrar implements InitializingBean, DisposableBean
(this.triggerTasks != null && !this.triggerTasks.isEmpty());
}
/**
* Calls {@link #scheduleTasks()} at bean construction time.
*/
public void afterPropertiesSet() {
scheduleTasks();
}
/**
* Schedule all registered tasks against the underlying {@linkplain
* #setTaskScheduler(TaskScheduler) task scheduler}.
*/
public void afterPropertiesSet() {
protected void scheduleTasks() {
long now = System.currentTimeMillis();
if (this.taskScheduler == null) {

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 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.
@@ -38,8 +38,10 @@ import org.w3c.dom.NodeList;
public class ScheduledTasksBeanDefinitionParser extends AbstractSingleBeanDefinitionParser {
private static final String ELEMENT_SCHEDULED = "scheduled";
private static final long ZERO_INITIAL_DELAY = 0;
@Override
protected boolean shouldGenerateId() {
return true;
@@ -47,7 +49,7 @@ public class ScheduledTasksBeanDefinitionParser extends AbstractSingleBeanDefini
@Override
protected String getBeanClassName(Element element) {
return "org.springframework.scheduling.config.ScheduledTaskRegistrar";
return "org.springframework.scheduling.config.ContextLifecycleScheduledTaskRegistrar";
}
@Override

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 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.
@@ -69,8 +69,21 @@ public class CronSequenceGenerator {
private final TimeZone timeZone;
/**
* Construct a {@link CronSequenceGenerator} from the pattern provided.
* Construct a {@link CronSequenceGenerator} from the pattern provided,
* using the default {@link TimeZone}.
* @param expression a space-separated list of time fields
* @throws IllegalArgumentException if the pattern cannot be parsed
* @see java.util.TimeZone#getDefault()
*/
public CronSequenceGenerator(String expression) {
this(expression, TimeZone.getDefault());
}
/**
* Construct a {@link CronSequenceGenerator} from the pattern provided,
* using the specified {@link TimeZone}.
* @param expression a space-separated list of time fields
* @param timeZone the TimeZone to use for generated trigger times
* @throws IllegalArgumentException if the pattern cannot be parsed
@@ -81,6 +94,7 @@ public class CronSequenceGenerator {
parse(expression);
}
/**
* Get the next {@link Date} in the sequence matching the Cron pattern and
* after the value provided. The return value will have a whole number of
@@ -112,12 +126,17 @@ public class CronSequenceGenerator {
calendar.setTimeZone(this.timeZone);
calendar.setTime(date);
// Truncate to the next whole second
calendar.add(Calendar.SECOND, 1);
// First, just reset the milliseconds and try to calculate from there...
calendar.set(Calendar.MILLISECOND, 0);
long originalTimestamp = calendar.getTimeInMillis();
doNext(calendar, calendar.get(Calendar.YEAR));
if (calendar.getTimeInMillis() == originalTimestamp) {
// We arrived at the original timestamp - round up to the next whole second and try again...
calendar.add(Calendar.SECOND, 1);
doNext(calendar, calendar.get(Calendar.YEAR));
}
return calendar.getTime();
}
@@ -135,7 +154,8 @@ public class CronSequenceGenerator {
int updateMinute = findNext(this.minutes, minute, calendar, Calendar.MINUTE, Calendar.HOUR_OF_DAY, resets);
if (minute == updateMinute) {
resets.add(Calendar.MINUTE);
} else {
}
else {
doNext(calendar, dot);
}
@@ -143,7 +163,8 @@ public class CronSequenceGenerator {
int updateHour = findNext(this.hours, hour, calendar, Calendar.HOUR_OF_DAY, Calendar.DAY_OF_WEEK, resets);
if (hour == updateHour) {
resets.add(Calendar.HOUR_OF_DAY);
} else {
}
else {
doNext(calendar, dot);
}
@@ -152,7 +173,8 @@ public class CronSequenceGenerator {
int updateDayOfMonth = findNextDay(calendar, this.daysOfMonth, dayOfMonth, daysOfWeek, dayOfWeek, resets);
if (dayOfMonth == updateDayOfMonth) {
resets.add(Calendar.DAY_OF_MONTH);
} else {
}
else {
doNext(calendar, dot);
}
@@ -160,7 +182,8 @@ public class CronSequenceGenerator {
int updateMonth = findNext(this.months, month, calendar, Calendar.MONTH, Calendar.YEAR, resets);
if (month != updateMonth) {
if (calendar.get(Calendar.YEAR) - dot > 4) {
throw new IllegalStateException("Invalid cron expression led to runaway search for next trigger");
throw new IllegalArgumentException("Invalid cron expression \"" + this.expression +
"\" led to runaway search for next trigger");
}
doNext(calendar, dot);
}
@@ -181,7 +204,7 @@ public class CronSequenceGenerator {
reset(calendar, resets);
}
if (count >= max) {
throw new IllegalStateException("Overflow in day for expression=" + this.expression);
throw new IllegalArgumentException("Overflow in day for expression \"" + this.expression + "\"");
}
return dayOfMonth;
}
@@ -222,7 +245,8 @@ public class CronSequenceGenerator {
}
}
// Parsing logic invoked by the constructor.
// Parsing logic invoked by the constructor
/**
* Parse the given pattern expression.
@@ -230,8 +254,8 @@ public class CronSequenceGenerator {
private void parse(String expression) throws IllegalArgumentException {
String[] fields = StringUtils.tokenizeToStringArray(expression, " ");
if (fields.length != 6) {
throw new IllegalArgumentException(String.format(""
+ "cron expression must consist of 6 fields (found %d in %s)", fields.length, expression));
throw new IllegalArgumentException(String.format(
"Cron expression must consist of 6 fields (found %d in \"%s\")", fields.length, expression));
}
setNumberHits(this.seconds, fields[0], 0, 60);
setNumberHits(this.minutes, fields[1], 0, 60);
@@ -296,10 +320,12 @@ public class CronSequenceGenerator {
// Not an incrementer so it must be a range (possibly empty)
int[] range = getRange(field, min, max);
bits.set(range[0], range[1] + 1);
} else {
}
else {
String[] split = StringUtils.delimitedListToStringArray(field, "/");
if (split.length > 2) {
throw new IllegalArgumentException("Incrementer has more than two fields: " + field);
throw new IllegalArgumentException("Incrementer has more than two fields: '" +
field + "' in expression \"" + this.expression + "\"");
}
int[] range = getRange(split[0], min, max);
if (!split[0].contains("-")) {
@@ -322,19 +348,23 @@ public class CronSequenceGenerator {
}
if (!field.contains("-")) {
result[0] = result[1] = Integer.valueOf(field);
} else {
}
else {
String[] split = StringUtils.delimitedListToStringArray(field, "-");
if (split.length > 2) {
throw new IllegalArgumentException("Range has more than two fields: " + field);
throw new IllegalArgumentException("Range has more than two fields: '" +
field + "' in expression \"" + this.expression + "\"");
}
result[0] = Integer.valueOf(split[0]);
result[1] = Integer.valueOf(split[1]);
}
if (result[0] >= max || result[1] >= max) {
throw new IllegalArgumentException("Range exceeds maximum (" + max + "): " + field);
throw new IllegalArgumentException("Range exceeds maximum (" + max + "): '" +
field + "' in expression \"" + this.expression + "\"");
}
if (result[0] < min || result[1] < min) {
throw new IllegalArgumentException("Range less than minimum (" + min + "): " + field);
throw new IllegalArgumentException("Range less than minimum (" + min + "): '" +
field + "' in expression \"" + this.expression + "\"");
}
return result;
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,12 +16,12 @@
package org.springframework.scheduling.support;
import java.util.Date;
import java.util.TimeZone;
import org.springframework.scheduling.Trigger;
import org.springframework.scheduling.TriggerContext;
import java.util.Date;
import java.util.TimeZone;
/**
* {@link Trigger} implementation for cron expressions.
* Wraps a {@link CronSequenceGenerator}.
@@ -41,7 +41,7 @@ public class CronTrigger implements Trigger {
* following cron expression conventions
*/
public CronTrigger(String cronExpression) {
this(cronExpression, TimeZone.getDefault());
this.sequenceGenerator = new CronSequenceGenerator(cronExpression);
}
/**
@@ -89,7 +89,7 @@ public class CronTrigger implements Trigger {
@Override
public String toString() {
return sequenceGenerator.toString();
return this.sequenceGenerator.toString();
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 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,8 +31,8 @@ import org.springframework.util.Assert;
* <emphasis>completion</emphasis> time). To measure the interval between the
* scheduled <emphasis>start</emphasis> time of each execution instead, set the
* 'fixedRate' property to {@code true}.
* <p>
* Note that the TaskScheduler interface already defines methods for scheduling
*
* <p>Note that the TaskScheduler interface already defines methods for scheduling
* tasks at fixed-rate or with fixed-delay. Both also support an optional value
* for the initial delay. Those methods should be used directly whenever
* possible. The value of this Trigger implementation is that it can be used
@@ -68,7 +68,7 @@ public class PeriodicTrigger implements Trigger {
*/
public PeriodicTrigger(long period, TimeUnit timeUnit) {
Assert.isTrue(period >= 0, "period must not be negative");
this.timeUnit = (timeUnit != null) ? timeUnit : TimeUnit.MILLISECONDS;
this.timeUnit = (timeUnit != null ? timeUnit : TimeUnit.MILLISECONDS);
this.period = this.timeUnit.toMillis(period);
}
@@ -91,6 +91,7 @@ public class PeriodicTrigger implements Trigger {
this.fixedRate = fixedRate;
}
/**
* Returns the time after which a task should run again.
*/
@@ -104,6 +105,7 @@ public class PeriodicTrigger implements Trigger {
return new Date(triggerContext.lastCompletionTime().getTime() + this.period);
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
@@ -113,16 +115,12 @@ public class PeriodicTrigger implements Trigger {
return false;
}
PeriodicTrigger other = (PeriodicTrigger) obj;
return this.fixedRate == other.fixedRate
&& this.initialDelay == other.initialDelay
&& this.period == other.period;
return (this.fixedRate == other.fixedRate && this.initialDelay == other.initialDelay && this.period == other.period);
}
@Override
public int hashCode() {
return (this.fixedRate ? 17 : 29) +
(int) (37 * this.period) +
(int) (41 * this.initialDelay);
return (this.fixedRate ? 17 : 29) + (int) (37 * this.period) + (int) (41 * this.initialDelay);
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 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.
@@ -26,6 +26,7 @@ import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionDefaults;
import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.beans.factory.xml.AbstractBeanDefinitionParser;
import org.springframework.beans.factory.xml.BeanDefinitionParserDelegate;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.beans.factory.xml.XmlReaderContext;
import org.springframework.scripting.support.ScriptFactoryPostProcessor;
@@ -64,6 +65,8 @@ class ScriptBeanDefinitionParser extends AbstractBeanDefinitionParser {
private static final String DEPENDENCY_CHECK_ATTRIBUTE = "dependency-check";
private static final String DEPENDS_ON_ATTRIBUTE = "depends-on";
private static final String INIT_METHOD_ATTRIBUTE = "init-method";
private static final String DESTROY_METHOD_ATTRIBUTE = "destroy-method";
@@ -138,6 +141,13 @@ class ScriptBeanDefinitionParser extends AbstractBeanDefinitionParser {
String dependencyCheck = element.getAttribute(DEPENDENCY_CHECK_ATTRIBUTE);
bd.setDependencyCheck(parserContext.getDelegate().getDependencyCheck(dependencyCheck));
// Parse depends-on list of bean names.
String dependsOn = element.getAttribute(DEPENDS_ON_ATTRIBUTE);
if (StringUtils.hasLength(dependsOn)) {
bd.setDependsOn(StringUtils.tokenizeToStringArray(
dependsOn, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS));
}
// Retrieve the defaults for bean definitions within this parser context
BeanDefinitionDefaults beanDefinitionDefaults = parserContext.getDelegate().getBeanDefinitionDefaults();

View File

@@ -81,7 +81,7 @@ public abstract class JRubyScriptUtils {
Node scriptRootNode = ruby.parseEval(scriptSource, "", null, 0);
// keep using the deprecated runNormally variant for JRuby 1.1/1.2 compatibility...
IRubyObject rubyObject = ruby.runNormally(scriptRootNode, false);
IRubyObject rubyObject = ruby.runNormally(scriptRootNode, false);
if (rubyObject instanceof RubyNil) {
String className = findClassName(scriptRootNode);

View File

@@ -126,4 +126,4 @@ public class ResourceScriptSource implements ScriptSource {
public String toString() {
return this.resource.toString();
}
}
}

View File

@@ -18,7 +18,11 @@ package org.springframework.validation;
import java.beans.PropertyEditor;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.commons.logging.Log;
@@ -141,7 +145,7 @@ public class DataBinder implements PropertyEditorRegistry, TypeConverter {
private BindingErrorProcessor bindingErrorProcessor = new DefaultBindingErrorProcessor();
private Validator validator;
private final List<Validator> validators = new ArrayList<Validator>();
private ConversionService conversionService;
@@ -493,21 +497,58 @@ public class DataBinder implements PropertyEditorRegistry, TypeConverter {
/**
* Set the Validator to apply after each binding step.
* @see #addValidators(Validator...)
* @see #replaceValidators(Validator...)
*/
public void setValidator(Validator validator) {
if (validator != null && (getTarget() != null && !validator.supports(getTarget().getClass()))) {
throw new IllegalStateException("Invalid target for Validator [" + validator + "]: " + getTarget());
assertValidators(validator);
this.validators.clear();
this.validators.add(validator);
}
private void assertValidators(Validator... validators) {
Assert.notNull(validators, "Validators required");
for (Validator validator : validators) {
if (validator != null && (getTarget() != null && !validator.supports(getTarget().getClass()))) {
throw new IllegalStateException("Invalid target for Validator [" + validator + "]: " + getTarget());
}
}
this.validator = validator;
}
/**
* Return the Validator to apply after each binding step, if any.
* Add Validators to apply after each binding step.
* @see #setValidator(Validator)
* @see #replaceValidators(Validator...)
*/
public Validator getValidator() {
return this.validator;
public void addValidators(Validator... validators) {
assertValidators(validators);
this.validators.addAll(Arrays.asList(validators));
}
/**
* Replace the Validators to apply after each binding step.
* @see #setValidator(Validator)
* @see #addValidators(Validator...)
*/
public void replaceValidators(Validator... validators) {
assertValidators(validators);
this.validators.clear();
this.validators.addAll(Arrays.asList(validators));
}
/**
* Return the primary Validator to apply after each binding step, if any.
*/
public Validator getValidator() {
return this.validators.size() > 0 ? this.validators.get(0) : null;
}
/**
* Return the Validators to apply after data binding.
*/
public List<Validator> getValidators() {
return Collections.unmodifiableList(this.validators);
}
//---------------------------------------------------------------------
// Implementation of PropertyEditorRegistry/TypeConverter interface
@@ -708,28 +749,31 @@ public class DataBinder implements PropertyEditorRegistry, TypeConverter {
/**
* Invoke the specified Validator, if any.
* Invoke the specified Validators, if any.
* @see #setValidator(Validator)
* @see #getBindingResult()
*/
public void validate() {
this.validator.validate(getTarget(), getBindingResult());
for (Validator validator : this.validators) {
validator.validate(getTarget(), getBindingResult());
}
}
/**
* Invoke the specified Validator, if any, with the given validation hints.
* Invoke the specified Validators, if any, with the given validation hints.
* <p>Note: Validation hints may get ignored by the actual target Validator.
* @param validationHints one or more hint objects to be passed to a {@link SmartValidator}
* @see #setValidator(Validator)
* @see SmartValidator#validate(Object, Errors, Object...)
*/
public void validate(Object... validationHints) {
Validator validator = getValidator();
if (!ObjectUtils.isEmpty(validationHints) && validator instanceof SmartValidator) {
((SmartValidator) validator).validate(getTarget(), getBindingResult(), validationHints);
}
else if (validator != null) {
validator.validate(getTarget(), getBindingResult());
for (Validator validator : getValidators()) {
if (!ObjectUtils.isEmpty(validationHints) && validator instanceof SmartValidator) {
((SmartValidator) validator).validate(getTarget(), getBindingResult(), validationHints);
}
else if (validator != null) {
validator.validate(getTarget(), getBindingResult());
}
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 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.
@@ -46,8 +46,8 @@ import org.springframework.validation.annotation.Validated;
* of that class. By default, JSR-303 will validate against its default group only.
*
* <p>As of Spring 3.1, this functionality requires Hibernate Validator 4.2 or higher.
* In Spring 3.1.2, this class will autodetect a Bean Validation 1.1 compliant provider
* and automatically use the standard method validation support there (once available).
* Once Bean Validation 1.1 becomes available, this class will autodetect a compliant
* provider and automatically use the standard method validation support there.
*
* @author Juergen Hoeller
* @since 3.1

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 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.
@@ -99,7 +99,8 @@ public class SpringValidatorAdapter implements SmartValidator, javax.validation.
}
}
}
processConstraintViolations(this.targetValidator.validate(target, groups.toArray(new Class[groups.size()])), errors);
processConstraintViolations(
this.targetValidator.validate(target, groups.toArray(new Class[groups.size()])), errors);
}
/**
@@ -114,10 +115,11 @@ public class SpringValidatorAdapter implements SmartValidator, javax.validation.
FieldError fieldError = errors.getFieldError(field);
if (fieldError == null || !fieldError.isBindingFailure()) {
try {
String errorCode = violation.getConstraintDescriptor().getAnnotation().annotationType().getSimpleName();
Object[] errorArgs = getArgumentsForConstraint(errors.getObjectName(), field, violation.getConstraintDescriptor());
ConstraintDescriptor<?> cd = violation.getConstraintDescriptor();
String errorCode = cd.getAnnotation().annotationType().getSimpleName();
Object[] errorArgs = getArgumentsForConstraint(errors.getObjectName(), field, cd);
if (errors instanceof BindingResult) {
// can do custom FieldError registration with invalid value from ConstraintViolation,
// Can do custom FieldError registration with invalid value from ConstraintViolation,
// as necessary for Hibernate Validator compatibility (non-indexed set path in field)
BindingResult bindingResult = (BindingResult) errors;
String nestedField = bindingResult.getNestedPath() + field;
@@ -128,8 +130,10 @@ public class SpringValidatorAdapter implements SmartValidator, javax.validation.
}
else {
Object invalidValue = violation.getInvalidValue();
if (!"".equals(field) && invalidValue == violation.getLeafBean()) {
// bean constraint with property path: retrieve the actual property value
if (!"".equals(field) && (invalidValue == violation.getLeafBean() ||
(field.contains(".") && !field.contains("[]")))) {
// Possibly a bean constraint with property path: retrieve the actual property value.
// However, explicitly avoid this for "address[]" style paths that we can't handle.
invalidValue = bindingResult.getRawFieldValue(field);
}
String[] errorCodes = bindingResult.resolveMessageCodes(errorCode, field);

View File

@@ -36,7 +36,7 @@
<xsd:annotation>
<xsd:documentation source="java:org.springframework.cache.CacheManager"><![CDATA[
The bean name of the CacheManager that is to be used to retrieve the backing caches.
This attribute is not required, and only needs to be specified
explicitly if the bean name of the desired CacheManager
is not 'cacheManager'.
@@ -52,7 +52,7 @@
<xsd:annotation>
<xsd:documentation source="java:org.springframework.cache.interceptor.KeyGenerator"><![CDATA[
The bean name of the KeyGenerator that is to be used to retrieve the backing caches.
This attribute is not required, and only needs to be specified
explicitly if the default strategy (DefaultKeyGenerator) is not sufficient.
]]></xsd:documentation>
@@ -150,7 +150,7 @@
<xsd:annotation>
<xsd:documentation source="java:org.springframework.cache.interceptor.KeyGenerator"><![CDATA[
The bean name of the KeyGenerator that is to be used to retrieve the backing caches.
This attribute is not required, and only needs to be specified
explicitly if the default strategy (DefaultKeyGenerator) is not sufficient.
]]></xsd:documentation>
@@ -160,7 +160,7 @@
</tool:annotation>
</xsd:appinfo>
</xsd:annotation>
</xsd:attribute>
</xsd:attribute>
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>
@@ -194,16 +194,42 @@
example, 'get*', 'handle*', '*Order', 'on*Event', etc.]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
</xsd:complexType>
<xsd:complexType name="definitionsType">
<xsd:complexContent>
<xsd:extension base="basedefinitionType">
<xsd:sequence>
<xsd:choice minOccurs="0" maxOccurs="unbounded">
<xsd:element name="cacheable" minOccurs="0" maxOccurs="unbounded" type="basedefinitionType"/>
<xsd:element name="cache-put" minOccurs="0" maxOccurs="unbounded" type="basedefinitionType"/>
<xsd:element name="cacheable" minOccurs="0" maxOccurs="unbounded">
<xsd:complexType>
<xsd:complexContent>
<xsd:extension base="basedefinitionType">
<xsd:attribute name="unless" type="xsd:string" use="optional">
<xsd:annotation>
<xsd:documentation><![CDATA[
The SpEL expression used to veto the method caching.]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>
</xsd:element>
<xsd:element name="cache-put" minOccurs="0" maxOccurs="unbounded">
<xsd:complexType>
<xsd:complexContent>
<xsd:extension base="basedefinitionType">
<xsd:attribute name="unless" type="xsd:string" use="optional">
<xsd:annotation>
<xsd:documentation><![CDATA[
The SpEL expression used to veto the method caching.]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>
</xsd:element>
<xsd:element name="cache-evict" minOccurs="0" maxOccurs="unbounded">
<xsd:complexType>
<xsd:complexContent>
@@ -217,16 +243,16 @@
<xsd:attribute name="before-invocation" type="xsd:boolean" use="optional">
<xsd:annotation>
<xsd:documentation><![CDATA[
Whether the eviction should occur after the method is successfully
Whether the eviction should occur after the method is successfully
invoked (default) or before.]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:choice>
</xsd:sequence>
</xsd:extension>
</xsd:complexContent>

View File

@@ -52,6 +52,39 @@
]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="mode" default="proxy">
<xsd:annotation>
<xsd:documentation><![CDATA[
Should annotated beans be proxied using Spring's AOP framework,
or should they rather be weaved with an AspectJ async execution aspect?
AspectJ weaving requires spring-aspects.jar on the classpath,
as well as load-time weaving (or compile-time weaving) enabled.
Note: The weaving-based aspect requires the @Async annotation to be
defined on the concrete class. Annotations in interfaces will not work
in that case (they will rather only work with interface-based proxies)!
]]></xsd:documentation>
</xsd:annotation>
<xsd:simpleType>
<xsd:restriction base="xsd:string">
<xsd:enumeration value="proxy"/>
<xsd:enumeration value="aspectj"/>
</xsd:restriction>
</xsd:simpleType>
</xsd:attribute>
<xsd:attribute name="proxy-target-class" type="xsd:boolean" default="false">
<xsd:annotation>
<xsd:documentation><![CDATA[
Are class-based (CGLIB) proxies to be created? By default, standard
Java interface-based proxies are created.
Note: Class-based proxies require the @Async annotation to be defined
on the concrete class. Annotations in interfaces will not work in
that case (they will rather only work with interface-based proxies)!
]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
</xsd:complexType>
</xsd:element>

View File

@@ -52,6 +52,39 @@
]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="mode" default="proxy">
<xsd:annotation>
<xsd:documentation><![CDATA[
Should annotated beans be proxied using Spring's AOP framework,
or should they rather be weaved with an AspectJ async execution aspect?
AspectJ weaving requires spring-aspects.jar on the classpath,
as well as load-time weaving (or compile-time weaving) enabled.
Note: The weaving-based aspect requires the @Async annotation to be
defined on the concrete class. Annotations in interfaces will not work
in that case (they will rather only work with interface-based proxies)!
]]></xsd:documentation>
</xsd:annotation>
<xsd:simpleType>
<xsd:restriction base="xsd:string">
<xsd:enumeration value="proxy"/>
<xsd:enumeration value="aspectj"/>
</xsd:restriction>
</xsd:simpleType>
</xsd:attribute>
<xsd:attribute name="proxy-target-class" type="xsd:boolean" default="false">
<xsd:annotation>
<xsd:documentation><![CDATA[
Are class-based (CGLIB) proxies to be created? By default, standard
Java interface-based proxies are created.
Note: Class-based proxies require the @Async annotation to be defined
on the concrete class. Annotations in interfaces will not work in
that case (they will rather only work with interface-based proxies)!
]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
</xsd:complexType>
</xsd:element>

View File

@@ -82,7 +82,7 @@
<xsd:annotation>
<xsd:documentation source="java:org.springframework.core.io.Resource"><![CDATA[
The resource containing the script for the dynamic language-backed bean.
Examples might be '/WEB-INF/scripts/Anais.groovy', 'classpath:Nin.bsh', etc.
]]></xsd:documentation>
</xsd:annotation>
@@ -137,13 +137,13 @@
<xsd:attribute name="depends-on" type="xsd:string">
<xsd:annotation>
<xsd:documentation><![CDATA[
The names of the beans that this bean depends on being initialized.
The bean factory will guarantee that these beans get initialized
before this bean.
The names of the beans that this bean depends on being initialized.
The bean factory will guarantee that these beans get initialized
before this bean.
Note that dependencies are normally expressed through bean properties.
This property should just be necessary other kinds of dependencies
like statics (*ugh*) or database preparation on startup.
Note that dependencies are normally expressed through bean properties.
This property should just be necessary for other kinds of dependencies
like statics (*ugh*) or database preparation on startup.
]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>

View File

@@ -82,7 +82,7 @@
<xsd:annotation>
<xsd:documentation source="java:org.springframework.core.io.Resource"><![CDATA[
The resource containing the script for the dynamic language-backed bean.
Examples might be '/WEB-INF/scripts/Anais.groovy', 'classpath:Nin.bsh', etc.
]]></xsd:documentation>
</xsd:annotation>
@@ -127,13 +127,13 @@
<xsd:attribute name="depends-on" type="xsd:string">
<xsd:annotation>
<xsd:documentation><![CDATA[
The names of the beans that this bean depends on being initialized.
The bean factory will guarantee that these beans get initialized
before this bean.
The names of the beans that this bean depends on being initialized.
The bean factory will guarantee that these beans get initialized
before this bean.
Note that dependencies are normally expressed through bean properties.
This property should just be necessary other kinds of dependencies
like statics (*ugh*) or database preparation on startup.
Note that dependencies are normally expressed through bean properties.
This property should just be necessary for other kinds of dependencies
like statics (*ugh*) or database preparation on startup.
]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>

View File

@@ -147,13 +147,13 @@
<xsd:attribute name="depends-on" type="xsd:string">
<xsd:annotation>
<xsd:documentation><![CDATA[
The names of the beans that this bean depends on being initialized.
The bean factory will guarantee that these beans get initialized
before this bean.
The names of the beans that this bean depends on being initialized.
The bean factory will guarantee that these beans get initialized
before this bean.
Note that dependencies are normally expressed through bean properties.
This property should just be necessary other kinds of dependencies
like statics (*ugh*) or database preparation on startup.
Note that dependencies are normally expressed through bean properties.
This property should just be necessary for other kinds of dependencies
like statics (*ugh*) or database preparation on startup.
]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>

View File

@@ -147,13 +147,13 @@
<xsd:attribute name="depends-on" type="xsd:string">
<xsd:annotation>
<xsd:documentation><![CDATA[
The names of the beans that this bean depends on being initialized.
The bean factory will guarantee that these beans get initialized
before this bean.
The names of the beans that this bean depends on being initialized.
The bean factory will guarantee that these beans get initialized
before this bean.
Note that dependencies are normally expressed through bean properties.
This property should just be necessary other kinds of dependencies
like statics (*ugh*) or database preparation on startup.
Note that dependencies are normally expressed through bean properties.
This property should just be necessary for other kinds of dependencies
like statics (*ugh*) or database preparation on startup.
]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>

View File

@@ -65,7 +65,6 @@ public class FooServiceImpl implements FooService {
private boolean initCalled = false;
@SuppressWarnings("unused")
@PostConstruct
private void init() {
if (this.initCalled) {

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 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.
@@ -25,8 +25,8 @@ import org.junit.Test;
import org.springframework.aop.aspectj.AdviceBindingTestAspect.AdviceBindingCollaborator;
import org.springframework.aop.framework.Advised;
import org.springframework.aop.support.AopUtils;
import org.springframework.beans.ITestBean;
import org.springframework.beans.TestBean;
import org.springframework.tests.sample.beans.ITestBean;
import org.springframework.tests.sample.beans.TestBean;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**

View File

@@ -19,6 +19,6 @@
<bean id="testAspect" class="org.springframework.aop.aspectj.AdviceBindingTestAspect"/>
<bean id="testBean" class="org.springframework.beans.TestBean"/>
<bean id="testBean" class="org.springframework.tests.sample.beans.TestBean"/>
</beans>

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 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.
@@ -26,8 +26,8 @@ import org.junit.Test;
import org.springframework.aop.aspectj.AfterReturningAdviceBindingTestAspect.AfterReturningAdviceBindingCollaborator;
import org.springframework.aop.framework.Advised;
import org.springframework.aop.support.AopUtils;
import org.springframework.beans.ITestBean;
import org.springframework.beans.TestBean;
import org.springframework.tests.sample.beans.ITestBean;
import org.springframework.tests.sample.beans.TestBean;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**

View File

@@ -18,7 +18,7 @@
<aop:after-returning method="oneObjectArg" returning="bean" pointcut="execution(* returnsThis())"/>
<aop:after-returning method="oneTestBeanArg" returning="bean" pointcut="execution(* returnsThis())"/>
<aop:after-returning method="testBeanArrayArg" returning="beans"
pointcut="execution(org.springframework.beans.ITestBean[] *(..))"/>
pointcut="execution(org.springframework.tests.sample.beans.ITestBean[] *(..))"/>
<aop:after-returning method="oneString" returning="name" pointcut="execution(* getSpouse())"/>
<aop:after-returning method="objectMatchNoArgs" returning="java.lang.Object"
pointcut="execution(* returnsThis())"/>
@@ -30,6 +30,6 @@
<bean id="testAspect" class="org.springframework.aop.aspectj.AfterReturningAdviceBindingTestAspect"/>
<bean id="testBean" class="org.springframework.beans.TestBean"/>
<bean id="testBean" class="org.springframework.tests.sample.beans.TestBean"/>
</beans>

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 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,7 +22,7 @@ import static org.mockito.Mockito.verify;
import org.junit.Before;
import org.junit.Test;
import org.springframework.aop.aspectj.AfterThrowingAdviceBindingTestAspect.AfterThrowingAdviceBindingCollaborator;
import org.springframework.beans.ITestBean;
import org.springframework.tests.sample.beans.ITestBean;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**

View File

@@ -37,6 +37,6 @@
<bean id="testAspect" class="org.springframework.aop.aspectj.AfterThrowingAdviceBindingTestAspect"/>
<bean id="testBean" class="org.springframework.beans.TestBean"/>
<bean id="testBean" class="org.springframework.tests.sample.beans.TestBean"/>
</beans>

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 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.
@@ -26,8 +26,8 @@ import org.junit.Test;
import org.springframework.aop.aspectj.AroundAdviceBindingTestAspect.AroundAdviceBindingCollaborator;
import org.springframework.aop.framework.Advised;
import org.springframework.aop.support.AopUtils;
import org.springframework.beans.ITestBean;
import org.springframework.beans.TestBean;
import org.springframework.tests.sample.beans.ITestBean;
import org.springframework.tests.sample.beans.TestBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

View File

@@ -17,6 +17,6 @@
<bean id="testAspect" class="org.springframework.aop.aspectj.AroundAdviceBindingTestAspect"/>
<bean id="testBean" class="org.springframework.beans.TestBean"/>
<bean id="testBean" class="org.springframework.tests.sample.beans.TestBean"/>
</beans>

View File

@@ -17,11 +17,11 @@
<bean id="testAspect" class="org.springframework.aop.aspectj.AroundAdviceBindingTestAspect"/>
<bean id="testBean" class="org.springframework.beans.TestBean">
<bean id="testBean" class="org.springframework.tests.sample.beans.TestBean">
<property name="spouse" ref="testBean2"/>
</bean>
<bean id="testBean2" class="org.springframework.beans.TestBean" autowire-candidate="false">
<bean id="testBean2" class="org.springframework.tests.sample.beans.TestBean" autowire-candidate="false">
<property name="spouse" ref="testBean"/>
</bean>

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 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.
@@ -24,7 +24,7 @@ import org.aspectj.lang.ProceedingJoinPoint;
import org.junit.Before;
import org.junit.Test;
import org.springframework.aop.MethodBeforeAdvice;
import org.springframework.beans.ITestBean;
import org.springframework.tests.sample.beans.ITestBean;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.core.Ordered;

View File

@@ -85,6 +85,6 @@
<bean id="lowPrecedenceAspect" class="org.springframework.aop.aspectj.PrecedenceTestAspect"/>
<bean id="testBean" class="org.springframework.beans.TestBean"/>
<bean id="testBean" class="org.springframework.tests.sample.beans.TestBean"/>
</beans>

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 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,7 +22,7 @@ import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.junit.Before;
import org.junit.Test;
import org.springframework.beans.ITestBean;
import org.springframework.tests.sample.beans.ITestBean;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**

View File

@@ -5,11 +5,11 @@
<bean id="proxyCreator" class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"/>
<bean id="testBean" class="org.springframework.beans.TestBean"/>
<bean id="testBean" class="org.springframework.tests.sample.beans.TestBean"/>
<bean id="advisor" class="org.springframework.aop.aspectj.AspectJExpressionPointcutAdvisor">
<property name="expression"
value="execution(org.springframework.beans.ITestBean[] org.springframework.beans.ITestBean.*(..))"/>
value="execution(org.springframework.tests.sample.beans.ITestBean[] org.springframework.tests.sample.beans.ITestBean.*(..))"/>
<property name="advice" ref="interceptor"/>
</bean>

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 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.
@@ -23,8 +23,8 @@ import org.aspectj.lang.annotation.Before;
import org.junit.Test;
import org.springframework.aop.aspectj.annotation.AspectJProxyFactory;
import org.springframework.aop.framework.Advised;
import org.springframework.beans.ITestBean;
import org.springframework.beans.TestBean;
import org.springframework.tests.sample.beans.ITestBean;
import org.springframework.tests.sample.beans.TestBean;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**

View File

@@ -6,10 +6,10 @@
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd">
<aop:aspectj-autoproxy/>
<bean id="testBean1" class="org.springframework.beans.TestBean"/>
<bean id="testBean2" class="org.springframework.beans.TestBean"/>
<bean id="testBean3" class="org.springframework.beans.TestBean"/>
<bean id="testBean1" class="org.springframework.tests.sample.beans.TestBean"/>
<bean id="testBean2" class="org.springframework.tests.sample.beans.TestBean"/>
<bean id="testBean3" class="org.springframework.tests.sample.beans.TestBean"/>
<bean id="counterAspect" class="org.springframework.aop.aspectj.CounterAspect"/>
</beans>
</beans>

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 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.
@@ -25,7 +25,7 @@ import org.junit.Before;
import org.junit.Test;
import org.springframework.aop.MethodBeforeAdvice;
import org.springframework.aop.framework.Advised;
import org.springframework.beans.ITestBean;
import org.springframework.tests.sample.beans.ITestBean;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.context.support.ClassPathXmlApplicationContext;

View File

@@ -21,13 +21,13 @@
</aop:aspect>
</aop:config>
<bean id="testBean1" name="myBean" class="org.springframework.beans.TestBean"/>
<bean id="testBean1" name="myBean" class="org.springframework.tests.sample.beans.TestBean"/>
<bean id="testBean2" class="org.springframework.beans.TestBean"/>
<bean id="testBean2" class="org.springframework.tests.sample.beans.TestBean"/>
<bean id="testBeanContainingNestedBean" class="org.springframework.beans.TestBean">
<bean id="testBeanContainingNestedBean" class="org.springframework.tests.sample.beans.TestBean">
<property name="doctor">
<bean class="org.springframework.beans.NestedTestBean"/>
<bean class="org.springframework.tests.sample.beans.NestedTestBean"/>
</property>
</bean>
@@ -53,9 +53,9 @@
<aop:advisor pointcut="bean(*This) and !bean(dont*)" advice-ref="testInterceptor"/>
</aop:config>
<bean id="interceptThis" class="org.springframework.beans.TestBean"/>
<bean id="interceptThis" class="org.springframework.tests.sample.beans.TestBean"/>
<bean id="dontInterceptThis" class="org.springframework.beans.TestBean"/>
<bean id="dontInterceptThis" class="org.springframework.tests.sample.beans.TestBean"/>
<bean id="testInterceptor" class="org.springframework.aop.aspectj.BeanNamePointcutTests$TestInterceptor"/>

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 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.
@@ -25,8 +25,8 @@ import org.junit.Test;
import org.springframework.aop.aspectj.AdviceBindingTestAspect.AdviceBindingCollaborator;
import org.springframework.aop.framework.Advised;
import org.springframework.aop.support.AopUtils;
import org.springframework.beans.ITestBean;
import org.springframework.beans.TestBean;
import org.springframework.tests.sample.beans.ITestBean;
import org.springframework.tests.sample.beans.TestBean;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**

View File

@@ -26,7 +26,7 @@
<bean id="testAspect" class="org.springframework.aop.aspectj.AdviceBindingTestAspect"/>
<bean id="testBean" class="org.springframework.beans.TestBean"/>
<bean id="testBean" class="org.springframework.tests.sample.beans.TestBean"/>
<bean id="authenticationLogger" class="org.springframework.aop.aspectj.AuthenticationLogger"/>

View File

@@ -20,8 +20,8 @@ import org.junit.Before;
import org.junit.Test;
import org.springframework.aop.framework.Advised;
import org.springframework.aop.support.AopUtils;
import org.springframework.beans.ITestBean;
import org.springframework.beans.TestBean;
import org.springframework.tests.sample.beans.ITestBean;
import org.springframework.tests.sample.beans.TestBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.tests.Assume;

Some files were not shown because too many files have changed in this diff Show More