Skip to content

Use method meta-data in getTypeForFactoryMethod #821

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,11 @@ public final AnnotationMetadata getMetadata() {
return this.metadata;
}

@Override
public String getFactoryMethodReturnType() {
return (this.factoryMethodMetadata == null ? null : this.factoryMethodMetadata.getReturnTypeName());
}

@Override
public final MethodMetadata getFactoryMethodMetadata() {
return this.factoryMethodMetadata;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,11 @@ public interface BeanDefinition extends AttributeAccessor, BeanMetadataElement {
*/
String getFactoryMethodName();

/**
* Return the class name of the factory method return type, if known in advance.
*/
String getFactoryMethodReturnType();

/**
* Specify a factory method, if any. This method will be invoked with
* constructor arguments, or with no arguments if none are specified.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.ObjectFactory;
import org.springframework.beans.factory.UnsatisfiedDependencyException;
import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanPostProcessor;
Expand All @@ -74,6 +75,7 @@
import org.springframework.core.MethodParameter;
import org.springframework.core.ParameterNameDiscoverer;
import org.springframework.core.PriorityOrdered;
import org.springframework.core.type.MethodMetadata;
import org.springframework.util.ClassUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.ReflectionUtils;
Expand Down Expand Up @@ -653,24 +655,25 @@ protected Class<?> getTypeForFactoryMethod(String beanName, RootBeanDefinition m
return preResolved;
}

Class<?> factoryClass;
boolean isStatic = true;

String factoryBeanName = mbd.getFactoryBeanName();
if (factoryBeanName != null) {
if (factoryBeanName.equals(beanName)) {
throw new BeanDefinitionStoreException(mbd.getResourceDescription(), beanName,
"factory-bean reference points back to the same bean definition");
boolean isStatic = (factoryBeanName == null);

// Use the predetermined return type if possible
if (factoryBeanName != null && mbd.getFactoryMethodReturnType() != null) {
if (mbd.getFactoryMethodReturnType() != null) {
try {
if (mbd.factoryMethodReturnType == null) {
mbd.factoryMethodReturnType = ClassUtils.forName(
mbd.getFactoryMethodReturnType(), getBeanClassLoader());
}
return mbd.factoryMethodReturnType;
}
catch (Exception ex) {
}
}
// Check declared factory method return type on factory class.
factoryClass = getType(factoryBeanName);
isStatic = false;
}
else {
// Check declared factory method return type on bean class.
factoryClass = resolveBeanClass(mbd, beanName, typesToMatch);
}

Class<?> factoryClass = getFactoryClass(beanName, mbd, factoryBeanName, typesToMatch);
if (factoryClass == null) {
return null;
}
Expand All @@ -689,29 +692,7 @@ protected Class<?> getTypeForFactoryMethod(String beanName, RootBeanDefinition m
if (factoryMethod.getTypeParameters().length > 0) {
try {
// Fully resolve parameter names and argument values.
Class<?>[] paramTypes = factoryMethod.getParameterTypes();
String[] paramNames = null;
ParameterNameDiscoverer pnd = getParameterNameDiscoverer();
if (pnd != null) {
paramNames = pnd.getParameterNames(factoryMethod);
}
ConstructorArgumentValues cav = mbd.getConstructorArgumentValues();
Set<ConstructorArgumentValues.ValueHolder> usedValueHolders =
new HashSet<ConstructorArgumentValues.ValueHolder>(paramTypes.length);
Object[] args = new Object[paramTypes.length];
for (int i = 0; i < args.length; i++) {
ConstructorArgumentValues.ValueHolder valueHolder = cav.getArgumentValue(
i, paramTypes[i], (paramNames != null ? paramNames[i] : null), usedValueHolders);
if (valueHolder == null) {
valueHolder = cav.getGenericArgumentValue(null, null, usedValueHolders);
}
if (valueHolder != null) {
args[i] = valueHolder.getValue();
usedValueHolders.add(valueHolder);
}
}
Class<?> returnType = AutowireUtils.resolveReturnTypeForFactoryMethod(
factoryMethod, args, getBeanClassLoader());
Class<?> returnType = getReturnType(mbd, factoryMethod);
if (returnType != null) {
cache = true;
commonType = ClassUtils.determineCommonAncestor(returnType, commonType);
Expand All @@ -730,16 +711,61 @@ protected Class<?> getTypeForFactoryMethod(String beanName, RootBeanDefinition m
}

if (commonType != null) {
if(mbd.resolvedFactoryMethodReturnType != null && !mbd.resolvedFactoryMethodReturnType.equals(commonType)) {
throw new IllegalStateException(commonType+" "+mbd.factoryMethodReturnType );
}
// Clear return type found: all factory methods return same type.
if (cache) {
mbd.resolvedFactoryMethodReturnType = commonType;
}
return commonType;
}
else {
// Ambiguous return types found: return null to indicate "not determinable".
return null;
// Ambiguous return types found: return null to indicate "not determinable".
return null;
}

private Class<?> getFactoryClass(String beanName, RootBeanDefinition mbd, String factoryBeanName,
Class<?>... typesToMatch) {
if (factoryBeanName != null) {
if (factoryBeanName.equals(beanName)) {
throw new BeanDefinitionStoreException(mbd.getResourceDescription(), beanName,
"factory-bean reference points back to the same bean definition");
}
// Check declared factory method return type on factory class.
return getType(factoryBeanName);
}
// Check declared factory method return type on bean class.
return resolveBeanClass(mbd, beanName, typesToMatch);
}

private Class<?> getReturnType(RootBeanDefinition mbd, Method factoryMethod) {
Class<?>[] paramTypes = factoryMethod.getParameterTypes();
String[] paramNames = getParameterNames(factoryMethod);
ConstructorArgumentValues cav = mbd.getConstructorArgumentValues();
Set<ConstructorArgumentValues.ValueHolder> usedValueHolders =
new HashSet<ConstructorArgumentValues.ValueHolder>(paramTypes.length);
Object[] args = new Object[paramTypes.length];
for (int i = 0; i < args.length; i++) {
ConstructorArgumentValues.ValueHolder valueHolder = cav.getArgumentValue(
i, paramTypes[i], (paramNames != null ? paramNames[i] : null), usedValueHolders);
if (valueHolder == null) {
valueHolder = cav.getGenericArgumentValue(null, null, usedValueHolders);
}
if (valueHolder != null) {
args[i] = valueHolder.getValue();
usedValueHolders.add(valueHolder);
}
}
return AutowireUtils.resolveReturnTypeForFactoryMethod(
factoryMethod, args, getBeanClassLoader());
}

private String[] getParameterNames(Method factoryMethod) {
ParameterNameDiscoverer discoverer = getParameterNameDiscoverer();
if (discoverer != null) {
return discoverer.getParameterNames(factoryMethod);
}
return null;
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -758,6 +758,11 @@ public String getFactoryMethodName() {
return this.factoryMethodName;
}

@Override
public String getFactoryMethodReturnType() {
return null;
}

/**
* Set the name of the initializer method. The default is {@code null}
* in which case there is no initializer method.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,9 @@ public class RootBeanDefinition extends AbstractBeanDefinition {
/** Package-visible field for caching the resolved constructor or factory method */
Object resolvedConstructorOrFactoryMethod;

/** Package-visible field for caching the loaded factory method return type */
volatile Class<?> factoryMethodReturnType;

/** Package-visible field for caching the return type of a generically typed factory method */
volatile Class<?> resolvedFactoryMethodReturnType;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import org.springframework.beans.factory.BeanDefinitionStoreException;
import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition;
import org.springframework.beans.factory.annotation.AnnotatedGenericBeanDefinition;
Expand Down Expand Up @@ -402,6 +401,11 @@ public AnnotationMetadata getMetadata() {
return this.annotationMetadata;
}

@Override
public String getFactoryMethodReturnType() {
return (this.factoryMethodMetadata == null ? null : this.factoryMethodMetadata.getReturnTypeName());
}

@Override
public MethodMetadata getFactoryMethodMetadata() {
return this.factoryMethodMetadata;
Expand Down