Fixed resolveReturnTypeForFactoryMethod to unwrap TypedStringValue

XML-defined arguments values are initially turned into TypedStringValue wrappers. If we encounter an unresolved argument, we need to unwrap such a TypedStringValue and then try to treat its content as a class name.

Issue: SPR-11034
master
Juergen Hoeller 11 years ago
parent 671fad3cb5
commit 960ba379ca
  1. 32
      spring-beans/src/main/java/org/springframework/beans/factory/support/AutowireUtils.java
  2. 38
      spring-beans/src/test/java/org/springframework/beans/factory/annotation/AutowiredAnnotationBeanPostProcessorTests.java
  3. 16
      spring-beans/src/test/java/org/springframework/beans/factory/support/BeanFactoryGenericsTests.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();
}
}
}

@ -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();

@ -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<String, Runnable> beans = bf.getBeansOfType(Runnable.class);
assertEquals(1, beans.size());
}
@Test
public void parameterizedInstanceFactoryMethodWithIndexedArgument() {
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();

Loading…
Cancel
Save