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 b5bddd600d..e83426e76a 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 @@ -32,6 +32,7 @@ import java.util.Comparator; import java.util.Set; import org.springframework.beans.factory.ObjectFactory; +import org.springframework.beans.factory.config.TypedStringValue; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; @@ -222,19 +223,28 @@ abstract class AutowireUtils { if (arg instanceof Class) { return (Class) arg; } - else if (arg instanceof String) { - try { - return classLoader.loadClass((String) arg); + else { + String className = null; + if (arg instanceof String) { + className = (String) arg; } - catch (ClassNotFoundException ex) { - throw new IllegalStateException( - "Could not resolve specified class name argument [" + arg + "]", ex); + else if (arg instanceof TypedStringValue) { + className = ((TypedStringValue) arg).getValue(); + } + if (className != null) { + try { + return classLoader.loadClass(className); + } + catch (ClassNotFoundException ex) { + throw new IllegalStateException( + "Could not resolve specified class name argument [" + arg + "]", ex); + } + } + else { + // Consider adding logic to determine the class of the typeArg, if possible. + // For now, just fall back... + return method.getReturnType(); } - } - else { - // Consider adding logic to determine the class of the typeArg, if possible. - // For now, just fall back... - return method.getReturnType(); } } } diff --git a/spring-beans/src/test/java/org/springframework/beans/factory/annotation/AutowiredAnnotationBeanPostProcessorTests.java b/spring-beans/src/test/java/org/springframework/beans/factory/annotation/AutowiredAnnotationBeanPostProcessorTests.java index 4a6654044c..3c4d474047 100644 --- a/spring-beans/src/test/java/org/springframework/beans/factory/annotation/AutowiredAnnotationBeanPostProcessorTests.java +++ b/spring-beans/src/test/java/org/springframework/beans/factory/annotation/AutowiredAnnotationBeanPostProcessorTests.java @@ -28,6 +28,7 @@ import java.util.List; import java.util.Map; import org.junit.Test; +import org.mockito.Mockito; import org.springframework.beans.factory.BeanCreationException; import org.springframework.beans.factory.BeanFactory; @@ -35,6 +36,7 @@ import org.springframework.beans.factory.FactoryBean; import org.springframework.beans.factory.ObjectFactory; import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; +import org.springframework.beans.factory.config.TypedStringValue; import org.springframework.beans.factory.support.AutowireCandidateQualifier; import org.springframework.beans.factory.support.DefaultListableBeanFactory; import org.springframework.beans.factory.support.GenericBeanDefinition; @@ -1355,6 +1357,42 @@ public class AutowiredAnnotationBeanPostProcessorTests { assertSame(repo, bean.stringRepositoryMap.get("repo")); } + @Test + public void testGenericsBasedFieldInjectionWithSimpleMatchAndMockito() { + DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); + bf.setAutowireCandidateResolver(new QualifierAnnotationAutowireCandidateResolver()); + AutowiredAnnotationBeanPostProcessor bpp = new AutowiredAnnotationBeanPostProcessor(); + bpp.setBeanFactory(bf); + bf.addBeanPostProcessor(bpp); + RootBeanDefinition bd = new RootBeanDefinition(RepositoryFieldInjectionBeanWithSimpleMatch.class); + bd.setScope(RootBeanDefinition.SCOPE_PROTOTYPE); + bf.registerBeanDefinition("annotatedBean", bd); + + RootBeanDefinition rbd = new RootBeanDefinition(); + rbd.setBeanClassName(Mockito.class.getName()); + rbd.setFactoryMethodName("mock"); + // TypedStringValue used to be equivalent to an XML-defined argument String + rbd.getConstructorArgumentValues().addGenericArgumentValue(new TypedStringValue(Repository.class.getName())); + bf.registerBeanDefinition("repo", rbd); + + RepositoryFieldInjectionBeanWithSimpleMatch bean = (RepositoryFieldInjectionBeanWithSimpleMatch) bf.getBean("annotatedBean"); + Repository repo = bf.getBean("repo", Repository.class); + assertSame(repo, bean.repository); + assertSame(repo, bean.stringRepository); + assertSame(1, bean.repositoryArray.length); + assertSame(1, bean.stringRepositoryArray.length); + assertSame(repo, bean.repositoryArray[0]); + assertSame(repo, bean.stringRepositoryArray[0]); + assertSame(1, bean.repositoryList.size()); + assertSame(1, bean.stringRepositoryList.size()); + assertSame(repo, bean.repositoryList.get(0)); + assertSame(repo, bean.stringRepositoryList.get(0)); + assertSame(1, bean.repositoryMap.size()); + assertSame(1, bean.stringRepositoryMap.size()); + assertSame(repo, bean.repositoryMap.get("repo")); + assertSame(repo, bean.stringRepositoryMap.get("repo")); + } + @Test public void testGenericsBasedMethodInjection() { DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); 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 e574999741..f35b2a5193 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 @@ -37,6 +37,7 @@ import org.mockito.Mockito; import org.springframework.beans.PropertyEditorRegistrar; import org.springframework.beans.PropertyEditorRegistry; import org.springframework.beans.factory.BeanCreationException; +import org.springframework.beans.factory.config.TypedStringValue; import org.springframework.beans.factory.xml.XmlBeanDefinitionReader; import org.springframework.beans.propertyeditors.CustomNumberEditor; import org.springframework.core.io.ClassPathResource; @@ -719,6 +720,21 @@ public class BeanFactoryGenericsTests { assertEquals(1, beans.size()); } + @Test + public void parameterizedInstanceFactoryMethodWithWrappedClassName() { + DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); + + RootBeanDefinition rbd = new RootBeanDefinition(); + rbd.setBeanClassName(Mockito.class.getName()); + rbd.setFactoryMethodName("mock"); + // TypedStringValue used to be equivalent to an XML-defined argument String + rbd.getConstructorArgumentValues().addGenericArgumentValue(new TypedStringValue(Runnable.class.getName())); + bf.registerBeanDefinition("mock", rbd); + + Map beans = bf.getBeansOfType(Runnable.class); + assertEquals(1, beans.size()); + } + @Test public void parameterizedInstanceFactoryMethodWithIndexedArgument() { DefaultListableBeanFactory bf = new DefaultListableBeanFactory();