BeanFactory supports ObjectFactory as a dependency type for @Autowired and @Value (SPR-6079)
This commit is contained in:
@@ -16,8 +16,12 @@
|
||||
|
||||
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.reflect.Field;
|
||||
import java.lang.reflect.Type;
|
||||
|
||||
import org.springframework.core.GenericCollectionTypeResolver;
|
||||
import org.springframework.core.MethodParameter;
|
||||
@@ -32,17 +36,27 @@ import org.springframework.util.Assert;
|
||||
* @author Juergen Hoeller
|
||||
* @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 eager;
|
||||
|
||||
private Annotation[] fieldAnnotations;
|
||||
private transient Annotation[] fieldAnnotations;
|
||||
|
||||
|
||||
/**
|
||||
@@ -65,6 +79,15 @@ public class DependencyDescriptor {
|
||||
public DependencyDescriptor(MethodParameter methodParameter, boolean required, boolean eager) {
|
||||
Assert.notNull(methodParameter, "MethodParameter must not be null");
|
||||
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.eager = eager;
|
||||
}
|
||||
@@ -89,6 +112,8 @@ public class DependencyDescriptor {
|
||||
public DependencyDescriptor(Field field, boolean required, boolean eager) {
|
||||
Assert.notNull(field, "Field must not be null");
|
||||
this.field = field;
|
||||
this.declaringClass = field.getDeclaringClass();
|
||||
this.fieldName = field.getName();
|
||||
this.required = required;
|
||||
this.eager = eager;
|
||||
}
|
||||
@@ -156,6 +181,14 @@ public class DependencyDescriptor {
|
||||
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.
|
||||
* @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.ref.Reference;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
import java.lang.reflect.Type;
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
import java.util.ArrayList;
|
||||
@@ -508,14 +510,13 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
|
||||
if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
|
||||
if (isFactoryBean(beanName)) {
|
||||
final FactoryBean factory = (FactoryBean) getBean(FACTORY_BEAN_PREFIX + beanName);
|
||||
boolean isEagerInit = false;
|
||||
|
||||
boolean isEagerInit;
|
||||
if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
|
||||
isEagerInit = AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
|
||||
public Boolean run() {
|
||||
return Boolean.valueOf(((SmartFactoryBean) factory).isEagerInit());
|
||||
return ((SmartFactoryBean) factory).isEagerInit();
|
||||
}
|
||||
}, getAccessControlContext()).booleanValue();
|
||||
}, getAccessControlContext());
|
||||
}
|
||||
else {
|
||||
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,
|
||||
Set<String> autowiredBeanNames, TypeConverter typeConverter) throws BeansException {
|
||||
|
||||
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);
|
||||
if (value != null) {
|
||||
@@ -649,7 +659,8 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
|
||||
String strVal = resolveEmbeddedValue((String) value);
|
||||
value = evaluateBeanDefinitionString(strVal, getMergedBeanDefinition(beanName));
|
||||
}
|
||||
return typeConverter.convertIfNecessary(value, type);
|
||||
TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter());
|
||||
return converter.convertIfNecessary(value, type);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user