diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/ConditionalOnWebApplication.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/ConditionalOnWebApplication.java index a5100ee1f2..ff410b956f 100644 --- a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/ConditionalOnWebApplication.java +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/ConditionalOnWebApplication.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2016 the original author or authors. + * Copyright 2012-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. @@ -25,10 +25,12 @@ import java.lang.annotation.Target; import org.springframework.context.annotation.Conditional; /** - * {@link Conditional} that only matches when the application context is a web application - * context. + * {@link Conditional} that matches when the application is a web application. By default, + * any web application will match but it can be narrowed using the {@link #type()} + * attribute. * * @author Dave Syer + * @author Stephane Nicoll */ @Target({ ElementType.TYPE, ElementType.METHOD }) @Retention(RetentionPolicy.RUNTIME) @@ -36,4 +38,32 @@ import org.springframework.context.annotation.Conditional; @Conditional(OnWebApplicationCondition.class) public @interface ConditionalOnWebApplication { + /** + * The required type of the web application. + * @return the required web application type + */ + Type type() default Type.ANY; + + /** + * Available application types. + */ + enum Type { + + /** + * Any web application will match. + */ + ANY, + + /** + * Only servlet-based web application will match. + */ + SERVLET, + + /** + * Only reactive-based web application will match. + */ + REACTIVE + + } + } diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/OnWebApplicationCondition.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/OnWebApplicationCondition.java index e06f0fba23..6b70305a7e 100644 --- a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/OnWebApplicationCondition.java +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/OnWebApplicationCondition.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2016 the original author or authors. + * Copyright 2012-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. @@ -16,6 +16,10 @@ package org.springframework.boot.autoconfigure.condition; +import java.util.Map; + +import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type; +import org.springframework.boot.context.embedded.ReactiveWebApplicationContext; import org.springframework.context.annotation.Condition; import org.springframework.context.annotation.ConditionContext; import org.springframework.core.Ordered; @@ -59,6 +63,35 @@ class OnWebApplicationCondition extends SpringBootCondition { AnnotatedTypeMetadata metadata, boolean required) { ConditionMessage.Builder message = ConditionMessage.forCondition( ConditionalOnWebApplication.class, required ? "(required)" : ""); + Type type = deduceType(metadata); + if (Type.SERVLET == type) { + return isServletWebApplication(context); + } + else if (Type.REACTIVE == type) { + return isReactiveWebApplication(context); + } + else { + ConditionOutcome servletOutcome = isServletWebApplication(context); + if (servletOutcome.isMatch() && required) { + return new ConditionOutcome(servletOutcome.isMatch(), + message.because(servletOutcome.getMessage())); + } + ConditionOutcome reactiveOutcome = isReactiveWebApplication(context); + if (reactiveOutcome.isMatch() && required) { + return new ConditionOutcome(reactiveOutcome.isMatch(), + message.because(reactiveOutcome.getMessage())); + } + boolean finalOutcome = (required ? + servletOutcome.isMatch() && reactiveOutcome.isMatch() : + servletOutcome.isMatch() || reactiveOutcome.isMatch()); + return new ConditionOutcome(finalOutcome, message.because( + servletOutcome.getMessage()).append("and").append( + reactiveOutcome.getMessage())); + } + } + + private ConditionOutcome isServletWebApplication(ConditionContext context) { + ConditionMessage.Builder message = ConditionMessage.forCondition(""); if (!ClassUtils.isPresent(WEB_CONTEXT_CLASS, context.getClassLoader())) { return ConditionOutcome .noMatch(message.didNotFind("web application classes").atAll()); @@ -76,7 +109,26 @@ class OnWebApplicationCondition extends SpringBootCondition { if (context.getResourceLoader() instanceof WebApplicationContext) { return ConditionOutcome.match(message.foundExactly("WebApplicationContext")); } - return ConditionOutcome.noMatch(message.because("not a web application")); + return ConditionOutcome.noMatch(message.because("not a servlet web application")); + } + + private ConditionOutcome isReactiveWebApplication(ConditionContext context) { + ConditionMessage.Builder message = ConditionMessage.forCondition(""); + if (context.getResourceLoader() instanceof ReactiveWebApplicationContext) { + return ConditionOutcome.match( + message.foundExactly("ReactiveWebApplicationContext")); + } + return ConditionOutcome.noMatch(message.because( + "not a reactive web application")); + } + + private Type deduceType(AnnotatedTypeMetadata metadata) { + Map attributes = metadata.getAnnotationAttributes( + ConditionalOnWebApplication.class.getName()); + if (attributes != null) { + return (Type) attributes.get("type"); + } + return Type.ANY; } } diff --git a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/condition/ConditionalOnNotWebApplicationTests.java b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/condition/ConditionalOnNotWebApplicationTests.java index 862a90e861..7489526162 100644 --- a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/condition/ConditionalOnNotWebApplicationTests.java +++ b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/condition/ConditionalOnNotWebApplicationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2016 the original author or authors. + * Copyright 2012-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. @@ -16,56 +16,76 @@ package org.springframework.boot.autoconfigure.condition; +import org.junit.After; import org.junit.Test; +import org.springframework.boot.context.embedded.ReactiveWebApplicationContext; +import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.mock.web.MockServletContext; +import org.springframework.web.context.support.AnnotationConfigWebApplicationContext; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.entry; /** * Tests for {@link ConditionalOnNotWebApplication}. * - * @author Dave Syer + * @author Dave Syer$ + * @author Stephane Nicoll */ public class ConditionalOnNotWebApplicationTests { - private final AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); + private ConfigurableApplicationContext context; + + @After + public void closeContext() { + if (this.context != null) { + this.context.close(); + } + } @Test - public void testWebApplication() { - this.context.register(BasicConfiguration.class); - this.context.refresh(); - assertThat(this.context.containsBean("foo")).isTrue(); - assertThat(this.context.getBean("foo")).isEqualTo("foo"); + public void testNotWebApplicationWithServletContext() { + AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext(); + ctx.register(NotWebApplicationConfiguration.class); + ctx.setServletContext(new MockServletContext()); + ctx.refresh(); + + this.context = ctx; + assertThat(this.context.getBeansOfType(String.class)).isEmpty(); + } + + @Test + public void testNotWebApplicationWithReactiveContext() { + ReactiveWebApplicationContext ctx = new ReactiveWebApplicationContext(); + ctx.register(NotWebApplicationConfiguration.class); + ctx.refresh(); + + this.context = ctx; + assertThat(this.context.getBeansOfType(String.class)).isEmpty(); } @Test public void testNotWebApplication() { - this.context.register(MissingConfiguration.class); - this.context.refresh(); - assertThat(this.context.containsBean("foo")).isFalse(); - } - - @Configuration - @ConditionalOnWebApplication - protected static class MissingConfiguration { - - @Bean - public String bar() { - return "bar"; - } + AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(); + ctx.register(NotWebApplicationConfiguration.class); + ctx.refresh(); + this.context = ctx; + assertThat(this.context.getBeansOfType(String.class)).containsExactly( + entry("none", "none")); } @Configuration @ConditionalOnNotWebApplication - protected static class BasicConfiguration { + protected static class NotWebApplicationConfiguration { @Bean - public String foo() { - return "foo"; + public String none() { + return "none"; } } diff --git a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/condition/ConditionalOnWebApplicationTests.java b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/condition/ConditionalOnWebApplicationTests.java index 4da7bd1156..e6b5252133 100644 --- a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/condition/ConditionalOnWebApplicationTests.java +++ b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/condition/ConditionalOnWebApplicationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2016 the original author or authors. + * Copyright 2012-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. @@ -16,59 +16,106 @@ package org.springframework.boot.autoconfigure.condition; +import org.junit.After; import org.junit.Test; +import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type; +import org.springframework.boot.context.embedded.ReactiveWebApplicationContext; +import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.mock.web.MockServletContext; import org.springframework.web.context.support.AnnotationConfigWebApplicationContext; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.entry; /** * Tests for {@link ConditionalOnWebApplication}. * * @author Dave Syer + * @author Stephane Nicoll */ public class ConditionalOnWebApplicationTests { - private final AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext(); + private ConfigurableApplicationContext context; - @Test - public void testWebApplication() { - this.context.register(BasicConfiguration.class); - this.context.setServletContext(new MockServletContext()); - this.context.refresh(); - assertThat(this.context.containsBean("foo")).isTrue(); - assertThat(this.context.getBean("foo")).isEqualTo("foo"); + @After + public void closeContext() { + if (this.context != null) { + this.context.close(); + } } @Test - public void testNotWebApplication() { - this.context.register(MissingConfiguration.class); - this.context.setServletContext(new MockServletContext()); - this.context.refresh(); - assertThat(this.context.containsBean("foo")).isFalse(); + public void testWebApplicationWithServletContext() { + AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext(); + ctx.register(AnyWebApplicationConfiguration.class, + ServletWebApplicationConfiguration.class, + ReactiveWebApplicationConfiguration.class); + ctx.setServletContext(new MockServletContext()); + ctx.refresh(); + + this.context = ctx; + assertThat(this.context.getBeansOfType(String.class)).containsExactly( + entry("any", "any"), entry("servlet", "servlet")); + } + + @Test + public void testWebApplicationWithReactiveContext() { + ReactiveWebApplicationContext ctx = new ReactiveWebApplicationContext(); + ctx.register(AnyWebApplicationConfiguration.class, + ServletWebApplicationConfiguration.class, + ReactiveWebApplicationConfiguration.class); + ctx.refresh(); + + this.context = ctx; + assertThat(this.context.getBeansOfType(String.class)).containsExactly( + entry("any", "any"), entry("reactive", "reactive")); + } + + @Test + public void testNonWebApplication() { + AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(); + ctx.register(AnyWebApplicationConfiguration.class, + ServletWebApplicationConfiguration.class, + ReactiveWebApplicationConfiguration.class); + ctx.refresh(); + + this.context = ctx; + assertThat(this.context.getBeansOfType(String.class)).isEmpty(); } @Configuration - @ConditionalOnNotWebApplication - protected static class MissingConfiguration { + @ConditionalOnWebApplication + protected static class AnyWebApplicationConfiguration { @Bean - public String bar() { - return "bar"; + public String any() { + return "any"; } } @Configuration - @ConditionalOnWebApplication - protected static class BasicConfiguration { + @ConditionalOnWebApplication(type = Type.SERVLET) + protected static class ServletWebApplicationConfiguration { @Bean - public String foo() { - return "foo"; + public String servlet() { + return "servlet"; + } + + } + + @Configuration + @ConditionalOnWebApplication(type = Type.REACTIVE) + protected static class ReactiveWebApplicationConfiguration { + + @Bean + public String reactive() { + return "reactive"; } } diff --git a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/logging/AutoConfigurationReportLoggingInitializerTests.java b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/logging/AutoConfigurationReportLoggingInitializerTests.java index 0e442c7b9e..baf64d4d98 100644 --- a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/logging/AutoConfigurationReportLoggingInitializerTests.java +++ b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/logging/AutoConfigurationReportLoggingInitializerTests.java @@ -171,7 +171,8 @@ public class AutoConfigurationReportLoggingInitializerTests { } // Just basic sanity check, test is for visual inspection String l = this.debugLog.get(0); - assertThat(l).contains("not a web application (OnWebApplicationCondition)"); + assertThat(l).contains( + "not a servlet web application (OnWebApplicationCondition)"); } @Test