Skip to content

Commit

Permalink
Fixed resolveReturnTypeForFactoryMethod to unwrap TypedStringValue
Browse files Browse the repository at this point in the history
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
  • Loading branch information
jhoeller committed Oct 27, 2013
1 parent 671fad3 commit 960ba37
Show file tree
Hide file tree
Showing 3 changed files with 75 additions and 11 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
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;

Expand Down Expand Up @@ -222,19 +223,28 @@ public static Class<?> resolveReturnTypeForFactoryMethod(Method method, Object[]
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();
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,15 @@
import java.util.Map;

import org.junit.Test;
import org.mockito.Mockito;

import org.springframework.beans.factory.BeanCreationException;
import org.springframework.beans.factory.BeanFactory;
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;
Expand Down Expand Up @@ -1355,6 +1357,42 @@ public void testGenericsBasedFieldInjectionWithSimpleMatchAndMock() {
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();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
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;
Expand Down Expand Up @@ -719,6 +720,21 @@ public void parameterizedInstanceFactoryMethodWithNonResolvedClassName() {
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();
Expand Down

0 comments on commit 960ba37

Please sign in to comment.