BeanFactory supports ObjectFactory as a dependency type for @Autowired and @Value (SPR-6079)
git-svn-id: https://src.springframework.org/svn/spring-framework/trunk@1850 50f2f4bb-b051-0410-bef5-90022cba6387
This commit is contained in:
parent
fd5b40d1cc
commit
1e16aecadd
|
|
@ -16,8 +16,12 @@
|
||||||
|
|
||||||
package org.springframework.beans.factory.config;
|
package org.springframework.beans.factory.config;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.ObjectInputStream;
|
||||||
|
import java.io.Serializable;
|
||||||
import java.lang.annotation.Annotation;
|
import java.lang.annotation.Annotation;
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
|
import java.lang.reflect.Type;
|
||||||
|
|
||||||
import org.springframework.core.GenericCollectionTypeResolver;
|
import org.springframework.core.GenericCollectionTypeResolver;
|
||||||
import org.springframework.core.MethodParameter;
|
import org.springframework.core.MethodParameter;
|
||||||
|
|
@ -32,17 +36,27 @@ import org.springframework.util.Assert;
|
||||||
* @author Juergen Hoeller
|
* @author Juergen Hoeller
|
||||||
* @since 2.5
|
* @since 2.5
|
||||||
*/
|
*/
|
||||||
public class DependencyDescriptor {
|
public class DependencyDescriptor implements Serializable {
|
||||||
|
|
||||||
private MethodParameter methodParameter;
|
private transient MethodParameter methodParameter;
|
||||||
|
|
||||||
private Field field;
|
private transient Field field;
|
||||||
|
|
||||||
|
private Class declaringClass;
|
||||||
|
|
||||||
|
private String methodName;
|
||||||
|
|
||||||
|
private Class[] parameterTypes;
|
||||||
|
|
||||||
|
private int parameterIndex;
|
||||||
|
|
||||||
|
private String fieldName;
|
||||||
|
|
||||||
private final boolean required;
|
private final boolean required;
|
||||||
|
|
||||||
private final boolean eager;
|
private final boolean eager;
|
||||||
|
|
||||||
private Annotation[] fieldAnnotations;
|
private transient Annotation[] fieldAnnotations;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -65,6 +79,15 @@ public class DependencyDescriptor {
|
||||||
public DependencyDescriptor(MethodParameter methodParameter, boolean required, boolean eager) {
|
public DependencyDescriptor(MethodParameter methodParameter, boolean required, boolean eager) {
|
||||||
Assert.notNull(methodParameter, "MethodParameter must not be null");
|
Assert.notNull(methodParameter, "MethodParameter must not be null");
|
||||||
this.methodParameter = methodParameter;
|
this.methodParameter = methodParameter;
|
||||||
|
this.declaringClass = methodParameter.getDeclaringClass();
|
||||||
|
if (this.methodParameter.getMethod() != null) {
|
||||||
|
this.methodName = methodParameter.getMethod().getName();
|
||||||
|
this.parameterTypes = methodParameter.getMethod().getParameterTypes();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this.parameterTypes = methodParameter.getConstructor().getParameterTypes();
|
||||||
|
}
|
||||||
|
this.parameterIndex = methodParameter.getParameterIndex();
|
||||||
this.required = required;
|
this.required = required;
|
||||||
this.eager = eager;
|
this.eager = eager;
|
||||||
}
|
}
|
||||||
|
|
@ -89,6 +112,8 @@ public class DependencyDescriptor {
|
||||||
public DependencyDescriptor(Field field, boolean required, boolean eager) {
|
public DependencyDescriptor(Field field, boolean required, boolean eager) {
|
||||||
Assert.notNull(field, "Field must not be null");
|
Assert.notNull(field, "Field must not be null");
|
||||||
this.field = field;
|
this.field = field;
|
||||||
|
this.declaringClass = field.getDeclaringClass();
|
||||||
|
this.fieldName = field.getName();
|
||||||
this.required = required;
|
this.required = required;
|
||||||
this.eager = eager;
|
this.eager = eager;
|
||||||
}
|
}
|
||||||
|
|
@ -156,6 +181,14 @@ public class DependencyDescriptor {
|
||||||
return (this.field != null ? this.field.getType() : this.methodParameter.getParameterType());
|
return (this.field != null ? this.field.getType() : this.methodParameter.getParameterType());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine the generic type of the wrapped parameter/field.
|
||||||
|
* @return the generic type (never <code>null</code>)
|
||||||
|
*/
|
||||||
|
public Type getGenericDependencyType() {
|
||||||
|
return (this.field != null ? this.field.getGenericType() : this.methodParameter.getGenericParameterType());
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determine the generic element type of the wrapped Collection parameter/field, if any.
|
* Determine the generic element type of the wrapped Collection parameter/field, if any.
|
||||||
* @return the generic type, or <code>null</code> if none
|
* @return the generic type, or <code>null</code> if none
|
||||||
|
|
@ -201,4 +234,32 @@ public class DependencyDescriptor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------
|
||||||
|
// Serialization support
|
||||||
|
//---------------------------------------------------------------------
|
||||||
|
|
||||||
|
private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
|
||||||
|
// Rely on default serialization; just initialize state after deserialization.
|
||||||
|
ois.defaultReadObject();
|
||||||
|
|
||||||
|
// Restore reflective handles (which are unfortunately not serializable)
|
||||||
|
try {
|
||||||
|
if (this.fieldName != null) {
|
||||||
|
this.field = this.declaringClass.getDeclaredField(this.fieldName);
|
||||||
|
}
|
||||||
|
else if (this.methodName != null) {
|
||||||
|
this.methodParameter = new MethodParameter(
|
||||||
|
this.declaringClass.getDeclaredMethod(this.methodName, this.parameterTypes), this.parameterIndex);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this.methodParameter = new MethodParameter(
|
||||||
|
this.declaringClass.getDeclaredConstructor(this.parameterTypes), this.parameterIndex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Throwable ex) {
|
||||||
|
throw new IllegalStateException("Could not find original class structure", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,8 @@ import java.io.Serializable;
|
||||||
import java.lang.annotation.Annotation;
|
import java.lang.annotation.Annotation;
|
||||||
import java.lang.ref.Reference;
|
import java.lang.ref.Reference;
|
||||||
import java.lang.ref.WeakReference;
|
import java.lang.ref.WeakReference;
|
||||||
|
import java.lang.reflect.ParameterizedType;
|
||||||
|
import java.lang.reflect.Type;
|
||||||
import java.security.AccessController;
|
import java.security.AccessController;
|
||||||
import java.security.PrivilegedAction;
|
import java.security.PrivilegedAction;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
|
@ -508,14 +510,13 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
|
||||||
if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
|
if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
|
||||||
if (isFactoryBean(beanName)) {
|
if (isFactoryBean(beanName)) {
|
||||||
final FactoryBean factory = (FactoryBean) getBean(FACTORY_BEAN_PREFIX + beanName);
|
final FactoryBean factory = (FactoryBean) getBean(FACTORY_BEAN_PREFIX + beanName);
|
||||||
boolean isEagerInit = false;
|
boolean isEagerInit;
|
||||||
|
|
||||||
if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
|
if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
|
||||||
isEagerInit = AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
|
isEagerInit = AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
|
||||||
public Boolean run() {
|
public Boolean run() {
|
||||||
return Boolean.valueOf(((SmartFactoryBean) factory).isEagerInit());
|
return ((SmartFactoryBean) factory).isEagerInit();
|
||||||
}
|
}
|
||||||
}, getAccessControlContext()).booleanValue();
|
}, getAccessControlContext());
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
isEagerInit = factory instanceof SmartFactoryBean && ((SmartFactoryBean) factory).isEagerInit();
|
isEagerInit = factory instanceof SmartFactoryBean && ((SmartFactoryBean) factory).isEagerInit();
|
||||||
|
|
@ -634,14 +635,23 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
|
||||||
|
|
||||||
|
|
||||||
//---------------------------------------------------------------------
|
//---------------------------------------------------------------------
|
||||||
// Implementation of superclass abstract methods
|
// Dependency resolution functionality
|
||||||
//---------------------------------------------------------------------
|
//---------------------------------------------------------------------
|
||||||
|
|
||||||
public Object resolveDependency(DependencyDescriptor descriptor, String beanName,
|
public Object resolveDependency(DependencyDescriptor descriptor, String beanName,
|
||||||
Set<String> autowiredBeanNames, TypeConverter typeConverter) throws BeansException {
|
Set<String> autowiredBeanNames, TypeConverter typeConverter) throws BeansException {
|
||||||
|
|
||||||
descriptor.initParameterNameDiscovery(getParameterNameDiscoverer());
|
descriptor.initParameterNameDiscovery(getParameterNameDiscoverer());
|
||||||
Class<?> type = descriptor.getDependencyType();
|
if (ObjectFactory.class.equals(descriptor.getDependencyType())) {
|
||||||
|
return new DependencyObjectFactory(descriptor, beanName);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return doResolveDependency(descriptor, descriptor.getDependencyType(), beanName, autowiredBeanNames, typeConverter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Object doResolveDependency(DependencyDescriptor descriptor, Class<?> type, String beanName,
|
||||||
|
Set<String> autowiredBeanNames, TypeConverter typeConverter) throws BeansException {
|
||||||
|
|
||||||
Object value = getAutowireCandidateResolver().getSuggestedValue(descriptor);
|
Object value = getAutowireCandidateResolver().getSuggestedValue(descriptor);
|
||||||
if (value != null) {
|
if (value != null) {
|
||||||
|
|
@ -649,7 +659,8 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
|
||||||
String strVal = resolveEmbeddedValue((String) value);
|
String strVal = resolveEmbeddedValue((String) value);
|
||||||
value = evaluateBeanDefinitionString(strVal, getMergedBeanDefinition(beanName));
|
value = evaluateBeanDefinitionString(strVal, getMergedBeanDefinition(beanName));
|
||||||
}
|
}
|
||||||
return typeConverter.convertIfNecessary(value, type);
|
TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter());
|
||||||
|
return converter.convertIfNecessary(value, type);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type.isArray()) {
|
if (type.isArray()) {
|
||||||
|
|
@ -907,4 +918,38 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Serializable ObjectFactory for lazy resolution of a dependency.
|
||||||
|
*/
|
||||||
|
private class DependencyObjectFactory implements ObjectFactory, Serializable {
|
||||||
|
|
||||||
|
private final DependencyDescriptor descriptor;
|
||||||
|
|
||||||
|
private final String beanName;
|
||||||
|
|
||||||
|
private final Class type;
|
||||||
|
|
||||||
|
public DependencyObjectFactory(DependencyDescriptor descriptor, String beanName) {
|
||||||
|
this.descriptor = descriptor;
|
||||||
|
this.beanName = beanName;
|
||||||
|
this.type = determineObjectFactoryType();
|
||||||
|
}
|
||||||
|
|
||||||
|
private Class determineObjectFactoryType() {
|
||||||
|
Type type = this.descriptor.getGenericDependencyType();
|
||||||
|
if (type instanceof ParameterizedType) {
|
||||||
|
Type arg = ((ParameterizedType) type).getActualTypeArguments()[0];
|
||||||
|
if (arg instanceof Class) {
|
||||||
|
return (Class) arg;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Object.class;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object getObject() throws BeansException {
|
||||||
|
return doResolveDependency(this.descriptor, this.type, this.beanName, null, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -16,8 +16,7 @@
|
||||||
|
|
||||||
package org.springframework.beans.factory.annotation;
|
package org.springframework.beans.factory.annotation;
|
||||||
|
|
||||||
import static org.junit.Assert.*;
|
import java.io.Serializable;
|
||||||
|
|
||||||
import java.lang.annotation.ElementType;
|
import java.lang.annotation.ElementType;
|
||||||
import java.lang.annotation.Retention;
|
import java.lang.annotation.Retention;
|
||||||
import java.lang.annotation.RetentionPolicy;
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
|
@ -25,20 +24,24 @@ import java.lang.annotation.Target;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
import static org.junit.Assert.*;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.springframework.beans.factory.BeanCreationException;
|
|
||||||
import org.springframework.beans.factory.BeanFactory;
|
|
||||||
import org.springframework.beans.factory.FactoryBean;
|
|
||||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
|
||||||
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
|
|
||||||
import org.springframework.beans.factory.support.GenericBeanDefinition;
|
|
||||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
|
||||||
|
|
||||||
import test.beans.ITestBean;
|
import test.beans.ITestBean;
|
||||||
import test.beans.IndexedTestBean;
|
import test.beans.IndexedTestBean;
|
||||||
import test.beans.NestedTestBean;
|
import test.beans.NestedTestBean;
|
||||||
import test.beans.TestBean;
|
import test.beans.TestBean;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.BeanCreationException;
|
||||||
|
import org.springframework.beans.factory.BeanFactory;
|
||||||
|
import org.springframework.beans.factory.FactoryBean;
|
||||||
|
import org.springframework.beans.factory.ObjectFactory;
|
||||||
|
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||||
|
import org.springframework.beans.factory.support.AutowireCandidateQualifier;
|
||||||
|
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
|
||||||
|
import org.springframework.beans.factory.support.GenericBeanDefinition;
|
||||||
|
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||||
|
import org.springframework.util.SerializationTestUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Unit tests for {@link AutowiredAnnotationBeanPostProcessor}.
|
* Unit tests for {@link AutowiredAnnotationBeanPostProcessor}.
|
||||||
*
|
*
|
||||||
|
|
@ -553,6 +556,53 @@ public final class AutowiredAnnotationBeanPostProcessorTests {
|
||||||
bf.destroySingletons();
|
bf.destroySingletons();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testObjectFactoryInjection() {
|
||||||
|
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
|
||||||
|
AutowiredAnnotationBeanPostProcessor bpp = new AutowiredAnnotationBeanPostProcessor();
|
||||||
|
bpp.setBeanFactory(bf);
|
||||||
|
bf.addBeanPostProcessor(bpp);
|
||||||
|
bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(ObjectFactoryInjectionBean.class));
|
||||||
|
bf.registerBeanDefinition("testBean", new RootBeanDefinition(TestBean.class));
|
||||||
|
|
||||||
|
ObjectFactoryInjectionBean bean = (ObjectFactoryInjectionBean) bf.getBean("annotatedBean");
|
||||||
|
assertSame(bf.getBean("testBean"), bean.getTestBean());
|
||||||
|
bf.destroySingletons();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testObjectFactoryQualifierInjection() {
|
||||||
|
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
|
||||||
|
AutowiredAnnotationBeanPostProcessor bpp = new AutowiredAnnotationBeanPostProcessor();
|
||||||
|
bpp.setBeanFactory(bf);
|
||||||
|
bf.addBeanPostProcessor(bpp);
|
||||||
|
bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(ObjectFactoryQualifierInjectionBean.class));
|
||||||
|
RootBeanDefinition bd = new RootBeanDefinition(TestBean.class);
|
||||||
|
bd.addQualifier(new AutowireCandidateQualifier(Qualifier.class, "testBean"));
|
||||||
|
bf.registerBeanDefinition("testBean", bd);
|
||||||
|
|
||||||
|
ObjectFactoryQualifierInjectionBean bean = (ObjectFactoryQualifierInjectionBean) bf.getBean("annotatedBean");
|
||||||
|
assertSame(bf.getBean("testBean"), bean.getTestBean());
|
||||||
|
bf.destroySingletons();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testObjectFactorySerialization() throws Exception {
|
||||||
|
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
|
||||||
|
AutowiredAnnotationBeanPostProcessor bpp = new AutowiredAnnotationBeanPostProcessor();
|
||||||
|
bpp.setBeanFactory(bf);
|
||||||
|
bf.addBeanPostProcessor(bpp);
|
||||||
|
bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(ObjectFactoryInjectionBean.class));
|
||||||
|
bf.registerBeanDefinition("testBean", new RootBeanDefinition(TestBean.class));
|
||||||
|
bf.setSerializationId("test");
|
||||||
|
|
||||||
|
ObjectFactoryInjectionBean bean = (ObjectFactoryInjectionBean) bf.getBean("annotatedBean");
|
||||||
|
assertSame(bf.getBean("testBean"), bean.getTestBean());
|
||||||
|
bean = (ObjectFactoryInjectionBean) SerializationTestUtils.serializeAndDeserialize(bean);
|
||||||
|
assertSame(bf.getBean("testBean"), bean.getTestBean());
|
||||||
|
bf.destroySingletons();
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testCustomAnnotationRequiredFieldResourceInjection() {
|
public void testCustomAnnotationRequiredFieldResourceInjection() {
|
||||||
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
|
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
|
||||||
|
|
@ -1218,6 +1268,29 @@ public final class AutowiredAnnotationBeanPostProcessorTests {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static class ObjectFactoryInjectionBean implements Serializable {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ObjectFactory<TestBean> testBeanFactory;
|
||||||
|
|
||||||
|
public TestBean getTestBean() {
|
||||||
|
return this.testBeanFactory.getObject();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static class ObjectFactoryQualifierInjectionBean {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
//@Qualifier("testBean")
|
||||||
|
private ObjectFactory<?> testBeanFactory;
|
||||||
|
|
||||||
|
public TestBean getTestBean() {
|
||||||
|
return (TestBean) this.testBeanFactory.getObject();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public static class CustomAnnotationRequiredFieldResourceInjectionBean {
|
public static class CustomAnnotationRequiredFieldResourceInjectionBean {
|
||||||
|
|
||||||
@MyAutowired(optional = false)
|
@MyAutowired(optional = false)
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@
|
||||||
package org.springframework.context.expression;
|
package org.springframework.context.expression;
|
||||||
|
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
import org.apache.commons.logging.Log;
|
import org.apache.commons.logging.Log;
|
||||||
import org.apache.commons.logging.LogFactory;
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
|
@ -37,6 +38,7 @@ import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||||
import org.springframework.context.annotation.AnnotationConfigUtils;
|
import org.springframework.context.annotation.AnnotationConfigUtils;
|
||||||
import org.springframework.context.support.GenericApplicationContext;
|
import org.springframework.context.support.GenericApplicationContext;
|
||||||
import org.springframework.util.StopWatch;
|
import org.springframework.util.StopWatch;
|
||||||
|
import org.springframework.util.SerializationTestUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Juergen Hoeller
|
* @author Juergen Hoeller
|
||||||
|
|
@ -47,7 +49,7 @@ public class ApplicationContextExpressionTests {
|
||||||
private static final Log factoryLog = LogFactory.getLog(DefaultListableBeanFactory.class);
|
private static final Log factoryLog = LogFactory.getLog(DefaultListableBeanFactory.class);
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void genericApplicationContext() {
|
public void genericApplicationContext() throws Exception {
|
||||||
GenericApplicationContext ac = new GenericApplicationContext();
|
GenericApplicationContext ac = new GenericApplicationContext();
|
||||||
AnnotationConfigUtils.registerAnnotationConfigProcessors(ac);
|
AnnotationConfigUtils.registerAnnotationConfigProcessors(ac);
|
||||||
|
|
||||||
|
|
@ -139,8 +141,12 @@ public class ApplicationContextExpressionTests {
|
||||||
assertEquals("XXXmyNameYYY42ZZZ", tb3.name);
|
assertEquals("XXXmyNameYYY42ZZZ", tb3.name);
|
||||||
assertEquals(42, tb3.age);
|
assertEquals(42, tb3.age);
|
||||||
assertEquals("123 UK", tb3.country);
|
assertEquals("123 UK", tb3.country);
|
||||||
|
assertEquals("123 UK", tb3.countryFactory.getObject());
|
||||||
assertSame(tb0, tb3.tb);
|
assertSame(tb0, tb3.tb);
|
||||||
|
|
||||||
|
tb3 = (ValueTestBean) SerializationTestUtils.serializeAndDeserialize(tb3);
|
||||||
|
assertEquals("123 UK", tb3.countryFactory.getObject());
|
||||||
|
|
||||||
ConstructorValueTestBean tb4 = ac.getBean("tb4", ConstructorValueTestBean.class);
|
ConstructorValueTestBean tb4 = ac.getBean("tb4", ConstructorValueTestBean.class);
|
||||||
assertEquals("XXXmyNameYYY42ZZZ", tb4.name);
|
assertEquals("XXXmyNameYYY42ZZZ", tb4.name);
|
||||||
assertEquals(42, tb4.age);
|
assertEquals(42, tb4.age);
|
||||||
|
|
@ -198,7 +204,7 @@ public class ApplicationContextExpressionTests {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static class ValueTestBean {
|
public static class ValueTestBean implements Serializable {
|
||||||
|
|
||||||
@Autowired @Value("XXX#{tb0.name}YYY#{mySpecialAttr}ZZZ")
|
@Autowired @Value("XXX#{tb0.name}YYY#{mySpecialAttr}ZZZ")
|
||||||
public String name;
|
public String name;
|
||||||
|
|
@ -209,8 +215,11 @@ public class ApplicationContextExpressionTests {
|
||||||
@Value("${code} #{systemProperties.country}")
|
@Value("${code} #{systemProperties.country}")
|
||||||
public String country;
|
public String country;
|
||||||
|
|
||||||
|
@Value("${code} #{systemProperties.country}")
|
||||||
|
public ObjectFactory<String> countryFactory;
|
||||||
|
|
||||||
@Autowired @Qualifier("original")
|
@Autowired @Qualifier("original")
|
||||||
public TestBean tb;
|
public transient TestBean tb;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -49,7 +49,9 @@ public class MethodParameter {
|
||||||
|
|
||||||
private final int parameterIndex;
|
private final int parameterIndex;
|
||||||
|
|
||||||
private Class parameterType;
|
private Class<?> parameterType;
|
||||||
|
|
||||||
|
private Type genericParameterType;
|
||||||
|
|
||||||
private Annotation[] parameterAnnotations;
|
private Annotation[] parameterAnnotations;
|
||||||
|
|
||||||
|
|
@ -167,7 +169,7 @@ public class MethodParameter {
|
||||||
/**
|
/**
|
||||||
* Set a resolved (generic) parameter type.
|
* Set a resolved (generic) parameter type.
|
||||||
*/
|
*/
|
||||||
void setParameterType(Class parameterType) {
|
void setParameterType(Class<?> parameterType) {
|
||||||
this.parameterType = parameterType;
|
this.parameterType = parameterType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -175,7 +177,7 @@ public class MethodParameter {
|
||||||
* Return the type of the method/constructor parameter.
|
* Return the type of the method/constructor parameter.
|
||||||
* @return the parameter type (never <code>null</code>)
|
* @return the parameter type (never <code>null</code>)
|
||||||
*/
|
*/
|
||||||
public Class getParameterType() {
|
public Class<?> getParameterType() {
|
||||||
if (this.parameterType == null) {
|
if (this.parameterType == null) {
|
||||||
if (this.parameterIndex < 0) {
|
if (this.parameterIndex < 0) {
|
||||||
this.parameterType = (this.method != null ? this.method.getReturnType() : null);
|
this.parameterType = (this.method != null ? this.method.getReturnType() : null);
|
||||||
|
|
@ -189,6 +191,24 @@ public class MethodParameter {
|
||||||
return this.parameterType;
|
return this.parameterType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the generic type of the method/constructor parameter.
|
||||||
|
* @return the parameter type (never <code>null</code>)
|
||||||
|
*/
|
||||||
|
public Type getGenericParameterType() {
|
||||||
|
if (this.genericParameterType == null) {
|
||||||
|
if (this.parameterIndex < 0) {
|
||||||
|
this.genericParameterType = (this.method != null ? this.method.getGenericReturnType() : null);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this.genericParameterType = (this.method != null ?
|
||||||
|
this.method.getGenericParameterTypes()[this.parameterIndex] :
|
||||||
|
this.constructor.getGenericParameterTypes()[this.parameterIndex]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return this.genericParameterType;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the annotations associated with the target method/constructor itself.
|
* Return the annotations associated with the target method/constructor itself.
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue