Announcement Announcement Module
Collapse
No announcement yet.
Overriding Bean Configuration with annotations Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Overriding Bean Configuration with annotations

    Use case: I have my container configured via classpath scanning @ComponentScan. For my test configuration I need the ability to mock specific beans.

    Due to the order of loading, beans loaded via classpath scan are not overriding properly when using @Configuration. The following code samples demonstrate the problem. BaseExample.java shows how it is possible to override beans via configuration. ScanExample.java shows that overriding a bean that was loaded via @ComponentScan is skipped (see final note).


    Code:
    // BaseExample.java
    
    package com.glassworks.mock;
    
    import org.mockito.Mockito;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.context.annotation.AnnotationConfigApplicationContext;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    
    import com.google.common.base.Joiner;
    
    public class BaseExample {
    	private static final Logger log = LoggerFactory.getLogger(BaseExample.class);
    	private static AnnotationConfigApplicationContext ctx;
    	
    	public static void main(String args[]) {
    		ctx = new AnnotationConfigApplicationContext(Config.class, OverrideConfig.class);
    		
    		String beans[] = ctx.getBeanDefinitionNames();
    		log.info("{} beans found: {}", beans.length, Joiner.on(",").join(beans));
    		
    		for(String bean : beans) {
    			log.info("{}: {}", bean, ctx.getBean(bean));
    		}
    	}
    
    	@Configuration
    	public static class Config {
    		@Bean
    		public AccountDao accountDao() {
    			log.debug("Creating accountDao [Config]");
    			return new AccountDao();
    		}
    	}
    	
    	@Configuration
    	public static class OverrideConfig {
    		@Bean
    		public Object accountDao() {
    			log.debug("Creating accountDao [OverrideConfig]");
    			return Mockito.mock(AccountDao.class);
    		}
    	}
    		
    }
    Output:
    21:05 INFO | com.glassworks.mock.BaseExample | accountDao: Mock for AccountDao, hashCode: 666537607

    Code:
    // ScanExample.java
    
    package com.glassworks.mock;
    
    import org.mockito.Mockito;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.context.annotation.AnnotationConfigApplicationContext;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.ComponentScan;
    import org.springframework.context.annotation.Configuration;
    
    import com.google.common.base.Joiner;
    
    public class ScanExample {
    	private static final Logger log = LoggerFactory.getLogger(ScanExample.class);
    	private static AnnotationConfigApplicationContext ctx;
    	
    	public static void main(String args[]) {
    		ctx = new AnnotationConfigApplicationContext(Config.class, OverrideConfig.class);
    		
    		String beans[] = ctx.getBeanDefinitionNames();
    		log.info("{} beans found: {}", beans.length, Joiner.on(",").join(beans));
    		
    		for(String bean : beans) {
    			log.info("{}: {}", bean, ctx.getBean(bean));
    		}
    	}
    
    	@Configuration
    	@ComponentScan("com.glassworks.services")
    	public static class Config {
    		
    	}
    	
    	@Configuration
    	public static class OverrideConfig {
    		@Bean
    		public AccountDao accountDao() {
    			log.debug("Creating accountDao [OverrideConfig]");
    			return Mockito.mock(AccountDao.class);
    		}
    	}
    		
    }
    Output:
    21:08 INFO | com.glassworks.mock.ScanExample | accountDao: com.glassworks.services.AccountDao@48805ebb

    Code:
    // AccountDao.java
    package com.glassworks.services;
    
    import org.springframework.stereotype.Repository;
    
    @Repository
    public class AccountDao {
    	
    }
    Note
    Its worth noting on that with logging set to debug, Spring indicates that it is skipping over the definition. This appears to be a bug.

    21:09 DEBUG | o.s.c.a.ConfigurationClassBeanDefinitionReader | Skipping loading bean definition for [BeanMethod:name=accountDao,declaringClass=com.glas sworks.mock.ScanExample$OverrideConfig]: a definition for bean 'accountDao' already exists. This is likely due to an override in XML.
    Last edited by dcompiled; Jul 5th, 2012, 08:12 PM. Reason: clarification

  • #2
    There's an open Jira for this problem:

    https://jira.springsource.org/browse...mment-tabpanel

    It might be worth voting on if you have a Jira login for the above, as the issue was raised over two years ago.

    Comment

    Working...
    X