Skip to content

Commit

Permalink
ResolvableType-based matching consistently respects generic factory m…
Browse files Browse the repository at this point in the history
…ethod return type (even for pre-initialized raw singleton instance)

Issue: SPR-17524

(cherry picked from commit ebbe14c)
  • Loading branch information
jhoeller committed Nov 25, 2018
1 parent cf8479c commit e9f7c35
Show file tree
Hide file tree
Showing 2 changed files with 180 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -509,12 +509,21 @@ else if (typeToMatch.hasGenerics() && containsBeanDefinition(beanName)) {
// Generics potentially only match on the target class, not on the proxy...
RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
Class<?> targetType = mbd.getTargetType();
if (targetType != null && targetType != ClassUtils.getUserClass(beanInstance) &&
typeToMatch.isAssignableFrom(targetType)) {
if (targetType != null && targetType != ClassUtils.getUserClass(beanInstance)) {
// Check raw class match as well, making sure it's exposed on the proxy.
Class<?> classToMatch = typeToMatch.resolve();
return (classToMatch == null || classToMatch.isInstance(beanInstance));
if (classToMatch != null && !classToMatch.isInstance(beanInstance)) {
return false;
}
if (typeToMatch.isAssignableFrom(targetType)) {
return true;
}
}
ResolvableType resolvableType = mbd.targetType;
if (resolvableType == null) {
resolvableType = mbd.factoryMethodReturnType;
}
return (resolvableType != null && typeToMatch.isAssignableFrom(resolvableType));
}
}
return false;
Expand Down Expand Up @@ -1363,6 +1372,7 @@ public void clearMetadataCache() {
*/
protected Class<?> resolveBeanClass(final RootBeanDefinition mbd, String beanName, final Class<?>... typesToMatch)
throws CannotLoadBeanClassException {

try {
if (mbd.hasBeanClass()) {
return mbd.getBeanClass();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -544,6 +544,10 @@ public void genericsBasedInjectionWithEarlyGenericsMatching() {
beanNames = beanFactory.getBeanNamesForType(ResolvableType.forClassWithGenerics(Repository.class, String.class));
assertEquals(1, beanNames.length);
assertEquals("stringRepo", beanNames[0]);

beanNames = beanFactory.getBeanNamesForType(ResolvableType.forClassWithGenerics(Repository.class, String.class));
assertEquals(1, beanNames.length);
assertEquals("stringRepo", beanNames[0]);
}

@Test
Expand All @@ -558,6 +562,78 @@ public void genericsBasedInjectionWithLateGenericsMatching() {
beanNames = beanFactory.getBeanNamesForType(ResolvableType.forClassWithGenerics(Repository.class, String.class));
assertEquals(1, beanNames.length);
assertEquals("stringRepo", beanNames[0]);

beanNames = beanFactory.getBeanNamesForType(ResolvableType.forClassWithGenerics(Repository.class, String.class));
assertEquals(1, beanNames.length);
assertEquals("stringRepo", beanNames[0]);
}

@Test
public void genericsBasedInjectionWithEarlyGenericsMatchingAndRawFactoryMethod() {
beanFactory.registerBeanDefinition("configClass", new RootBeanDefinition(RawFactoryMethodRepositoryConfiguration.class));
new ConfigurationClassPostProcessor().postProcessBeanFactory(beanFactory);

String[] beanNames = beanFactory.getBeanNamesForType(Repository.class);
assertTrue(ObjectUtils.containsElement(beanNames, "stringRepo"));

beanNames = beanFactory.getBeanNamesForType(ResolvableType.forClassWithGenerics(Repository.class, String.class));
assertEquals(0, beanNames.length);

beanNames = beanFactory.getBeanNamesForType(ResolvableType.forClassWithGenerics(Repository.class, String.class));
assertEquals(0, beanNames.length);
}

@Test
public void genericsBasedInjectionWithLateGenericsMatchingAndRawFactoryMethod() {
beanFactory.registerBeanDefinition("configClass", new RootBeanDefinition(RawFactoryMethodRepositoryConfiguration.class));
new ConfigurationClassPostProcessor().postProcessBeanFactory(beanFactory);
beanFactory.preInstantiateSingletons();

String[] beanNames = beanFactory.getBeanNamesForType(Repository.class);
assertTrue(ObjectUtils.containsElement(beanNames, "stringRepo"));

beanNames = beanFactory.getBeanNamesForType(ResolvableType.forClassWithGenerics(Repository.class, String.class));
assertEquals(1, beanNames.length);
assertEquals("stringRepo", beanNames[0]);

beanNames = beanFactory.getBeanNamesForType(ResolvableType.forClassWithGenerics(Repository.class, String.class));
assertEquals(1, beanNames.length);
assertEquals("stringRepo", beanNames[0]);
}

@Test
public void genericsBasedInjectionWithEarlyGenericsMatchingAndRawInstance() {
beanFactory.registerBeanDefinition("configClass", new RootBeanDefinition(RawInstanceRepositoryConfiguration.class));
new ConfigurationClassPostProcessor().postProcessBeanFactory(beanFactory);

String[] beanNames = beanFactory.getBeanNamesForType(Repository.class);
assertTrue(ObjectUtils.containsElement(beanNames, "stringRepo"));

beanNames = beanFactory.getBeanNamesForType(ResolvableType.forClassWithGenerics(Repository.class, String.class));
assertEquals(1, beanNames.length);
assertEquals("stringRepo", beanNames[0]);

beanNames = beanFactory.getBeanNamesForType(ResolvableType.forClassWithGenerics(Repository.class, String.class));
assertEquals(1, beanNames.length);
assertEquals("stringRepo", beanNames[0]);
}

@Test
public void genericsBasedInjectionWithLateGenericsMatchingAndRawInstance() {
beanFactory.registerBeanDefinition("configClass", new RootBeanDefinition(RawInstanceRepositoryConfiguration.class));
new ConfigurationClassPostProcessor().postProcessBeanFactory(beanFactory);
beanFactory.preInstantiateSingletons();

String[] beanNames = beanFactory.getBeanNamesForType(Repository.class);
assertTrue(ObjectUtils.containsElement(beanNames, "stringRepo"));

beanNames = beanFactory.getBeanNamesForType(ResolvableType.forClassWithGenerics(Repository.class, String.class));
assertEquals(1, beanNames.length);
assertEquals("stringRepo", beanNames[0]);

beanNames = beanFactory.getBeanNamesForType(ResolvableType.forClassWithGenerics(Repository.class, String.class));
assertEquals(1, beanNames.length);
assertEquals("stringRepo", beanNames[0]);
}

@Test
Expand All @@ -577,6 +653,10 @@ public void genericsBasedInjectionWithEarlyGenericsMatchingOnCglibProxy() {
assertEquals(1, beanNames.length);
assertEquals("stringRepo", beanNames[0]);

beanNames = beanFactory.getBeanNamesForType(ResolvableType.forClassWithGenerics(Repository.class, String.class));
assertEquals(1, beanNames.length);
assertEquals("stringRepo", beanNames[0]);

assertTrue(AopUtils.isCglibProxy(beanFactory.getBean("stringRepo")));
}

Expand All @@ -598,12 +678,16 @@ public void genericsBasedInjectionWithLateGenericsMatchingOnCglibProxy() {
assertEquals(1, beanNames.length);
assertEquals("stringRepo", beanNames[0]);

beanNames = beanFactory.getBeanNamesForType(ResolvableType.forClassWithGenerics(Repository.class, String.class));
assertEquals(1, beanNames.length);
assertEquals("stringRepo", beanNames[0]);

assertTrue(AopUtils.isCglibProxy(beanFactory.getBean("stringRepo")));
}

@Test
public void genericsBasedInjectionWithLateGenericsMatchingOnCglibProxyAndRawFactoryMethod() {
beanFactory.registerBeanDefinition("configClass", new RootBeanDefinition(RawRepositoryConfiguration.class));
beanFactory.registerBeanDefinition("configClass", new RootBeanDefinition(RawFactoryMethodRepositoryConfiguration.class));
new ConfigurationClassPostProcessor().postProcessBeanFactory(beanFactory);
DefaultAdvisorAutoProxyCreator autoProxyCreator = new DefaultAdvisorAutoProxyCreator();
autoProxyCreator.setProxyTargetClass(true);
Expand All @@ -619,6 +703,35 @@ public void genericsBasedInjectionWithLateGenericsMatchingOnCglibProxyAndRawFact
assertEquals(1, beanNames.length);
assertEquals("stringRepo", beanNames[0]);

beanNames = beanFactory.getBeanNamesForType(ResolvableType.forClassWithGenerics(Repository.class, String.class));
assertEquals(1, beanNames.length);
assertEquals("stringRepo", beanNames[0]);

assertTrue(AopUtils.isCglibProxy(beanFactory.getBean("stringRepo")));
}

@Test
public void genericsBasedInjectionWithLateGenericsMatchingOnCglibProxyAndRawInstance() {
beanFactory.registerBeanDefinition("configClass", new RootBeanDefinition(RawInstanceRepositoryConfiguration.class));
new ConfigurationClassPostProcessor().postProcessBeanFactory(beanFactory);
DefaultAdvisorAutoProxyCreator autoProxyCreator = new DefaultAdvisorAutoProxyCreator();
autoProxyCreator.setProxyTargetClass(true);
autoProxyCreator.setBeanFactory(beanFactory);
beanFactory.addBeanPostProcessor(autoProxyCreator);
beanFactory.registerSingleton("traceInterceptor", new DefaultPointcutAdvisor(new SimpleTraceInterceptor()));
beanFactory.preInstantiateSingletons();

String[] beanNames = beanFactory.getBeanNamesForType(Repository.class);
assertTrue(ObjectUtils.containsElement(beanNames, "stringRepo"));

beanNames = beanFactory.getBeanNamesForType(ResolvableType.forClassWithGenerics(Repository.class, String.class));
assertEquals(1, beanNames.length);
assertEquals("stringRepo", beanNames[0]);

beanNames = beanFactory.getBeanNamesForType(ResolvableType.forClassWithGenerics(Repository.class, String.class));
assertEquals(1, beanNames.length);
assertEquals("stringRepo", beanNames[0]);

assertTrue(AopUtils.isCglibProxy(beanFactory.getBean("stringRepo")));
}

Expand All @@ -638,6 +751,10 @@ public void genericsBasedInjectionWithEarlyGenericsMatchingOnJdkProxy() {
assertEquals(1, beanNames.length);
assertEquals("stringRepo", beanNames[0]);

beanNames = beanFactory.getBeanNamesForType(ResolvableType.forClassWithGenerics(RepositoryInterface.class, String.class));
assertEquals(1, beanNames.length);
assertEquals("stringRepo", beanNames[0]);

assertTrue(AopUtils.isJdkDynamicProxy(beanFactory.getBean("stringRepo")));
}

Expand All @@ -658,12 +775,16 @@ public void genericsBasedInjectionWithLateGenericsMatchingOnJdkProxy() {
assertEquals(1, beanNames.length);
assertEquals("stringRepo", beanNames[0]);

beanNames = beanFactory.getBeanNamesForType(ResolvableType.forClassWithGenerics(RepositoryInterface.class, String.class));
assertEquals(1, beanNames.length);
assertEquals("stringRepo", beanNames[0]);

assertTrue(AopUtils.isJdkDynamicProxy(beanFactory.getBean("stringRepo")));
}

@Test
public void genericsBasedInjectionWithLateGenericsMatchingOnJdkProxyAndRawFactoryMethod() {
beanFactory.registerBeanDefinition("configClass", new RootBeanDefinition(RawRepositoryConfiguration.class));
beanFactory.registerBeanDefinition("configClass", new RootBeanDefinition(RawFactoryMethodRepositoryConfiguration.class));
new ConfigurationClassPostProcessor().postProcessBeanFactory(beanFactory);
DefaultAdvisorAutoProxyCreator autoProxyCreator = new DefaultAdvisorAutoProxyCreator();
autoProxyCreator.setBeanFactory(beanFactory);
Expand All @@ -678,6 +799,34 @@ public void genericsBasedInjectionWithLateGenericsMatchingOnJdkProxyAndRawFactor
assertEquals(1, beanNames.length);
assertEquals("stringRepo", beanNames[0]);

beanNames = beanFactory.getBeanNamesForType(ResolvableType.forClassWithGenerics(RepositoryInterface.class, String.class));
assertEquals(1, beanNames.length);
assertEquals("stringRepo", beanNames[0]);

assertTrue(AopUtils.isJdkDynamicProxy(beanFactory.getBean("stringRepo")));
}

@Test
public void genericsBasedInjectionWithLateGenericsMatchingOnJdkProxyAndRawInstance() {
beanFactory.registerBeanDefinition("configClass", new RootBeanDefinition(RawInstanceRepositoryConfiguration.class));
new ConfigurationClassPostProcessor().postProcessBeanFactory(beanFactory);
DefaultAdvisorAutoProxyCreator autoProxyCreator = new DefaultAdvisorAutoProxyCreator();
autoProxyCreator.setBeanFactory(beanFactory);
beanFactory.addBeanPostProcessor(autoProxyCreator);
beanFactory.registerSingleton("traceInterceptor", new DefaultPointcutAdvisor(new SimpleTraceInterceptor()));
beanFactory.preInstantiateSingletons();

String[] beanNames = beanFactory.getBeanNamesForType(RepositoryInterface.class);
assertTrue(ObjectUtils.containsElement(beanNames, "stringRepo"));

beanNames = beanFactory.getBeanNamesForType(ResolvableType.forClassWithGenerics(RepositoryInterface.class, String.class));
assertEquals(1, beanNames.length);
assertEquals("stringRepo", beanNames[0]);

beanNames = beanFactory.getBeanNamesForType(ResolvableType.forClassWithGenerics(RepositoryInterface.class, String.class));
assertEquals(1, beanNames.length);
assertEquals("stringRepo", beanNames[0]);

assertTrue(AopUtils.isJdkDynamicProxy(beanFactory.getBean("stringRepo")));
}

Expand Down Expand Up @@ -980,7 +1129,7 @@ public String toString() {
}

@Configuration
public static class RawRepositoryConfiguration {
public static class RawFactoryMethodRepositoryConfiguration {

@Bean
public Repository stringRepo() {
Expand All @@ -993,6 +1142,21 @@ public String toString() {
}
}

@Configuration
public static class RawInstanceRepositoryConfiguration {

@SuppressWarnings({"rawtypes", "unchecked"})
@Bean
public Repository<String> stringRepo() {
return new Repository() {
@Override
public String toString() {
return "Repository<String>";
}
};
}
}

@Configuration
public static class ScopedRepositoryConfiguration {

Expand Down

0 comments on commit e9f7c35

Please sign in to comment.