qualifier annotations and @Value can be used at method level as well (applying to all parameters);
fixed EL evaluation of prepared constructor arguments for repeated prototype creation git-svn-id: https://src.springframework.org/svn/spring-framework/trunk@799 50f2f4bb-b051-0410-bef5-90022cba6387
This commit is contained in:
parent
182acb9c87
commit
cc21b308e2
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2008 the original author or authors.
|
* Copyright 2002-2009 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,11 +22,13 @@ import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import org.springframework.beans.SimpleTypeConverter;
|
import org.springframework.beans.SimpleTypeConverter;
|
||||||
|
import org.springframework.beans.TypeConverter;
|
||||||
import org.springframework.beans.factory.config.BeanDefinitionHolder;
|
import org.springframework.beans.factory.config.BeanDefinitionHolder;
|
||||||
import org.springframework.beans.factory.config.DependencyDescriptor;
|
import org.springframework.beans.factory.config.DependencyDescriptor;
|
||||||
import org.springframework.beans.factory.support.AbstractBeanDefinition;
|
import org.springframework.beans.factory.support.AbstractBeanDefinition;
|
||||||
import org.springframework.beans.factory.support.AutowireCandidateQualifier;
|
import org.springframework.beans.factory.support.AutowireCandidateQualifier;
|
||||||
import org.springframework.beans.factory.support.AutowireCandidateResolver;
|
import org.springframework.beans.factory.support.AutowireCandidateResolver;
|
||||||
|
import org.springframework.core.MethodParameter;
|
||||||
import org.springframework.core.annotation.AnnotationUtils;
|
import org.springframework.core.annotation.AnnotationUtils;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
import org.springframework.util.ClassUtils;
|
import org.springframework.util.ClassUtils;
|
||||||
|
|
@ -111,7 +113,7 @@ public class QualifierAnnotationAutowireCandidateResolver implements AutowireCan
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determine if the provided bean definition is an autowire candidate.
|
* Determine whether the provided bean definition is an autowire candidate.
|
||||||
* <p>To be considered a candidate the bean's <em>autowire-candidate</em>
|
* <p>To be considered a candidate the bean's <em>autowire-candidate</em>
|
||||||
* attribute must not have been set to 'false'. Also if an annotation on
|
* attribute must not have been set to 'false'. Also if an annotation on
|
||||||
* the field or parameter to be autowired is recognized by this bean factory
|
* the field or parameter to be autowired is recognized by this bean factory
|
||||||
|
|
@ -120,68 +122,38 @@ public class QualifierAnnotationAutowireCandidateResolver implements AutowireCan
|
||||||
* the same qualifier or match by meta attributes. A "value" attribute will
|
* the same qualifier or match by meta attributes. A "value" attribute will
|
||||||
* fallback to match against the bean name or an alias if a qualifier or
|
* fallback to match against the bean name or an alias if a qualifier or
|
||||||
* attribute does not match.
|
* attribute does not match.
|
||||||
|
* @see Qualifier
|
||||||
*/
|
*/
|
||||||
public boolean isAutowireCandidate(BeanDefinitionHolder bdHolder, DependencyDescriptor descriptor) {
|
public boolean isAutowireCandidate(BeanDefinitionHolder bdHolder, DependencyDescriptor descriptor) {
|
||||||
if (!bdHolder.getBeanDefinition().isAutowireCandidate()) {
|
if (!bdHolder.getBeanDefinition().isAutowireCandidate()) {
|
||||||
// if explicitly false, do not proceed with qualifier check
|
// if explicitly false, do not proceed with qualifier check
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (descriptor == null || ObjectUtils.isEmpty(descriptor.getAnnotations())) {
|
if (descriptor == null) {
|
||||||
// no qualification necessary
|
// no qualification necessary
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
AbstractBeanDefinition bd = (AbstractBeanDefinition) bdHolder.getBeanDefinition();
|
boolean match = checkQualifiers(bdHolder, descriptor.getAnnotations());
|
||||||
|
if (match && descriptor.getMethodParameter() != null) {
|
||||||
|
match = checkQualifiers(bdHolder, descriptor.getMethodParameter().getAnnotations());
|
||||||
|
}
|
||||||
|
return match;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Match the given qualifier annotations against the candidate bean definition.
|
||||||
|
*/
|
||||||
|
protected boolean checkQualifiers(BeanDefinitionHolder bdHolder, Annotation[] annotationsToSearch) {
|
||||||
|
if (ObjectUtils.isEmpty(annotationsToSearch)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
SimpleTypeConverter typeConverter = new SimpleTypeConverter();
|
SimpleTypeConverter typeConverter = new SimpleTypeConverter();
|
||||||
Annotation[] annotations = descriptor.getAnnotations();
|
for (Annotation annotation : annotationsToSearch) {
|
||||||
for (Annotation annotation : annotations) {
|
|
||||||
Class<? extends Annotation> type = annotation.annotationType();
|
Class<? extends Annotation> type = annotation.annotationType();
|
||||||
if (isQualifier(type)) {
|
if (isQualifier(type)) {
|
||||||
AutowireCandidateQualifier qualifier = bd.getQualifier(type.getName());
|
if (!checkQualifier(bdHolder, annotation, typeConverter)) {
|
||||||
if (qualifier == null) {
|
|
||||||
qualifier = bd.getQualifier(ClassUtils.getShortName(type));
|
|
||||||
}
|
|
||||||
if (qualifier == null && bd.hasBeanClass()) {
|
|
||||||
// look for matching annotation on the target class
|
|
||||||
Class<?> beanClass = bd.getBeanClass();
|
|
||||||
Annotation targetAnnotation = beanClass.getAnnotation(type);
|
|
||||||
if (targetAnnotation != null && targetAnnotation.equals(annotation)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Map<String, Object> attributes = AnnotationUtils.getAnnotationAttributes(annotation);
|
|
||||||
if (attributes.isEmpty() && qualifier == null) {
|
|
||||||
// if no attributes, the qualifier must be present
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
for (Map.Entry<String, Object> entry : attributes.entrySet()) {
|
|
||||||
String attributeName = entry.getKey();
|
|
||||||
Object expectedValue = entry.getValue();
|
|
||||||
Object actualValue = null;
|
|
||||||
// check qualifier first
|
|
||||||
if (qualifier != null) {
|
|
||||||
actualValue = qualifier.getAttribute(attributeName);
|
|
||||||
}
|
|
||||||
if (actualValue == null) {
|
|
||||||
// fall back on bean definition attribute
|
|
||||||
actualValue = bd.getAttribute(attributeName);
|
|
||||||
}
|
|
||||||
if (actualValue == null && attributeName.equals(AutowireCandidateQualifier.VALUE_KEY) &&
|
|
||||||
(expectedValue.equals(bdHolder.getBeanName()) ||
|
|
||||||
ObjectUtils.containsElement(bdHolder.getAliases(), expectedValue))) {
|
|
||||||
// fall back on bean name (or alias) match
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (actualValue == null && qualifier != null) {
|
|
||||||
// fall back on default, but only if the qualifier is present
|
|
||||||
actualValue = AnnotationUtils.getDefaultValue(annotation, attributeName);
|
|
||||||
}
|
|
||||||
if (actualValue != null) {
|
|
||||||
actualValue = typeConverter.convertIfNecessary(actualValue, expectedValue.getClass());
|
|
||||||
}
|
|
||||||
if (!expectedValue.equals(actualValue)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -190,7 +162,7 @@ public class QualifierAnnotationAutowireCandidateResolver implements AutowireCan
|
||||||
/**
|
/**
|
||||||
* Checks whether the given annotation type is a recognized qualifier type.
|
* Checks whether the given annotation type is a recognized qualifier type.
|
||||||
*/
|
*/
|
||||||
private boolean isQualifier(Class<? extends Annotation> annotationType) {
|
protected boolean isQualifier(Class<? extends Annotation> annotationType) {
|
||||||
for (Class<? extends Annotation> qualifierType : this.qualifierTypes) {
|
for (Class<? extends Annotation> qualifierType : this.qualifierTypes) {
|
||||||
if (annotationType.equals(qualifierType) || annotationType.isAnnotationPresent(qualifierType)) {
|
if (annotationType.equals(qualifierType) || annotationType.isAnnotationPresent(qualifierType)) {
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -199,8 +171,84 @@ public class QualifierAnnotationAutowireCandidateResolver implements AutowireCan
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Match the given qualifier annotation against the candidate bean definition.
|
||||||
|
*/
|
||||||
|
protected boolean checkQualifier(
|
||||||
|
BeanDefinitionHolder bdHolder, Annotation annotation, TypeConverter typeConverter) {
|
||||||
|
|
||||||
|
Class<? extends Annotation> type = annotation.annotationType();
|
||||||
|
AbstractBeanDefinition bd = (AbstractBeanDefinition) bdHolder.getBeanDefinition();
|
||||||
|
AutowireCandidateQualifier qualifier = bd.getQualifier(type.getName());
|
||||||
|
if (qualifier == null) {
|
||||||
|
qualifier = bd.getQualifier(ClassUtils.getShortName(type));
|
||||||
|
}
|
||||||
|
if (qualifier == null && bd.hasBeanClass()) {
|
||||||
|
// look for matching annotation on the target class
|
||||||
|
Class<?> beanClass = bd.getBeanClass();
|
||||||
|
Annotation targetAnnotation = beanClass.getAnnotation(type);
|
||||||
|
if (targetAnnotation != null && targetAnnotation.equals(annotation)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Map<String, Object> attributes = AnnotationUtils.getAnnotationAttributes(annotation);
|
||||||
|
if (attributes.isEmpty() && qualifier == null) {
|
||||||
|
// if no attributes, the qualifier must be present
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
for (Map.Entry<String, Object> entry : attributes.entrySet()) {
|
||||||
|
String attributeName = entry.getKey();
|
||||||
|
Object expectedValue = entry.getValue();
|
||||||
|
Object actualValue = null;
|
||||||
|
// check qualifier first
|
||||||
|
if (qualifier != null) {
|
||||||
|
actualValue = qualifier.getAttribute(attributeName);
|
||||||
|
}
|
||||||
|
if (actualValue == null) {
|
||||||
|
// fall back on bean definition attribute
|
||||||
|
actualValue = bd.getAttribute(attributeName);
|
||||||
|
}
|
||||||
|
if (actualValue == null && attributeName.equals(AutowireCandidateQualifier.VALUE_KEY) &&
|
||||||
|
(expectedValue.equals(bdHolder.getBeanName()) ||
|
||||||
|
ObjectUtils.containsElement(bdHolder.getAliases(), expectedValue))) {
|
||||||
|
// fall back on bean name (or alias) match
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (actualValue == null && qualifier != null) {
|
||||||
|
// fall back on default, but only if the qualifier is present
|
||||||
|
actualValue = AnnotationUtils.getDefaultValue(annotation, attributeName);
|
||||||
|
}
|
||||||
|
if (actualValue != null) {
|
||||||
|
actualValue = typeConverter.convertIfNecessary(actualValue, expectedValue.getClass());
|
||||||
|
}
|
||||||
|
if (!expectedValue.equals(actualValue)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine whether the given dependency carries a value annotation.
|
||||||
|
* @see Value
|
||||||
|
*/
|
||||||
public Object getSuggestedValue(DependencyDescriptor descriptor) {
|
public Object getSuggestedValue(DependencyDescriptor descriptor) {
|
||||||
for (Annotation annotation : descriptor.getAnnotations()) {
|
Object value = findValue(descriptor.getAnnotations());
|
||||||
|
if (value == null) {
|
||||||
|
MethodParameter methodParam = descriptor.getMethodParameter();
|
||||||
|
if (methodParam != null) {
|
||||||
|
value = findValue(methodParam.getAnnotations());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine a suggested value from any of the given candidate annotations.
|
||||||
|
*/
|
||||||
|
protected Object findValue(Annotation[] annotationsToSearch) {
|
||||||
|
for (Annotation annotation : annotationsToSearch) {
|
||||||
if (this.valueAnnotationType.isInstance(annotation)) {
|
if (this.valueAnnotationType.isInstance(annotation)) {
|
||||||
Object value = AnnotationUtils.getValue(annotation);
|
Object value = AnnotationUtils.getValue(annotation);
|
||||||
if (value == null) {
|
if (value == null) {
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2008 the original author or authors.
|
* Copyright 2002-2009 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.
|
||||||
|
|
@ -34,7 +34,7 @@ import java.lang.annotation.Target;
|
||||||
* @see org.springframework.beans.factory.support.AutowireCandidateResolver#getSuggestedValue
|
* @see org.springframework.beans.factory.support.AutowireCandidateResolver#getSuggestedValue
|
||||||
*/
|
*/
|
||||||
@Retention(RetentionPolicy.RUNTIME)
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
@Target({ElementType.FIELD, ElementType.PARAMETER})
|
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER})
|
||||||
public @interface Value {
|
public @interface Value {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@
|
||||||
package org.springframework.beans.factory.support;
|
package org.springframework.beans.factory.support;
|
||||||
|
|
||||||
import java.lang.reflect.Constructor;
|
import java.lang.reflect.Constructor;
|
||||||
|
import java.lang.reflect.Member;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.lang.reflect.Modifier;
|
import java.lang.reflect.Modifier;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
|
@ -120,24 +121,7 @@ class ConstructorResolver {
|
||||||
// Found a cached constructor...
|
// Found a cached constructor...
|
||||||
argsToUse = mbd.resolvedConstructorArguments;
|
argsToUse = mbd.resolvedConstructorArguments;
|
||||||
if (argsToUse == null) {
|
if (argsToUse == null) {
|
||||||
Class[] paramTypes = constructorToUse.getParameterTypes();
|
argsToUse = resolvePreparedArguments(beanName, mbd, bw, constructorToUse);
|
||||||
Object[] argsToResolve = mbd.preparedConstructorArguments;
|
|
||||||
TypeConverter converter = (this.typeConverter != null ? this.typeConverter : bw);
|
|
||||||
BeanDefinitionValueResolver valueResolver =
|
|
||||||
new BeanDefinitionValueResolver(this.beanFactory, beanName, mbd, converter);
|
|
||||||
argsToUse = new Object[argsToResolve.length];
|
|
||||||
for (int i = 0; i < argsToResolve.length; i++) {
|
|
||||||
Object argValue = argsToResolve[i];
|
|
||||||
MethodParameter methodParam = new MethodParameter(constructorToUse, i);
|
|
||||||
GenericTypeResolver.resolveParameterType(methodParam, constructorToUse.getDeclaringClass());
|
|
||||||
if (argValue instanceof AutowiredArgumentMarker) {
|
|
||||||
argValue = resolveAutowiredArgument(methodParam, beanName, null, converter);
|
|
||||||
}
|
|
||||||
else if (argValue instanceof BeanMetadataElement) {
|
|
||||||
argValue = valueResolver.resolveValueIfNecessary("constructor argument", argValue);
|
|
||||||
}
|
|
||||||
argsToUse[i] = converter.convertIfNecessary(argValue, paramTypes[i], methodParam);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -317,24 +301,7 @@ class ConstructorResolver {
|
||||||
// Found a cached factory method...
|
// Found a cached factory method...
|
||||||
argsToUse = mbd.resolvedConstructorArguments;
|
argsToUse = mbd.resolvedConstructorArguments;
|
||||||
if (argsToUse == null) {
|
if (argsToUse == null) {
|
||||||
Class[] paramTypes = factoryMethodToUse.getParameterTypes();
|
argsToUse = resolvePreparedArguments(beanName, mbd, bw, factoryMethodToUse);
|
||||||
Object[] argsToResolve = mbd.preparedConstructorArguments;
|
|
||||||
TypeConverter converter = (this.typeConverter != null ? this.typeConverter : bw);
|
|
||||||
BeanDefinitionValueResolver valueResolver =
|
|
||||||
new BeanDefinitionValueResolver(this.beanFactory, beanName, mbd, converter);
|
|
||||||
argsToUse = new Object[argsToResolve.length];
|
|
||||||
for (int i = 0; i < argsToResolve.length; i++) {
|
|
||||||
Object argValue = argsToResolve[i];
|
|
||||||
MethodParameter methodParam = new MethodParameter(factoryMethodToUse, i);
|
|
||||||
GenericTypeResolver.resolveParameterType(methodParam, factoryClass);
|
|
||||||
if (argValue instanceof AutowiredArgumentMarker) {
|
|
||||||
argValue = resolveAutowiredArgument(methodParam, beanName, null, converter);
|
|
||||||
}
|
|
||||||
else if (argValue instanceof BeanMetadataElement) {
|
|
||||||
argValue = valueResolver.resolveValueIfNecessary("factory method argument", argValue);
|
|
||||||
}
|
|
||||||
argsToUse[i] = converter.convertIfNecessary(argValue, paramTypes[i], methodParam);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -615,6 +582,48 @@ class ConstructorResolver {
|
||||||
return args;
|
return args;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resolve the prepared arguments stored in the given bean definition.
|
||||||
|
*/
|
||||||
|
private Object[] resolvePreparedArguments(
|
||||||
|
String beanName, RootBeanDefinition mbd, BeanWrapper bw, Member methodOrCtor) {
|
||||||
|
|
||||||
|
Class[] paramTypes = (methodOrCtor instanceof Method ?
|
||||||
|
((Method) methodOrCtor).getParameterTypes() : ((Constructor) methodOrCtor).getParameterTypes());
|
||||||
|
Object[] argsToResolve = mbd.preparedConstructorArguments;
|
||||||
|
TypeConverter converter = (this.typeConverter != null ? this.typeConverter : bw);
|
||||||
|
BeanDefinitionValueResolver valueResolver =
|
||||||
|
new BeanDefinitionValueResolver(this.beanFactory, beanName, mbd, converter);
|
||||||
|
Object[] resolvedArgs = new Object[argsToResolve.length];
|
||||||
|
for (int argIndex = 0; argIndex < argsToResolve.length; argIndex++) {
|
||||||
|
Object argValue = argsToResolve[argIndex];
|
||||||
|
MethodParameter methodParam = MethodParameter.forMethodOrConstructor(methodOrCtor, argIndex);
|
||||||
|
GenericTypeResolver.resolveParameterType(methodParam, methodOrCtor.getDeclaringClass());
|
||||||
|
if (argValue instanceof AutowiredArgumentMarker) {
|
||||||
|
argValue = resolveAutowiredArgument(methodParam, beanName, null, converter);
|
||||||
|
}
|
||||||
|
else if (argValue instanceof BeanMetadataElement) {
|
||||||
|
argValue = valueResolver.resolveValueIfNecessary("constructor argument", argValue);
|
||||||
|
}
|
||||||
|
else if (argValue instanceof String) {
|
||||||
|
argValue = this.beanFactory.evaluateBeanDefinitionString((String) argValue, mbd);
|
||||||
|
}
|
||||||
|
Class paramType = paramTypes[argIndex];
|
||||||
|
try {
|
||||||
|
resolvedArgs[argIndex] = converter.convertIfNecessary(argValue, paramType, methodParam);
|
||||||
|
}
|
||||||
|
catch (TypeMismatchException ex) {
|
||||||
|
String methodType = (methodOrCtor instanceof Constructor ? "constructor" : "factory method");
|
||||||
|
throw new UnsatisfiedDependencyException(
|
||||||
|
mbd.getResourceDescription(), beanName, argIndex, paramType,
|
||||||
|
"Could not convert " + methodType + " argument value of type [" +
|
||||||
|
ObjectUtils.nullSafeClassName(argValue) +
|
||||||
|
"] to required type [" + paramType.getName() + "]: " + ex.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return resolvedArgs;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Template method for resolving the specified argument which is supposed to be autowired.
|
* Template method for resolving the specified argument which is supposed to be autowired.
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -106,6 +106,11 @@ public class ApplicationContextExpressionTests {
|
||||||
bd5.setScope("myScope");
|
bd5.setScope("myScope");
|
||||||
ac.registerBeanDefinition("tb5", bd5);
|
ac.registerBeanDefinition("tb5", bd5);
|
||||||
|
|
||||||
|
GenericBeanDefinition bd6 = new GenericBeanDefinition();
|
||||||
|
bd6.setBeanClass(PropertyValueTestBean.class);
|
||||||
|
bd6.setScope("myScope");
|
||||||
|
ac.registerBeanDefinition("tb6", bd6);
|
||||||
|
|
||||||
System.getProperties().put("country", "UK");
|
System.getProperties().put("country", "UK");
|
||||||
try {
|
try {
|
||||||
ac.refresh();
|
ac.refresh();
|
||||||
|
|
@ -138,6 +143,12 @@ public class ApplicationContextExpressionTests {
|
||||||
assertEquals(42, tb5.age);
|
assertEquals(42, tb5.age);
|
||||||
assertEquals("UK", tb5.country);
|
assertEquals("UK", tb5.country);
|
||||||
assertSame(tb0, tb5.tb);
|
assertSame(tb0, tb5.tb);
|
||||||
|
|
||||||
|
PropertyValueTestBean tb6 = ac.getBean("tb6", PropertyValueTestBean.class);
|
||||||
|
assertEquals("XXXmyNameYYY42ZZZ", tb6.name);
|
||||||
|
assertEquals(42, tb6.age);
|
||||||
|
assertEquals("UK", tb6.country);
|
||||||
|
assertSame(tb0, tb6.tb);
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
System.getProperties().remove("country");
|
System.getProperties().remove("country");
|
||||||
|
|
@ -153,12 +164,13 @@ public class ApplicationContextExpressionTests {
|
||||||
GenericApplicationContext ac = new GenericApplicationContext();
|
GenericApplicationContext ac = new GenericApplicationContext();
|
||||||
RootBeanDefinition rbd = new RootBeanDefinition(TestBean.class);
|
RootBeanDefinition rbd = new RootBeanDefinition(TestBean.class);
|
||||||
rbd.setScope(RootBeanDefinition.SCOPE_PROTOTYPE);
|
rbd.setScope(RootBeanDefinition.SCOPE_PROTOTYPE);
|
||||||
rbd.getPropertyValues().addPropertyValue("name", "juergen");
|
rbd.getConstructorArgumentValues().addGenericArgumentValue("#{systemProperties.name}");
|
||||||
rbd.getPropertyValues().addPropertyValue("country", "#{systemProperties.country}");
|
rbd.getPropertyValues().addPropertyValue("country", "#{systemProperties.country}");
|
||||||
ac.registerBeanDefinition("test", rbd);
|
ac.registerBeanDefinition("test", rbd);
|
||||||
ac.refresh();
|
ac.refresh();
|
||||||
StopWatch sw = new StopWatch();
|
StopWatch sw = new StopWatch();
|
||||||
sw.start("prototype");
|
sw.start("prototype");
|
||||||
|
System.getProperties().put("name", "juergen");
|
||||||
System.getProperties().put("country", "UK");
|
System.getProperties().put("country", "UK");
|
||||||
try {
|
try {
|
||||||
for (int i = 0; i < 100000; i++) {
|
for (int i = 0; i < 100000; i++) {
|
||||||
|
|
@ -170,6 +182,7 @@ public class ApplicationContextExpressionTests {
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
System.getProperties().remove("country");
|
System.getProperties().remove("country");
|
||||||
|
System.getProperties().remove("name");
|
||||||
}
|
}
|
||||||
System.out.println(sw.getTotalTimeMillis());
|
System.out.println(sw.getTotalTimeMillis());
|
||||||
assertTrue("Prototype creation took too long: " + sw.getTotalTimeMillis(), sw.getTotalTimeMillis() < 6000);
|
assertTrue("Prototype creation took too long: " + sw.getTotalTimeMillis(), sw.getTotalTimeMillis() < 6000);
|
||||||
|
|
@ -230,7 +243,7 @@ public class ApplicationContextExpressionTests {
|
||||||
public void configure(
|
public void configure(
|
||||||
@Qualifier("original") TestBean tb,
|
@Qualifier("original") TestBean tb,
|
||||||
@Value("XXX#{tb0.name}YYY#{mySpecialAttr}ZZZ") String name,
|
@Value("XXX#{tb0.name}YYY#{mySpecialAttr}ZZZ") String name,
|
||||||
@Value("#{mySpecialAttr}")int age,
|
@Value("#{mySpecialAttr}") int age,
|
||||||
@Value("#{systemProperties.country}") String country) {
|
@Value("#{systemProperties.country}") String country) {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.age = age;
|
this.age = age;
|
||||||
|
|
@ -239,4 +252,36 @@ public class ApplicationContextExpressionTests {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static class PropertyValueTestBean {
|
||||||
|
|
||||||
|
public String name;
|
||||||
|
|
||||||
|
public int age;
|
||||||
|
|
||||||
|
public String country;
|
||||||
|
|
||||||
|
public TestBean tb;
|
||||||
|
|
||||||
|
@Value("XXX#{tb0.name}YYY#{mySpecialAttr}ZZZ")
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Value("#{mySpecialAttr}")
|
||||||
|
public void setAge(int age) {
|
||||||
|
this.age = age;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Value("#{systemProperties.country}")
|
||||||
|
public void setCountry(String country) {
|
||||||
|
this.country = country;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Qualifier("original")
|
||||||
|
public void setTb(TestBean tb) {
|
||||||
|
this.tb = tb;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2008 the original author or authors.
|
* Copyright 2002-2009 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.
|
||||||
|
|
@ -19,8 +19,8 @@ package org.springframework.core;
|
||||||
import java.lang.annotation.Annotation;
|
import java.lang.annotation.Annotation;
|
||||||
import java.lang.reflect.Constructor;
|
import java.lang.reflect.Constructor;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.lang.reflect.TypeVariable;
|
|
||||||
import java.lang.reflect.Type;
|
import java.lang.reflect.Type;
|
||||||
|
import java.lang.reflect.TypeVariable;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
|
@ -177,7 +177,14 @@ public class MethodParameter {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the annotations associated with the method/constructor parameter.
|
* Return the annotations associated with the target method/constructor itself.
|
||||||
|
*/
|
||||||
|
public Annotation[] getAnnotations() {
|
||||||
|
return (this.method != null ? this.method.getAnnotations() : this.constructor.getAnnotations());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the annotations associated with the specific method/constructor parameter.
|
||||||
*/
|
*/
|
||||||
public Annotation[] getParameterAnnotations() {
|
public Annotation[] getParameterAnnotations() {
|
||||||
if (this.parameterAnnotations == null) {
|
if (this.parameterAnnotations == null) {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue