8 changed files with 1028 additions and 74 deletions
@ -0,0 +1,110 @@ |
|||||||
|
/* |
||||||
|
* 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 org.springframework.util.PathMatcher; |
||||||
|
import org.springframework.web.util.HttpRequestPathHelper; |
||||||
|
|
||||||
|
/** |
||||||
|
* Assist with configuring {@code HandlerMapping}'s with path matching options. |
||||||
|
* |
||||||
|
* @author Rossen Stoyanchev |
||||||
|
*/ |
||||||
|
public class PathMatchConfigurer { |
||||||
|
|
||||||
|
private Boolean suffixPatternMatch; |
||||||
|
|
||||||
|
private Boolean trailingSlashMatch; |
||||||
|
|
||||||
|
private Boolean registeredSuffixPatternMatch; |
||||||
|
|
||||||
|
private HttpRequestPathHelper pathHelper; |
||||||
|
|
||||||
|
private PathMatcher pathMatcher; |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* Whether to use suffix pattern match (".*") when matching patterns to |
||||||
|
* requests. If enabled a method mapped to "/users" also matches to "/users.*". |
||||||
|
* <p>By default this is set to {@code true}. |
||||||
|
* @see #registeredSuffixPatternMatch |
||||||
|
*/ |
||||||
|
public PathMatchConfigurer setUseSuffixPatternMatch(Boolean suffixPatternMatch) { |
||||||
|
this.suffixPatternMatch = suffixPatternMatch; |
||||||
|
return this; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Whether to match to URLs irrespective of the presence of a trailing slash. |
||||||
|
* If enabled a method mapped to "/users" also matches to "/users/". |
||||||
|
* <p>The default value is {@code true}. |
||||||
|
*/ |
||||||
|
public PathMatchConfigurer setUseTrailingSlashMatch(Boolean trailingSlashMatch) { |
||||||
|
this.trailingSlashMatch = trailingSlashMatch; |
||||||
|
return this; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Whether suffix pattern matching should work only against path extensions |
||||||
|
* that are explicitly registered. This is generally recommended to reduce |
||||||
|
* ambiguity and to avoid issues such as when a "." (dot) appears in the path |
||||||
|
* for other reasons. |
||||||
|
* <p>By default this is set to "true". |
||||||
|
*/ |
||||||
|
public PathMatchConfigurer setUseRegisteredSuffixPatternMatch(Boolean registeredSuffixPatternMatch) { |
||||||
|
this.registeredSuffixPatternMatch = registeredSuffixPatternMatch; |
||||||
|
return this; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Set a {@code HttpRequestPathHelper} for the resolution of lookup paths. |
||||||
|
* <p>Default is {@code HttpRequestPathHelper}. |
||||||
|
*/ |
||||||
|
public PathMatchConfigurer setPathHelper(HttpRequestPathHelper pathHelper) { |
||||||
|
this.pathHelper = pathHelper; |
||||||
|
return this; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Set the PathMatcher for matching URL paths against registered URL patterns. |
||||||
|
* <p>Default is {@link org.springframework.util.AntPathMatcher AntPathMatcher}. |
||||||
|
*/ |
||||||
|
public PathMatchConfigurer setPathMatcher(PathMatcher pathMatcher) { |
||||||
|
this.pathMatcher = pathMatcher; |
||||||
|
return this; |
||||||
|
} |
||||||
|
|
||||||
|
protected Boolean isUseSuffixPatternMatch() { |
||||||
|
return this.suffixPatternMatch; |
||||||
|
} |
||||||
|
|
||||||
|
protected Boolean isUseTrailingSlashMatch() { |
||||||
|
return this.trailingSlashMatch; |
||||||
|
} |
||||||
|
|
||||||
|
protected Boolean isUseRegisteredSuffixPatternMatch() { |
||||||
|
return this.registeredSuffixPatternMatch; |
||||||
|
} |
||||||
|
|
||||||
|
protected HttpRequestPathHelper getPathHelper() { |
||||||
|
return this.pathHelper; |
||||||
|
} |
||||||
|
|
||||||
|
protected PathMatcher getPathMatcher() { |
||||||
|
return this.pathMatcher; |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
@ -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 org.springframework.util.Assert; |
||||||
|
import org.springframework.web.reactive.result.view.UrlBasedViewResolver; |
||||||
|
|
||||||
|
/** |
||||||
|
* Assist with configuring properties of a {@link UrlBasedViewResolver}. |
||||||
|
* |
||||||
|
* @author Rossen Stoyanchev |
||||||
|
*/ |
||||||
|
public class UrlBasedViewResolverRegistration { |
||||||
|
|
||||||
|
private final UrlBasedViewResolver viewResolver; |
||||||
|
|
||||||
|
|
||||||
|
public UrlBasedViewResolverRegistration(UrlBasedViewResolver viewResolver) { |
||||||
|
Assert.notNull(viewResolver); |
||||||
|
this.viewResolver = viewResolver; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* Set the prefix that gets prepended to view names when building a URL. |
||||||
|
* @see UrlBasedViewResolver#setPrefix |
||||||
|
*/ |
||||||
|
public UrlBasedViewResolverRegistration prefix(String prefix) { |
||||||
|
this.viewResolver.setPrefix(prefix); |
||||||
|
return this; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Set the suffix that gets appended to view names when building a URL. |
||||||
|
* @see UrlBasedViewResolver#setSuffix |
||||||
|
*/ |
||||||
|
public UrlBasedViewResolverRegistration suffix(String suffix) { |
||||||
|
this.viewResolver.setSuffix(suffix); |
||||||
|
return this; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Set the view class that should be used to create views. |
||||||
|
* @see UrlBasedViewResolver#setViewClass |
||||||
|
*/ |
||||||
|
public UrlBasedViewResolverRegistration viewClass(Class<?> viewClass) { |
||||||
|
this.viewResolver.setViewClass(viewClass); |
||||||
|
return this; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Set the view names (or name patterns) that can be handled by this view |
||||||
|
* resolver. View names can contain simple wildcards such that 'my*', '*Report' |
||||||
|
* and '*Repo*' will all match the view name 'myReport'. |
||||||
|
* @see UrlBasedViewResolver#setViewNames |
||||||
|
*/ |
||||||
|
public UrlBasedViewResolverRegistration viewNames(String... viewNames) { |
||||||
|
this.viewResolver.setViewNames(viewNames); |
||||||
|
return this; |
||||||
|
} |
||||||
|
|
||||||
|
protected UrlBasedViewResolver getViewResolver() { |
||||||
|
return this.viewResolver; |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
@ -0,0 +1,146 @@ |
|||||||
|
/* |
||||||
|
* 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.Arrays; |
||||||
|
import java.util.List; |
||||||
|
|
||||||
|
import org.springframework.beans.factory.BeanFactoryUtils; |
||||||
|
import org.springframework.beans.factory.BeanInitializationException; |
||||||
|
import org.springframework.context.ApplicationContext; |
||||||
|
import org.springframework.core.Ordered; |
||||||
|
import org.springframework.util.Assert; |
||||||
|
import org.springframework.util.ObjectUtils; |
||||||
|
import org.springframework.web.reactive.result.view.UrlBasedViewResolver; |
||||||
|
import org.springframework.web.reactive.result.view.View; |
||||||
|
import org.springframework.web.reactive.result.view.ViewResolver; |
||||||
|
import org.springframework.web.reactive.result.view.freemarker.FreeMarkerConfigurer; |
||||||
|
import org.springframework.web.reactive.result.view.freemarker.FreeMarkerViewResolver; |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* Assist with the configuration of a chain of {@link ViewResolver}'s supporting |
||||||
|
* different template mechanisms. |
||||||
|
* |
||||||
|
* <p>In addition, you can also configure {@link #defaultViews(View...) |
||||||
|
* defaultViews} for rendering according to the requested content type, e.g. |
||||||
|
* JSON, XML, etc. |
||||||
|
* |
||||||
|
* @author Rossen Stoyanchev |
||||||
|
*/ |
||||||
|
public class ViewResolverRegistry { |
||||||
|
|
||||||
|
private final List<ViewResolver> viewResolvers = new ArrayList<>(4); |
||||||
|
|
||||||
|
private final List<View> defaultViews = new ArrayList<>(4); |
||||||
|
|
||||||
|
private Integer order; |
||||||
|
|
||||||
|
private final ApplicationContext applicationContext; |
||||||
|
|
||||||
|
|
||||||
|
public ViewResolverRegistry(ApplicationContext applicationContext) { |
||||||
|
Assert.notNull(applicationContext); |
||||||
|
this.applicationContext = applicationContext; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* Register a {@code FreeMarkerViewResolver} with a ".ftl" suffix. |
||||||
|
* <p><strong>Note</strong> that you must also configure FreeMarker by |
||||||
|
* adding a {@link FreeMarkerConfigurer} bean. |
||||||
|
*/ |
||||||
|
public UrlBasedViewResolverRegistration freeMarker() { |
||||||
|
if (this.applicationContext != null && !hasBeanOfType(FreeMarkerConfigurer.class)) { |
||||||
|
throw new BeanInitializationException("In addition to a FreeMarker view resolver " + |
||||||
|
"there must also be a single FreeMarkerConfig bean in this web application context " + |
||||||
|
"(or its parent): FreeMarkerConfigurer is the usual implementation. " + |
||||||
|
"This bean may be given any name."); |
||||||
|
} |
||||||
|
FreeMarkerRegistration registration = new FreeMarkerRegistration(); |
||||||
|
UrlBasedViewResolver resolver = registration.getViewResolver(); |
||||||
|
resolver.setApplicationContext(this.applicationContext); |
||||||
|
this.viewResolvers.add(resolver); |
||||||
|
return registration; |
||||||
|
} |
||||||
|
|
||||||
|
protected boolean hasBeanOfType(Class<?> beanType) { |
||||||
|
return !ObjectUtils.isEmpty(BeanFactoryUtils.beanNamesForTypeIncludingAncestors( |
||||||
|
this.applicationContext, beanType, false, false)); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Register a {@link ViewResolver} bean instance. This may be useful to |
||||||
|
* configure a 3rd party resolver implementation or as an alternative to |
||||||
|
* other registration methods in this class when they don't expose some |
||||||
|
* more advanced property that needs to be set. |
||||||
|
*/ |
||||||
|
public void viewResolver(ViewResolver viewResolver) { |
||||||
|
this.viewResolvers.add(viewResolver); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Set default views associated with any view name and selected based on the |
||||||
|
* best match for the requested content type. |
||||||
|
* <p>Use {@link org.springframework.web.reactive.result.view.HttpMessageConverterView |
||||||
|
* HttpMessageConverterView} to adapt and use any existing |
||||||
|
* {@code HttpMessageConverter} (e.g. JSON, XML) as a {@code View}. |
||||||
|
*/ |
||||||
|
public void defaultViews(View... defaultViews) { |
||||||
|
this.defaultViews.addAll(Arrays.asList(defaultViews)); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Whether any view resolvers have been registered. |
||||||
|
*/ |
||||||
|
public boolean hasRegistrations() { |
||||||
|
return (!this.viewResolvers.isEmpty()); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Set the order for the |
||||||
|
* {@link org.springframework.web.reactive.result.view.ViewResolutionResultHandler |
||||||
|
* ViewResolutionResultHandler}. |
||||||
|
* <p>By default this property is not set, which means the result handler is |
||||||
|
* ordered at {@link Ordered#LOWEST_PRECEDENCE}. |
||||||
|
*/ |
||||||
|
public void order(int order) { |
||||||
|
this.order = order; |
||||||
|
} |
||||||
|
|
||||||
|
protected int getOrder() { |
||||||
|
return (this.order != null ? this.order : Ordered.LOWEST_PRECEDENCE); |
||||||
|
} |
||||||
|
|
||||||
|
protected List<ViewResolver> getViewResolvers() { |
||||||
|
return this.viewResolvers; |
||||||
|
} |
||||||
|
|
||||||
|
protected List<View> getDefaultViews() { |
||||||
|
return this.defaultViews; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
private static class FreeMarkerRegistration extends UrlBasedViewResolverRegistration { |
||||||
|
|
||||||
|
public FreeMarkerRegistration() { |
||||||
|
super(new FreeMarkerViewResolver()); |
||||||
|
getViewResolver().setSuffix(".ftl"); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
@ -0,0 +1,316 @@ |
|||||||
|
/* |
||||||
|
* 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.HashMap; |
||||||
|
import java.util.List; |
||||||
|
import java.util.Map; |
||||||
|
|
||||||
|
import reactor.core.converter.DependencyUtils; |
||||||
|
|
||||||
|
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.Decoder; |
||||||
|
import org.springframework.core.codec.Encoder; |
||||||
|
import org.springframework.core.codec.support.ByteBufferDecoder; |
||||||
|
import org.springframework.core.codec.support.ByteBufferEncoder; |
||||||
|
import org.springframework.core.codec.support.JacksonJsonDecoder; |
||||||
|
import org.springframework.core.codec.support.JacksonJsonEncoder; |
||||||
|
import org.springframework.core.codec.support.Jaxb2Decoder; |
||||||
|
import org.springframework.core.codec.support.Jaxb2Encoder; |
||||||
|
import org.springframework.core.codec.support.JsonObjectDecoder; |
||||||
|
import org.springframework.core.codec.support.StringDecoder; |
||||||
|
import org.springframework.core.codec.support.StringEncoder; |
||||||
|
import org.springframework.core.convert.converter.Converter; |
||||||
|
import org.springframework.core.convert.converter.ConverterRegistry; |
||||||
|
import org.springframework.core.convert.support.GenericConversionService; |
||||||
|
import org.springframework.core.convert.support.ReactiveStreamsToCompletableFutureConverter; |
||||||
|
import org.springframework.core.convert.support.ReactiveStreamsToRxJava1Converter; |
||||||
|
import org.springframework.format.Formatter; |
||||||
|
import org.springframework.http.MediaType; |
||||||
|
import org.springframework.http.converter.reactive.CodecHttpMessageConverter; |
||||||
|
import org.springframework.http.converter.reactive.HttpMessageConverter; |
||||||
|
import org.springframework.http.converter.reactive.ResourceHttpMessageConverter; |
||||||
|
import org.springframework.util.ClassUtils; |
||||||
|
import org.springframework.web.reactive.accept.RequestedContentTypeResolver; |
||||||
|
import org.springframework.web.reactive.accept.RequestedContentTypeResolverBuilder; |
||||||
|
import org.springframework.web.reactive.result.SimpleHandlerAdapter; |
||||||
|
import org.springframework.web.reactive.result.SimpleResultHandler; |
||||||
|
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; |
||||||
|
import org.springframework.web.reactive.result.method.annotation.ResponseBodyResultHandler; |
||||||
|
import org.springframework.web.reactive.result.view.ViewResolutionResultHandler; |
||||||
|
import org.springframework.web.reactive.result.view.ViewResolver; |
||||||
|
|
||||||
|
/** |
||||||
|
* The main class for Spring Web Reactive configuration. |
||||||
|
* |
||||||
|
* <p>Import directly or extend and override protected methods to customize. |
||||||
|
* |
||||||
|
* @author Rossen Stoyanchev |
||||||
|
*/ |
||||||
|
@Configuration @SuppressWarnings("unused") |
||||||
|
public class WebReactiveConfiguration implements ApplicationContextAware { |
||||||
|
|
||||||
|
private static final ClassLoader classLoader = WebReactiveConfiguration.class.getClassLoader(); |
||||||
|
|
||||||
|
private static final boolean jackson2Present = |
||||||
|
ClassUtils.isPresent("com.fasterxml.jackson.databind.ObjectMapper", classLoader) && |
||||||
|
ClassUtils.isPresent("com.fasterxml.jackson.core.JsonGenerator", classLoader); |
||||||
|
|
||||||
|
private static final boolean jaxb2Present = |
||||||
|
ClassUtils.isPresent("javax.xml.bind.Binder", classLoader); |
||||||
|
|
||||||
|
|
||||||
|
private PathMatchConfigurer pathMatchConfigurer; |
||||||
|
|
||||||
|
private List<HttpMessageConverter<?>> messageConverters; |
||||||
|
|
||||||
|
private ApplicationContext applicationContext; |
||||||
|
|
||||||
|
|
||||||
|
@Override |
||||||
|
public void setApplicationContext(ApplicationContext applicationContext) { |
||||||
|
this.applicationContext = applicationContext; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
@Bean |
||||||
|
public RequestMappingHandlerMapping requestMappingHandlerMapping() { |
||||||
|
RequestMappingHandlerMapping mapping = createRequestMappingHandlerMapping(); |
||||||
|
mapping.setOrder(0); |
||||||
|
mapping.setContentTypeResolver(mvcContentTypeResolver()); |
||||||
|
|
||||||
|
PathMatchConfigurer configurer = getPathMatchConfigurer(); |
||||||
|
if (configurer.isUseSuffixPatternMatch() != null) { |
||||||
|
mapping.setUseSuffixPatternMatch(configurer.isUseSuffixPatternMatch()); |
||||||
|
} |
||||||
|
if (configurer.isUseRegisteredSuffixPatternMatch() != null) { |
||||||
|
mapping.setUseRegisteredSuffixPatternMatch(configurer.isUseRegisteredSuffixPatternMatch()); |
||||||
|
} |
||||||
|
if (configurer.isUseTrailingSlashMatch() != null) { |
||||||
|
mapping.setUseTrailingSlashMatch(configurer.isUseTrailingSlashMatch()); |
||||||
|
} |
||||||
|
if (configurer.getPathMatcher() != null) { |
||||||
|
mapping.setPathMatcher(configurer.getPathMatcher()); |
||||||
|
} |
||||||
|
if (configurer.getPathHelper() != null) { |
||||||
|
mapping.setPathHelper(configurer.getPathHelper()); |
||||||
|
} |
||||||
|
|
||||||
|
return mapping; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Override to plug a sub-class of {@link RequestMappingHandlerMapping}. |
||||||
|
*/ |
||||||
|
protected RequestMappingHandlerMapping createRequestMappingHandlerMapping() { |
||||||
|
return new RequestMappingHandlerMapping(); |
||||||
|
} |
||||||
|
|
||||||
|
@Bean |
||||||
|
public RequestedContentTypeResolver mvcContentTypeResolver() { |
||||||
|
RequestedContentTypeResolverBuilder builder = new RequestedContentTypeResolverBuilder(); |
||||||
|
builder.mediaTypes(getDefaultMediaTypeMappings()); |
||||||
|
configureRequestedContentTypeResolver(builder); |
||||||
|
return builder.build(); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Override to configure media type mappings. |
||||||
|
* @see RequestedContentTypeResolverBuilder#mediaTypes(Map) |
||||||
|
*/ |
||||||
|
protected Map<String, MediaType> getDefaultMediaTypeMappings() { |
||||||
|
Map<String, MediaType> map = new HashMap<>(); |
||||||
|
if (jackson2Present) { |
||||||
|
map.put("json", MediaType.APPLICATION_JSON); |
||||||
|
} |
||||||
|
return map; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Override to configure how the requested content type is resolved. |
||||||
|
*/ |
||||||
|
protected void configureRequestedContentTypeResolver(RequestedContentTypeResolverBuilder builder) { |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Callback for building the {@link PathMatchConfigurer}. This method is |
||||||
|
* final, use {@link #configurePathMatching} to customize path matching. |
||||||
|
*/ |
||||||
|
protected final PathMatchConfigurer getPathMatchConfigurer() { |
||||||
|
if (this.pathMatchConfigurer == null) { |
||||||
|
this.pathMatchConfigurer = new PathMatchConfigurer(); |
||||||
|
configurePathMatching(this.pathMatchConfigurer); |
||||||
|
} |
||||||
|
return this.pathMatchConfigurer; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Override to configure path matching options. |
||||||
|
*/ |
||||||
|
public void configurePathMatching(PathMatchConfigurer configurer) { |
||||||
|
} |
||||||
|
|
||||||
|
@Bean |
||||||
|
public RequestMappingHandlerAdapter requestMappingHandlerAdapter() { |
||||||
|
RequestMappingHandlerAdapter adapter = createRequestMappingHandlerAdapter(); |
||||||
|
|
||||||
|
List<HandlerMethodArgumentResolver> resolvers = new ArrayList<>(); |
||||||
|
addArgumentResolvers(resolvers); |
||||||
|
if (!resolvers.isEmpty()) { |
||||||
|
adapter.setCustomArgumentResolvers(resolvers); |
||||||
|
} |
||||||
|
|
||||||
|
adapter.setMessageConverters(getMessageConverters()); |
||||||
|
adapter.setConversionService(mvcConversionService()); |
||||||
|
|
||||||
|
return adapter; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Override to plug a sub-class of {@link RequestMappingHandlerAdapter}. |
||||||
|
*/ |
||||||
|
protected RequestMappingHandlerAdapter createRequestMappingHandlerAdapter() { |
||||||
|
return new RequestMappingHandlerAdapter(); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Provide custom argument resolvers without overriding the built-in ones. |
||||||
|
*/ |
||||||
|
protected void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) { |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Main method to access message converters to use for decoding |
||||||
|
* controller method arguments and encoding return values. |
||||||
|
* <p>Use {@link #configureMessageConverters} to configure the list or |
||||||
|
* {@link #extendMessageConverters} to add in addition to the default ones. |
||||||
|
*/ |
||||||
|
protected final List<HttpMessageConverter<?>> getMessageConverters() { |
||||||
|
if (this.messageConverters == null) { |
||||||
|
this.messageConverters = new ArrayList<>(); |
||||||
|
configureMessageConverters(this.messageConverters); |
||||||
|
if (this.messageConverters.isEmpty()) { |
||||||
|
addDefaultHttpMessageConverters(this.messageConverters); |
||||||
|
} |
||||||
|
extendMessageConverters(this.messageConverters); |
||||||
|
} |
||||||
|
return this.messageConverters; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Override to configure the message converters to use for decoding |
||||||
|
* controller method arguments and encoding return values. |
||||||
|
* <p>If no converters are specified, default will be added via |
||||||
|
* {@link #addDefaultHttpMessageConverters}. |
||||||
|
* @param converters a list to add converters to, initially an empty |
||||||
|
*/ |
||||||
|
protected void configureMessageConverters(List<HttpMessageConverter<?>> converters) { |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Adds default converters that sub-classes can call from |
||||||
|
* {@link #configureMessageConverters(List)}. |
||||||
|
*/ |
||||||
|
protected final void addDefaultHttpMessageConverters(List<HttpMessageConverter<?>> converters) { |
||||||
|
converters.add(converter(new ByteBufferEncoder(), new ByteBufferDecoder())); |
||||||
|
converters.add(converter(new StringEncoder(), new StringDecoder())); |
||||||
|
converters.add(new ResourceHttpMessageConverter()); |
||||||
|
if (jaxb2Present) { |
||||||
|
converters.add(converter(new Jaxb2Encoder(), new Jaxb2Decoder())); |
||||||
|
} |
||||||
|
if (jackson2Present) { |
||||||
|
JsonObjectDecoder objectDecoder = new JsonObjectDecoder(); |
||||||
|
converters.add(converter(new JacksonJsonEncoder(), new JacksonJsonDecoder(objectDecoder))); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private static <T> HttpMessageConverter<T> converter(Encoder<T> encoder, Decoder<T> decoder) { |
||||||
|
return new CodecHttpMessageConverter<>(encoder, decoder); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Override this to modify the list of converters after it has been |
||||||
|
* configured, for example to add some in addition to the default ones. |
||||||
|
*/ |
||||||
|
protected void extendMessageConverters(List<HttpMessageConverter<?>> converters) { |
||||||
|
} |
||||||
|
|
||||||
|
// TODO: switch to DefaultFormattingConversionService
|
||||||
|
|
||||||
|
@Bean |
||||||
|
public GenericConversionService mvcConversionService() { |
||||||
|
GenericConversionService service = new GenericConversionService(); |
||||||
|
addFormatters(service); |
||||||
|
return service; |
||||||
|
} |
||||||
|
|
||||||
|
// TODO: switch to FormatterRegistry
|
||||||
|
|
||||||
|
/** |
||||||
|
* Override to add custom {@link Converter}s and {@link Formatter}s. |
||||||
|
* <p>By default this method method registers: |
||||||
|
* <ul> |
||||||
|
* <li>{@link ReactiveStreamsToCompletableFutureConverter} |
||||||
|
* <li>{@link ReactiveStreamsToRxJava1Converter} |
||||||
|
* </ul> |
||||||
|
*/ |
||||||
|
protected void addFormatters(ConverterRegistry registry) { |
||||||
|
registry.addConverter(new ReactiveStreamsToCompletableFutureConverter()); |
||||||
|
if (DependencyUtils.hasRxJava1()) { |
||||||
|
registry.addConverter(new ReactiveStreamsToRxJava1Converter()); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@Bean |
||||||
|
public SimpleHandlerAdapter simpleHandlerAdapter() { |
||||||
|
return new SimpleHandlerAdapter(); |
||||||
|
} |
||||||
|
|
||||||
|
@Bean |
||||||
|
public ResponseBodyResultHandler responseBodyResultHandler() { |
||||||
|
return new ResponseBodyResultHandler(getMessageConverters(), mvcConversionService()); |
||||||
|
} |
||||||
|
|
||||||
|
@Bean |
||||||
|
public SimpleResultHandler simpleResultHandler() { |
||||||
|
return new SimpleResultHandler(mvcConversionService()); |
||||||
|
} |
||||||
|
|
||||||
|
@Bean |
||||||
|
public ViewResolutionResultHandler viewResolutionResultHandler() { |
||||||
|
ViewResolverRegistry registry = new ViewResolverRegistry(this.applicationContext); |
||||||
|
configureViewResolvers(registry); |
||||||
|
List<ViewResolver> resolvers = registry.getViewResolvers(); |
||||||
|
ViewResolutionResultHandler handler = new ViewResolutionResultHandler(resolvers, mvcConversionService()); |
||||||
|
handler.setDefaultViews(registry.getDefaultViews()); |
||||||
|
handler.setOrder(registry.getOrder()); |
||||||
|
return handler; |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Override this to configure view resolution. |
||||||
|
*/ |
||||||
|
protected void configureViewResolvers(ViewResolverRegistry registry) { |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
@ -0,0 +1,4 @@ |
|||||||
|
/** |
||||||
|
* Defines Spring Web Reactive configuration. |
||||||
|
*/ |
||||||
|
package org.springframework.web.reactive.config; |
||||||
@ -0,0 +1,90 @@ |
|||||||
|
/* |
||||||
|
* 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 org.junit.Before; |
||||||
|
import org.junit.Test; |
||||||
|
|
||||||
|
import org.springframework.core.Ordered; |
||||||
|
import org.springframework.core.codec.support.JacksonJsonEncoder; |
||||||
|
import org.springframework.web.context.support.StaticWebApplicationContext; |
||||||
|
import org.springframework.web.reactive.result.view.HttpMessageConverterView; |
||||||
|
import org.springframework.web.reactive.result.view.UrlBasedViewResolver; |
||||||
|
import org.springframework.web.reactive.result.view.View; |
||||||
|
import org.springframework.web.reactive.result.view.freemarker.FreeMarkerConfigurer; |
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals; |
||||||
|
import static org.junit.Assert.assertFalse; |
||||||
|
import static org.junit.Assert.assertNotNull; |
||||||
|
import static org.junit.Assert.assertSame; |
||||||
|
import static org.junit.Assert.assertTrue; |
||||||
|
|
||||||
|
/** |
||||||
|
* Unit tests for {@link ViewResolverRegistry}. |
||||||
|
* |
||||||
|
* @author Rossen Stoyanchev |
||||||
|
*/ |
||||||
|
public class ViewResolverRegistryTests { |
||||||
|
|
||||||
|
private ViewResolverRegistry registry; |
||||||
|
|
||||||
|
|
||||||
|
@Before |
||||||
|
public void setUp() { |
||||||
|
StaticWebApplicationContext context = new StaticWebApplicationContext(); |
||||||
|
context.registerSingleton("freeMarkerConfigurer", FreeMarkerConfigurer.class); |
||||||
|
this.registry = new ViewResolverRegistry(context); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void order() { |
||||||
|
assertEquals(Ordered.LOWEST_PRECEDENCE, this.registry.getOrder()); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void hasRegistrations() { |
||||||
|
assertFalse(this.registry.hasRegistrations()); |
||||||
|
|
||||||
|
this.registry.freeMarker(); |
||||||
|
assertTrue(this.registry.hasRegistrations()); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void noResolvers() { |
||||||
|
assertNotNull(this.registry.getViewResolvers()); |
||||||
|
assertEquals(0, this.registry.getViewResolvers().size()); |
||||||
|
assertFalse(this.registry.hasRegistrations()); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void customViewResolver() { |
||||||
|
UrlBasedViewResolver viewResolver = new UrlBasedViewResolver(); |
||||||
|
this.registry.viewResolver(viewResolver); |
||||||
|
|
||||||
|
assertSame(viewResolver, this.registry.getViewResolvers().get(0)); |
||||||
|
assertEquals(1, this.registry.getViewResolvers().size()); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void defaultViews() throws Exception { |
||||||
|
View view = new HttpMessageConverterView(new JacksonJsonEncoder()); |
||||||
|
this.registry.defaultViews(view); |
||||||
|
|
||||||
|
assertEquals(1, this.registry.getDefaultViews().size()); |
||||||
|
assertSame(view, this.registry.getDefaultViews().get(0)); |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
@ -0,0 +1,277 @@ |
|||||||
|
/* |
||||||
|
* 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.net.URI; |
||||||
|
import java.nio.ByteBuffer; |
||||||
|
import java.util.Collections; |
||||||
|
import java.util.List; |
||||||
|
import java.util.concurrent.CompletableFuture; |
||||||
|
|
||||||
|
import org.junit.Before; |
||||||
|
import org.junit.Test; |
||||||
|
import reactor.core.publisher.Flux; |
||||||
|
import reactor.core.publisher.Mono; |
||||||
|
import rx.Observable; |
||||||
|
|
||||||
|
import org.springframework.context.ApplicationContext; |
||||||
|
import org.springframework.context.annotation.AnnotationConfigApplicationContext; |
||||||
|
import org.springframework.context.annotation.Bean; |
||||||
|
import org.springframework.context.annotation.Configuration; |
||||||
|
import org.springframework.core.Ordered; |
||||||
|
import org.springframework.core.ResolvableType; |
||||||
|
import org.springframework.core.codec.support.JacksonJsonEncoder; |
||||||
|
import org.springframework.core.codec.support.Jaxb2Decoder; |
||||||
|
import org.springframework.core.codec.support.Jaxb2Encoder; |
||||||
|
import org.springframework.core.codec.support.Pojo; |
||||||
|
import org.springframework.core.codec.support.StringDecoder; |
||||||
|
import org.springframework.core.codec.support.StringEncoder; |
||||||
|
import org.springframework.core.convert.ConversionService; |
||||||
|
import org.springframework.core.io.Resource; |
||||||
|
import org.springframework.http.HttpMethod; |
||||||
|
import org.springframework.http.MediaType; |
||||||
|
import org.springframework.http.converter.reactive.CodecHttpMessageConverter; |
||||||
|
import org.springframework.http.converter.reactive.HttpMessageConverter; |
||||||
|
import org.springframework.http.server.reactive.MockServerHttpRequest; |
||||||
|
import org.springframework.http.server.reactive.MockServerHttpResponse; |
||||||
|
import org.springframework.util.MimeType; |
||||||
|
import org.springframework.util.MimeTypeUtils; |
||||||
|
import org.springframework.web.reactive.accept.RequestedContentTypeResolver; |
||||||
|
import org.springframework.web.reactive.result.method.annotation.RequestMappingHandlerAdapter; |
||||||
|
import org.springframework.web.reactive.result.method.annotation.RequestMappingHandlerMapping; |
||||||
|
import org.springframework.web.reactive.result.method.annotation.ResponseBodyResultHandler; |
||||||
|
import org.springframework.web.reactive.result.view.HttpMessageConverterView; |
||||||
|
import org.springframework.web.reactive.result.view.View; |
||||||
|
import org.springframework.web.reactive.result.view.ViewResolutionResultHandler; |
||||||
|
import org.springframework.web.reactive.result.view.ViewResolver; |
||||||
|
import org.springframework.web.reactive.result.view.freemarker.FreeMarkerConfigurer; |
||||||
|
import org.springframework.web.reactive.result.view.freemarker.FreeMarkerViewResolver; |
||||||
|
import org.springframework.web.server.ServerWebExchange; |
||||||
|
import org.springframework.web.server.adapter.DefaultServerWebExchange; |
||||||
|
import org.springframework.web.server.session.WebSessionManager; |
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals; |
||||||
|
import static org.junit.Assert.assertFalse; |
||||||
|
import static org.junit.Assert.assertNotNull; |
||||||
|
import static org.junit.Assert.assertSame; |
||||||
|
import static org.junit.Assert.assertTrue; |
||||||
|
import static org.mockito.Mockito.mock; |
||||||
|
|
||||||
|
/** |
||||||
|
* Unit tests for {@link WebReactiveConfiguration}. |
||||||
|
* @author Rossen Stoyanchev |
||||||
|
*/ |
||||||
|
public class WebReactiveConfigurationTests { |
||||||
|
|
||||||
|
private MockServerHttpRequest request; |
||||||
|
|
||||||
|
private ServerWebExchange exchange; |
||||||
|
|
||||||
|
|
||||||
|
@Before |
||||||
|
public void setUp() throws Exception { |
||||||
|
this.request = new MockServerHttpRequest(HttpMethod.GET, new URI("/")); |
||||||
|
MockServerHttpResponse response = new MockServerHttpResponse(); |
||||||
|
this.exchange = new DefaultServerWebExchange(this.request, response, mock(WebSessionManager.class)); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
@Test |
||||||
|
public void requestMappingHandlerMapping() throws Exception { |
||||||
|
ApplicationContext context = loadConfig(WebReactiveConfiguration.class); |
||||||
|
|
||||||
|
String name = "requestMappingHandlerMapping"; |
||||||
|
RequestMappingHandlerMapping mapping = context.getBean(name, RequestMappingHandlerMapping.class); |
||||||
|
assertNotNull(mapping); |
||||||
|
|
||||||
|
assertEquals(0, mapping.getOrder()); |
||||||
|
|
||||||
|
assertTrue(mapping.useSuffixPatternMatch()); |
||||||
|
assertTrue(mapping.useTrailingSlashMatch()); |
||||||
|
assertTrue(mapping.useRegisteredSuffixPatternMatch()); |
||||||
|
|
||||||
|
name = "mvcContentTypeResolver"; |
||||||
|
RequestedContentTypeResolver resolver = context.getBean(name, RequestedContentTypeResolver.class); |
||||||
|
assertSame(resolver, mapping.getContentTypeResolver()); |
||||||
|
|
||||||
|
this.request.setUri(new URI("/path.json")); |
||||||
|
List<MediaType> list = Collections.singletonList(MediaType.APPLICATION_JSON); |
||||||
|
assertEquals(list, resolver.resolveMediaTypes(this.exchange)); |
||||||
|
|
||||||
|
this.request.setUri(new URI("/path.xml")); |
||||||
|
assertEquals(Collections.emptyList(), resolver.resolveMediaTypes(this.exchange)); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void customPathMatchConfig() throws Exception { |
||||||
|
ApplicationContext context = loadConfig(CustomPatchMatchConfig.class); |
||||||
|
|
||||||
|
String name = "requestMappingHandlerMapping"; |
||||||
|
RequestMappingHandlerMapping mapping = context.getBean(name, RequestMappingHandlerMapping.class); |
||||||
|
assertNotNull(mapping); |
||||||
|
|
||||||
|
assertFalse(mapping.useSuffixPatternMatch()); |
||||||
|
assertFalse(mapping.useTrailingSlashMatch()); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void requestMappingHandlerAdapter() throws Exception { |
||||||
|
ApplicationContext context = loadConfig(WebReactiveConfiguration.class); |
||||||
|
|
||||||
|
String name = "requestMappingHandlerAdapter"; |
||||||
|
RequestMappingHandlerAdapter adapter = context.getBean(name, RequestMappingHandlerAdapter.class); |
||||||
|
assertNotNull(adapter); |
||||||
|
|
||||||
|
List<HttpMessageConverter<?>> converters = adapter.getMessageConverters(); |
||||||
|
assertEquals(5, converters.size()); |
||||||
|
|
||||||
|
assertHasConverter(converters, ByteBuffer.class, MediaType.APPLICATION_OCTET_STREAM); |
||||||
|
assertHasConverter(converters, String.class, MediaType.TEXT_PLAIN); |
||||||
|
assertHasConverter(converters, Resource.class, MediaType.IMAGE_PNG); |
||||||
|
assertHasConverter(converters, Pojo.class, MediaType.APPLICATION_XML); |
||||||
|
assertHasConverter(converters, Pojo.class, MediaType.APPLICATION_JSON); |
||||||
|
|
||||||
|
name = "mvcConversionService"; |
||||||
|
ConversionService service = context.getBean(name, ConversionService.class); |
||||||
|
assertSame(service, adapter.getConversionService()); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void customMessageConverterConfig() throws Exception { |
||||||
|
ApplicationContext context = loadConfig(CustomMessageConverterConfig.class); |
||||||
|
|
||||||
|
String name = "requestMappingHandlerAdapter"; |
||||||
|
RequestMappingHandlerAdapter adapter = context.getBean(name, RequestMappingHandlerAdapter.class); |
||||||
|
assertNotNull(adapter); |
||||||
|
|
||||||
|
List<HttpMessageConverter<?>> converters = adapter.getMessageConverters(); |
||||||
|
assertEquals(2, converters.size()); |
||||||
|
|
||||||
|
assertHasConverter(converters, String.class, MediaType.TEXT_PLAIN); |
||||||
|
assertHasConverter(converters, Pojo.class, MediaType.APPLICATION_XML); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void mvcConversionService() throws Exception { |
||||||
|
ApplicationContext context = loadConfig(WebReactiveConfiguration.class); |
||||||
|
|
||||||
|
String name = "mvcConversionService"; |
||||||
|
ConversionService service = context.getBean(name, ConversionService.class); |
||||||
|
assertNotNull(service); |
||||||
|
|
||||||
|
service.canConvert(CompletableFuture.class, Mono.class); |
||||||
|
service.canConvert(Observable.class, Flux.class); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
@Test |
||||||
|
public void responseBodyResultHandler() throws Exception { |
||||||
|
ApplicationContext context = loadConfig(WebReactiveConfiguration.class); |
||||||
|
|
||||||
|
String name = "responseBodyResultHandler"; |
||||||
|
ResponseBodyResultHandler handler = context.getBean(name, ResponseBodyResultHandler.class); |
||||||
|
assertNotNull(handler); |
||||||
|
|
||||||
|
assertEquals(0, handler.getOrder()); |
||||||
|
|
||||||
|
List<HttpMessageConverter<?>> converters = handler.getMessageConverters(); |
||||||
|
assertEquals(5, converters.size()); |
||||||
|
|
||||||
|
assertHasConverter(converters, ByteBuffer.class, MediaType.APPLICATION_OCTET_STREAM); |
||||||
|
assertHasConverter(converters, String.class, MediaType.TEXT_PLAIN); |
||||||
|
assertHasConverter(converters, Resource.class, MediaType.IMAGE_PNG); |
||||||
|
assertHasConverter(converters, Pojo.class, MediaType.APPLICATION_XML); |
||||||
|
assertHasConverter(converters, Pojo.class, MediaType.APPLICATION_JSON); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void viewResolutionResultHandler() throws Exception { |
||||||
|
ApplicationContext context = loadConfig(CustomViewResolverConfig.class); |
||||||
|
|
||||||
|
String name = "viewResolutionResultHandler"; |
||||||
|
ViewResolutionResultHandler handler = context.getBean(name, ViewResolutionResultHandler.class); |
||||||
|
assertNotNull(handler); |
||||||
|
|
||||||
|
assertEquals(Ordered.LOWEST_PRECEDENCE, handler.getOrder()); |
||||||
|
|
||||||
|
List<ViewResolver> resolvers = handler.getViewResolvers(); |
||||||
|
assertEquals(1, resolvers.size()); |
||||||
|
assertEquals(FreeMarkerViewResolver.class, resolvers.get(0).getClass()); |
||||||
|
|
||||||
|
List<View> views = handler.getDefaultViews(); |
||||||
|
assertEquals(1, views.size()); |
||||||
|
|
||||||
|
MimeType type = MimeTypeUtils.parseMimeType("application/json;charset=UTF-8"); |
||||||
|
assertEquals(type, views.get(0).getSupportedMediaTypes().get(0)); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
private void assertHasConverter(List<HttpMessageConverter<?>> converters, Class<?> clazz, MediaType mediaType) { |
||||||
|
ResolvableType type = ResolvableType.forClass(clazz); |
||||||
|
assertTrue(converters.stream() |
||||||
|
.filter(c -> c.canRead(type, mediaType) && c.canWrite(type, mediaType)) |
||||||
|
.findAny() |
||||||
|
.isPresent()); |
||||||
|
} |
||||||
|
|
||||||
|
private ApplicationContext loadConfig(Class<?>... configurationClasses) { |
||||||
|
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); |
||||||
|
context.register(configurationClasses); |
||||||
|
context.refresh(); |
||||||
|
return context; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
@Configuration |
||||||
|
static class CustomPatchMatchConfig extends WebReactiveConfiguration { |
||||||
|
|
||||||
|
@Override |
||||||
|
public void configurePathMatching(PathMatchConfigurer configurer) { |
||||||
|
configurer.setUseSuffixPatternMatch(false); |
||||||
|
configurer.setUseTrailingSlashMatch(false); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@Configuration |
||||||
|
static class CustomMessageConverterConfig extends WebReactiveConfiguration { |
||||||
|
|
||||||
|
@Override |
||||||
|
protected void configureMessageConverters(List<HttpMessageConverter<?>> converters) { |
||||||
|
converters.add(new CodecHttpMessageConverter<>(new StringEncoder(), new StringDecoder())); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
protected void extendMessageConverters(List<HttpMessageConverter<?>> converters) { |
||||||
|
converters.add(new CodecHttpMessageConverter<>(new Jaxb2Encoder(), new Jaxb2Decoder())); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@Configuration @SuppressWarnings("unused") |
||||||
|
static class CustomViewResolverConfig extends WebReactiveConfiguration { |
||||||
|
|
||||||
|
@Override |
||||||
|
protected void configureViewResolvers(ViewResolverRegistry registry) { |
||||||
|
registry.freeMarker(); |
||||||
|
registry.defaultViews(new HttpMessageConverterView(new JacksonJsonEncoder())); |
||||||
|
} |
||||||
|
|
||||||
|
@Bean |
||||||
|
public FreeMarkerConfigurer freeMarkerConfig() { |
||||||
|
return new FreeMarkerConfigurer(); |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
} |
||||||
Loading…
Reference in new issue