Detect Reactive web applications

This commit improves `@ConditionalOnWebApplication` to specify the
requested web application type. By default, any web application will
match but it can also match only if a recactive (or servlet) web
application is present.

Closes gh-8118
pull/8059/merge
Stephane Nicoll 8 years ago
parent b2ec03cd4e
commit 8e6f1218e1

@ -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
}
}

@ -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<String, Object> attributes = metadata.getAnnotationAttributes(
ConditionalOnWebApplication.class.getName());
if (attributes != null) {
return (Type) attributes.get("type");
}
return Type.ANY;
}
}

@ -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;
@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");
@After
public void closeContext() {
if (this.context != null) {
this.context.close();
}
}
@Test
public void testNotWebApplication() {
this.context.register(MissingConfiguration.class);
this.context.refresh();
assertThat(this.context.containsBean("foo")).isFalse();
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();
}
@Configuration
@ConditionalOnWebApplication
protected static class MissingConfiguration {
@Test
public void testNotWebApplicationWithReactiveContext() {
ReactiveWebApplicationContext ctx = new ReactiveWebApplicationContext();
ctx.register(NotWebApplicationConfiguration.class);
ctx.refresh();
@Bean
public String bar() {
return "bar";
this.context = ctx;
assertThat(this.context.getBeansOfType(String.class)).isEmpty();
}
@Test
public void testNotWebApplication() {
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";
}
}

@ -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;
@After
public void closeContext() {
if (this.context != null) {
this.context.close();
}
}
@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");
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 testNotWebApplication() {
this.context.register(MissingConfiguration.class);
this.context.setServletContext(new MockServletContext());
this.context.refresh();
assertThat(this.context.containsBean("foo")).isFalse();
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 servlet() {
return "servlet";
}
}
@Configuration
@ConditionalOnWebApplication(type = Type.REACTIVE)
protected static class ReactiveWebApplicationConfiguration {
@Bean
public String foo() {
return "foo";
public String reactive() {
return "reactive";
}
}

@ -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

Loading…
Cancel
Save