From 8084da59a74baee7ba8404e5c4b300a875159868 Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Thu, 12 Jan 2017 21:15:41 +0100 Subject: [PATCH] Map resolution for multiple beans applies to plain Map interface declaration only Issue: SPR-15117 --- .../support/DefaultListableBeanFactory.java | 4 +- ...wiredAnnotationBeanPostProcessorTests.java | 146 +++++++++++++++++- 2 files changed, 146 insertions(+), 4 deletions(-) diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/support/DefaultListableBeanFactory.java b/spring-beans/src/main/java/org/springframework/beans/factory/support/DefaultListableBeanFactory.java index d801a30cf41..b2c52d775fe 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/support/DefaultListableBeanFactory.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/support/DefaultListableBeanFactory.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2016 the original author or authors. + * Copyright 2002-2017 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. @@ -1173,7 +1173,7 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto } return result; } - else if (Map.class.isAssignableFrom(type) && type.isInterface()) { + else if (Map.class == type) { Class keyType = descriptor.getMapKeyType(); if (String.class != keyType) { return null; diff --git a/spring-beans/src/test/java/org/springframework/beans/factory/annotation/AutowiredAnnotationBeanPostProcessorTests.java b/spring-beans/src/test/java/org/springframework/beans/factory/annotation/AutowiredAnnotationBeanPostProcessorTests.java index 45f7896991b..bc388847a12 100644 --- a/spring-beans/src/test/java/org/springframework/beans/factory/annotation/AutowiredAnnotationBeanPostProcessorTests.java +++ b/spring-beans/src/test/java/org/springframework/beans/factory/annotation/AutowiredAnnotationBeanPostProcessorTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2016 the original author or authors. + * Copyright 2002-2017 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. @@ -929,6 +929,28 @@ public class AutowiredAnnotationBeanPostProcessorTests { assertSame(bf.getBean("myTestBeanMap"), bean.getTestBeanMap()); } + @Test + public void testConstructorInjectionWithCustomMapAsBean() { + DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); + bf.setAutowireCandidateResolver(new QualifierAnnotationAutowireCandidateResolver()); + AutowiredAnnotationBeanPostProcessor bpp = new AutowiredAnnotationBeanPostProcessor(); + bpp.setBeanFactory(bf); + bf.addBeanPostProcessor(bpp); + RootBeanDefinition bd = new RootBeanDefinition(CustomMapConstructorInjectionBean.class); + bd.setScope(RootBeanDefinition.SCOPE_PROTOTYPE); + bf.registerBeanDefinition("annotatedBean", bd); + RootBeanDefinition tbm = new RootBeanDefinition(CustomCollectionFactoryMethods.class); + tbm.setUniqueFactoryMethodName("testBeanMap"); + bf.registerBeanDefinition("myTestBeanMap", tbm); + bf.registerSingleton("testBean1", new TestBean()); + bf.registerSingleton("testBean2", new TestBean()); + + CustomMapConstructorInjectionBean bean = (CustomMapConstructorInjectionBean) bf.getBean("annotatedBean"); + assertSame(bf.getBean("myTestBeanMap"), bean.getTestBeanMap()); + bean = (CustomMapConstructorInjectionBean) bf.getBean("annotatedBean"); + assertSame(bf.getBean("myTestBeanMap"), bean.getTestBeanMap()); + } + @Test public void testConstructorInjectionWithTypedSetAsBean() { DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); @@ -972,6 +994,26 @@ public class AutowiredAnnotationBeanPostProcessorTests { assertSame(bf.getBean("myTestBeanSet"), bean.getTestBeanSet()); } + @Test + public void testConstructorInjectionWithCustomSetAsBean() { + DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); + bf.setAutowireCandidateResolver(new QualifierAnnotationAutowireCandidateResolver()); + AutowiredAnnotationBeanPostProcessor bpp = new AutowiredAnnotationBeanPostProcessor(); + bpp.setBeanFactory(bf); + bf.addBeanPostProcessor(bpp); + RootBeanDefinition bd = new RootBeanDefinition(CustomSetConstructorInjectionBean.class); + bd.setScope(RootBeanDefinition.SCOPE_PROTOTYPE); + bf.registerBeanDefinition("annotatedBean", bd); + RootBeanDefinition tbs = new RootBeanDefinition(CustomCollectionFactoryMethods.class); + tbs.setUniqueFactoryMethodName("testBeanSet"); + bf.registerBeanDefinition("myTestBeanSet", tbs); + + CustomSetConstructorInjectionBean bean = (CustomSetConstructorInjectionBean) bf.getBean("annotatedBean"); + assertSame(bf.getBean("myTestBeanSet"), bean.getTestBeanSet()); + bean = (CustomSetConstructorInjectionBean) bf.getBean("annotatedBean"); + assertSame(bf.getBean("myTestBeanSet"), bean.getTestBeanSet()); + } + @Test public void testSelfReference() { DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); @@ -2195,6 +2237,18 @@ public class AutowiredAnnotationBeanPostProcessorTests { assertNotNull(bf.getBean("annotatedBean")); } + @Test @Ignore // SPR-15125 + public void testFactoryBeanSelfInjection() { + DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); + AutowiredAnnotationBeanPostProcessor bpp = new AutowiredAnnotationBeanPostProcessor(); + bpp.setBeanFactory(bf); + bf.addBeanPostProcessor(bpp); + bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(SelfInjectingFactoryBean.class)); + + SelfInjectingFactoryBean bean = bf.getBean(SelfInjectingFactoryBean.class); + assertSame(bf.getBean("annotatedBean"), bean.testBean); + } + @Qualifier("integerRepo") private Repository integerRepositoryQualifierProvider; @@ -3251,7 +3305,7 @@ public class AutowiredAnnotationBeanPostProcessorTests { public interface GenericInterface2 { - public String doSomethingMoreGeneric(K o); + String doSomethingMoreGeneric(K o); } @@ -3437,6 +3491,70 @@ public class AutowiredAnnotationBeanPostProcessorTests { } + public static class CustomCollectionFactoryMethods { + + public static CustomMap testBeanMap() { + CustomMap tbm = new CustomHashMap<>(); + tbm.put("testBean1", new TestBean("tb1")); + tbm.put("testBean2", new TestBean("tb2")); + return tbm; + } + + public static CustomSet testBeanSet() { + CustomSet tbs = new CustomHashSet<>(); + tbs.add(new TestBean("tb1")); + tbs.add(new TestBean("tb2")); + return tbs; + } + } + + + public static class CustomMapConstructorInjectionBean { + + private CustomMap testBeanMap; + + @Autowired + public CustomMapConstructorInjectionBean(CustomMap testBeanMap) { + this.testBeanMap = testBeanMap; + } + + public CustomMap getTestBeanMap() { + return this.testBeanMap; + } + } + + + public static class CustomSetConstructorInjectionBean { + + private CustomSet testBeanSet; + + @Autowired + public CustomSetConstructorInjectionBean(CustomSet testBeanSet) { + this.testBeanSet = testBeanSet; + } + + public CustomSet getTestBeanSet() { + return this.testBeanSet; + } + } + + + public interface CustomMap extends Map { + } + + + public static class CustomHashMap extends LinkedHashMap implements CustomMap { + } + + + public interface CustomSet extends Set { + } + + + public static class CustomHashSet extends LinkedHashSet implements CustomSet { + } + + public static class AnnotatedDefaultConstructorBean { @Autowired @@ -3444,4 +3562,28 @@ public class AutowiredAnnotationBeanPostProcessorTests { } } + + public static class SelfInjectingFactoryBean implements FactoryBean { + + private final TestBean exposedTestBean = new TestBean(); + + @Autowired + TestBean testBean; + + @Override + public TestBean getObject() { + return exposedTestBean; + } + + @Override + public Class getObjectType() { + return TestBean.class; + } + + @Override + public boolean isSingleton() { + return true; + } + } + }