Minor optimizations in factory method handling
Optimized getTypeForFactoryMethod's implementation for non-generic factory methods, and reduced calls to getResolvedFactoryMethod in order to avoid repeated synchronization. Derived from work around SPR-11034.
This commit is contained in:
@@ -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 use this file except in compliance with the License.
|
||||
@@ -233,8 +233,9 @@ public class QualifierAnnotationAutowireCandidateResolver implements AutowireCan
|
||||
}
|
||||
if (qualifier == null) {
|
||||
Annotation targetAnnotation = null;
|
||||
if (bd.getResolvedFactoryMethod() != null) {
|
||||
targetAnnotation = AnnotationUtils.getAnnotation(bd.getResolvedFactoryMethod(), type);
|
||||
Method resolvedFactoryMethod = bd.getResolvedFactoryMethod();
|
||||
if (resolvedFactoryMethod != null) {
|
||||
targetAnnotation = AnnotationUtils.getAnnotation(resolvedFactoryMethod, type);
|
||||
}
|
||||
if (targetAnnotation == null) {
|
||||
// look for matching annotation on the target class
|
||||
|
||||
@@ -569,7 +569,7 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Class<?> predictBeanType(String beanName, RootBeanDefinition mbd, Class... typesToMatch) {
|
||||
protected Class<?> predictBeanType(String beanName, RootBeanDefinition mbd, Class<?>... typesToMatch) {
|
||||
Class<?> targetType = mbd.getTargetType();
|
||||
if (targetType == null) {
|
||||
targetType = (mbd.getFactoryMethodName() != null ? getTypeForFactoryMethod(beanName, mbd, typesToMatch) :
|
||||
@@ -641,31 +641,38 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
|
||||
if (Modifier.isStatic(factoryMethod.getModifiers()) == isStatic &&
|
||||
factoryMethod.getName().equals(mbd.getFactoryMethodName()) &&
|
||||
factoryMethod.getParameterTypes().length >= minNrOfArgs) {
|
||||
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);
|
||||
// No declared type variables to inspect, so just process the standard return type.
|
||||
if (factoryMethod.getTypeParameters().length > 0) {
|
||||
// Fully resolve parameter names and argument values.
|
||||
Class<?>[] paramTypes = factoryMethod.getParameterTypes();
|
||||
String[] paramNames = null;
|
||||
ParameterNameDiscoverer pnd = getParameterNameDiscoverer();
|
||||
if (pnd != null) {
|
||||
paramNames = pnd.getParameterNames(factoryMethod);
|
||||
}
|
||||
if (valueHolder != null) {
|
||||
args[i] = valueHolder.getValue();
|
||||
usedValueHolders.add(valueHolder);
|
||||
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());
|
||||
if (returnType != null) {
|
||||
returnTypes.add(returnType);
|
||||
}
|
||||
}
|
||||
Class<?> returnType = AutowireUtils.resolveReturnTypeForFactoryMethod(
|
||||
factoryMethod, args, getBeanClassLoader());
|
||||
if (returnType != null) {
|
||||
returnTypes.add(returnType);
|
||||
else {
|
||||
returnTypes.add(factoryMethod.getReturnType());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -193,17 +193,7 @@ abstract class AutowireUtils {
|
||||
TypeVariable<Method>[] declaredTypeVariables = method.getTypeParameters();
|
||||
Type genericReturnType = method.getGenericReturnType();
|
||||
Type[] methodArgumentTypes = method.getGenericParameterTypes();
|
||||
|
||||
// No declared type variables to inspect, so just return the standard return type.
|
||||
if (declaredTypeVariables.length == 0) {
|
||||
return method.getReturnType();
|
||||
}
|
||||
|
||||
// The supplied argument list is too short for the method's signature, so
|
||||
// return null, since such a method invocation would fail.
|
||||
if (args.length < methodArgumentTypes.length) {
|
||||
return null;
|
||||
}
|
||||
Assert.isTrue(args.length == methodArgumentTypes.length, "Argument array does not match parameter count");
|
||||
|
||||
// Ensure that the type variable (e.g., T) is declared directly on the method
|
||||
// itself (e.g., via <T>), not on the enclosing class or interface.
|
||||
|
||||
@@ -49,9 +49,6 @@ public class AutowireUtilsTests {
|
||||
|
||||
Method createNamedProxyWithDifferentTypes = ReflectionUtils.findMethod(MyTypeWithMethods.class, "createNamedProxy",
|
||||
new Class[] { String.class, Object.class });
|
||||
// one argument to few
|
||||
assertNull(
|
||||
AutowireUtils.resolveReturnTypeForFactoryMethod(createNamedProxyWithDifferentTypes, new Object[]{"enigma"}, getClass().getClassLoader()));
|
||||
assertEquals(Long.class,
|
||||
AutowireUtils.resolveReturnTypeForFactoryMethod(createNamedProxyWithDifferentTypes, new Object[] { "enigma", 99L }, getClass().getClassLoader()));
|
||||
|
||||
|
||||
@@ -654,17 +654,13 @@ public class BeanFactoryGenericsTests {
|
||||
/**
|
||||
* Tests support for parameterized static {@code factory-method} declarations such as
|
||||
* Mockito's {@code mock()} method which has the following signature.
|
||||
*
|
||||
* <pre>
|
||||
* {@code
|
||||
* public static <T> T mock(Class<T> classToMock)
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* <p>
|
||||
* See SPR-9493
|
||||
*
|
||||
* @since 3.2
|
||||
*/
|
||||
@Test
|
||||
public void parameterizedStaticFactoryMethod() {
|
||||
@@ -701,7 +697,6 @@ public class BeanFactoryGenericsTests {
|
||||
rbd.setFactoryBeanName("mocksControl");
|
||||
rbd.setFactoryMethodName("createMock");
|
||||
rbd.getConstructorArgumentValues().addGenericArgumentValue(Runnable.class);
|
||||
|
||||
bf.registerBeanDefinition("mock", rbd);
|
||||
|
||||
Map<String, Runnable> beans = bf.getBeansOfType(Runnable.class);
|
||||
@@ -719,7 +714,6 @@ public class BeanFactoryGenericsTests {
|
||||
rbd.setFactoryBeanName("mocksControl");
|
||||
rbd.setFactoryMethodName("createMock");
|
||||
rbd.getConstructorArgumentValues().addGenericArgumentValue(Runnable.class.getName());
|
||||
|
||||
bf.registerBeanDefinition("mock", rbd);
|
||||
|
||||
Map<String, Runnable> beans = bf.getBeansOfType(Runnable.class);
|
||||
@@ -737,7 +731,6 @@ public class BeanFactoryGenericsTests {
|
||||
rbd.setFactoryBeanName("mocksControl");
|
||||
rbd.setFactoryMethodName("createMock");
|
||||
rbd.getConstructorArgumentValues().addIndexedArgumentValue(0, Runnable.class);
|
||||
|
||||
bf.registerBeanDefinition("mock", rbd);
|
||||
|
||||
Map<String, Runnable> beans = bf.getBeansOfType(Runnable.class);
|
||||
@@ -788,6 +781,7 @@ public class BeanFactoryGenericsTests {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Pseudo-implementation of EasyMock's {@code MocksControl} class.
|
||||
*/
|
||||
@@ -795,14 +789,10 @@ public class BeanFactoryGenericsTests {
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> T createMock(Class<T> toMock) {
|
||||
|
||||
return (T) Proxy.newProxyInstance(
|
||||
BeanFactoryGenericsTests.class.getClassLoader(),
|
||||
new Class[] { toMock }, new InvocationHandler() {
|
||||
|
||||
return (T) Proxy.newProxyInstance(BeanFactoryGenericsTests.class.getClassLoader(), new Class<?>[] {toMock},
|
||||
new InvocationHandler() {
|
||||
@Override
|
||||
public Object invoke(Object proxy, Method method, Object[] args)
|
||||
throws Throwable {
|
||||
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
|
||||
throw new UnsupportedOperationException("mocked!");
|
||||
}
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user