/*
* Copyright 2002-2016 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.context.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.Map;
import org.junit.Test;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.core.type.AnnotatedTypeMetadata;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.stereotype.Component;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;
/**
* Test for {@link Conditional} beans.
*
* @author Phillip Webb
* @author Juergen Hoeller
*/
@SuppressWarnings("resource")
public class ConfigurationClassWithConditionTests {
@Test
public void conditionalOnMissingBeanMatch() throws Exception {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.register(BeanOneConfiguration.class, BeanTwoConfiguration.class);
ctx.refresh();
assertTrue(ctx.containsBean("bean1"));
assertFalse(ctx.containsBean("bean2"));
assertFalse(ctx.containsBean("configurationClassWithConditionTests.BeanTwoConfiguration"));
}
@Test
public void conditionalOnMissingBeanNoMatch() throws Exception {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.register(BeanTwoConfiguration.class);
ctx.refresh();
assertFalse(ctx.containsBean("bean1"));
assertTrue(ctx.containsBean("bean2"));
assertTrue(ctx.containsBean("configurationClassWithConditionTests.BeanTwoConfiguration"));
}
@Test
public void conditionalOnBeanMatch() throws Exception {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.register(BeanOneConfiguration.class, BeanThreeConfiguration.class);
ctx.refresh();
assertTrue(ctx.containsBean("bean1"));
assertTrue(ctx.containsBean("bean3"));
}
@Test
public void conditionalOnBeanNoMatch() throws Exception {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.register(BeanThreeConfiguration.class);
ctx.refresh();
assertFalse(ctx.containsBean("bean1"));
assertFalse(ctx.containsBean("bean3"));
}
@Test
public void metaConditional() throws Exception {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.register(ConfigurationWithMetaCondition.class);
ctx.refresh();
assertTrue(ctx.containsBean("bean"));
}
@Test
public void metaConditionalWithAsm() throws Exception {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.registerBeanDefinition("config", new RootBeanDefinition(ConfigurationWithMetaCondition.class.getName()));
ctx.refresh();
assertTrue(ctx.containsBean("bean"));
}
@Test
public void nonConfigurationClass() throws Exception {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.register(NonConfigurationClass.class);
ctx.refresh();
assertFalse(ctx.containsBean("bean1"));
}
@Test
public void nonConfigurationClassWithAsm() throws Exception {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.registerBeanDefinition("config", new RootBeanDefinition(NonConfigurationClass.class.getName()));
ctx.refresh();
assertFalse(ctx.containsBean("bean1"));
}
@Test
public void methodConditional() throws Exception {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.register(ConditionOnMethodConfiguration.class);
ctx.refresh();
assertFalse(ctx.containsBean("bean1"));
}
@Test
public void methodConditionalWithAsm() throws Exception {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.registerBeanDefinition("config", new RootBeanDefinition(ConditionOnMethodConfiguration.class.getName()));
ctx.refresh();
assertFalse(ctx.containsBean("bean1"));
}
@Test
public void importsNotCreated() throws Exception {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.register(ImportsNotCreated.class);
ctx.refresh();
}
@Test
public void conditionOnOverriddenMethodHonored() {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ConfigWithBeanSkipped.class);
assertEquals(0, context.getBeansOfType(ExampleBean.class).size());
}
@Test
public void noConditionOnOverriddenMethodHonored() {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ConfigWithBeanReactivated.class);
Map<String, ExampleBean> beans = context.getBeansOfType(ExampleBean.class);
assertEquals(1, beans.size());
assertEquals("baz", beans.keySet().iterator().next());
}
@Test
public void configWithAlternativeBeans() {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ConfigWithAlternativeBeans.class);
Map<String, ExampleBean> beans = context.getBeansOfType(ExampleBean.class);
assertEquals(1, beans.size());
assertEquals("baz", beans.keySet().iterator().next());
}
@Configuration
static class BeanOneConfiguration {
@Bean
public ExampleBean bean1() {
return new ExampleBean();
}
}
@Configuration
@Conditional(NoBeanOneCondition.class)
static class BeanTwoConfiguration {
@Bean
public ExampleBean bean2() {
return new ExampleBean();
}
}
@Configuration
@Conditional(HasBeanOneCondition.class)
static class BeanThreeConfiguration {
@Bean
public ExampleBean bean3() {
return new ExampleBean();
}
}
@Configuration
@MetaConditional("test")
static class ConfigurationWithMetaCondition {
@Bean
public ExampleBean bean() {
return new ExampleBean();
}
}
@Conditional(MetaConditionalFilter.class)
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface MetaConditional {
String value();
}
@Conditional(NeverCondition.class)
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD})
public @interface Never {
}
@Conditional(AlwaysCondition.class)
@Never
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD})
public @interface MetaNever {
}
static class NoBeanOneCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
return !context.getBeanFactory().containsBeanDefinition("bean1");
}
}
static class HasBeanOneCondition implements ConfigurationCondition {
@Override
public ConfigurationPhase getConfigurationPhase() {
return ConfigurationPhase.REGISTER_BEAN;
}
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
return context.getBeanFactory().containsBeanDefinition("bean1");
}
}
static class MetaConditionalFilter implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
AnnotationAttributes attributes = AnnotationAttributes.fromMap(metadata.getAnnotationAttributes(MetaConditional.class.getName()));
assertThat(attributes.getString("value"), equalTo("test"));
return true;
}
}
static class NeverCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
return false;
}
}
static class AlwaysCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
return true;
}
}
@Component
@MetaNever
static class NonConfigurationClass {
@Bean
public ExampleBean bean1() {
return new ExampleBean();
}
}
@Configuration
static class ConditionOnMethodConfiguration {
@Bean
@Never
public ExampleBean bean1() {
return new ExampleBean();
}
}
@Configuration
@Never
@Import({ConfigurationNotCreated.class, RegistrarNotCreated.class, ImportSelectorNotCreated.class})
static class ImportsNotCreated {
static {
if (true) throw new RuntimeException();
}
}
@Configuration
static class ConfigurationNotCreated {
static {
if (true) throw new RuntimeException();
}
}
static class RegistrarNotCreated implements ImportBeanDefinitionRegistrar {
static {
if (true) throw new RuntimeException();
}
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata,
BeanDefinitionRegistry registry) {
}
}
static class ImportSelectorNotCreated implements ImportSelector {
static {
if (true) throw new RuntimeException();
}
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
return new String[] {};
}
}
static class ExampleBean {
}
@Configuration
static class ConfigWithBeanActive {
@Bean
public ExampleBean baz() {
return new ExampleBean();
}
}
static class ConfigWithBeanSkipped extends ConfigWithBeanActive {
@Override
@Bean
@Conditional(NeverCondition.class)
public ExampleBean baz() {
return new ExampleBean();
}
}
static class ConfigWithBeanReactivated extends ConfigWithBeanSkipped {
@Override
@Bean
public ExampleBean baz() {
return new ExampleBean();
}
}
@Configuration
static class ConfigWithAlternativeBeans {
@Bean(name = "baz")
@Conditional(AlwaysCondition.class)
public ExampleBean baz1() {
return new ExampleBean();
}
@Bean(name = "baz")
@Conditional(NeverCondition.class)
public ExampleBean baz2() {
return new ExampleBean();
}
}
}