package org.springframework.context.annotation; import static org.hamcrest.CoreMatchers.equalTo; import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import org.junit.Test; import org.springframework.beans.factory.parsing.BeanDefinitionParsingException; /** * Tests regarding overloading and overriding of bean methods. * Related to SPR-6618. * * Bean-annotated methods should be able to be overridden, just as any regular * method. This is straightforward. * * Bean-annotated methods should be able to be overloaded, though supporting this * is more subtle. Essentially, it must be unambiguous to the container which bean * method to call. A simple way to think about this is that no one Configuration * class may declare two bean methods with the same name. In the case of inheritance, * the most specific subclass bean method will always be the one that is invoked. * * @author Chris Beams */ public class BeanMethodPolymorphismTests { @Test public void beanMethodOverloadingWithoutInheritance() { @SuppressWarnings("unused") @Configuration class Config { @Bean String aString() { return "na"; } @Bean String aString(Integer dependency) { return "na"; } } try { new AnnotationConfigApplicationContext(Config.class); fail("expected bean method overloading exception"); } catch (BeanDefinitionParsingException ex) { assertTrue(ex.getMessage(), ex.getMessage().contains("2 overloaded @Bean methods named 'aString'")); } } @Test public void beanMethodOverloadingWithInheritance() { AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(SubConfig.class); assertThat(ctx.getBean(String.class), equalTo("overloaded5")); } static @Configuration class SuperConfig { @Bean String aString() { return "super"; } } static @Configuration class SubConfig { @Bean Integer anInt() { return 5; } @Bean String aString(Integer dependency) { return "overloaded"+dependency; } } /** * When inheritance is not involved, it is still possible to override a bean method from * the container's point of view. This is not strictly 'overloading' of a method per se, * so it's referred to here as 'shadowing' to distinguish the difference. */ @Test public void beanMethodShadowing() { AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(ShadowConfig.class); assertThat(ctx.getBean(String.class), equalTo("shadow")); } @Import(SubConfig.class) static @Configuration class ShadowConfig { @Bean String aString() { return "shadow"; } } }