Add EnableWebReactive + WebReactiveConfigurer

This commit improves the existing web reactive configuration
infrastructure with the following changes:

* renamed `WebReactiveConfiguration` to
`WebReactiveConfigurationSupport` and is is no longer a Configuration
class
* created the `WebReactiveConfigurer` interface; Configuration classes
implementing it will augment the web reactive configuration support
* created the `DelegatingWebReactiveConfiguration` and
`WebReactiveConfigurerComposite` to effectively tie those custom-defined
configurers to the main configuration support
* created the `@EnableWebReactive` to active that support in
configuration classes

Issue: SPR-14754
This commit is contained in:
Brian Clozel
2016-10-13 20:55:42 +02:00
committed by Rossen Stoyanchev
parent ea319345ed
commit 3533024ab8
16 changed files with 683 additions and 42 deletions

View File

@@ -0,0 +1,128 @@
package org.springframework.web.reactive.config;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import org.junit.Before;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.springframework.context.support.StaticApplicationContext;
import org.springframework.core.convert.ConversionService;
import org.springframework.format.FormatterRegistry;
import org.springframework.http.codec.HttpMessageReader;
import org.springframework.http.codec.HttpMessageWriter;
import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;
import org.springframework.web.bind.support.ConfigurableWebBindingInitializer;
import org.springframework.web.reactive.accept.RequestedContentTypeResolverBuilder;
import org.springframework.web.reactive.result.method.annotation.RequestMappingHandlerAdapter;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
import static org.mockito.BDDMockito.given;
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.verify;
/**
* Test fixture for {@link DelegatingWebReactiveConfiguration} tests.
*
* @author Brian Clozel
*/
public class DelegatingWebReactiveConfigurationTests {
private DelegatingWebReactiveConfiguration delegatingConfig;
@Mock
private WebReactiveConfigurer webReactiveConfigurer;
@Captor
private ArgumentCaptor<List<HttpMessageReader<?>>> readers;
@Captor
private ArgumentCaptor<List<HttpMessageWriter<?>>> writers;
@Captor
private ArgumentCaptor<FormatterRegistry> formatterRegistry;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
delegatingConfig = new DelegatingWebReactiveConfiguration();
delegatingConfig.setApplicationContext(new StaticApplicationContext());
given(webReactiveConfigurer.createRequestMappingHandlerMapping()).willReturn(Optional.empty());
given(webReactiveConfigurer.createRequestMappingHandlerAdapter()).willReturn(Optional.empty());
given(webReactiveConfigurer.getValidator()).willReturn(Optional.empty());
given(webReactiveConfigurer.getMessageCodesResolver()).willReturn(Optional.empty());
}
@Test
public void requestMappingHandlerAdapter() throws Exception {
delegatingConfig.setConfigurers(Collections.singletonList(webReactiveConfigurer));
RequestMappingHandlerAdapter adapter = delegatingConfig.requestMappingHandlerAdapter();
ConfigurableWebBindingInitializer initializer = (ConfigurableWebBindingInitializer) adapter.getWebBindingInitializer();
ConversionService initializerConversionService = initializer.getConversionService();
assertTrue(initializer.getValidator() instanceof LocalValidatorFactoryBean);
verify(webReactiveConfigurer).createRequestMappingHandlerAdapter();
verify(webReactiveConfigurer).configureMessageReaders(readers.capture());
verify(webReactiveConfigurer).extendMessageReaders(readers.capture());
verify(webReactiveConfigurer).getValidator();
verify(webReactiveConfigurer).getMessageCodesResolver();
verify(webReactiveConfigurer).addFormatters(formatterRegistry.capture());
verify(webReactiveConfigurer).addArgumentResolvers(any());
assertSame(formatterRegistry.getValue(), initializerConversionService);
assertEquals(5, readers.getValue().size());
}
@Test
public void requestMappingHandlerMapping() throws Exception {
delegatingConfig.setConfigurers(Collections.singletonList(webReactiveConfigurer));
delegatingConfig.requestMappingHandlerMapping();
verify(webReactiveConfigurer).createRequestMappingHandlerMapping();
verify(webReactiveConfigurer).configureRequestedContentTypeResolver(any(RequestedContentTypeResolverBuilder.class));
verify(webReactiveConfigurer).addCorsMappings(any(CorsRegistry.class));
verify(webReactiveConfigurer).configurePathMatching(any(PathMatchConfigurer.class));
}
@Test
public void resourceHandlerMapping() throws Exception {
delegatingConfig.setConfigurers(Collections.singletonList(webReactiveConfigurer));
doAnswer(invocation -> {
ResourceHandlerRegistry registry = invocation.getArgumentAt(0, ResourceHandlerRegistry.class);
registry.addResourceHandler("/static/**").addResourceLocations("classpath:/static");
return null;
}).when(webReactiveConfigurer).addResourceHandlers(any(ResourceHandlerRegistry.class));
delegatingConfig.resourceHandlerMapping();
verify(webReactiveConfigurer).addResourceHandlers(any(ResourceHandlerRegistry.class));
verify(webReactiveConfigurer).configurePathMatching(any(PathMatchConfigurer.class));
}
@Test
public void responseBodyResultHandler() throws Exception {
delegatingConfig.setConfigurers(Collections.singletonList(webReactiveConfigurer));
delegatingConfig.responseBodyResultHandler();
verify(webReactiveConfigurer).configureMessageWriters(writers.capture());
verify(webReactiveConfigurer).extendMessageWriters(writers.capture());
verify(webReactiveConfigurer).configureRequestedContentTypeResolver(any(RequestedContentTypeResolverBuilder.class));
}
@Test
public void viewResolutionResultHandler() throws Exception {
delegatingConfig.setConfigurers(Collections.singletonList(webReactiveConfigurer));
delegatingConfig.viewResolutionResultHandler();
verify(webReactiveConfigurer).configureViewResolvers(any(ViewResolverRegistry.class));
}
}

View File

@@ -80,10 +80,10 @@ import static org.springframework.http.MediaType.IMAGE_PNG;
import static org.springframework.http.MediaType.TEXT_PLAIN;
/**
* Unit tests for {@link WebReactiveConfiguration}.
* Unit tests for {@link WebReactiveConfigurationSupport}.
* @author Rossen Stoyanchev
*/
public class WebReactiveConfigurationTests {
public class WebReactiveConfigurationSupportTests {
private MockServerHttpRequest request;
@@ -100,7 +100,7 @@ public class WebReactiveConfigurationTests {
@Test
public void requestMappingHandlerMapping() throws Exception {
ApplicationContext context = loadConfig(WebReactiveConfiguration.class);
ApplicationContext context = loadConfig(WebReactiveConfig.class);
String name = "requestMappingHandlerMapping";
RequestMappingHandlerMapping mapping = context.getBean(name, RequestMappingHandlerMapping.class);
@@ -138,10 +138,10 @@ public class WebReactiveConfigurationTests {
@Test
public void requestMappingHandlerAdapter() throws Exception {
ApplicationContext context = loadConfig(WebReactiveConfiguration.class);
ApplicationContext context = loadConfig(WebReactiveConfig.class);
String name = "requestMappingHandlerAdapter";
RequestMappingHandlerAdapter adapter = context.getBean(name, RequestMappingHandlerAdapter.class);
RequestMappingHandlerAdapter adapter = context.getBean(name, RequestMappingHandlerAdapter.class);
assertNotNull(adapter);
List<HttpMessageReader<?>> readers = adapter.getMessageReaders();
@@ -185,7 +185,7 @@ public class WebReactiveConfigurationTests {
@Test
public void responseEntityResultHandler() throws Exception {
ApplicationContext context = loadConfig(WebReactiveConfiguration.class);
ApplicationContext context = loadConfig(WebReactiveConfig.class);
String name = "responseEntityResultHandler";
ResponseEntityResultHandler handler = context.getBean(name, ResponseEntityResultHandler.class);
@@ -210,7 +210,7 @@ public class WebReactiveConfigurationTests {
@Test
public void responseBodyResultHandler() throws Exception {
ApplicationContext context = loadConfig(WebReactiveConfiguration.class);
ApplicationContext context = loadConfig(WebReactiveConfig.class);
String name = "responseBodyResultHandler";
ResponseBodyResultHandler handler = context.getBean(name, ResponseBodyResultHandler.class);
@@ -262,7 +262,7 @@ public class WebReactiveConfigurationTests {
AbstractHandlerMapping handlerMapping = context.getBean(name, AbstractHandlerMapping.class);
assertNotNull(handlerMapping);
assertEquals(Ordered.LOWEST_PRECEDENCE -1, handlerMapping.getOrder());
assertEquals(Ordered.LOWEST_PRECEDENCE - 1, handlerMapping.getOrder());
assertNotNull(handlerMapping.getPathHelper());
assertNotNull(handlerMapping.getPathMatcher());
@@ -296,9 +296,12 @@ public class WebReactiveConfigurationTests {
return context;
}
@EnableWebReactive
static class WebReactiveConfig {
}
@Configuration
static class CustomPatchMatchConfig extends WebReactiveConfiguration {
static class CustomPatchMatchConfig extends WebReactiveConfigurationSupport {
@Override
public void configurePathMatching(PathMatchConfigurer configurer) {
@@ -308,7 +311,7 @@ public class WebReactiveConfigurationTests {
}
@Configuration
static class CustomMessageConverterConfig extends WebReactiveConfiguration {
static class CustomMessageConverterConfig extends WebReactiveConfigurationSupport {
@Override
protected void configureMessageReaders(List<HttpMessageReader<?>> messageReaders) {
@@ -331,8 +334,9 @@ public class WebReactiveConfigurationTests {
}
}
@Configuration @SuppressWarnings("unused")
static class CustomViewResolverConfig extends WebReactiveConfiguration {
@Configuration
@SuppressWarnings("unused")
static class CustomViewResolverConfig extends WebReactiveConfigurationSupport {
@Override
protected void configureViewResolvers(ViewResolverRegistry registry) {
@@ -348,7 +352,7 @@ public class WebReactiveConfigurationTests {
}
@Configuration
static class CustomResourceHandlingConfig extends WebReactiveConfiguration {
static class CustomResourceHandlingConfig extends WebReactiveConfigurationSupport {
@Override
protected void addResourceHandlers(ResourceHandlerRegistry registry) {

View File

@@ -43,7 +43,7 @@ import org.springframework.web.client.RestTemplate;
import org.springframework.web.reactive.DispatcherHandler;
import org.springframework.web.reactive.HandlerAdapter;
import org.springframework.web.reactive.HandlerMapping;
import org.springframework.web.reactive.config.WebReactiveConfiguration;
import org.springframework.web.reactive.config.WebReactiveConfigurationSupport;
import org.springframework.web.reactive.function.support.HandlerFunctionAdapter;
import org.springframework.web.reactive.function.support.ResponseResultHandler;
import org.springframework.web.reactive.result.view.ViewResolver;
@@ -104,7 +104,7 @@ public class DispatcherHandlerIntegrationTests extends AbstractHttpHandlerIntegr
@Configuration
static class TestConfiguration extends WebReactiveConfiguration {
static class TestConfiguration extends WebReactiveConfigurationSupport {
@Bean
public PersonHandler personHandler() {

View File

@@ -39,7 +39,7 @@ import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.reactive.config.WebReactiveConfiguration;
import org.springframework.web.reactive.config.EnableWebReactive;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
@@ -222,9 +222,10 @@ public class CrossOriginAnnotationIntegrationTests extends AbstractRequestMappin
@Configuration
@EnableWebReactive
@ComponentScan(resourcePattern = "**/CrossOriginAnnotationIntegrationTests*")
@SuppressWarnings({"unused", "WeakerAccess"})
static class WebConfig extends WebReactiveConfiguration {
static class WebConfig {
}
@RestController @SuppressWarnings("unused")

View File

@@ -32,7 +32,7 @@ import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.HttpClientErrorException;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.reactive.config.CorsRegistry;
import org.springframework.web.reactive.config.WebReactiveConfiguration;
import org.springframework.web.reactive.config.WebReactiveConfigurationSupport;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
@@ -137,7 +137,7 @@ public class GlobalCorsConfigIntegrationTests extends AbstractRequestMappingInte
@Configuration
@ComponentScan(resourcePattern = "**/GlobalCorsConfigIntegrationTests*.class")
@SuppressWarnings({"unused", "WeakerAccess"})
static class WebConfig extends WebReactiveConfiguration {
static class WebConfig extends WebReactiveConfigurationSupport {
@Override
protected void addCorsMappings(CorsRegistry registry) {

View File

@@ -34,7 +34,7 @@ import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.reactive.config.WebReactiveConfiguration;
import org.springframework.web.reactive.config.EnableWebReactive;
/**
* @author Sebastien Deleuze
@@ -93,8 +93,9 @@ public class JacksonHintsIntegrationTests extends AbstractRequestMappingIntegrat
@Configuration
@ComponentScan(resourcePattern = "**/JacksonHintsIntegrationTests*.class")
@EnableWebReactive
@SuppressWarnings({"unused", "WeakerAccess"})
static class WebConfig extends WebReactiveConfiguration {
static class WebConfig {
}
@RestController

View File

@@ -28,7 +28,7 @@ import org.springframework.http.HttpHeaders;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.reactive.config.WebReactiveConfiguration;
import org.springframework.web.reactive.config.EnableWebReactive;
import static org.junit.Assert.assertEquals;
@@ -64,9 +64,10 @@ public class RequestMappingExceptionHandlingIntegrationTests extends AbstractReq
@Configuration
@EnableWebReactive
@ComponentScan(resourcePattern = "**/RequestMappingExceptionHandlingIntegrationTests$*.class")
@SuppressWarnings({"unused", "WeakerAccess"})
static class WebConfig extends WebReactiveConfiguration {
static class WebConfig {
}

View File

@@ -29,7 +29,7 @@ import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.reactive.config.WebReactiveConfiguration;
import org.springframework.web.reactive.config.EnableWebReactive;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
@@ -74,9 +74,10 @@ public class RequestMappingIntegrationTests extends AbstractRequestMappingIntegr
@Configuration
@EnableWebReactive
@ComponentScan(resourcePattern = "**/RequestMappingIntegrationTests$*.class")
@SuppressWarnings({"unused", "WeakerAccess"})
static class WebConfig extends WebReactiveConfiguration {
static class WebConfig {
}
@RestController

View File

@@ -56,11 +56,12 @@ import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.reactive.config.WebReactiveConfiguration;
import org.springframework.web.reactive.config.EnableWebReactive;
import static java.util.Arrays.*;
import static org.junit.Assert.*;
import static org.springframework.http.MediaType.*;
import static java.util.Arrays.asList;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.springframework.http.MediaType.APPLICATION_XML;
/**
* {@code @RequestMapping} integration tests focusing on serialization and
@@ -371,9 +372,10 @@ public class RequestMappingMessageConversionIntegrationTests extends AbstractReq
@Configuration
@EnableWebReactive
@ComponentScan(resourcePattern = "**/RequestMappingMessageConversionIntegrationTests$*.class")
@SuppressWarnings({"unused", "WeakerAccess"})
static class WebConfig extends WebReactiveConfiguration {
static class WebConfig {
}

View File

@@ -35,7 +35,7 @@ import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.reactive.config.ViewResolverRegistry;
import org.springframework.web.reactive.config.WebReactiveConfiguration;
import org.springframework.web.reactive.config.WebReactiveConfigurationSupport;
import org.springframework.web.reactive.result.view.freemarker.FreeMarkerConfigurer;
import org.springframework.web.server.ServerWebExchange;
@@ -81,7 +81,7 @@ public class RequestMappingViewResolutionIntegrationTests extends AbstractReques
@Configuration
@ComponentScan(resourcePattern = "**/RequestMappingViewResolutionIntegrationTests$*.class")
@SuppressWarnings({"unused", "WeakerAccess"})
static class WebConfig extends WebReactiveConfiguration {
static class WebConfig extends WebReactiveConfigurationSupport {
@Override
protected void configureViewResolvers(ViewResolverRegistry registry) {

View File

@@ -36,7 +36,7 @@ import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.reactive.WebClient;
import org.springframework.web.reactive.DispatcherHandler;
import org.springframework.web.reactive.config.WebReactiveConfiguration;
import org.springframework.web.reactive.config.EnableWebReactive;
import org.springframework.web.server.adapter.WebHttpHandlerBuilder;
import static org.springframework.web.client.reactive.ClientWebRequestBuilders.get;
@@ -163,8 +163,9 @@ public class SseIntegrationTests extends AbstractHttpHandlerIntegrationTests {
}
@Configuration
@EnableWebReactive
@SuppressWarnings("unused")
static class TestConfiguration extends WebReactiveConfiguration {
static class TestConfiguration {
@Bean
public SseController sseController() {