Merge branch '3.2.x' into cleanup-3.2.x
* 3.2.x: Promote use of @PostConstruct and @PreDestroy @Scheduled provides String variants of fixedDelay, fixedRate, initialDelay for placeholder support Further preparations for 3.2.2 @Scheduled provides String variants of fixedDelay, fixedRate, initialDelay for placeholder support Folded a FactoryBean-specific check into predictBeanType now Fix Assert.instanceOf exception message Allow for ordering of mixed AspectJ before/after advices Minor javadoc and source layout polishing Fixed documentation for "depends-on" attribute "depends-on" attribute on lang namespace element actually respected at runtime now Allow for ordering of mixed AspectJ before/after advices
This commit is contained in:
commit
c4f79bb997
|
|
@ -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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
@ -16,8 +16,8 @@
|
||||||
|
|
||||||
package org.springframework.aop.aspectj.autoproxy;
|
package org.springframework.aop.aspectj.autoproxy;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
import java.util.LinkedList;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.aopalliance.aop.Advice;
|
import org.aopalliance.aop.Advice;
|
||||||
|
|
@ -67,29 +67,24 @@ public class AspectJAwareAdvisorAutoProxyCreator extends AbstractAdvisorAutoProx
|
||||||
@Override
|
@Override
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
protected List<Advisor> sortAdvisors(List<Advisor> advisors) {
|
protected List<Advisor> sortAdvisors(List<Advisor> advisors) {
|
||||||
// build list for sorting
|
|
||||||
List<PartiallyComparableAdvisorHolder> partiallyComparableAdvisors =
|
List<PartiallyComparableAdvisorHolder> partiallyComparableAdvisors =
|
||||||
new LinkedList<PartiallyComparableAdvisorHolder>();
|
new ArrayList<PartiallyComparableAdvisorHolder>(advisors.size());
|
||||||
for (Advisor element : advisors) {
|
for (Advisor element : advisors) {
|
||||||
partiallyComparableAdvisors.add(
|
partiallyComparableAdvisors.add(
|
||||||
new PartiallyComparableAdvisorHolder(element, DEFAULT_PRECEDENCE_COMPARATOR));
|
new PartiallyComparableAdvisorHolder(element, DEFAULT_PRECEDENCE_COMPARATOR));
|
||||||
}
|
}
|
||||||
|
|
||||||
// sort it
|
|
||||||
List<PartiallyComparableAdvisorHolder> sorted =
|
List<PartiallyComparableAdvisorHolder> sorted =
|
||||||
PartialOrder.sort(partiallyComparableAdvisors);
|
PartialOrder.sort(partiallyComparableAdvisors);
|
||||||
if (sorted == null) {
|
if (sorted != null) {
|
||||||
// TODO: work harder to give a better error message here.
|
List<Advisor> result = new ArrayList<Advisor>(advisors.size());
|
||||||
throw new IllegalArgumentException("Advice precedence circularity error");
|
for (PartiallyComparableAdvisorHolder pcAdvisor : sorted) {
|
||||||
|
result.add(pcAdvisor.getAdvisor());
|
||||||
|
}
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
// extract results again
|
return super.sortAdvisors(advisors);
|
||||||
List<Advisor> result = new LinkedList<Advisor>();
|
|
||||||
for (PartiallyComparableAdvisorHolder pcAdvisor : sorted) {
|
|
||||||
result.add(pcAdvisor.getAdvisor());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
@ -53,7 +53,6 @@ class AspectJPrecedenceComparator implements Comparator {
|
||||||
private static final int HIGHER_PRECEDENCE = -1;
|
private static final int HIGHER_PRECEDENCE = -1;
|
||||||
private static final int SAME_PRECEDENCE = 0;
|
private static final int SAME_PRECEDENCE = 0;
|
||||||
private static final int LOWER_PRECEDENCE = 1;
|
private static final int LOWER_PRECEDENCE = 1;
|
||||||
private static final int NOT_COMPARABLE = 0;
|
|
||||||
|
|
||||||
private final Comparator<? super Advisor> advisorComparator;
|
private final Comparator<? super Advisor> advisorComparator;
|
||||||
|
|
||||||
|
|
@ -85,21 +84,11 @@ class AspectJPrecedenceComparator implements Comparator {
|
||||||
|
|
||||||
Advisor advisor1 = (Advisor) o1;
|
Advisor advisor1 = (Advisor) o1;
|
||||||
Advisor advisor2 = (Advisor) o2;
|
Advisor advisor2 = (Advisor) o2;
|
||||||
|
int advisorPrecedence = this.advisorComparator.compare(advisor1, advisor2);
|
||||||
boolean oneOrOtherIsAfterAdvice =
|
if (advisorPrecedence == SAME_PRECEDENCE && declaredInSameAspect(advisor1, advisor2)) {
|
||||||
(AspectJAopUtils.isAfterAdvice(advisor1) || AspectJAopUtils.isAfterAdvice(advisor2));
|
advisorPrecedence = comparePrecedenceWithinAspect(advisor1, advisor2);
|
||||||
boolean oneOrOtherIsBeforeAdvice =
|
|
||||||
(AspectJAopUtils.isBeforeAdvice(advisor1) || AspectJAopUtils.isBeforeAdvice(advisor2));
|
|
||||||
if (oneOrOtherIsAfterAdvice && oneOrOtherIsBeforeAdvice) {
|
|
||||||
return NOT_COMPARABLE;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
int advisorPrecedence = this.advisorComparator.compare(advisor1, advisor2);
|
|
||||||
if (advisorPrecedence == SAME_PRECEDENCE && declaredInSameAspect(advisor1, advisor2)) {
|
|
||||||
advisorPrecedence = comparePrecedenceWithinAspect(advisor1, advisor2);
|
|
||||||
}
|
|
||||||
return advisorPrecedence;
|
|
||||||
}
|
}
|
||||||
|
return advisorPrecedence;
|
||||||
}
|
}
|
||||||
|
|
||||||
private int comparePrecedenceWithinAspect(Advisor advisor1, Advisor advisor2) {
|
private int comparePrecedenceWithinAspect(Advisor advisor1, Advisor advisor2) {
|
||||||
|
|
|
||||||
|
|
@ -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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
@ -16,12 +16,11 @@
|
||||||
|
|
||||||
package org.springframework.aop.aspectj.autoproxy;
|
package org.springframework.aop.aspectj.autoproxy;
|
||||||
|
|
||||||
import static org.junit.Assert.*;
|
|
||||||
|
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
|
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import org.springframework.aop.Advisor;
|
import org.springframework.aop.Advisor;
|
||||||
import org.springframework.aop.AfterReturningAdvice;
|
import org.springframework.aop.AfterReturningAdvice;
|
||||||
import org.springframework.aop.BeforeAdvice;
|
import org.springframework.aop.BeforeAdvice;
|
||||||
|
|
@ -35,11 +34,13 @@ import org.springframework.aop.aspectj.AspectJMethodBeforeAdvice;
|
||||||
import org.springframework.aop.aspectj.AspectJPointcutAdvisor;
|
import org.springframework.aop.aspectj.AspectJPointcutAdvisor;
|
||||||
import org.springframework.aop.support.DefaultPointcutAdvisor;
|
import org.springframework.aop.support.DefaultPointcutAdvisor;
|
||||||
|
|
||||||
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Adrian Colyer
|
* @author Adrian Colyer
|
||||||
* @author Chris Beams
|
* @author Chris Beams
|
||||||
*/
|
*/
|
||||||
public final class AspectJPrecedenceComparatorTests {
|
public class AspectJPrecedenceComparatorTests {
|
||||||
|
|
||||||
private static final int HIGH_PRECEDENCE_ADVISOR_ORDER = 100;
|
private static final int HIGH_PRECEDENCE_ADVISOR_ORDER = 100;
|
||||||
private static final int LOW_PRECEDENCE_ADVISOR_ORDER = 200;
|
private static final int LOW_PRECEDENCE_ADVISOR_ORDER = 200;
|
||||||
|
|
@ -89,7 +90,7 @@ public final class AspectJPrecedenceComparatorTests {
|
||||||
public void testSameAspectOneOfEach() {
|
public void testSameAspectOneOfEach() {
|
||||||
Advisor advisor1 = createAspectJAfterAdvice(HIGH_PRECEDENCE_ADVISOR_ORDER, EARLY_ADVICE_DECLARATION_ORDER, "someAspect");
|
Advisor advisor1 = createAspectJAfterAdvice(HIGH_PRECEDENCE_ADVISOR_ORDER, EARLY_ADVICE_DECLARATION_ORDER, "someAspect");
|
||||||
Advisor advisor2 = createAspectJBeforeAdvice(HIGH_PRECEDENCE_ADVISOR_ORDER, LATE_ADVICE_DECLARATION_ORDER, "someAspect");
|
Advisor advisor2 = createAspectJBeforeAdvice(HIGH_PRECEDENCE_ADVISOR_ORDER, LATE_ADVICE_DECLARATION_ORDER, "someAspect");
|
||||||
assertEquals("advisor1 and advisor2 not comparable", 0, this.comparator.compare(advisor1, advisor2));
|
assertEquals("advisor1 and advisor2 not comparable", 1, this.comparator.compare(advisor1, advisor2));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
|
||||||
|
|
@ -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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
@ -586,9 +586,10 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
|
||||||
for (BeanPostProcessor bp : getBeanPostProcessors()) {
|
for (BeanPostProcessor bp : getBeanPostProcessors()) {
|
||||||
if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
|
if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
|
||||||
SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
|
SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
|
||||||
Class processedType = ibp.predictBeanType(beanClass, beanName);
|
Class predictedType = ibp.predictBeanType(beanClass, beanName);
|
||||||
if (processedType != null) {
|
if (predictedType != null && (typesToMatch.length > 1 ||
|
||||||
return processedType;
|
!FactoryBean.class.equals(typesToMatch[0]) || FactoryBean.class.isAssignableFrom(predictedType))) {
|
||||||
|
return predictedType;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
@ -497,18 +497,21 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
|
||||||
// Retrieve corresponding bean definition.
|
// Retrieve corresponding bean definition.
|
||||||
RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
|
RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
|
||||||
|
|
||||||
|
Class[] typesToMatch = (FactoryBean.class.equals(typeToMatch) ?
|
||||||
|
new Class[] {typeToMatch} : new Class[] {FactoryBean.class, typeToMatch});
|
||||||
|
|
||||||
// Check decorated bean definition, if any: We assume it'll be easier
|
// Check decorated bean definition, if any: We assume it'll be easier
|
||||||
// to determine the decorated bean's type than the proxy's type.
|
// to determine the decorated bean's type than the proxy's type.
|
||||||
BeanDefinitionHolder dbd = mbd.getDecoratedDefinition();
|
BeanDefinitionHolder dbd = mbd.getDecoratedDefinition();
|
||||||
if (dbd != null && !BeanFactoryUtils.isFactoryDereference(name)) {
|
if (dbd != null && !BeanFactoryUtils.isFactoryDereference(name)) {
|
||||||
RootBeanDefinition tbd = getMergedBeanDefinition(dbd.getBeanName(), dbd.getBeanDefinition(), mbd);
|
RootBeanDefinition tbd = getMergedBeanDefinition(dbd.getBeanName(), dbd.getBeanDefinition(), mbd);
|
||||||
Class<?> targetClass = predictBeanType(dbd.getBeanName(), tbd, FactoryBean.class, typeToMatch);
|
Class<?> targetClass = predictBeanType(dbd.getBeanName(), tbd, typesToMatch);
|
||||||
if (targetClass != null && !FactoryBean.class.isAssignableFrom(targetClass)) {
|
if (targetClass != null && !FactoryBean.class.isAssignableFrom(targetClass)) {
|
||||||
return typeToMatch.isAssignableFrom(targetClass);
|
return typeToMatch.isAssignableFrom(targetClass);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Class<?> beanClass = predictBeanType(beanName, mbd, FactoryBean.class, typeToMatch);
|
Class<?> beanClass = predictBeanType(beanName, mbd, typesToMatch);
|
||||||
if (beanClass == null) {
|
if (beanClass == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
@ -1332,9 +1335,8 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
|
||||||
* @param mbd the corresponding bean definition
|
* @param mbd the corresponding bean definition
|
||||||
*/
|
*/
|
||||||
protected boolean isFactoryBean(String beanName, RootBeanDefinition mbd) {
|
protected boolean isFactoryBean(String beanName, RootBeanDefinition mbd) {
|
||||||
Class<?> predictedType = predictBeanType(beanName, mbd, FactoryBean.class);
|
Class<?> beanClass = predictBeanType(beanName, mbd, FactoryBean.class);
|
||||||
return (predictedType != null && FactoryBean.class.isAssignableFrom(predictedType)) ||
|
return (beanClass != null && FactoryBean.class.isAssignableFrom(beanClass));
|
||||||
(mbd.hasBeanClass() && FactoryBean.class.isAssignableFrom(mbd.getBeanClass()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
@ -16,11 +16,11 @@
|
||||||
|
|
||||||
package org.springframework.beans.factory.xml;
|
package org.springframework.beans.factory.xml;
|
||||||
|
|
||||||
|
import org.w3c.dom.Document;
|
||||||
|
|
||||||
import org.springframework.beans.factory.BeanDefinitionStoreException;
|
import org.springframework.beans.factory.BeanDefinitionStoreException;
|
||||||
import org.springframework.core.env.Environment;
|
import org.springframework.core.env.Environment;
|
||||||
|
|
||||||
import org.w3c.dom.Document;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* SPI for parsing an XML document that contains Spring bean definitions.
|
* SPI for parsing an XML document that contains Spring bean definitions.
|
||||||
* Used by XmlBeanDefinitionReader for actually parsing a DOM document.
|
* Used by XmlBeanDefinitionReader for actually parsing a DOM document.
|
||||||
|
|
@ -38,20 +38,21 @@ import org.w3c.dom.Document;
|
||||||
public interface BeanDefinitionDocumentReader {
|
public interface BeanDefinitionDocumentReader {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Read bean definitions from the given DOM document,
|
* Set the Environment to use when reading bean definitions.
|
||||||
* and register them with the given bean factory.
|
* <p>Used for evaluating profile information to determine whether a
|
||||||
|
* {@code <beans/>} document/element should be included or ignored.
|
||||||
|
*/
|
||||||
|
void setEnvironment(Environment environment);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read bean definitions from the given DOM document and
|
||||||
|
* register them with the registry in the given reader context.
|
||||||
* @param doc the DOM document
|
* @param doc the DOM document
|
||||||
* @param readerContext the current context of the reader. Includes the resource being parsed
|
* @param readerContext the current context of the reader
|
||||||
|
* (includes the target registry and the resource being parsed)
|
||||||
* @throws BeanDefinitionStoreException in case of parsing errors
|
* @throws BeanDefinitionStoreException in case of parsing errors
|
||||||
*/
|
*/
|
||||||
void registerBeanDefinitions(Document doc, XmlReaderContext readerContext)
|
void registerBeanDefinitions(Document doc, XmlReaderContext readerContext)
|
||||||
throws BeanDefinitionStoreException;
|
throws BeanDefinitionStoreException;
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the Environment to use when reading bean definitions. Used for evaluating
|
|
||||||
* profile information to determine whether a {@code <beans/>} document/element should
|
|
||||||
* be included or omitted.
|
|
||||||
*/
|
|
||||||
void setEnvironment(Environment environment);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
@ -72,16 +72,15 @@ public class DefaultBeanDefinitionDocumentReader implements BeanDefinitionDocume
|
||||||
|
|
||||||
public static final String RESOURCE_ATTRIBUTE = "resource";
|
public static final String RESOURCE_ATTRIBUTE = "resource";
|
||||||
|
|
||||||
/** @see org.springframework.context.annotation.Profile */
|
|
||||||
public static final String PROFILE_ATTRIBUTE = "profile";
|
public static final String PROFILE_ATTRIBUTE = "profile";
|
||||||
|
|
||||||
|
|
||||||
protected final Log logger = LogFactory.getLog(getClass());
|
protected final Log logger = LogFactory.getLog(getClass());
|
||||||
|
|
||||||
private XmlReaderContext readerContext;
|
|
||||||
|
|
||||||
private Environment environment;
|
private Environment environment;
|
||||||
|
|
||||||
|
private XmlReaderContext readerContext;
|
||||||
|
|
||||||
private BeanDefinitionParserDelegate delegate;
|
private BeanDefinitionParserDelegate delegate;
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -104,13 +103,12 @@ public class DefaultBeanDefinitionDocumentReader implements BeanDefinitionDocume
|
||||||
*/
|
*/
|
||||||
public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
|
public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
|
||||||
this.readerContext = readerContext;
|
this.readerContext = readerContext;
|
||||||
|
|
||||||
logger.debug("Loading bean definitions");
|
logger.debug("Loading bean definitions");
|
||||||
Element root = doc.getDocumentElement();
|
Element root = doc.getDocumentElement();
|
||||||
|
|
||||||
doRegisterBeanDefinitions(root);
|
doRegisterBeanDefinitions(root);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Register each bean definition within the given root {@code <beans/>} element.
|
* Register each bean definition within the given root {@code <beans/>} element.
|
||||||
* @throws IllegalStateException if {@code <beans profile="..."} attribute is present
|
* @throws IllegalStateException if {@code <beans profile="..."} attribute is present
|
||||||
|
|
@ -120,21 +118,22 @@ public class DefaultBeanDefinitionDocumentReader implements BeanDefinitionDocume
|
||||||
protected void doRegisterBeanDefinitions(Element root) {
|
protected void doRegisterBeanDefinitions(Element root) {
|
||||||
String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
|
String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
|
||||||
if (StringUtils.hasText(profileSpec)) {
|
if (StringUtils.hasText(profileSpec)) {
|
||||||
Assert.state(this.environment != null, "environment property must not be null");
|
Assert.state(this.environment != null, "Environment must be set for evaluating profiles");
|
||||||
String[] specifiedProfiles = StringUtils.tokenizeToStringArray(profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);
|
String[] specifiedProfiles = StringUtils.tokenizeToStringArray(
|
||||||
|
profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);
|
||||||
if (!this.environment.acceptsProfiles(specifiedProfiles)) {
|
if (!this.environment.acceptsProfiles(specifiedProfiles)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// any nested <beans> elements will cause recursion in this method. In
|
// Any nested <beans> elements will cause recursion in this method. In
|
||||||
// order to propagate and preserve <beans> default-* attributes correctly,
|
// order to propagate and preserve <beans> default-* attributes correctly,
|
||||||
// keep track of the current (parent) delegate, which may be null. Create
|
// keep track of the current (parent) delegate, which may be null. Create
|
||||||
// the new (child) delegate with a reference to the parent for fallback purposes,
|
// the new (child) delegate with a reference to the parent for fallback purposes,
|
||||||
// then ultimately reset this.delegate back to its original (parent) reference.
|
// then ultimately reset this.delegate back to its original (parent) reference.
|
||||||
// this behavior emulates a stack of delegates without actually necessitating one.
|
// this behavior emulates a stack of delegates without actually necessitating one.
|
||||||
BeanDefinitionParserDelegate parent = this.delegate;
|
BeanDefinitionParserDelegate parent = this.delegate;
|
||||||
this.delegate = createHelper(readerContext, root, parent);
|
this.delegate = createHelper(this.readerContext, root, parent);
|
||||||
|
|
||||||
preProcessXml(root);
|
preProcessXml(root);
|
||||||
parseBeanDefinitions(root, this.delegate);
|
parseBeanDefinitions(root, this.delegate);
|
||||||
|
|
@ -143,7 +142,9 @@ public class DefaultBeanDefinitionDocumentReader implements BeanDefinitionDocume
|
||||||
this.delegate = parent;
|
this.delegate = parent;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected BeanDefinitionParserDelegate createHelper(XmlReaderContext readerContext, Element root, BeanDefinitionParserDelegate parentDelegate) {
|
protected BeanDefinitionParserDelegate createHelper(
|
||||||
|
XmlReaderContext readerContext, Element root, BeanDefinitionParserDelegate parentDelegate) {
|
||||||
|
|
||||||
BeanDefinitionParserDelegate delegate = new BeanDefinitionParserDelegate(readerContext, environment);
|
BeanDefinitionParserDelegate delegate = new BeanDefinitionParserDelegate(readerContext, environment);
|
||||||
delegate.initDefaults(root, parentDelegate);
|
delegate.initDefaults(root, parentDelegate);
|
||||||
return delegate;
|
return delegate;
|
||||||
|
|
|
||||||
|
|
@ -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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
@ -22,6 +22,8 @@ import static org.junit.Assert.*;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import org.springframework.beans.BeansException;
|
||||||
import org.springframework.beans.factory.FactoryBean;
|
import org.springframework.beans.factory.FactoryBean;
|
||||||
import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessorAdapter;
|
import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessorAdapter;
|
||||||
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
|
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
|
||||||
|
|
@ -49,6 +51,8 @@ public class Spr8954Tests {
|
||||||
assertThat(bf.getBean("foo"), instanceOf(Foo.class));
|
assertThat(bf.getBean("foo"), instanceOf(Foo.class));
|
||||||
assertThat(bf.getBean("&foo"), instanceOf(FooFactoryBean.class));
|
assertThat(bf.getBean("&foo"), instanceOf(FooFactoryBean.class));
|
||||||
|
|
||||||
|
assertThat(bf.isTypeMatch("&foo", FactoryBean.class), is(true));
|
||||||
|
|
||||||
@SuppressWarnings("rawtypes")
|
@SuppressWarnings("rawtypes")
|
||||||
Map<String, FactoryBean> fbBeans = bf.getBeansOfType(FactoryBean.class);
|
Map<String, FactoryBean> fbBeans = bf.getBeansOfType(FactoryBean.class);
|
||||||
assertThat(1, equalTo(fbBeans.size()));
|
assertThat(1, equalTo(fbBeans.size()));
|
||||||
|
|
@ -59,6 +63,25 @@ public class Spr8954Tests {
|
||||||
assertThat("&foo", equalTo(aiBeans.keySet().iterator().next()));
|
assertThat("&foo", equalTo(aiBeans.keySet().iterator().next()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void findsBeansByTypeIfNotInstantiated() {
|
||||||
|
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
|
||||||
|
bf.registerBeanDefinition("foo", new RootBeanDefinition(FooFactoryBean.class));
|
||||||
|
bf.addBeanPostProcessor(new PredictingBPP());
|
||||||
|
|
||||||
|
assertThat(bf.isTypeMatch("&foo", FactoryBean.class), is(true));
|
||||||
|
|
||||||
|
@SuppressWarnings("rawtypes")
|
||||||
|
Map<String, FactoryBean> fbBeans = bf.getBeansOfType(FactoryBean.class);
|
||||||
|
assertThat(1, equalTo(fbBeans.size()));
|
||||||
|
assertThat("&foo", equalTo(fbBeans.keySet().iterator().next()));
|
||||||
|
|
||||||
|
Map<String, AnInterface> aiBeans = bf.getBeansOfType(AnInterface.class);
|
||||||
|
assertThat(1, equalTo(aiBeans.size()));
|
||||||
|
assertThat("&foo", equalTo(aiBeans.keySet().iterator().next()));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static class FooFactoryBean implements FactoryBean<Foo>, AnInterface {
|
static class FooFactoryBean implements FactoryBean<Foo>, AnInterface {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -84,7 +107,9 @@ public class Spr8954Tests {
|
||||||
}
|
}
|
||||||
|
|
||||||
interface PredictedType {
|
interface PredictedType {
|
||||||
|
}
|
||||||
|
|
||||||
|
static class PredictedTypeImpl implements PredictedType {
|
||||||
}
|
}
|
||||||
|
|
||||||
static class PredictingBPP extends InstantiationAwareBeanPostProcessorAdapter {
|
static class PredictingBPP extends InstantiationAwareBeanPostProcessorAdapter {
|
||||||
|
|
@ -92,8 +117,8 @@ public class Spr8954Tests {
|
||||||
@Override
|
@Override
|
||||||
public Class<?> predictBeanType(Class<?> beanClass, String beanName) {
|
public Class<?> predictBeanType(Class<?> beanClass, String beanName) {
|
||||||
return FactoryBean.class.isAssignableFrom(beanClass) ?
|
return FactoryBean.class.isAssignableFrom(beanClass) ?
|
||||||
PredictedType.class :
|
PredictedType.class : null;
|
||||||
super.predictBeanType(beanClass, beanName);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with 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;
|
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.
|
* Execute the annotated method with a fixed period between invocations.
|
||||||
* @return the period in milliseconds
|
* @return the period in milliseconds
|
||||||
*/
|
*/
|
||||||
long fixedRate() default -1;
|
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
|
* Number of milliseconds to delay before the first execution of a
|
||||||
* {@link #fixedRate()} or {@link #fixedDelay()} task.
|
* {@link #fixedRate()} or {@link #fixedDelay()} task.
|
||||||
* @return the initial delay in milliseconds
|
* @return the initial delay in milliseconds
|
||||||
* @since 3.2
|
* @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 "";
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
@ -17,7 +17,6 @@
|
||||||
package org.springframework.scheduling.annotation;
|
package org.springframework.scheduling.annotation;
|
||||||
|
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.concurrent.ScheduledExecutorService;
|
import java.util.concurrent.ScheduledExecutorService;
|
||||||
|
|
@ -111,53 +110,115 @@ public class ScheduledAnnotationBeanPostProcessor
|
||||||
public void doWith(Method method) throws IllegalArgumentException, IllegalAccessException {
|
public void doWith(Method method) throws IllegalArgumentException, IllegalAccessException {
|
||||||
Scheduled annotation = AnnotationUtils.getAnnotation(method, Scheduled.class);
|
Scheduled annotation = AnnotationUtils.getAnnotation(method, Scheduled.class);
|
||||||
if (annotation != null) {
|
if (annotation != null) {
|
||||||
Assert.isTrue(void.class.equals(method.getReturnType()),
|
try {
|
||||||
"Only void-returning methods may be annotated with @Scheduled.");
|
Assert.isTrue(void.class.equals(method.getReturnType()),
|
||||||
Assert.isTrue(method.getParameterTypes().length == 0,
|
"Only void-returning methods may be annotated with @Scheduled");
|
||||||
"Only no-arg methods may be annotated with @Scheduled.");
|
Assert.isTrue(method.getParameterTypes().length == 0,
|
||||||
if (AopUtils.isJdkDynamicProxy(bean)) {
|
"Only no-arg methods may be annotated with @Scheduled");
|
||||||
try {
|
if (AopUtils.isJdkDynamicProxy(bean)) {
|
||||||
// found a @Scheduled method on the target class for this JDK proxy -> is it
|
try {
|
||||||
// also present on the proxy itself?
|
// found a @Scheduled method on the target class for this JDK proxy -> is it
|
||||||
method = bean.getClass().getMethod(method.getName(), method.getParameterTypes());
|
// 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) {
|
Runnable runnable = new ScheduledMethodRunnable(bean, method);
|
||||||
ReflectionUtils.handleReflectionException(ex);
|
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) {
|
// Check cron expression
|
||||||
throw new IllegalStateException(String.format(
|
String cron = annotation.cron();
|
||||||
"@Scheduled method '%s' found on bean target class '%s', " +
|
if (!"".equals(cron)) {
|
||||||
"but not found in any interface(s) for bean JDK proxy. Either " +
|
Assert.isTrue(initialDelay == -1, "'initialDelay' not supported for cron triggers");
|
||||||
"pull the method up to an interface or switch to subclass (CGLIB) " +
|
processedSchedule = true;
|
||||||
"proxies by setting proxy-target-class/proxyTargetClass " +
|
if (embeddedValueResolver != null) {
|
||||||
"attribute to 'true'", method.getName(), targetClass.getSimpleName()));
|
cron = embeddedValueResolver.resolveStringValue(cron);
|
||||||
|
}
|
||||||
|
registrar.addCronTask(new CronTask(runnable, cron));
|
||||||
}
|
}
|
||||||
}
|
// At this point we don't need to differentiate between initial delay set or not anymore
|
||||||
Runnable runnable = new ScheduledMethodRunnable(bean, method);
|
if (initialDelay < 0) {
|
||||||
boolean processedSchedule = false;
|
initialDelay = 0;
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
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();
|
catch (IllegalArgumentException ex) {
|
||||||
long fixedDelay = annotation.fixedDelay();
|
throw new IllegalStateException(
|
||||||
if (fixedDelay >= 0) {
|
"Encountered invalid @Scheduled method '" + method.getName() + "': " + ex.getMessage());
|
||||||
Assert.isTrue(!processedSchedule, errorMessage);
|
|
||||||
processedSchedule = true;
|
|
||||||
registrar.addFixedDelayTask(new IntervalTask(runnable, fixedDelay, initialDelay));
|
|
||||||
}
|
}
|
||||||
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) {
|
if (event.getApplicationContext() != this.applicationContext) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Map<String, SchedulingConfigurer> configurers =
|
Map<String, SchedulingConfigurer> configurers =
|
||||||
this.applicationContext.getBeansOfType(SchedulingConfigurer.class);
|
this.applicationContext.getBeansOfType(SchedulingConfigurer.class);
|
||||||
|
|
||||||
if (this.scheduler != null) {
|
if (this.scheduler != null) {
|
||||||
this.registrar.setScheduler(this.scheduler);
|
this.registrar.setScheduler(this.scheduler);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (SchedulingConfigurer configurer : configurers.values()) {
|
for (SchedulingConfigurer configurer : configurers.values()) {
|
||||||
configurer.configureTasks(this.registrar);
|
configurer.configureTasks(this.registrar);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.registrar.hasTasks() && this.registrar.getScheduler() == null) {
|
if (this.registrar.hasTasks() && this.registrar.getScheduler() == null) {
|
||||||
Map<String, ? super Object> schedulers = new HashMap<String, Object>();
|
Map<String, ? super Object> schedulers = new HashMap<String, Object>();
|
||||||
schedulers.putAll(applicationContext.getBeansOfType(TaskScheduler.class));
|
schedulers.putAll(applicationContext.getBeansOfType(TaskScheduler.class));
|
||||||
|
|
@ -199,7 +256,6 @@ public class ScheduledAnnotationBeanPostProcessor
|
||||||
"configureTasks() callback. Found the following beans: " + schedulers.keySet());
|
"configureTasks() callback. Found the following beans: " + schedulers.keySet());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.registrar.afterPropertiesSet();
|
this.registrar.afterPropertiesSet();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with 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) {
|
public IntervalTask(Runnable runnable, long interval, long initialDelay) {
|
||||||
super(runnable);
|
super(runnable);
|
||||||
this.initialDelay = initialDelay;
|
|
||||||
this.interval = interval;
|
this.interval = interval;
|
||||||
|
this.initialDelay = initialDelay;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -59,10 +59,11 @@ public class IntervalTask extends Task {
|
||||||
|
|
||||||
|
|
||||||
public long getInterval() {
|
public long getInterval() {
|
||||||
return interval;
|
return this.interval;
|
||||||
}
|
}
|
||||||
|
|
||||||
public long getInitialDelay() {
|
public long getInitialDelay() {
|
||||||
return initialDelay;
|
return this.initialDelay;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
@ -69,6 +69,7 @@ public class CronSequenceGenerator {
|
||||||
|
|
||||||
private final TimeZone timeZone;
|
private final TimeZone timeZone;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct a {@link CronSequenceGenerator} from the pattern provided.
|
* Construct a {@link CronSequenceGenerator} from the pattern provided.
|
||||||
* @param expression a space-separated list of time fields
|
* @param expression a space-separated list of time fields
|
||||||
|
|
@ -81,6 +82,7 @@ public class CronSequenceGenerator {
|
||||||
parse(expression);
|
parse(expression);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the next {@link Date} in the sequence matching the Cron pattern and
|
* 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
|
* after the value provided. The return value will have a whole number of
|
||||||
|
|
@ -135,7 +137,8 @@ public class CronSequenceGenerator {
|
||||||
int updateMinute = findNext(this.minutes, minute, calendar, Calendar.MINUTE, Calendar.HOUR_OF_DAY, resets);
|
int updateMinute = findNext(this.minutes, minute, calendar, Calendar.MINUTE, Calendar.HOUR_OF_DAY, resets);
|
||||||
if (minute == updateMinute) {
|
if (minute == updateMinute) {
|
||||||
resets.add(Calendar.MINUTE);
|
resets.add(Calendar.MINUTE);
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
doNext(calendar, dot);
|
doNext(calendar, dot);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -143,7 +146,8 @@ public class CronSequenceGenerator {
|
||||||
int updateHour = findNext(this.hours, hour, calendar, Calendar.HOUR_OF_DAY, Calendar.DAY_OF_WEEK, resets);
|
int updateHour = findNext(this.hours, hour, calendar, Calendar.HOUR_OF_DAY, Calendar.DAY_OF_WEEK, resets);
|
||||||
if (hour == updateHour) {
|
if (hour == updateHour) {
|
||||||
resets.add(Calendar.HOUR_OF_DAY);
|
resets.add(Calendar.HOUR_OF_DAY);
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
doNext(calendar, dot);
|
doNext(calendar, dot);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -152,7 +156,8 @@ public class CronSequenceGenerator {
|
||||||
int updateDayOfMonth = findNextDay(calendar, this.daysOfMonth, dayOfMonth, daysOfWeek, dayOfWeek, resets);
|
int updateDayOfMonth = findNextDay(calendar, this.daysOfMonth, dayOfMonth, daysOfWeek, dayOfWeek, resets);
|
||||||
if (dayOfMonth == updateDayOfMonth) {
|
if (dayOfMonth == updateDayOfMonth) {
|
||||||
resets.add(Calendar.DAY_OF_MONTH);
|
resets.add(Calendar.DAY_OF_MONTH);
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
doNext(calendar, dot);
|
doNext(calendar, dot);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -160,7 +165,8 @@ public class CronSequenceGenerator {
|
||||||
int updateMonth = findNext(this.months, month, calendar, Calendar.MONTH, Calendar.YEAR, resets);
|
int updateMonth = findNext(this.months, month, calendar, Calendar.MONTH, Calendar.YEAR, resets);
|
||||||
if (month != updateMonth) {
|
if (month != updateMonth) {
|
||||||
if (calendar.get(Calendar.YEAR) - dot > 4) {
|
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);
|
doNext(calendar, dot);
|
||||||
}
|
}
|
||||||
|
|
@ -181,7 +187,7 @@ public class CronSequenceGenerator {
|
||||||
reset(calendar, resets);
|
reset(calendar, resets);
|
||||||
}
|
}
|
||||||
if (count >= max) {
|
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;
|
return dayOfMonth;
|
||||||
}
|
}
|
||||||
|
|
@ -222,7 +228,8 @@ public class CronSequenceGenerator {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parsing logic invoked by the constructor.
|
|
||||||
|
// Parsing logic invoked by the constructor
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parse the given pattern expression.
|
* Parse the given pattern expression.
|
||||||
|
|
@ -230,8 +237,8 @@ public class CronSequenceGenerator {
|
||||||
private void parse(String expression) throws IllegalArgumentException {
|
private void parse(String expression) throws IllegalArgumentException {
|
||||||
String[] fields = StringUtils.tokenizeToStringArray(expression, " ");
|
String[] fields = StringUtils.tokenizeToStringArray(expression, " ");
|
||||||
if (fields.length != 6) {
|
if (fields.length != 6) {
|
||||||
throw new IllegalArgumentException(String.format(""
|
throw new IllegalArgumentException(String.format(
|
||||||
+ "cron expression must consist of 6 fields (found %d in %s)", fields.length, expression));
|
"Cron expression must consist of 6 fields (found %d in \"%s\")", fields.length, expression));
|
||||||
}
|
}
|
||||||
setNumberHits(this.seconds, fields[0], 0, 60);
|
setNumberHits(this.seconds, fields[0], 0, 60);
|
||||||
setNumberHits(this.minutes, fields[1], 0, 60);
|
setNumberHits(this.minutes, fields[1], 0, 60);
|
||||||
|
|
@ -296,10 +303,12 @@ public class CronSequenceGenerator {
|
||||||
// Not an incrementer so it must be a range (possibly empty)
|
// Not an incrementer so it must be a range (possibly empty)
|
||||||
int[] range = getRange(field, min, max);
|
int[] range = getRange(field, min, max);
|
||||||
bits.set(range[0], range[1] + 1);
|
bits.set(range[0], range[1] + 1);
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
String[] split = StringUtils.delimitedListToStringArray(field, "/");
|
String[] split = StringUtils.delimitedListToStringArray(field, "/");
|
||||||
if (split.length > 2) {
|
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);
|
int[] range = getRange(split[0], min, max);
|
||||||
if (!split[0].contains("-")) {
|
if (!split[0].contains("-")) {
|
||||||
|
|
@ -322,19 +331,23 @@ public class CronSequenceGenerator {
|
||||||
}
|
}
|
||||||
if (!field.contains("-")) {
|
if (!field.contains("-")) {
|
||||||
result[0] = result[1] = Integer.valueOf(field);
|
result[0] = result[1] = Integer.valueOf(field);
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
String[] split = StringUtils.delimitedListToStringArray(field, "-");
|
String[] split = StringUtils.delimitedListToStringArray(field, "-");
|
||||||
if (split.length > 2) {
|
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[0] = Integer.valueOf(split[0]);
|
||||||
result[1] = Integer.valueOf(split[1]);
|
result[1] = Integer.valueOf(split[1]);
|
||||||
}
|
}
|
||||||
if (result[0] >= max || result[1] >= max) {
|
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) {
|
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;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with 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.BeanDefinitionDefaults;
|
||||||
import org.springframework.beans.factory.support.GenericBeanDefinition;
|
import org.springframework.beans.factory.support.GenericBeanDefinition;
|
||||||
import org.springframework.beans.factory.xml.AbstractBeanDefinitionParser;
|
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.ParserContext;
|
||||||
import org.springframework.beans.factory.xml.XmlReaderContext;
|
import org.springframework.beans.factory.xml.XmlReaderContext;
|
||||||
import org.springframework.scripting.support.ScriptFactoryPostProcessor;
|
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 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 INIT_METHOD_ATTRIBUTE = "init-method";
|
||||||
|
|
||||||
private static final String DESTROY_METHOD_ATTRIBUTE = "destroy-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);
|
String dependencyCheck = element.getAttribute(DEPENDENCY_CHECK_ATTRIBUTE);
|
||||||
bd.setDependencyCheck(parserContext.getDelegate().getDependencyCheck(dependencyCheck));
|
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
|
// Retrieve the defaults for bean definitions within this parser context
|
||||||
BeanDefinitionDefaults beanDefinitionDefaults = parserContext.getDelegate().getBeanDefinitionDefaults();
|
BeanDefinitionDefaults beanDefinitionDefaults = parserContext.getDelegate().getBeanDefinitionDefaults();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -82,7 +82,7 @@
|
||||||
<xsd:annotation>
|
<xsd:annotation>
|
||||||
<xsd:documentation source="java:org.springframework.core.io.Resource"><![CDATA[
|
<xsd:documentation source="java:org.springframework.core.io.Resource"><![CDATA[
|
||||||
The resource containing the script for the dynamic language-backed bean.
|
The resource containing the script for the dynamic language-backed bean.
|
||||||
|
|
||||||
Examples might be '/WEB-INF/scripts/Anais.groovy', 'classpath:Nin.bsh', etc.
|
Examples might be '/WEB-INF/scripts/Anais.groovy', 'classpath:Nin.bsh', etc.
|
||||||
]]></xsd:documentation>
|
]]></xsd:documentation>
|
||||||
</xsd:annotation>
|
</xsd:annotation>
|
||||||
|
|
@ -137,13 +137,13 @@
|
||||||
<xsd:attribute name="depends-on" type="xsd:string">
|
<xsd:attribute name="depends-on" type="xsd:string">
|
||||||
<xsd:annotation>
|
<xsd:annotation>
|
||||||
<xsd:documentation><![CDATA[
|
<xsd:documentation><![CDATA[
|
||||||
The names of the beans that this bean depends on being initialized.
|
The names of the beans that this bean depends on being initialized.
|
||||||
The bean factory will guarantee that these beans get initialized
|
The bean factory will guarantee that these beans get initialized
|
||||||
before this bean.
|
before this bean.
|
||||||
|
|
||||||
Note that dependencies are normally expressed through bean properties.
|
Note that dependencies are normally expressed through bean properties.
|
||||||
This property should just be necessary other kinds of dependencies
|
This property should just be necessary for other kinds of dependencies
|
||||||
like statics (*ugh*) or database preparation on startup.
|
like statics (*ugh*) or database preparation on startup.
|
||||||
]]></xsd:documentation>
|
]]></xsd:documentation>
|
||||||
</xsd:annotation>
|
</xsd:annotation>
|
||||||
</xsd:attribute>
|
</xsd:attribute>
|
||||||
|
|
|
||||||
|
|
@ -82,7 +82,7 @@
|
||||||
<xsd:annotation>
|
<xsd:annotation>
|
||||||
<xsd:documentation source="java:org.springframework.core.io.Resource"><![CDATA[
|
<xsd:documentation source="java:org.springframework.core.io.Resource"><![CDATA[
|
||||||
The resource containing the script for the dynamic language-backed bean.
|
The resource containing the script for the dynamic language-backed bean.
|
||||||
|
|
||||||
Examples might be '/WEB-INF/scripts/Anais.groovy', 'classpath:Nin.bsh', etc.
|
Examples might be '/WEB-INF/scripts/Anais.groovy', 'classpath:Nin.bsh', etc.
|
||||||
]]></xsd:documentation>
|
]]></xsd:documentation>
|
||||||
</xsd:annotation>
|
</xsd:annotation>
|
||||||
|
|
@ -127,13 +127,13 @@
|
||||||
<xsd:attribute name="depends-on" type="xsd:string">
|
<xsd:attribute name="depends-on" type="xsd:string">
|
||||||
<xsd:annotation>
|
<xsd:annotation>
|
||||||
<xsd:documentation><![CDATA[
|
<xsd:documentation><![CDATA[
|
||||||
The names of the beans that this bean depends on being initialized.
|
The names of the beans that this bean depends on being initialized.
|
||||||
The bean factory will guarantee that these beans get initialized
|
The bean factory will guarantee that these beans get initialized
|
||||||
before this bean.
|
before this bean.
|
||||||
|
|
||||||
Note that dependencies are normally expressed through bean properties.
|
Note that dependencies are normally expressed through bean properties.
|
||||||
This property should just be necessary other kinds of dependencies
|
This property should just be necessary for other kinds of dependencies
|
||||||
like statics (*ugh*) or database preparation on startup.
|
like statics (*ugh*) or database preparation on startup.
|
||||||
]]></xsd:documentation>
|
]]></xsd:documentation>
|
||||||
</xsd:annotation>
|
</xsd:annotation>
|
||||||
</xsd:attribute>
|
</xsd:attribute>
|
||||||
|
|
|
||||||
|
|
@ -147,13 +147,13 @@
|
||||||
<xsd:attribute name="depends-on" type="xsd:string">
|
<xsd:attribute name="depends-on" type="xsd:string">
|
||||||
<xsd:annotation>
|
<xsd:annotation>
|
||||||
<xsd:documentation><![CDATA[
|
<xsd:documentation><![CDATA[
|
||||||
The names of the beans that this bean depends on being initialized.
|
The names of the beans that this bean depends on being initialized.
|
||||||
The bean factory will guarantee that these beans get initialized
|
The bean factory will guarantee that these beans get initialized
|
||||||
before this bean.
|
before this bean.
|
||||||
|
|
||||||
Note that dependencies are normally expressed through bean properties.
|
Note that dependencies are normally expressed through bean properties.
|
||||||
This property should just be necessary other kinds of dependencies
|
This property should just be necessary for other kinds of dependencies
|
||||||
like statics (*ugh*) or database preparation on startup.
|
like statics (*ugh*) or database preparation on startup.
|
||||||
]]></xsd:documentation>
|
]]></xsd:documentation>
|
||||||
</xsd:annotation>
|
</xsd:annotation>
|
||||||
</xsd:attribute>
|
</xsd:attribute>
|
||||||
|
|
|
||||||
|
|
@ -147,13 +147,13 @@
|
||||||
<xsd:attribute name="depends-on" type="xsd:string">
|
<xsd:attribute name="depends-on" type="xsd:string">
|
||||||
<xsd:annotation>
|
<xsd:annotation>
|
||||||
<xsd:documentation><![CDATA[
|
<xsd:documentation><![CDATA[
|
||||||
The names of the beans that this bean depends on being initialized.
|
The names of the beans that this bean depends on being initialized.
|
||||||
The bean factory will guarantee that these beans get initialized
|
The bean factory will guarantee that these beans get initialized
|
||||||
before this bean.
|
before this bean.
|
||||||
|
|
||||||
Note that dependencies are normally expressed through bean properties.
|
Note that dependencies are normally expressed through bean properties.
|
||||||
This property should just be necessary other kinds of dependencies
|
This property should just be necessary for other kinds of dependencies
|
||||||
like statics (*ugh*) or database preparation on startup.
|
like statics (*ugh*) or database preparation on startup.
|
||||||
]]></xsd:documentation>
|
]]></xsd:documentation>
|
||||||
</xsd:annotation>
|
</xsd:annotation>
|
||||||
</xsd:attribute>
|
</xsd:attribute>
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,132 @@
|
||||||
|
/*
|
||||||
|
* 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.context.annotation;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.FactoryBean;
|
||||||
|
import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessorAdapter;
|
||||||
|
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
|
||||||
|
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||||
|
|
||||||
|
import static org.hamcrest.CoreMatchers.*;
|
||||||
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unit tests for SPR-8954, in which a custom {@link InstantiationAwareBeanPostProcessor}
|
||||||
|
* forces the predicted type of a FactoryBean, effectively preventing retrieval of the
|
||||||
|
* bean from calls to #getBeansOfType(FactoryBean.class). The implementation of
|
||||||
|
* {@link AbstractBeanFactory#isFactoryBean(String, RootBeanDefinition)} now ensures
|
||||||
|
* that not only the predicted bean type is considered, but also the original bean
|
||||||
|
* definition's beanClass.
|
||||||
|
*
|
||||||
|
* @author Chris Beams
|
||||||
|
* @author Oliver Gierke
|
||||||
|
*/
|
||||||
|
public class ConfigurationClassSpr8954Tests {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void repro() {
|
||||||
|
AnnotationConfigApplicationContext bf = new AnnotationConfigApplicationContext();
|
||||||
|
bf.registerBeanDefinition("fooConfig", new RootBeanDefinition(FooConfig.class));
|
||||||
|
bf.getBeanFactory().addBeanPostProcessor(new PredictingBPP());
|
||||||
|
bf.refresh();
|
||||||
|
|
||||||
|
assertThat(bf.getBean("foo"), instanceOf(Foo.class));
|
||||||
|
assertThat(bf.getBean("&foo"), instanceOf(FooFactoryBean.class));
|
||||||
|
|
||||||
|
assertThat(bf.isTypeMatch("&foo", FactoryBean.class), is(true));
|
||||||
|
|
||||||
|
@SuppressWarnings("rawtypes")
|
||||||
|
Map<String, FactoryBean> fbBeans = bf.getBeansOfType(FactoryBean.class);
|
||||||
|
assertThat(1, equalTo(fbBeans.size()));
|
||||||
|
assertThat("&foo", equalTo(fbBeans.keySet().iterator().next()));
|
||||||
|
|
||||||
|
Map<String, AnInterface> aiBeans = bf.getBeansOfType(AnInterface.class);
|
||||||
|
assertThat(1, equalTo(aiBeans.size()));
|
||||||
|
assertThat("&foo", equalTo(aiBeans.keySet().iterator().next()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void findsBeansByTypeIfNotInstantiated() {
|
||||||
|
AnnotationConfigApplicationContext bf = new AnnotationConfigApplicationContext();
|
||||||
|
bf.registerBeanDefinition("fooConfig", new RootBeanDefinition(FooConfig.class));
|
||||||
|
bf.getBeanFactory().addBeanPostProcessor(new PredictingBPP());
|
||||||
|
bf.refresh();
|
||||||
|
|
||||||
|
assertThat(bf.isTypeMatch("&foo", FactoryBean.class), is(true));
|
||||||
|
|
||||||
|
@SuppressWarnings("rawtypes")
|
||||||
|
Map<String, FactoryBean> fbBeans = bf.getBeansOfType(FactoryBean.class);
|
||||||
|
assertThat(1, equalTo(fbBeans.size()));
|
||||||
|
assertThat("&foo", equalTo(fbBeans.keySet().iterator().next()));
|
||||||
|
|
||||||
|
Map<String, AnInterface> aiBeans = bf.getBeansOfType(AnInterface.class);
|
||||||
|
assertThat(1, equalTo(aiBeans.size()));
|
||||||
|
assertThat("&foo", equalTo(aiBeans.keySet().iterator().next()));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static class FooConfig {
|
||||||
|
|
||||||
|
@Bean FooFactoryBean foo() {
|
||||||
|
return new FooFactoryBean();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static class FooFactoryBean implements FactoryBean<Foo>, AnInterface {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Foo getObject() throws Exception {
|
||||||
|
return new Foo();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Class<?> getObjectType() {
|
||||||
|
return Foo.class;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isSingleton() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
interface AnInterface {
|
||||||
|
}
|
||||||
|
|
||||||
|
static class Foo {
|
||||||
|
}
|
||||||
|
|
||||||
|
interface PredictedType {
|
||||||
|
}
|
||||||
|
|
||||||
|
static class PredictedTypeImpl implements PredictedType {
|
||||||
|
}
|
||||||
|
|
||||||
|
static class PredictingBPP extends InstantiationAwareBeanPostProcessorAdapter {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Class<?> predictBeanType(Class<?> beanClass, String beanName) {
|
||||||
|
return FactoryBean.class.isAssignableFrom(beanClass) ?
|
||||||
|
PredictedType.class : null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -26,6 +26,7 @@ import java.util.List;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import org.springframework.beans.DirectFieldAccessor;
|
import org.springframework.beans.DirectFieldAccessor;
|
||||||
import org.springframework.beans.factory.BeanCreationException;
|
import org.springframework.beans.factory.BeanCreationException;
|
||||||
import org.springframework.beans.factory.config.BeanDefinition;
|
import org.springframework.beans.factory.config.BeanDefinition;
|
||||||
|
|
@ -52,8 +53,7 @@ public class ScheduledAnnotationBeanPostProcessorTests {
|
||||||
public void fixedDelayTask() {
|
public void fixedDelayTask() {
|
||||||
StaticApplicationContext context = new StaticApplicationContext();
|
StaticApplicationContext context = new StaticApplicationContext();
|
||||||
BeanDefinition processorDefinition = new RootBeanDefinition(ScheduledAnnotationBeanPostProcessor.class);
|
BeanDefinition processorDefinition = new RootBeanDefinition(ScheduledAnnotationBeanPostProcessor.class);
|
||||||
BeanDefinition targetDefinition = new RootBeanDefinition(
|
BeanDefinition targetDefinition = new RootBeanDefinition(FixedDelayTestBean.class);
|
||||||
ScheduledAnnotationBeanPostProcessorTests.FixedDelayTestBean.class);
|
|
||||||
context.registerBeanDefinition("postProcessor", processorDefinition);
|
context.registerBeanDefinition("postProcessor", processorDefinition);
|
||||||
context.registerBeanDefinition("target", targetDefinition);
|
context.registerBeanDefinition("target", targetDefinition);
|
||||||
context.refresh();
|
context.refresh();
|
||||||
|
|
@ -106,8 +106,7 @@ public class ScheduledAnnotationBeanPostProcessorTests {
|
||||||
public void fixedRateTaskWithInitialDelay() {
|
public void fixedRateTaskWithInitialDelay() {
|
||||||
StaticApplicationContext context = new StaticApplicationContext();
|
StaticApplicationContext context = new StaticApplicationContext();
|
||||||
BeanDefinition processorDefinition = new RootBeanDefinition(ScheduledAnnotationBeanPostProcessor.class);
|
BeanDefinition processorDefinition = new RootBeanDefinition(ScheduledAnnotationBeanPostProcessor.class);
|
||||||
BeanDefinition targetDefinition = new RootBeanDefinition(
|
BeanDefinition targetDefinition = new RootBeanDefinition(FixedRateWithInitialDelayTestBean.class);
|
||||||
ScheduledAnnotationBeanPostProcessorTests.FixedRateWithInitialDelayTestBean.class);
|
|
||||||
context.registerBeanDefinition("postProcessor", processorDefinition);
|
context.registerBeanDefinition("postProcessor", processorDefinition);
|
||||||
context.registerBeanDefinition("target", targetDefinition);
|
context.registerBeanDefinition("target", targetDefinition);
|
||||||
context.refresh();
|
context.refresh();
|
||||||
|
|
@ -162,8 +161,7 @@ public class ScheduledAnnotationBeanPostProcessorTests {
|
||||||
public void metaAnnotationWithFixedRate() {
|
public void metaAnnotationWithFixedRate() {
|
||||||
StaticApplicationContext context = new StaticApplicationContext();
|
StaticApplicationContext context = new StaticApplicationContext();
|
||||||
BeanDefinition processorDefinition = new RootBeanDefinition(ScheduledAnnotationBeanPostProcessor.class);
|
BeanDefinition processorDefinition = new RootBeanDefinition(ScheduledAnnotationBeanPostProcessor.class);
|
||||||
BeanDefinition targetDefinition = new RootBeanDefinition(
|
BeanDefinition targetDefinition = new RootBeanDefinition(MetaAnnotationFixedRateTestBean.class);
|
||||||
ScheduledAnnotationBeanPostProcessorTests.MetaAnnotationFixedRateTestBean.class);
|
|
||||||
context.registerBeanDefinition("postProcessor", processorDefinition);
|
context.registerBeanDefinition("postProcessor", processorDefinition);
|
||||||
context.registerBeanDefinition("target", targetDefinition);
|
context.registerBeanDefinition("target", targetDefinition);
|
||||||
context.refresh();
|
context.refresh();
|
||||||
|
|
@ -211,7 +209,7 @@ public class ScheduledAnnotationBeanPostProcessorTests {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void propertyPlaceholderWithCronExpression() {
|
public void propertyPlaceholderWithCron() {
|
||||||
String businessHoursCronExpression = "0 0 9-17 * * MON-FRI";
|
String businessHoursCronExpression = "0 0 9-17 * * MON-FRI";
|
||||||
StaticApplicationContext context = new StaticApplicationContext();
|
StaticApplicationContext context = new StaticApplicationContext();
|
||||||
BeanDefinition processorDefinition = new RootBeanDefinition(ScheduledAnnotationBeanPostProcessor.class);
|
BeanDefinition processorDefinition = new RootBeanDefinition(ScheduledAnnotationBeanPostProcessor.class);
|
||||||
|
|
@ -219,8 +217,7 @@ public class ScheduledAnnotationBeanPostProcessorTests {
|
||||||
Properties properties = new Properties();
|
Properties properties = new Properties();
|
||||||
properties.setProperty("schedules.businessHours", businessHoursCronExpression);
|
properties.setProperty("schedules.businessHours", businessHoursCronExpression);
|
||||||
placeholderDefinition.getPropertyValues().addPropertyValue("properties", properties);
|
placeholderDefinition.getPropertyValues().addPropertyValue("properties", properties);
|
||||||
BeanDefinition targetDefinition = new RootBeanDefinition(
|
BeanDefinition targetDefinition = new RootBeanDefinition(PropertyPlaceholderWithCronTestBean.class);
|
||||||
ScheduledAnnotationBeanPostProcessorTests.PropertyPlaceholderTestBean.class);
|
|
||||||
context.registerBeanDefinition("placeholder", placeholderDefinition);
|
context.registerBeanDefinition("placeholder", placeholderDefinition);
|
||||||
context.registerBeanDefinition("postProcessor", processorDefinition);
|
context.registerBeanDefinition("postProcessor", processorDefinition);
|
||||||
context.registerBeanDefinition("target", targetDefinition);
|
context.registerBeanDefinition("target", targetDefinition);
|
||||||
|
|
@ -242,6 +239,70 @@ public class ScheduledAnnotationBeanPostProcessorTests {
|
||||||
assertEquals(businessHoursCronExpression, task.getExpression());
|
assertEquals(businessHoursCronExpression, task.getExpression());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void propertyPlaceholderWithFixedDelay() {
|
||||||
|
StaticApplicationContext context = new StaticApplicationContext();
|
||||||
|
BeanDefinition processorDefinition = new RootBeanDefinition(ScheduledAnnotationBeanPostProcessor.class);
|
||||||
|
BeanDefinition placeholderDefinition = new RootBeanDefinition(PropertyPlaceholderConfigurer.class);
|
||||||
|
Properties properties = new Properties();
|
||||||
|
properties.setProperty("fixedDelay", "5000");
|
||||||
|
properties.setProperty("initialDelay", "1000");
|
||||||
|
placeholderDefinition.getPropertyValues().addPropertyValue("properties", properties);
|
||||||
|
BeanDefinition targetDefinition = new RootBeanDefinition(PropertyPlaceholderWithFixedDelayTestBean.class);
|
||||||
|
context.registerBeanDefinition("placeholder", placeholderDefinition);
|
||||||
|
context.registerBeanDefinition("postProcessor", processorDefinition);
|
||||||
|
context.registerBeanDefinition("target", targetDefinition);
|
||||||
|
context.refresh();
|
||||||
|
Object postProcessor = context.getBean("postProcessor");
|
||||||
|
Object target = context.getBean("target");
|
||||||
|
ScheduledTaskRegistrar registrar = (ScheduledTaskRegistrar)
|
||||||
|
new DirectFieldAccessor(postProcessor).getPropertyValue("registrar");
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
List<IntervalTask> fixedDelayTasks = (List<IntervalTask>)
|
||||||
|
new DirectFieldAccessor(registrar).getPropertyValue("fixedDelayTasks");
|
||||||
|
assertEquals(1, fixedDelayTasks.size());
|
||||||
|
IntervalTask task = fixedDelayTasks.get(0);
|
||||||
|
ScheduledMethodRunnable runnable = (ScheduledMethodRunnable) task.getRunnable();
|
||||||
|
Object targetObject = runnable.getTarget();
|
||||||
|
Method targetMethod = runnable.getMethod();
|
||||||
|
assertEquals(target, targetObject);
|
||||||
|
assertEquals("fixedDelay", targetMethod.getName());
|
||||||
|
assertEquals(1000L, task.getInitialDelay());
|
||||||
|
assertEquals(5000L, task.getInterval());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void propertyPlaceholderWithFixedRate() {
|
||||||
|
StaticApplicationContext context = new StaticApplicationContext();
|
||||||
|
BeanDefinition processorDefinition = new RootBeanDefinition(ScheduledAnnotationBeanPostProcessor.class);
|
||||||
|
BeanDefinition placeholderDefinition = new RootBeanDefinition(PropertyPlaceholderConfigurer.class);
|
||||||
|
Properties properties = new Properties();
|
||||||
|
properties.setProperty("fixedRate", "3000");
|
||||||
|
properties.setProperty("initialDelay", "1000");
|
||||||
|
placeholderDefinition.getPropertyValues().addPropertyValue("properties", properties);
|
||||||
|
BeanDefinition targetDefinition = new RootBeanDefinition(PropertyPlaceholderWithFixedRateTestBean.class);
|
||||||
|
context.registerBeanDefinition("placeholder", placeholderDefinition);
|
||||||
|
context.registerBeanDefinition("postProcessor", processorDefinition);
|
||||||
|
context.registerBeanDefinition("target", targetDefinition);
|
||||||
|
context.refresh();
|
||||||
|
Object postProcessor = context.getBean("postProcessor");
|
||||||
|
Object target = context.getBean("target");
|
||||||
|
ScheduledTaskRegistrar registrar = (ScheduledTaskRegistrar)
|
||||||
|
new DirectFieldAccessor(postProcessor).getPropertyValue("registrar");
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
List<IntervalTask> fixedRateTasks = (List<IntervalTask>)
|
||||||
|
new DirectFieldAccessor(registrar).getPropertyValue("fixedRateTasks");
|
||||||
|
assertEquals(1, fixedRateTasks.size());
|
||||||
|
IntervalTask task = fixedRateTasks.get(0);
|
||||||
|
ScheduledMethodRunnable runnable = (ScheduledMethodRunnable) task.getRunnable();
|
||||||
|
Object targetObject = runnable.getTarget();
|
||||||
|
Method targetMethod = runnable.getMethod();
|
||||||
|
assertEquals(target, targetObject);
|
||||||
|
assertEquals("fixedRate", targetMethod.getName());
|
||||||
|
assertEquals(1000L, task.getInitialDelay());
|
||||||
|
assertEquals(3000L, task.getInterval());
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void propertyPlaceholderForMetaAnnotation() {
|
public void propertyPlaceholderForMetaAnnotation() {
|
||||||
String businessHoursCronExpression = "0 0 9-17 * * MON-FRI";
|
String businessHoursCronExpression = "0 0 9-17 * * MON-FRI";
|
||||||
|
|
@ -285,7 +346,7 @@ public class ScheduledAnnotationBeanPostProcessorTests {
|
||||||
context.refresh();
|
context.refresh();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(expected = IllegalArgumentException.class)
|
@Test(expected = BeanCreationException.class)
|
||||||
public void invalidCron() throws Throwable {
|
public void invalidCron() throws Throwable {
|
||||||
StaticApplicationContext context = new StaticApplicationContext();
|
StaticApplicationContext context = new StaticApplicationContext();
|
||||||
BeanDefinition processorDefinition = new RootBeanDefinition(ScheduledAnnotationBeanPostProcessor.class);
|
BeanDefinition processorDefinition = new RootBeanDefinition(ScheduledAnnotationBeanPostProcessor.class);
|
||||||
|
|
@ -293,12 +354,7 @@ public class ScheduledAnnotationBeanPostProcessorTests {
|
||||||
ScheduledAnnotationBeanPostProcessorTests.InvalidCronTestBean.class);
|
ScheduledAnnotationBeanPostProcessorTests.InvalidCronTestBean.class);
|
||||||
context.registerBeanDefinition("postProcessor", processorDefinition);
|
context.registerBeanDefinition("postProcessor", processorDefinition);
|
||||||
context.registerBeanDefinition("target", targetDefinition);
|
context.registerBeanDefinition("target", targetDefinition);
|
||||||
try {
|
context.refresh();
|
||||||
context.refresh();
|
|
||||||
fail("expected exception");
|
|
||||||
} catch (BeanCreationException ex) {
|
|
||||||
throw ex.getRootCause();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(expected = BeanCreationException.class)
|
@Test(expected = BeanCreationException.class)
|
||||||
|
|
@ -342,7 +398,7 @@ public class ScheduledAnnotationBeanPostProcessorTests {
|
||||||
|
|
||||||
static class FixedRateWithInitialDelayTestBean {
|
static class FixedRateWithInitialDelayTestBean {
|
||||||
|
|
||||||
@Scheduled(initialDelay=1000, fixedRate=3000)
|
@Scheduled(fixedRate=3000, initialDelay=1000)
|
||||||
public void fixedRate() {
|
public void fixedRate() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -395,13 +451,13 @@ public class ScheduledAnnotationBeanPostProcessorTests {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Scheduled(fixedRate = 5000)
|
@Scheduled(fixedRate=5000)
|
||||||
@Target(ElementType.METHOD)
|
@Target(ElementType.METHOD)
|
||||||
@Retention(RetentionPolicy.RUNTIME)
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
private static @interface EveryFiveSeconds {}
|
private static @interface EveryFiveSeconds {}
|
||||||
|
|
||||||
|
|
||||||
@Scheduled(cron = "0 0 * * * ?")
|
@Scheduled(cron="0 0 * * * ?")
|
||||||
@Target(ElementType.METHOD)
|
@Target(ElementType.METHOD)
|
||||||
@Retention(RetentionPolicy.RUNTIME)
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
private static @interface Hourly {}
|
private static @interface Hourly {}
|
||||||
|
|
@ -423,7 +479,7 @@ public class ScheduledAnnotationBeanPostProcessorTests {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static class PropertyPlaceholderTestBean {
|
static class PropertyPlaceholderWithCronTestBean {
|
||||||
|
|
||||||
@Scheduled(cron = "${schedules.businessHours}")
|
@Scheduled(cron = "${schedules.businessHours}")
|
||||||
public void x() {
|
public void x() {
|
||||||
|
|
@ -431,7 +487,23 @@ public class ScheduledAnnotationBeanPostProcessorTests {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Scheduled(cron = "${schedules.businessHours}")
|
static class PropertyPlaceholderWithFixedDelayTestBean {
|
||||||
|
|
||||||
|
@Scheduled(fixedDelayString="${fixedDelay}", initialDelayString="${initialDelay}")
|
||||||
|
public void fixedDelay() {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static class PropertyPlaceholderWithFixedRateTestBean {
|
||||||
|
|
||||||
|
@Scheduled(fixedRateString="${fixedRate}", initialDelayString="${initialDelay}")
|
||||||
|
public void fixedRate() {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Scheduled(cron="${schedules.businessHours}")
|
||||||
@Target(ElementType.METHOD)
|
@Target(ElementType.METHOD)
|
||||||
@Retention(RetentionPolicy.RUNTIME)
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
private static @interface BusinessHours {}
|
private static @interface BusinessHours {}
|
||||||
|
|
|
||||||
|
|
@ -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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
@ -487,7 +487,7 @@ public class CronTriggerTests {
|
||||||
assertEquals(calendar.getTime(), date = trigger.nextExecutionTime(context2));
|
assertEquals(calendar.getTime(), date = trigger.nextExecutionTime(context2));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(expected=IllegalStateException.class)
|
@Test(expected = IllegalArgumentException.class)
|
||||||
public void testNonExistentSpecificDate() throws Exception {
|
public void testNonExistentSpecificDate() throws Exception {
|
||||||
// TODO: maybe try and detect this as a special case in parser?
|
// TODO: maybe try and detect this as a special case in parser?
|
||||||
CronTrigger trigger = new CronTrigger("0 0 0 31 6 *", timeZone);
|
CronTrigger trigger = new CronTrigger("0 0 0 31 6 *", timeZone);
|
||||||
|
|
|
||||||
|
|
@ -16,31 +16,22 @@
|
||||||
|
|
||||||
package org.springframework.scripting.groovy;
|
package org.springframework.scripting.groovy;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
|
||||||
import static org.junit.Assert.assertFalse;
|
|
||||||
import static org.junit.Assert.assertNotNull;
|
|
||||||
import static org.junit.Assert.assertNotSame;
|
|
||||||
import static org.junit.Assert.assertSame;
|
|
||||||
import static org.junit.Assert.assertTrue;
|
|
||||||
import static org.junit.Assert.fail;
|
|
||||||
import static org.mockito.BDDMockito.given;
|
|
||||||
import static org.mockito.Mockito.mock;
|
|
||||||
import groovy.lang.DelegatingMetaClass;
|
|
||||||
import groovy.lang.GroovyObject;
|
|
||||||
|
|
||||||
import java.io.FileNotFoundException;
|
import java.io.FileNotFoundException;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
import groovy.lang.DelegatingMetaClass;
|
||||||
|
import groovy.lang.GroovyObject;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Ignore;
|
import org.junit.Ignore;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import org.springframework.aop.support.AopUtils;
|
import org.springframework.aop.support.AopUtils;
|
||||||
import org.springframework.aop.target.dynamic.Refreshable;
|
import org.springframework.aop.target.dynamic.Refreshable;
|
||||||
import org.springframework.tests.sample.beans.TestBean;
|
|
||||||
import org.springframework.beans.factory.BeanCreationException;
|
import org.springframework.beans.factory.BeanCreationException;
|
||||||
import org.springframework.beans.factory.FactoryBean;
|
import org.springframework.beans.factory.FactoryBean;
|
||||||
import org.springframework.beans.factory.UnsatisfiedDependencyException;
|
import org.springframework.beans.factory.UnsatisfiedDependencyException;
|
||||||
|
import org.springframework.beans.factory.config.BeanDefinition;
|
||||||
import org.springframework.context.ApplicationContext;
|
import org.springframework.context.ApplicationContext;
|
||||||
import org.springframework.context.support.ClassPathXmlApplicationContext;
|
import org.springframework.context.support.ClassPathXmlApplicationContext;
|
||||||
import org.springframework.core.NestedRuntimeException;
|
import org.springframework.core.NestedRuntimeException;
|
||||||
|
|
@ -56,6 +47,12 @@ import org.springframework.scripting.support.ScriptFactoryPostProcessor;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
import org.springframework.tests.Assume;
|
import org.springframework.tests.Assume;
|
||||||
import org.springframework.tests.TestGroup;
|
import org.springframework.tests.TestGroup;
|
||||||
|
import org.springframework.tests.sample.beans.TestBean;
|
||||||
|
import org.springframework.util.ObjectUtils;
|
||||||
|
|
||||||
|
import static org.junit.Assert.*;
|
||||||
|
import static org.mockito.BDDMockito.*;
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Rob Harrop
|
* @author Rob Harrop
|
||||||
|
|
@ -350,7 +347,9 @@ public class GroovyScriptFactoryTests {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testInlineScriptFromTag() throws Exception {
|
public void testInlineScriptFromTag() throws Exception {
|
||||||
ApplicationContext ctx = new ClassPathXmlApplicationContext("groovy-with-xsd.xml", getClass());
|
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("groovy-with-xsd.xml", getClass());
|
||||||
|
BeanDefinition bd = ctx.getBeanFactory().getBeanDefinition("calculator");
|
||||||
|
assertTrue(ObjectUtils.containsElement(bd.getDependsOn(), "messenger"));
|
||||||
Calculator calculator = (Calculator) ctx.getBean("calculator");
|
Calculator calculator = (Calculator) ctx.getBean("calculator");
|
||||||
assertNotNull(calculator);
|
assertNotNull(calculator);
|
||||||
assertFalse(calculator instanceof Refreshable);
|
assertFalse(calculator instanceof Refreshable);
|
||||||
|
|
|
||||||
|
|
@ -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
|
* 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
|
* use this file except in compliance with the License. You may obtain a copy of
|
||||||
|
|
@ -334,8 +334,9 @@ public abstract class Assert {
|
||||||
public static void isInstanceOf(Class type, Object obj, String message) {
|
public static void isInstanceOf(Class type, Object obj, String message) {
|
||||||
notNull(type, "Type to check against must not be null");
|
notNull(type, "Type to check against must not be null");
|
||||||
if (!type.isInstance(obj)) {
|
if (!type.isInstance(obj)) {
|
||||||
throw new IllegalArgumentException(message +
|
throw new IllegalArgumentException(
|
||||||
". Object of class [" + (obj != null ? obj.getClass().getName() : "null") +
|
(StringUtils.hasLength(message) ? message + " " : "") +
|
||||||
|
"Object of class [" + (obj != null ? obj.getClass().getName() : "null") +
|
||||||
"] must be an instance of " + type);
|
"] must be an instance of " + type);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
@ -24,7 +24,9 @@ import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.junit.Rule;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
import org.junit.rules.ExpectedException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Unit tests for the {@link Assert} class.
|
* Unit tests for the {@link Assert} class.
|
||||||
|
|
@ -36,6 +38,9 @@ import org.junit.Test;
|
||||||
*/
|
*/
|
||||||
public class AssertTests {
|
public class AssertTests {
|
||||||
|
|
||||||
|
@Rule
|
||||||
|
public ExpectedException thrown = ExpectedException.none();
|
||||||
|
|
||||||
@Test(expected = IllegalArgumentException.class)
|
@Test(expected = IllegalArgumentException.class)
|
||||||
public void instanceOf() {
|
public void instanceOf() {
|
||||||
final Set<?> set = new HashSet<Object>();
|
final Set<?> set = new HashSet<Object>();
|
||||||
|
|
@ -43,6 +48,22 @@ public class AssertTests {
|
||||||
Assert.isInstanceOf(HashMap.class, set);
|
Assert.isInstanceOf(HashMap.class, set);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void instanceOfNoMessage() throws Exception {
|
||||||
|
thrown.expect(IllegalArgumentException.class);
|
||||||
|
thrown.expectMessage("Object of class [java.lang.Object] must be an instance " +
|
||||||
|
"of interface java.util.Set");
|
||||||
|
Assert.isInstanceOf(Set.class, new Object(), null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void instanceOfMessage() throws Exception {
|
||||||
|
thrown.expect(IllegalArgumentException.class);
|
||||||
|
thrown.expectMessage("Custom message. Object of class [java.lang.Object] must " +
|
||||||
|
"be an instance of interface java.util.Set");
|
||||||
|
Assert.isInstanceOf(Set.class, new Object(), "Custom message.");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void isNullDoesNotThrowExceptionIfArgumentIsNullWithMessage() {
|
public void isNullDoesNotThrowExceptionIfArgumentIsNullWithMessage() {
|
||||||
Assert.isNull(null, "Bla");
|
Assert.isNull(null, "Bla");
|
||||||
|
|
|
||||||
|
|
@ -6,10 +6,13 @@ http://www.springsource.org
|
||||||
Changes in version 3.2.2 (2013-03-07)
|
Changes in version 3.2.2 (2013-03-07)
|
||||||
--------------------------------------
|
--------------------------------------
|
||||||
|
|
||||||
* official support for Hibernate 4.2
|
* official support for Hibernate 4.2 (SPR-10255)
|
||||||
* ConfigurationClassPostProcessor consistently uses ClassLoader, not loading core JDK annotations via ASM (SPR-10249)
|
* ConfigurationClassPostProcessor consistently uses ClassLoader, not loading core JDK annotations via ASM (SPR-10249)
|
||||||
* ConfigurationClassPostProcessor allows for overriding of scoped-proxy bean definitions (SPR-10265)
|
* ConfigurationClassPostProcessor allows for overriding of scoped-proxy bean definitions (SPR-10265)
|
||||||
|
* "depends-on" attribute on lang namespace element actually respected at runtime now (SPR-8625)
|
||||||
|
* allow for ordering of mixed AspectJ before/after advices (SPR-9438)
|
||||||
* added "maximumAutoGrowSize" property to SpelParserConfiguration (SPR-10229)
|
* added "maximumAutoGrowSize" property to SpelParserConfiguration (SPR-10229)
|
||||||
|
* @Scheduled provides String variants of fixedDelay, fixedRate, initialDelay for placeholder support (SPR-8067)
|
||||||
* SQLErrorCodeSQLExceptionTranslator tries to find SQLException with actual error code among causes (SPR-10260)
|
* SQLErrorCodeSQLExceptionTranslator tries to find SQLException with actual error code among causes (SPR-10260)
|
||||||
* DefaultMessageListenerContainer invokes specified ExceptionListener for recovery exceptions as well (SPR-10230)
|
* DefaultMessageListenerContainer invokes specified ExceptionListener for recovery exceptions as well (SPR-10230)
|
||||||
* DefaultMessageListenerContainer logs recovery failures at error level and exposes "isRecovering()" method (SPR-10230)
|
* DefaultMessageListenerContainer logs recovery failures at error level and exposes "isRecovering()" method (SPR-10230)
|
||||||
|
|
|
||||||
|
|
@ -13,18 +13,25 @@
|
||||||
<section xml:id="beans-factory-lifecycle">
|
<section xml:id="beans-factory-lifecycle">
|
||||||
<title>Lifecycle callbacks</title>
|
<title>Lifecycle callbacks</title>
|
||||||
|
|
||||||
<!-- MLP Beverly to review: Old Text: The Spring Framework provides several callback interfaces to
|
|
||||||
change the behavior of your bean in the container; they include -->
|
|
||||||
|
|
||||||
<para>To interact with the container's management of the bean lifecycle, you
|
<para>To interact with the container's management of the bean lifecycle, you
|
||||||
can implement the Spring <interfacename>InitializingBean</interfacename>
|
can implement the Spring <interfacename>InitializingBean</interfacename>
|
||||||
and <interfacename>DisposableBean</interfacename> interfaces. The
|
and <interfacename>DisposableBean</interfacename> interfaces. The
|
||||||
container calls <methodname>afterPropertiesSet()</methodname> for the
|
container calls <methodname>afterPropertiesSet()</methodname> for the
|
||||||
former and <methodname>destroy()</methodname> for the latter to allow the
|
former and <methodname>destroy()</methodname> for the latter to allow the
|
||||||
bean to perform certain actions upon initialization and destruction of
|
bean to perform certain actions upon initialization and destruction of
|
||||||
your beans. You can also achieve the same integration with the container
|
your beans.</para>
|
||||||
without coupling your classes to Spring interfaces through the use of
|
|
||||||
init-method and destroy method object definition metadata.</para>
|
<tip>
|
||||||
|
<para>The JSR-250 <interfacename>@PostConstruct</interfacename> and
|
||||||
|
<interfacename>@PreDestroy</interfacename> annotations are generally
|
||||||
|
considered best practice for receiving lifecycle callbacks in a modern
|
||||||
|
Spring application. Using these annotations means that your beans are not
|
||||||
|
coupled to Spring specific interfaces. For details see
|
||||||
|
<xref linkend="beans-postconstruct-and-predestroy-annotations"/>.</para>
|
||||||
|
<para>If you don't want to use the JSR-250 annotations but you are still
|
||||||
|
looking to remove coupling consider the use of init-method and destroy-method
|
||||||
|
object definition metadata.</para>
|
||||||
|
</tip>
|
||||||
|
|
||||||
<para>Internally, the Spring Framework uses
|
<para>Internally, the Spring Framework uses
|
||||||
<interfacename>BeanPostProcessor</interfacename> implementations to
|
<interfacename>BeanPostProcessor</interfacename> implementations to
|
||||||
|
|
@ -57,7 +64,9 @@
|
||||||
|
|
||||||
<para>It is recommended that you do not use the
|
<para>It is recommended that you do not use the
|
||||||
<interfacename>InitializingBean</interfacename> interface because it
|
<interfacename>InitializingBean</interfacename> interface because it
|
||||||
unnecessarily couples the code to Spring. Alternatively, specify a POJO
|
unnecessarily couples the code to Spring. Alternatively, use the
|
||||||
|
<link linkend="beans-postconstruct-and-predestroy-annotations">
|
||||||
|
<interfacename>@PostConstruct</interfacename> annotation</link> or specify a POJO
|
||||||
initialization method. In the case of XML-based configuration metadata,
|
initialization method. In the case of XML-based configuration metadata,
|
||||||
you use the <literal>init-method</literal> attribute to specify the name
|
you use the <literal>init-method</literal> attribute to specify the name
|
||||||
of the method that has a void no-argument signature. For example, the
|
of the method that has a void no-argument signature. For example, the
|
||||||
|
|
@ -99,7 +108,9 @@
|
||||||
|
|
||||||
<para>It is recommended that you do not use the
|
<para>It is recommended that you do not use the
|
||||||
<interfacename>DisposableBean</interfacename> callback interface because
|
<interfacename>DisposableBean</interfacename> callback interface because
|
||||||
it unnecessarily couples the code to Spring. Alternatively, specify a
|
it unnecessarily couples the code to Spring. Alternatively, use the
|
||||||
|
<link linkend="beans-postconstruct-and-predestroy-annotations">
|
||||||
|
<interfacename>@PreDestroy</interfacename> annotation</link> or specify a
|
||||||
generic method that is supported by bean definitions. With XML-based
|
generic method that is supported by bean definitions. With XML-based
|
||||||
configuration metadata, you use the <literal>destroy-method</literal>
|
configuration metadata, you use the <literal>destroy-method</literal>
|
||||||
attribute on the <literal><bean/></literal>. For example, the
|
attribute on the <literal><bean/></literal>. For example, the
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue