Browse Source

Merge pull request #1202 from bclozel/SPR-14754

pull/1193/merge
Rossen Stoyanchev 9 years ago
parent
commit
351cfb8eef
  1. 131
      spring-web-reactive/src/main/java/org/springframework/web/reactive/config/DelegatingWebReactiveConfiguration.java
  2. 79
      spring-web-reactive/src/main/java/org/springframework/web/reactive/config/EnableWebReactive.java
  3. 15
      spring-web-reactive/src/main/java/org/springframework/web/reactive/config/WebReactiveConfigurationSupport.java
  4. 174
      spring-web-reactive/src/main/java/org/springframework/web/reactive/config/WebReactiveConfigurer.java
  5. 150
      spring-web-reactive/src/main/java/org/springframework/web/reactive/config/WebReactiveConfigurerComposite.java
  6. 144
      spring-web-reactive/src/test/java/org/springframework/web/reactive/config/DelegatingWebReactiveConfigurationTests.java
  7. 30
      spring-web-reactive/src/test/java/org/springframework/web/reactive/config/WebReactiveConfigurationSupportTests.java
  8. 4
      spring-web-reactive/src/test/java/org/springframework/web/reactive/function/DispatcherHandlerIntegrationTests.java
  9. 5
      spring-web-reactive/src/test/java/org/springframework/web/reactive/result/method/annotation/CrossOriginAnnotationIntegrationTests.java
  10. 4
      spring-web-reactive/src/test/java/org/springframework/web/reactive/result/method/annotation/GlobalCorsConfigIntegrationTests.java
  11. 5
      spring-web-reactive/src/test/java/org/springframework/web/reactive/result/method/annotation/JacksonHintsIntegrationTests.java
  12. 5
      spring-web-reactive/src/test/java/org/springframework/web/reactive/result/method/annotation/RequestMappingExceptionHandlingIntegrationTests.java
  13. 5
      spring-web-reactive/src/test/java/org/springframework/web/reactive/result/method/annotation/RequestMappingIntegrationTests.java
  14. 12
      spring-web-reactive/src/test/java/org/springframework/web/reactive/result/method/annotation/RequestMappingMessageConversionIntegrationTests.java
  15. 4
      spring-web-reactive/src/test/java/org/springframework/web/reactive/result/method/annotation/RequestMappingViewResolutionIntegrationTests.java
  16. 5
      spring-web-reactive/src/test/java/org/springframework/web/reactive/result/method/annotation/SseIntegrationTests.java
  17. 2
      src/asciidoc/web-reactive.adoc

131
spring-web-reactive/src/main/java/org/springframework/web/reactive/config/DelegatingWebReactiveConfiguration.java

@ -0,0 +1,131 @@ @@ -0,0 +1,131 @@
/*
* 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.web.reactive.config;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.format.FormatterRegistry;
import org.springframework.http.codec.HttpMessageReader;
import org.springframework.http.codec.HttpMessageWriter;
import org.springframework.util.CollectionUtils;
import org.springframework.validation.MessageCodesResolver;
import org.springframework.validation.Validator;
import org.springframework.web.reactive.accept.RequestedContentTypeResolverBuilder;
import org.springframework.web.reactive.result.method.HandlerMethodArgumentResolver;
import org.springframework.web.reactive.result.method.annotation.RequestMappingHandlerAdapter;
import org.springframework.web.reactive.result.method.annotation.RequestMappingHandlerMapping;
/**
* A subclass of {@code WebReactiveConfigurationSupport} that detects and delegates
* to all beans of type {@link WebReactiveConfigurer} allowing them to customize the
* configuration provided by {@code WebReactiveConfigurationSupport}. This is the
* class actually imported by {@link EnableWebReactive @EnableWebReactive}.
*
* @author Brian Clozel
* @since 5.0
*/
@Configuration
public class DelegatingWebReactiveConfiguration extends WebReactiveConfigurationSupport {
private final WebReactiveConfigurerComposite configurers = new WebReactiveConfigurerComposite();
@Autowired(required = false)
public void setConfigurers(List<WebReactiveConfigurer> configurers) {
if (!CollectionUtils.isEmpty(configurers)) {
this.configurers.addWebReactiveConfigurers(configurers);
}
}
@Override
protected RequestMappingHandlerMapping createRequestMappingHandlerMapping() {
return this.configurers.createRequestMappingHandlerMapping()
.orElse(super.createRequestMappingHandlerMapping());
}
@Override
protected void configureRequestedContentTypeResolver(RequestedContentTypeResolverBuilder builder) {
this.configurers.configureRequestedContentTypeResolver(builder);
}
@Override
protected void addCorsMappings(CorsRegistry registry) {
this.configurers.addCorsMappings(registry);
}
@Override
public void configurePathMatching(PathMatchConfigurer configurer) {
this.configurers.configurePathMatching(configurer);
}
@Override
protected void addResourceHandlers(ResourceHandlerRegistry registry) {
this.configurers.addResourceHandlers(registry);
}
@Override
protected RequestMappingHandlerAdapter createRequestMappingHandlerAdapter() {
return this.configurers.createRequestMappingHandlerAdapter()
.orElse(super.createRequestMappingHandlerAdapter());
}
@Override
protected void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
this.configurers.addArgumentResolvers(resolvers);
}
@Override
protected void configureMessageReaders(List<HttpMessageReader<?>> messageReaders) {
this.configurers.configureMessageReaders(messageReaders);
}
@Override
protected void extendMessageReaders(List<HttpMessageReader<?>> messageReaders) {
this.configurers.extendMessageReaders(messageReaders);
}
@Override
protected void addFormatters(FormatterRegistry registry) {
this.configurers.addFormatters(registry);
}
@Override
protected Validator getValidator() {
return this.configurers.getValidator().orElse(super.getValidator());
}
@Override
protected MessageCodesResolver getMessageCodesResolver() {
return this.configurers.getMessageCodesResolver().orElse(super.getMessageCodesResolver());
}
@Override
protected void configureMessageWriters(List<HttpMessageWriter<?>> messageWriters) {
this.configurers.configureMessageWriters(messageWriters);
}
@Override
protected void extendMessageWriters(List<HttpMessageWriter<?>> messageWriters) {
this.configurers.extendMessageWriters(messageWriters);
}
@Override
protected void configureViewResolvers(ViewResolverRegistry registry) {
this.configurers.configureViewResolvers(registry);
}
}

79
spring-web-reactive/src/main/java/org/springframework/web/reactive/config/EnableWebReactive.java

@ -0,0 +1,79 @@ @@ -0,0 +1,79 @@
/*
* 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.web.reactive.config;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.context.annotation.Import;
/**
* Adding this annotation to an {@code @Configuration} class imports the Spring Web
* Reactive configuration from {@link WebReactiveConfigurationSupport}, e.g.:
*
* <pre class="code">
* &#064;Configuration
* &#064;EnableWebReactive
* &#064;ComponentScan(basePackageClasses = { MyConfiguration.class })
* public class MyWebConfiguration {
*
* }
* </pre>
*
* <p>To customize the imported configuration, implement the interface
* {@link WebReactiveConfigurer} and override individual methods, e.g.:
*
* <pre class="code">
* &#064;Configuration
* &#064;EnableWebMvc
* &#064;ComponentScan(basePackageClasses = { MyConfiguration.class })
* public class MyConfiguration implements WebReactiveConfigurer {
*
* &#064;Override
* public void addFormatters(FormatterRegistry formatterRegistry) {
* formatterRegistry.addConverter(new MyConverter());
* }
*
* &#064;Override
* public void configureMessageWriters(List&lt;HttpMessageWriter&lt;?&gt&gt messageWriters) {
* messageWriters.add(new MyHttpMessageWriter());
* }
*
* // More overridden methods ...
* }
* </pre>
*
* <p>If {@link WebReactiveConfigurer} does not expose some advanced setting that
* needs to be configured, consider removing the {@code @EnableWebReactive}
* annotation and extending directly from {@link WebReactiveConfigurationSupport}
* or {@link DelegatingWebReactiveConfiguration} if you still want to allow
* {@link WebReactiveConfigurer} instances to customize the configuration.
*
* @author Brian Clozel
* @since 5.0
* @see WebReactiveConfigurer
* @see WebReactiveConfigurationSupport
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(DelegatingWebReactiveConfiguration.class)
public @interface EnableWebReactive {
}

15
spring-web-reactive/src/main/java/org/springframework/web/reactive/config/WebReactiveConfiguration.java → spring-web-reactive/src/main/java/org/springframework/web/reactive/config/WebReactiveConfigurationSupport.java

@ -28,7 +28,6 @@ import org.springframework.beans.factory.BeanInitializationException; @@ -28,7 +28,6 @@ import org.springframework.beans.factory.BeanInitializationException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.codec.ByteBufferDecoder;
import org.springframework.core.codec.ByteBufferEncoder;
import org.springframework.core.codec.CharSequenceEncoder;
@ -82,17 +81,16 @@ import org.springframework.web.server.ServerWebExchange; @@ -82,17 +81,16 @@ import org.springframework.web.server.ServerWebExchange;
* @author Rossen Stoyanchev
* @since 5.0
*/
@Configuration
public class WebReactiveConfiguration implements ApplicationContextAware {
public class WebReactiveConfigurationSupport implements ApplicationContextAware {
private static final boolean jackson2Present =
ClassUtils.isPresent("com.fasterxml.jackson.databind.ObjectMapper",
WebReactiveConfiguration.class.getClassLoader()) &&
WebReactiveConfigurationSupport.class.getClassLoader()) &&
ClassUtils.isPresent("com.fasterxml.jackson.core.JsonGenerator",
WebReactiveConfiguration.class.getClassLoader());
WebReactiveConfigurationSupport.class.getClassLoader());
private static final boolean jaxb2Present =
ClassUtils.isPresent("javax.xml.bind.Binder", WebReactiveConfiguration.class.getClassLoader());
ClassUtils.isPresent("javax.xml.bind.Binder", WebReactiveConfigurationSupport.class.getClassLoader());
private Map<String, CorsConfiguration> corsConfigurations;
@ -234,7 +232,6 @@ public class WebReactiveConfiguration implements ApplicationContextAware { @@ -234,7 +232,6 @@ public class WebReactiveConfiguration implements ApplicationContextAware {
if (pathMatchConfigurer.getPathHelper() != null) {
handlerMapping.setPathHelper(pathMatchConfigurer.getPathHelper());
}
}
else {
handlerMapping = new EmptyHandlerMapping();
@ -464,6 +461,7 @@ public class WebReactiveConfiguration implements ApplicationContextAware { @@ -464,6 +461,7 @@ public class WebReactiveConfiguration implements ApplicationContextAware {
writers.add(new ServerSentEventHttpMessageWriter(sseDataEncoders));
}
}
/**
* Override this to modify the list of message writers after it has been
* configured, for example to add some in addition to the default ones.
@ -484,7 +482,8 @@ public class WebReactiveConfiguration implements ApplicationContextAware { @@ -484,7 +482,8 @@ public class WebReactiveConfiguration implements ApplicationContextAware {
}
/**
* Override this to configure view resolution.
* Configure view resolution for supporting template engines.
* @see ViewResolverRegistry
*/
protected void configureViewResolvers(ViewResolverRegistry registry) {
}

174
spring-web-reactive/src/main/java/org/springframework/web/reactive/config/WebReactiveConfigurer.java

@ -0,0 +1,174 @@ @@ -0,0 +1,174 @@
/*
* 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.web.reactive.config;
import java.util.List;
import java.util.Optional;
import org.springframework.core.convert.converter.Converter;
import org.springframework.format.Formatter;
import org.springframework.format.FormatterRegistry;
import org.springframework.http.codec.HttpMessageReader;
import org.springframework.http.codec.HttpMessageWriter;
import org.springframework.validation.MessageCodesResolver;
import org.springframework.validation.Validator;
import org.springframework.web.reactive.accept.CompositeContentTypeResolver;
import org.springframework.web.reactive.accept.RequestedContentTypeResolver;
import org.springframework.web.reactive.accept.RequestedContentTypeResolverBuilder;
import org.springframework.web.reactive.result.method.HandlerMethodArgumentResolver;
import org.springframework.web.reactive.result.method.annotation.RequestMappingHandlerAdapter;
import org.springframework.web.reactive.result.method.annotation.RequestMappingHandlerMapping;
/**
* Defines callback methods to customize the configuration for Web Reactive
* applications enabled via {@code @EnableWebReactive}.
*
* <p>{@code @EnableWebReactive}-annotated configuration classes may implement
* this interface to be called back and given a chance to customize the
* default configuration. Consider implementing this interface and
* overriding the relevant methods for your needs.
*
* @author Brian Clozel
* @since 5.0
*/
public interface WebReactiveConfigurer {
/**
* Configure how the requested content type is resolved.
* <p>The given builder will create a composite of multiple
* {@link RequestedContentTypeResolver}s, each defining a way to resolve the
* the requested content type (accept HTTP header, path extension, parameter, etc).
* @param builder factory that creates a {@link CompositeContentTypeResolver} instance
*/
default void configureRequestedContentTypeResolver(RequestedContentTypeResolverBuilder builder) {
}
/**
* Configure cross origin requests processing.
* @see CorsRegistry
*/
default void addCorsMappings(CorsRegistry registry) {
}
/**
* Configure path matching options.
* <p>The given configurer assists with configuring
* {@code HandlerMapping}s with path matching options.
* @param configurer the {@link PathMatchConfigurer} instance
*/
default void configurePathMatching(PathMatchConfigurer configurer) {
}
/**
* Add resource handlers for serving static resources.
* @see ResourceHandlerRegistry
*/
default void addResourceHandlers(ResourceHandlerRegistry registry) {
}
/**
* Provide custom argument resolvers without overriding the built-in ones.
* @param resolvers a list of resolvers to add to the built-in ones
*/
default void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
}
/**
* Configure the message readers to use for decoding controller method arguments.
* <p>If no message readers are specified, default readers will be added via
* {@link WebReactiveConfigurationSupport#addDefaultHttpMessageReaders}.
* @param readers a list to add message readers to, initially an empty list
*/
default void configureMessageReaders(List<HttpMessageReader<?>> readers) {
}
/**
* Modify the list of message readers to use for decoding controller method arguments,
* for example to add some in addition to the ones already configured.
*/
default void extendMessageReaders(List<HttpMessageReader<?>> readers) {
}
/**
* Add custom {@link Converter}s and {@link Formatter}s.
*/
default void addFormatters(FormatterRegistry registry) {
}
/**
* Provide a custom {@link Validator}, instead of the instance configured by default.
* <p>Only a single instance is allowed, an error will be thrown if multiple
* {@code Validator}s are returned by {@code WebReactiveConfigurer}s.
* The default implementation returns {@code Optional.empty()}.
*/
default Optional<Validator> getValidator() {
return Optional.empty();
}
/**
* Provide a custom {@link MessageCodesResolver}, instead of using the one
* provided by {@link org.springframework.validation.DataBinder} instances.
* The default implementation returns {@code Optional.empty()}.
*/
default Optional<MessageCodesResolver> getMessageCodesResolver() {
return Optional.empty();
}
/**
* Configure the message writers to use for encoding return values.
* <p>If no message writers are specified, default writers will be added via
* {@link WebReactiveConfigurationSupport#addDefaultHttpMessageWriters(List)}.
* @param writers a list to add message writers to, initially an empty list
*/
default void configureMessageWriters(List<HttpMessageWriter<?>> writers) {
}
/**
* Modify the list of message writers to use for encoding return values,
* for example to add some in addition to the ones already configured.
*/
default void extendMessageWriters(List<HttpMessageWriter<?>> writers) {
}
/**
* Configure view resolution for supporting template engines.
* @see ViewResolverRegistry
*/
default void configureViewResolvers(ViewResolverRegistry registry) {
}
/**
* Factory method for the {@link RequestMappingHandlerMapping} bean creating
* an instance or a custom extension of it. Note that only one configurer
* is allowed to implement this method.
* The default implementation returns {@code Optional.empty()}.
*/
default Optional<RequestMappingHandlerMapping> createRequestMappingHandlerMapping() {
return Optional.empty();
}
/**
* Factory method for the {@link RequestMappingHandlerAdapter} bean creating
* an instance or a custom extension of it. Note that only one configurer
* is allowed to implement this method.
* The default implementation returns {@code Optional.empty()}.
*/
default Optional<RequestMappingHandlerAdapter> createRequestMappingHandlerAdapter() {
return Optional.empty();
}
}

150
spring-web-reactive/src/main/java/org/springframework/web/reactive/config/WebReactiveConfigurerComposite.java

@ -0,0 +1,150 @@ @@ -0,0 +1,150 @@
/*
* 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.web.reactive.config;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.function.Function;
import java.util.stream.Collectors;
import org.springframework.format.FormatterRegistry;
import org.springframework.http.codec.HttpMessageReader;
import org.springframework.http.codec.HttpMessageWriter;
import org.springframework.util.CollectionUtils;
import org.springframework.validation.MessageCodesResolver;
import org.springframework.validation.Validator;
import org.springframework.web.reactive.accept.RequestedContentTypeResolverBuilder;
import org.springframework.web.reactive.result.method.HandlerMethodArgumentResolver;
import org.springframework.web.reactive.result.method.annotation.RequestMappingHandlerAdapter;
import org.springframework.web.reactive.result.method.annotation.RequestMappingHandlerMapping;
/**
* A {@link WebReactiveConfigurer} that delegates to one or more others.
*
* @author Brian Clozel
* @author Rossen Stoyanchev
* @since 5.0
*/
public class WebReactiveConfigurerComposite implements WebReactiveConfigurer {
private final List<WebReactiveConfigurer> delegates = new ArrayList<>();
public void addWebReactiveConfigurers(List<WebReactiveConfigurer> configurers) {
if (!CollectionUtils.isEmpty(configurers)) {
this.delegates.addAll(configurers);
}
}
@Override
public void configureRequestedContentTypeResolver(RequestedContentTypeResolverBuilder builder) {
this.delegates.stream().forEach(delegate -> delegate.configureRequestedContentTypeResolver(builder));
}
@Override
public void addCorsMappings(CorsRegistry registry) {
this.delegates.stream().forEach(delegate -> delegate.addCorsMappings(registry));
}
@Override
public void configurePathMatching(PathMatchConfigurer configurer) {
this.delegates.stream().forEach(delegate -> delegate.configurePathMatching(configurer));
}
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
this.delegates.stream().forEach(delegate -> delegate.addResourceHandlers(registry));
}
@Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
this.delegates.stream().forEach(delegate -> delegate.addArgumentResolvers(resolvers));
}
@Override
public void configureMessageReaders(List<HttpMessageReader<?>> readers) {
this.delegates.stream().forEach(delegate -> delegate.configureMessageReaders(readers));
}
@Override
public void extendMessageReaders(List<HttpMessageReader<?>> readers) {
this.delegates.stream().forEach(delegate -> delegate.extendMessageReaders(readers));
}
@Override
public void addFormatters(FormatterRegistry registry) {
this.delegates.stream().forEach(delegate -> delegate.addFormatters(registry));
}
@Override
public Optional<Validator> getValidator() {
return createSingleBean(WebReactiveConfigurer::getValidator, Validator.class);
}
@Override
public Optional<MessageCodesResolver> getMessageCodesResolver() {
return createSingleBean(WebReactiveConfigurer::getMessageCodesResolver, MessageCodesResolver.class);
}
@Override
public void configureMessageWriters(List<HttpMessageWriter<?>> writers) {
this.delegates.stream().forEach(delegate -> delegate.configureMessageWriters(writers));
}
@Override
public void extendMessageWriters(List<HttpMessageWriter<?>> writers) {
this.delegates.stream().forEach(delegate -> delegate.extendMessageWriters(writers));
}
@Override
public void configureViewResolvers(ViewResolverRegistry registry) {
this.delegates.stream().forEach(delegate -> delegate.configureViewResolvers(registry));
}
@Override
public Optional<RequestMappingHandlerMapping> createRequestMappingHandlerMapping() {
return createSingleBean(WebReactiveConfigurer::createRequestMappingHandlerMapping,
RequestMappingHandlerMapping.class);
}
@Override
public Optional<RequestMappingHandlerAdapter> createRequestMappingHandlerAdapter() {
return createSingleBean(WebReactiveConfigurer::createRequestMappingHandlerAdapter,
RequestMappingHandlerAdapter.class);
}
private <T> Optional<T> createSingleBean(Function<WebReactiveConfigurer, Optional<T>> factory,
Class<T> beanType) {
List<Optional<T>> result = this.delegates.stream()
.map(factory).filter(Optional::isPresent).collect(Collectors.toList());
if (result.isEmpty()) {
return Optional.empty();
}
else if (result.size() == 1) {
return result.get(1);
}
else {
throw new IllegalStateException("More than one WebReactiveConfigurer implements " +
beanType.getSimpleName() + " factory method.");
}
}
}

144
spring-web-reactive/src/test/java/org/springframework/web/reactive/config/DelegatingWebReactiveConfigurationTests.java

@ -0,0 +1,144 @@ @@ -0,0 +1,144 @@
/*
* 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.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));
}
}

30
spring-web-reactive/src/test/java/org/springframework/web/reactive/config/WebReactiveConfigurationTests.java → spring-web-reactive/src/test/java/org/springframework/web/reactive/config/WebReactiveConfigurationSupportTests.java

@ -80,10 +80,10 @@ import static org.springframework.http.MediaType.IMAGE_PNG; @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -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 { @@ -348,7 +352,7 @@ public class WebReactiveConfigurationTests {
}
@Configuration
static class CustomResourceHandlingConfig extends WebReactiveConfiguration {
static class CustomResourceHandlingConfig extends WebReactiveConfigurationSupport {
@Override
protected void addResourceHandlers(ResourceHandlerRegistry registry) {

4
spring-web-reactive/src/test/java/org/springframework/web/reactive/function/DispatcherHandlerIntegrationTests.java

@ -43,7 +43,7 @@ import org.springframework.web.client.RestTemplate; @@ -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 @@ -104,7 +104,7 @@ public class DispatcherHandlerIntegrationTests extends AbstractHttpHandlerIntegr
@Configuration
static class TestConfiguration extends WebReactiveConfiguration {
static class TestConfiguration extends WebReactiveConfigurationSupport {
@Bean
public PersonHandler personHandler() {

5
spring-web-reactive/src/test/java/org/springframework/web/reactive/result/method/annotation/CrossOriginAnnotationIntegrationTests.java

@ -39,7 +39,7 @@ import org.springframework.web.bind.annotation.RequestMapping; @@ -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 @@ -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")

4
spring-web-reactive/src/test/java/org/springframework/web/reactive/result/method/annotation/GlobalCorsConfigIntegrationTests.java

@ -32,7 +32,7 @@ import org.springframework.web.bind.annotation.RestController; @@ -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 @@ -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) {

5
spring-web-reactive/src/test/java/org/springframework/web/reactive/result/method/annotation/JacksonHintsIntegrationTests.java

@ -34,7 +34,7 @@ import org.springframework.web.bind.annotation.GetMapping; @@ -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 @@ -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

5
spring-web-reactive/src/test/java/org/springframework/web/reactive/result/method/annotation/RequestMappingExceptionHandlingIntegrationTests.java

@ -28,7 +28,7 @@ import org.springframework.http.HttpHeaders; @@ -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 @@ -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 {
}

5
spring-web-reactive/src/test/java/org/springframework/web/reactive/result/method/annotation/RequestMappingIntegrationTests.java

@ -29,7 +29,7 @@ import org.springframework.http.MediaType; @@ -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 @@ -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

12
spring-web-reactive/src/test/java/org/springframework/web/reactive/result/method/annotation/RequestMappingMessageConversionIntegrationTests.java

@ -56,11 +56,12 @@ import org.springframework.web.bind.annotation.PostMapping; @@ -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 @@ -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 {
}

4
spring-web-reactive/src/test/java/org/springframework/web/reactive/result/method/annotation/RequestMappingViewResolutionIntegrationTests.java

@ -35,7 +35,7 @@ import org.springframework.ui.Model; @@ -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 @@ -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) {

5
spring-web-reactive/src/test/java/org/springframework/web/reactive/result/method/annotation/SseIntegrationTests.java

@ -36,7 +36,7 @@ import org.springframework.web.bind.annotation.RequestMapping; @@ -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 { @@ -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() {

2
src/asciidoc/web-reactive.adoc

@ -182,7 +182,7 @@ For the bootstrap code start with: @@ -182,7 +182,7 @@ For the bootstrap code start with:
[source,java,indent=0]
[subs="verbatim,quotes"]
----
ApplicationContext context = new AnnotationConfigApplicationContext(WebReactiveConfiguration.class); // (1)
ApplicationContext context = new AnnotationConfigApplicationContext(DelegatingWebReactiveConfiguration.class); // (1)
HttpHandler handler = DispatcherHandler.toHttpHandler(context); // (2)
----

Loading…
Cancel
Save