From ff9c695599bb05b43e87e6568552396026671d84 Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Sun, 27 Oct 2013 00:55:02 +0200 Subject: [PATCH] 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. --- ...erAnnotationAutowireCandidateResolver.java | 7 +-- .../AbstractAutowireCapableBeanFactory.java | 53 +++++++++++-------- .../beans/factory/support/AutowireUtils.java | 12 +---- .../factory/support/AutowireUtilsTests.java | 3 -- .../support/BeanFactoryGenericsTests.java | 18 ++----- 5 files changed, 39 insertions(+), 54 deletions(-) diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/annotation/QualifierAnnotationAutowireCandidateResolver.java b/spring-beans/src/main/java/org/springframework/beans/factory/annotation/QualifierAnnotationAutowireCandidateResolver.java index 657ee22666..76c36efbba 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/annotation/QualifierAnnotationAutowireCandidateResolver.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/annotation/QualifierAnnotationAutowireCandidateResolver.java @@ -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 diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractAutowireCapableBeanFactory.java b/spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractAutowireCapableBeanFactory.java index 25c8bb893d..dead703a97 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractAutowireCapableBeanFactory.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractAutowireCapableBeanFactory.java @@ -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 usedValueHolders = - new HashSet(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 usedValueHolders = + new HashSet(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()); } } } diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/support/AutowireUtils.java b/spring-beans/src/main/java/org/springframework/beans/factory/support/AutowireUtils.java index 8c2db33875..16cba97064 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/support/AutowireUtils.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/support/AutowireUtils.java @@ -193,17 +193,7 @@ abstract class AutowireUtils { TypeVariable[] 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 ), not on the enclosing class or interface. diff --git a/spring-beans/src/test/java/org/springframework/beans/factory/support/AutowireUtilsTests.java b/spring-beans/src/test/java/org/springframework/beans/factory/support/AutowireUtilsTests.java index 9a834424d6..56fcde6ec9 100644 --- a/spring-beans/src/test/java/org/springframework/beans/factory/support/AutowireUtilsTests.java +++ b/spring-beans/src/test/java/org/springframework/beans/factory/support/AutowireUtilsTests.java @@ -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())); diff --git a/spring-beans/src/test/java/org/springframework/beans/factory/support/BeanFactoryGenericsTests.java b/spring-beans/src/test/java/org/springframework/beans/factory/support/BeanFactoryGenericsTests.java index 99768b6552..7cdfae4c24 100644 --- a/spring-beans/src/test/java/org/springframework/beans/factory/support/BeanFactoryGenericsTests.java +++ b/spring-beans/src/test/java/org/springframework/beans/factory/support/BeanFactoryGenericsTests.java @@ -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. - * *
 	 * {@code
 	 * public static  T mock(Class classToMock)
 	 * }
 	 * 
- * *

* 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 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 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 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 createMock(Class 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!"); } });