ResolvableType-based matching respects generic factory method return type

Includes consistent use of ResolvableType.resolve() wherever applicable.

Issue: SPR-15011
(cherry picked from commit 4c005e6)
This commit is contained in:
Juergen Hoeller
2016-12-17 23:10:48 +01:00
parent faab4f9e28
commit b9c4f1fa95
14 changed files with 145 additions and 53 deletions

View File

@@ -343,17 +343,15 @@ public class ApplicationListenerMethodAdapter implements GenericApplicationListe
ResolvableType payloadType = null;
if (event instanceof PayloadApplicationEvent) {
PayloadApplicationEvent<?> payloadEvent = (PayloadApplicationEvent<?>) event;
payloadType = payloadEvent.getResolvableType().as(
PayloadApplicationEvent.class).getGeneric(0);
payloadType = payloadEvent.getResolvableType().as(PayloadApplicationEvent.class).getGeneric();
}
for (ResolvableType declaredEventType : this.declaredEventTypes) {
if (!ApplicationEvent.class.isAssignableFrom(declaredEventType.getRawClass())
&& payloadType != null) {
if (!ApplicationEvent.class.isAssignableFrom(declaredEventType.getRawClass()) && payloadType != null) {
if (declaredEventType.isAssignableFrom(payloadType)) {
return declaredEventType;
}
}
if (declaredEventType.getRawClass().isAssignableFrom(event.getClass())) {
if (declaredEventType.getRawClass().isInstance(event)) {
return declaredEventType;
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2015 the original author or authors.
* Copyright 2002-2016 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.
@@ -60,8 +60,8 @@ public class GenericApplicationListenerAdapter implements GenericApplicationList
@SuppressWarnings("unchecked")
public boolean supportsEventType(ResolvableType eventType) {
if (this.delegate instanceof SmartApplicationListener) {
Class<? extends ApplicationEvent> eventClass = (Class<? extends ApplicationEvent>) eventType.getRawClass();
return ((SmartApplicationListener) this.delegate).supportsEventType(eventClass);
Class<? extends ApplicationEvent> eventClass = (Class<? extends ApplicationEvent>) eventType.resolve();
return (eventClass != null && ((SmartApplicationListener) this.delegate).supportsEventType(eventClass));
}
else {
return (this.declaredEventType == null || this.declaredEventType.isAssignableFrom(eventType));
@@ -70,7 +70,7 @@ public class GenericApplicationListenerAdapter implements GenericApplicationList
@Override
public boolean supportsEventType(Class<? extends ApplicationEvent> eventType) {
return supportsEventType(ResolvableType.forType(eventType));
return supportsEventType(ResolvableType.forClass(eventType));
}
@Override

View File

@@ -20,6 +20,7 @@ import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.List;
import javax.annotation.PostConstruct;
import org.junit.Before;
@@ -42,6 +43,7 @@ import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.componentscan.simple.SimpleComponent;
import org.springframework.core.ResolvableType;
import org.springframework.core.annotation.Order;
import org.springframework.core.env.StandardEnvironment;
import org.springframework.core.io.DescriptiveResource;
@@ -49,6 +51,7 @@ import org.springframework.stereotype.Component;
import org.springframework.tests.sample.beans.ITestBean;
import org.springframework.tests.sample.beans.TestBean;
import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;
import static org.junit.Assert.*;
@@ -521,6 +524,33 @@ public class ConfigurationClassPostProcessorTests {
assertSame(beanFactory.getBean("genericRepo"), beanFactory.getBean("repoConsumer"));
}
@Test
public void genericsBasedInjectionWithLateGenericsMatching() {
beanFactory.registerBeanDefinition("configClass", new RootBeanDefinition(RepositoryConfiguration.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]);
}
@Test
public void genericsBasedInjectionWithEarlyGenericsMatching() {
beanFactory.registerBeanDefinition("configClass", new RootBeanDefinition(RepositoryConfiguration.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]);
}
@Test
public void testSelfReferenceExclusionForFactoryMethodOnSameBean() {
AutowiredAnnotationBeanPostProcessor bpp = new AutowiredAnnotationBeanPostProcessor();
@@ -615,6 +645,15 @@ public class ConfigurationClassPostProcessorTests {
assertSame(ctx.getBean(BarImpl.class), ctx.getBean(FooImpl.class).bar);
}
@Test
public void testCollectionInjectionFromSameConfigurationClass() {
ApplicationContext ctx = new AnnotationConfigApplicationContext(CollectionInjectionConfiguration.class);
CollectionInjectionConfiguration bean = ctx.getBean(CollectionInjectionConfiguration.class);
assertNotNull(bean.testBeans);
assertEquals(1, bean.testBeans.size());
assertSame(ctx.getBean(TestBean.class), bean.testBeans.get(0));
}
// -------------------------------------------------------------------------
@@ -1253,4 +1292,16 @@ public class ConfigurationClassPostProcessorTests {
}
}
@Configuration
static class CollectionInjectionConfiguration {
@Autowired(required = false)
public List<TestBean> testBeans;
@Bean
public TestBean thing() {
return new TestBean();
}
}
}