Skip to content

Commit f958418

Browse files
committed
Allow for specific instance-based match to override factory method signature match
Issue: SPR-11046
1 parent ac7e27b commit f958418

File tree

2 files changed

+122
-21
lines changed

2 files changed

+122
-21
lines changed

spring-beans/src/main/java/org/springframework/beans/factory/support/GenericTypeAwareAutowireCandidateResolver.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,12 @@ protected boolean checkGenericTypeMatch(BeanDefinitionHolder bdHolder, Dependenc
8787
else {
8888
Method resolvedFactoryMethod = rbd.getResolvedFactoryMethod();
8989
if (resolvedFactoryMethod != null) {
90-
targetType = ResolvableType.forMethodReturnType(resolvedFactoryMethod);
90+
if (descriptor.getDependencyType().isAssignableFrom(resolvedFactoryMethod.getReturnType())) {
91+
// Only use factory method metadata if the return type is actually expressive enough
92+
// for our dependency. Otherwise, the returned instance type may have matched instead
93+
// in case of a singleton instance having been registered with the container already.
94+
targetType = ResolvableType.forMethodReturnType(resolvedFactoryMethod);
95+
}
9196
}
9297
}
9398
}

spring-context/src/test/java/org/springframework/context/annotation/ConfigurationClassPostProcessorTests.java

Lines changed: 116 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,10 @@
1616

1717
package org.springframework.context.annotation;
1818

19+
import org.junit.Before;
1920
import org.junit.Test;
2021

22+
import org.springframework.beans.factory.FactoryBean;
2123
import org.springframework.beans.factory.annotation.Autowired;
2224
import org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor;
2325
import org.springframework.beans.factory.annotation.QualifierAnnotationAutowireCandidateResolver;
@@ -31,9 +33,21 @@
3133

3234
/**
3335
* @author Chris Beams
36+
* @author Juergen Hoeller
3437
*/
3538
public class ConfigurationClassPostProcessorTests {
3639

40+
private DefaultListableBeanFactory beanFactory;
41+
42+
@Before
43+
public void setUp() {
44+
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
45+
QualifierAnnotationAutowireCandidateResolver acr = new QualifierAnnotationAutowireCandidateResolver();
46+
acr.setBeanFactory(bf);
47+
bf.setAutowireCandidateResolver(acr);
48+
this.beanFactory = bf;
49+
}
50+
3751
/**
3852
* Enhanced {@link Configuration} classes are only necessary for respecting
3953
* certain bean semantics, like singleton-scoping, scoped proxies, etc.
@@ -45,7 +59,6 @@ public class ConfigurationClassPostProcessorTests {
4559
*/
4660
@Test
4761
public void testEnhancementIsPresentBecauseSingletonSemanticsAreRespected() {
48-
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
4962
beanFactory.registerBeanDefinition("config", new RootBeanDefinition(SingletonBeanConfig.class));
5063
ConfigurationClassPostProcessor pp = new ConfigurationClassPostProcessor();
5164
pp.postProcessBeanFactory(beanFactory);
@@ -60,7 +73,6 @@ public void testEnhancementIsPresentBecauseSingletonSemanticsAreRespected() {
6073
*/
6174
@Test
6275
public void testAlreadyLoadedConfigurationClasses() {
63-
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
6476
beanFactory.registerBeanDefinition("unloadedConfig",
6577
new RootBeanDefinition(UnloadedConfig.class.getName(), null, null));
6678
beanFactory.registerBeanDefinition("loadedConfig", new RootBeanDefinition(LoadedConfig.class));
@@ -76,7 +88,6 @@ public void testAlreadyLoadedConfigurationClasses() {
7688
*/
7789
@Test
7890
public void testPostProcessorIntrospectsInheritedDefinitionsCorrectly() {
79-
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
8091
beanFactory.registerBeanDefinition("config", new RootBeanDefinition(SingletonBeanConfig.class));
8192
beanFactory.registerBeanDefinition("parent", new RootBeanDefinition(TestBean.class));
8293
beanFactory.registerBeanDefinition("child", new ChildBeanDefinition("parent"));
@@ -89,7 +100,6 @@ public void testPostProcessorIntrospectsInheritedDefinitionsCorrectly() {
89100

90101
@Test
91102
public void testPostProcessorOverridesNonApplicationBeanDefinitions() {
92-
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
93103
RootBeanDefinition rbd = new RootBeanDefinition(TestBean.class);
94104
rbd.setRole(RootBeanDefinition.ROLE_SUPPORT);
95105
beanFactory.registerBeanDefinition("bar", rbd);
@@ -103,7 +113,6 @@ public void testPostProcessorOverridesNonApplicationBeanDefinitions() {
103113

104114
@Test
105115
public void testPostProcessorDoesNotOverrideRegularBeanDefinitions() {
106-
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
107116
RootBeanDefinition rbd = new RootBeanDefinition(TestBean.class);
108117
rbd.setResource(new DescriptiveResource("XML or something"));
109118
beanFactory.registerBeanDefinition("bar", rbd);
@@ -137,32 +146,62 @@ public void testProcessingAllowedOnlyOncePerProcessorRegistryPair() {
137146

138147
@Test
139148
public void testGenericsBasedInjection() {
140-
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
141-
bf.setAutowireCandidateResolver(new QualifierAnnotationAutowireCandidateResolver());
142149
AutowiredAnnotationBeanPostProcessor bpp = new AutowiredAnnotationBeanPostProcessor();
143-
bpp.setBeanFactory(bf);
144-
bf.addBeanPostProcessor(bpp);
150+
bpp.setBeanFactory(beanFactory);
151+
beanFactory.addBeanPostProcessor(bpp);
145152
RootBeanDefinition bd = new RootBeanDefinition(RepositoryInjectionBean.class);
146153
bd.setScope(RootBeanDefinition.SCOPE_PROTOTYPE);
147-
bf.registerBeanDefinition("annotatedBean", bd);
148-
bf.registerBeanDefinition("configClass", new RootBeanDefinition(RepositoryConfiguration.class));
154+
beanFactory.registerBeanDefinition("annotatedBean", bd);
155+
beanFactory.registerBeanDefinition("configClass", new RootBeanDefinition(RepositoryConfiguration.class));
156+
ConfigurationClassPostProcessor pp = new ConfigurationClassPostProcessor();
157+
pp.postProcessBeanFactory(beanFactory);
158+
159+
RepositoryInjectionBean bean = (RepositoryInjectionBean) beanFactory.getBean("annotatedBean");
160+
assertSame(beanFactory.getBean("stringRepo"), bean.stringRepository);
161+
assertSame(beanFactory.getBean("integerRepo"), bean.integerRepository);
162+
}
163+
164+
@Test
165+
public void testGenericsBasedInjectionWithImplTypeAtInjectionPoint() {
166+
AutowiredAnnotationBeanPostProcessor bpp = new AutowiredAnnotationBeanPostProcessor();
167+
bpp.setBeanFactory(beanFactory);
168+
beanFactory.addBeanPostProcessor(bpp);
169+
RootBeanDefinition bd = new RootBeanDefinition(SpecificRepositoryInjectionBean.class);
170+
bd.setScope(RootBeanDefinition.SCOPE_PROTOTYPE);
171+
beanFactory.registerBeanDefinition("annotatedBean", bd);
172+
beanFactory.registerBeanDefinition("configClass", new RootBeanDefinition(SpecificRepositoryConfiguration.class));
173+
ConfigurationClassPostProcessor pp = new ConfigurationClassPostProcessor();
174+
pp.postProcessBeanFactory(beanFactory);
175+
beanFactory.preInstantiateSingletons();
176+
177+
SpecificRepositoryInjectionBean bean = (SpecificRepositoryInjectionBean) beanFactory.getBean("annotatedBean");
178+
assertSame(beanFactory.getBean("genericRepo"), bean.genericRepository);
179+
}
180+
181+
@Test
182+
public void testGenericsBasedInjectionWithFactoryBean() {
183+
AutowiredAnnotationBeanPostProcessor bpp = new AutowiredAnnotationBeanPostProcessor();
184+
bpp.setBeanFactory(beanFactory);
185+
beanFactory.addBeanPostProcessor(bpp);
186+
RootBeanDefinition bd = new RootBeanDefinition(RepositoryFactoryBeanInjectionBean.class);
187+
bd.setScope(RootBeanDefinition.SCOPE_PROTOTYPE);
188+
beanFactory.registerBeanDefinition("annotatedBean", bd);
189+
beanFactory.registerBeanDefinition("configClass", new RootBeanDefinition(RepositoryFactoryBeanConfiguration.class));
149190
ConfigurationClassPostProcessor pp = new ConfigurationClassPostProcessor();
150-
pp.postProcessBeanFactory(bf);
191+
pp.postProcessBeanFactory(beanFactory);
192+
beanFactory.preInstantiateSingletons();
151193

152-
RepositoryInjectionBean bean = (RepositoryInjectionBean) bf.getBean("annotatedBean");
153-
assertSame(bf.getBean("stringRepo"), bean.stringRepository);
154-
assertSame(bf.getBean("integerRepo"), bean.integerRepository);
194+
RepositoryFactoryBeanInjectionBean bean = (RepositoryFactoryBeanInjectionBean) beanFactory.getBean("annotatedBean");
195+
assertSame(beanFactory.getBean("&repoFactoryBean"), bean.repositoryFactoryBean);
155196
}
156197

157198
@Test
158199
public void testGenericsBasedInjectionWithRawMatch() {
159-
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
160-
bf.setAutowireCandidateResolver(new QualifierAnnotationAutowireCandidateResolver());
161-
bf.registerBeanDefinition("configClass", new RootBeanDefinition(RawMatchingConfiguration.class));
200+
beanFactory.registerBeanDefinition("configClass", new RootBeanDefinition(RawMatchingConfiguration.class));
162201
ConfigurationClassPostProcessor pp = new ConfigurationClassPostProcessor();
163-
pp.postProcessBeanFactory(bf);
202+
pp.postProcessBeanFactory(beanFactory);
164203

165-
assertSame(bf.getBean("repo"), bf.getBean("repoConsumer"));
204+
assertSame(beanFactory.getBean("repo"), beanFactory.getBean("repoConsumer"));
166205
}
167206

168207

@@ -215,6 +254,29 @@ public static class Repository<T> {
215254
}
216255

217256

257+
public static class GenericRepository<T> extends Repository<T> {
258+
}
259+
260+
261+
public static class RepositoryFactoryBean<T> implements FactoryBean<T> {
262+
263+
@Override
264+
public T getObject() {
265+
throw new IllegalStateException();
266+
}
267+
268+
@Override
269+
public Class<?> getObjectType() {
270+
return Object.class;
271+
}
272+
273+
@Override
274+
public boolean isSingleton() {
275+
return false;
276+
}
277+
}
278+
279+
218280
public static class RepositoryInjectionBean {
219281

220282
@Autowired
@@ -240,6 +302,40 @@ public Repository<Integer> integerRepo() {
240302
}
241303

242304

305+
public static class SpecificRepositoryInjectionBean {
306+
307+
@Autowired
308+
public GenericRepository<?> genericRepository;
309+
}
310+
311+
312+
@Configuration
313+
public static class SpecificRepositoryConfiguration {
314+
315+
@Bean
316+
public Repository<Object> genericRepo() {
317+
return new GenericRepository<Object>();
318+
}
319+
}
320+
321+
322+
public static class RepositoryFactoryBeanInjectionBean {
323+
324+
@Autowired
325+
public RepositoryFactoryBean<?> repositoryFactoryBean;
326+
}
327+
328+
329+
@Configuration
330+
public static class RepositoryFactoryBeanConfiguration {
331+
332+
@Bean
333+
public RepositoryFactoryBean<Object> repoFactoryBean() {
334+
return new RepositoryFactoryBean<>();
335+
}
336+
}
337+
338+
243339
@Configuration
244340
public static class RawMatchingConfiguration {
245341

0 commit comments

Comments
 (0)