Announcement Announcement Module
Collapse
No announcement yet.
Trouble autowiring a list with dynamic beans Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Trouble autowiring a list with dynamic beans

    Hi all,

    I'm having some trouble getting a list autowired, with beans that are at runtime dynamically added to the Spring context. Basically, I'm instantiating a prototype bean which has an autowired annotation on a List. When I instantiate this prototype bean the first time, the list can be empty.

    If it was empty the first time, then all further instantiations of my prototype bean will use an empty list, regardless of matching beans having been added to the context.

    However, if it was not empty the first time, then newly registered matches for this list will get picked up as appropriate.

    Here is my prototype bean:

    Code:
    @Scope("prototype")
    @Component("TextProviderUser")
    public class TextProviderUser {
    
      @Autowired(required = false)
      private List<TextProvider> textProviders;
    
      public Set<String> getAllTexts() {
        Set<String> set = new HashSet<>();
    
        if(textProviders != null) {
          for(TextProvider provider : textProviders) {
            set.add(provider.provideText());
          }
        }
    
        return set;
      }
    }
    And here is a working unit test that uses it:

    Code:
    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration(classes = {ApplicationConfiguration.class})
    public class WiringTest {
    
      @Autowired
      private ConfigurableApplicationContext applicationContext;
    
      private BeanDefinitionRegistry registry;
    
      @Before
      public void before() {
        registry = (BeanDefinitionRegistry)applicationContext.getBeanFactory();
      }
    
      @Test
      public void shouldAutowireTextProviderUser() {
        registry.registerBeanDefinition("dynamicBean1", new RootBeanDefinition(DefaultTextProvider.class));
    
        TextProviderUser user1 = (TextProviderUser)applicationContext.getBean("TextProviderUser");
    
        Assert.assertNotNull(user1);
        Assert.assertEquals(1, user1.getAllTexts().size());
    
        registry.registerBeanDefinition("dynamicBean2", new RootBeanDefinition(AnotherTextProvider.class));
    
        TextProviderUser user2 = (TextProviderUser)applicationContext.getBean("TextProviderUser");
    
        Assert.assertEquals(2, user2.getAllTexts().size());
        Assert.assertNotEquals(user1, user2);
        Assert.assertEquals(1, user1.getAllTexts().size());
      }
    }
    And here is a failing unit test, which starts with an empty list by not registering any TextProvider beans at the start (note that you must run the test separately as I did not clean the context properly in this simple example):

    Code:
      @Test
      public void shouldAutowireTextProviderUser() {
        TextProviderUser user1 = (TextProviderUser)applicationContext.getBean("TextProviderUser");
    
        Assert.assertNotNull(user1);
        Assert.assertEquals(0, user1.getAllTexts().size());
    
        registry.registerBeanDefinition("dynamicBean2", new RootBeanDefinition(AnotherTextProvider.class));
    
        TextProviderUser user2 = (TextProviderUser)applicationContext.getBean("TextProviderUser");
    
        Assert.assertEquals(1, user2.getAllTexts().size());   // FAILS HERE
        Assert.assertNotEquals(user1, user2);
        Assert.assertEquals(0, user1.getAllTexts().size());
      }
    My application configuration looks like this:

    Code:
    @Configuration
    @ComponentScan(basePackages = {"hs.dm"})
    public class ApplicationConfiguration {
    
    }
    And the TextProvider interface is simply:

    Code:
    public interface TextProvider {
      String provideText();
    }
    I'm not sure what is going wrong. It seems that there might be some caching in play, but I'm not that experienced with Spring yet to diagnose this. Any insight would be appreciated.

    --John

    ps. for those wondering, the reason I'm adding the TextProvider beans dynamically is because they will be loaded as plugins, and thus I have no choice to add them dynamically.
Working...
X