Skip to content

Commit ff9c695

Browse files
committed
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.
1 parent 6021822 commit ff9c695

File tree

5 files changed

+39
-54
lines changed

5 files changed

+39
-54
lines changed

spring-beans/src/main/java/org/springframework/beans/factory/annotation/QualifierAnnotationAutowireCandidateResolver.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2012 the original author or authors.
2+
* Copyright 2002-2013 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -233,8 +233,9 @@ protected boolean checkQualifier(
233233
}
234234
if (qualifier == null) {
235235
Annotation targetAnnotation = null;
236-
if (bd.getResolvedFactoryMethod() != null) {
237-
targetAnnotation = AnnotationUtils.getAnnotation(bd.getResolvedFactoryMethod(), type);
236+
Method resolvedFactoryMethod = bd.getResolvedFactoryMethod();
237+
if (resolvedFactoryMethod != null) {
238+
targetAnnotation = AnnotationUtils.getAnnotation(resolvedFactoryMethod, type);
238239
}
239240
if (targetAnnotation == null) {
240241
// look for matching annotation on the target class

spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractAutowireCapableBeanFactory.java

Lines changed: 30 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -569,7 +569,7 @@ else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
569569
}
570570

571571
@Override
572-
protected Class<?> predictBeanType(String beanName, RootBeanDefinition mbd, Class... typesToMatch) {
572+
protected Class<?> predictBeanType(String beanName, RootBeanDefinition mbd, Class<?>... typesToMatch) {
573573
Class<?> targetType = mbd.getTargetType();
574574
if (targetType == null) {
575575
targetType = (mbd.getFactoryMethodName() != null ? getTypeForFactoryMethod(beanName, mbd, typesToMatch) :
@@ -641,31 +641,38 @@ protected Class<?> getTypeForFactoryMethod(String beanName, RootBeanDefinition m
641641
if (Modifier.isStatic(factoryMethod.getModifiers()) == isStatic &&
642642
factoryMethod.getName().equals(mbd.getFactoryMethodName()) &&
643643
factoryMethod.getParameterTypes().length >= minNrOfArgs) {
644-
Class<?>[] paramTypes = factoryMethod.getParameterTypes();
645-
String[] paramNames = null;
646-
ParameterNameDiscoverer pnd = getParameterNameDiscoverer();
647-
if (pnd != null) {
648-
paramNames = pnd.getParameterNames(factoryMethod);
649-
}
650-
ConstructorArgumentValues cav = mbd.getConstructorArgumentValues();
651-
Set<ConstructorArgumentValues.ValueHolder> usedValueHolders =
652-
new HashSet<ConstructorArgumentValues.ValueHolder>(paramTypes.length);
653-
Object[] args = new Object[paramTypes.length];
654-
for (int i = 0; i < args.length; i++) {
655-
ConstructorArgumentValues.ValueHolder valueHolder = cav.getArgumentValue(
656-
i, paramTypes[i], (paramNames != null ? paramNames[i] : null), usedValueHolders);
657-
if (valueHolder == null) {
658-
valueHolder = cav.getGenericArgumentValue(null, null, usedValueHolders);
644+
// No declared type variables to inspect, so just process the standard return type.
645+
if (factoryMethod.getTypeParameters().length > 0) {
646+
// Fully resolve parameter names and argument values.
647+
Class<?>[] paramTypes = factoryMethod.getParameterTypes();
648+
String[] paramNames = null;
649+
ParameterNameDiscoverer pnd = getParameterNameDiscoverer();
650+
if (pnd != null) {
651+
paramNames = pnd.getParameterNames(factoryMethod);
659652
}
660-
if (valueHolder != null) {
661-
args[i] = valueHolder.getValue();
662-
usedValueHolders.add(valueHolder);
653+
ConstructorArgumentValues cav = mbd.getConstructorArgumentValues();
654+
Set<ConstructorArgumentValues.ValueHolder> usedValueHolders =
655+
new HashSet<ConstructorArgumentValues.ValueHolder>(paramTypes.length);
656+
Object[] args = new Object[paramTypes.length];
657+
for (int i = 0; i < args.length; i++) {
658+
ConstructorArgumentValues.ValueHolder valueHolder = cav.getArgumentValue(
659+
i, paramTypes[i], (paramNames != null ? paramNames[i] : null), usedValueHolders);
660+
if (valueHolder == null) {
661+
valueHolder = cav.getGenericArgumentValue(null, null, usedValueHolders);
662+
}
663+
if (valueHolder != null) {
664+
args[i] = valueHolder.getValue();
665+
usedValueHolders.add(valueHolder);
666+
}
667+
}
668+
Class<?> returnType = AutowireUtils.resolveReturnTypeForFactoryMethod(
669+
factoryMethod, args, getBeanClassLoader());
670+
if (returnType != null) {
671+
returnTypes.add(returnType);
663672
}
664673
}
665-
Class<?> returnType = AutowireUtils.resolveReturnTypeForFactoryMethod(
666-
factoryMethod, args, getBeanClassLoader());
667-
if (returnType != null) {
668-
returnTypes.add(returnType);
674+
else {
675+
returnTypes.add(factoryMethod.getReturnType());
669676
}
670677
}
671678
}

spring-beans/src/main/java/org/springframework/beans/factory/support/AutowireUtils.java

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -193,17 +193,7 @@ public static Class<?> resolveReturnTypeForFactoryMethod(Method method, Object[]
193193
TypeVariable<Method>[] declaredTypeVariables = method.getTypeParameters();
194194
Type genericReturnType = method.getGenericReturnType();
195195
Type[] methodArgumentTypes = method.getGenericParameterTypes();
196-
197-
// No declared type variables to inspect, so just return the standard return type.
198-
if (declaredTypeVariables.length == 0) {
199-
return method.getReturnType();
200-
}
201-
202-
// The supplied argument list is too short for the method's signature, so
203-
// return null, since such a method invocation would fail.
204-
if (args.length < methodArgumentTypes.length) {
205-
return null;
206-
}
196+
Assert.isTrue(args.length == methodArgumentTypes.length, "Argument array does not match parameter count");
207197

208198
// Ensure that the type variable (e.g., T) is declared directly on the method
209199
// itself (e.g., via <T>), not on the enclosing class or interface.

spring-beans/src/test/java/org/springframework/beans/factory/support/AutowireUtilsTests.java

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,9 +49,6 @@ public void genericMethodReturnTypes() {
4949

5050
Method createNamedProxyWithDifferentTypes = ReflectionUtils.findMethod(MyTypeWithMethods.class, "createNamedProxy",
5151
new Class[] { String.class, Object.class });
52-
// one argument to few
53-
assertNull(
54-
AutowireUtils.resolveReturnTypeForFactoryMethod(createNamedProxyWithDifferentTypes, new Object[]{"enigma"}, getClass().getClassLoader()));
5552
assertEquals(Long.class,
5653
AutowireUtils.resolveReturnTypeForFactoryMethod(createNamedProxyWithDifferentTypes, new Object[] { "enigma", 99L }, getClass().getClassLoader()));
5754

spring-beans/src/test/java/org/springframework/beans/factory/support/BeanFactoryGenericsTests.java

Lines changed: 4 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -654,17 +654,13 @@ public void testSetBean() throws Exception {
654654
/**
655655
* Tests support for parameterized static {@code factory-method} declarations such as
656656
* Mockito's {@code mock()} method which has the following signature.
657-
*
658657
* <pre>
659658
* {@code
660659
* public static <T> T mock(Class<T> classToMock)
661660
* }
662661
* </pre>
663-
*
664662
* <p>
665663
* See SPR-9493
666-
*
667-
* @since 3.2
668664
*/
669665
@Test
670666
public void parameterizedStaticFactoryMethod() {
@@ -701,7 +697,6 @@ public void parameterizedInstanceFactoryMethod() {
701697
rbd.setFactoryBeanName("mocksControl");
702698
rbd.setFactoryMethodName("createMock");
703699
rbd.getConstructorArgumentValues().addGenericArgumentValue(Runnable.class);
704-
705700
bf.registerBeanDefinition("mock", rbd);
706701

707702
Map<String, Runnable> beans = bf.getBeansOfType(Runnable.class);
@@ -719,7 +714,6 @@ public void parameterizedInstanceFactoryMethodWithNonResolvedClassName() {
719714
rbd.setFactoryBeanName("mocksControl");
720715
rbd.setFactoryMethodName("createMock");
721716
rbd.getConstructorArgumentValues().addGenericArgumentValue(Runnable.class.getName());
722-
723717
bf.registerBeanDefinition("mock", rbd);
724718

725719
Map<String, Runnable> beans = bf.getBeansOfType(Runnable.class);
@@ -737,7 +731,6 @@ public void parameterizedInstanceFactoryMethodWithIndexedArgument() {
737731
rbd.setFactoryBeanName("mocksControl");
738732
rbd.setFactoryMethodName("createMock");
739733
rbd.getConstructorArgumentValues().addIndexedArgumentValue(0, Runnable.class);
740-
741734
bf.registerBeanDefinition("mock", rbd);
742735

743736
Map<String, Runnable> beans = bf.getBeansOfType(Runnable.class);
@@ -788,21 +781,18 @@ public void setUrlNames(Set<URI> urlNames) throws MalformedURLException {
788781
}
789782
}
790783

784+
791785
/**
792786
* Pseudo-implementation of EasyMock's {@code MocksControl} class.
793787
*/
794788
public static class MocksControl {
795789

796790
@SuppressWarnings("unchecked")
797791
public <T> T createMock(Class<T> toMock) {
798-
799-
return (T) Proxy.newProxyInstance(
800-
BeanFactoryGenericsTests.class.getClassLoader(),
801-
new Class[] { toMock }, new InvocationHandler() {
802-
792+
return (T) Proxy.newProxyInstance(BeanFactoryGenericsTests.class.getClassLoader(), new Class<?>[] {toMock},
793+
new InvocationHandler() {
803794
@Override
804-
public Object invoke(Object proxy, Method method, Object[] args)
805-
throws Throwable {
795+
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
806796
throw new UnsupportedOperationException("mocked!");
807797
}
808798
});

0 commit comments

Comments
 (0)