parent
580b8b92f8
commit
b28b3e8877
|
|
@ -815,6 +815,8 @@ project("spring-web-reactive") {
|
|||
optional "org.apache.httpcomponents:httpclient:${httpclientVersion}"
|
||||
optional('org.webjars:webjars-locator:0.32')
|
||||
testCompile("javax.validation:validation-api:${beanvalVersion}")
|
||||
testCompile("org.hibernate:hibernate-validator:${hibval5Version}")
|
||||
testCompile("javax.el:javax.el-api:${elApiVersion}")
|
||||
testCompile("org.apache.tomcat:tomcat-util:${tomcatVersion}")
|
||||
testCompile("org.apache.tomcat.embed:tomcat-embed-core:${tomcatVersion}")
|
||||
testCompile("org.eclipse.jetty:jetty-server:${jettyVersion}")
|
||||
|
|
|
|||
|
|
@ -55,7 +55,10 @@ import org.springframework.http.codec.xml.Jaxb2XmlDecoder;
|
|||
import org.springframework.http.codec.xml.Jaxb2XmlEncoder;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.validation.Errors;
|
||||
import org.springframework.validation.MessageCodesResolver;
|
||||
import org.springframework.validation.Validator;
|
||||
import org.springframework.web.bind.WebDataBinder;
|
||||
import org.springframework.web.bind.support.ConfigurableWebBindingInitializer;
|
||||
import org.springframework.web.cors.CorsConfiguration;
|
||||
import org.springframework.web.reactive.HandlerMapping;
|
||||
import org.springframework.web.reactive.accept.CompositeContentTypeResolver;
|
||||
|
|
@ -255,6 +258,7 @@ public class WebReactiveConfiguration implements ApplicationContextAware {
|
|||
}
|
||||
|
||||
adapter.setMessageReaders(getMessageReaders());
|
||||
adapter.setWebBindingInitializer(getConfigurableWebBindingInitializer());
|
||||
adapter.setConversionService(mvcConversionService());
|
||||
adapter.setValidator(mvcValidator());
|
||||
|
||||
|
|
@ -325,6 +329,18 @@ public class WebReactiveConfiguration implements ApplicationContextAware {
|
|||
protected void extendMessageReaders(List<HttpMessageReader<?>> messageReaders) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the {@link ConfigurableWebBindingInitializer} to use for
|
||||
* initializing all {@link WebDataBinder} instances.
|
||||
*/
|
||||
protected ConfigurableWebBindingInitializer getConfigurableWebBindingInitializer() {
|
||||
ConfigurableWebBindingInitializer initializer = new ConfigurableWebBindingInitializer();
|
||||
initializer.setConversionService(mvcConversionService());
|
||||
initializer.setValidator(mvcValidator());
|
||||
initializer.setMessageCodesResolver(getMessageCodesResolver());
|
||||
return initializer;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public FormattingConversionService mvcConversionService() {
|
||||
FormattingConversionService service = new DefaultFormattingConversionService();
|
||||
|
|
@ -378,6 +394,13 @@ public class WebReactiveConfiguration implements ApplicationContextAware {
|
|||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Override this method to provide a custom {@link MessageCodesResolver}.
|
||||
*/
|
||||
protected MessageCodesResolver getMessageCodesResolver() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public SimpleHandlerAdapter simpleHandlerAdapter() {
|
||||
return new SimpleHandlerAdapter();
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@ import org.springframework.http.codec.HttpMessageReader;
|
|||
import org.springframework.ui.ExtendedModelMap;
|
||||
import org.springframework.ui.ModelMap;
|
||||
import org.springframework.validation.Validator;
|
||||
import org.springframework.web.bind.support.WebBindingInitializer;
|
||||
import org.springframework.web.method.HandlerMethod;
|
||||
import org.springframework.web.method.annotation.ExceptionHandlerMethodResolver;
|
||||
import org.springframework.web.reactive.HandlerAdapter;
|
||||
|
|
@ -68,6 +69,8 @@ public class RequestMappingHandlerAdapter implements HandlerAdapter, BeanFactory
|
|||
|
||||
private ReactiveAdapterRegistry reactiveAdapters = new ReactiveAdapterRegistry();
|
||||
|
||||
private WebBindingInitializer webBindingInitializer;
|
||||
|
||||
private ConversionService conversionService = new DefaultFormattingConversionService();
|
||||
|
||||
private Validator validator;
|
||||
|
|
@ -136,6 +139,21 @@ public class RequestMappingHandlerAdapter implements HandlerAdapter, BeanFactory
|
|||
return this.reactiveAdapters;
|
||||
}
|
||||
|
||||
/**
|
||||
* Provide a WebBindingInitializer with "global" initialization to apply
|
||||
* to every DataBinder instance.
|
||||
*/
|
||||
public void setWebBindingInitializer(WebBindingInitializer webBindingInitializer) {
|
||||
this.webBindingInitializer = webBindingInitializer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the configured WebBindingInitializer, or {@code null} if none.
|
||||
*/
|
||||
public WebBindingInitializer getWebBindingInitializer() {
|
||||
return this.webBindingInitializer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure a ConversionService for type conversion of controller method
|
||||
* arguments as well as for converting from different async types to
|
||||
|
|
|
|||
|
|
@ -49,6 +49,8 @@ import org.springframework.util.MimeType;
|
|||
import org.springframework.util.MimeTypeUtils;
|
||||
import org.springframework.validation.Validator;
|
||||
import org.springframework.validation.beanvalidation.OptionalValidatorFactoryBean;
|
||||
import org.springframework.web.bind.WebExchangeDataBinder;
|
||||
import org.springframework.web.bind.support.WebBindingInitializer;
|
||||
import org.springframework.web.reactive.accept.RequestedContentTypeResolver;
|
||||
import org.springframework.web.reactive.handler.AbstractHandlerMapping;
|
||||
import org.springframework.web.reactive.handler.SimpleUrlHandlerMapping;
|
||||
|
|
@ -161,6 +163,13 @@ public class WebReactiveConfigurationTests {
|
|||
Validator validator = context.getBean(name, Validator.class);
|
||||
assertSame(validator, adapter.getValidator());
|
||||
assertEquals(OptionalValidatorFactoryBean.class, validator.getClass());
|
||||
|
||||
WebBindingInitializer bindingInitializer = adapter.getWebBindingInitializer();
|
||||
assertNotNull(bindingInitializer);
|
||||
WebExchangeDataBinder binder = new WebExchangeDataBinder(new Object());
|
||||
bindingInitializer.initBinder(binder);
|
||||
assertSame(service, binder.getConversionService());
|
||||
assertSame(validator, binder.getValidator());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
|||
|
|
@ -0,0 +1,166 @@
|
|||
/*
|
||||
* 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.bind;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import org.springframework.beans.MutablePropertyValues;
|
||||
import org.springframework.core.ResolvableType;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.codec.HttpMessageReader;
|
||||
import org.springframework.http.server.reactive.ServerHttpRequest;
|
||||
import org.springframework.util.LinkedMultiValueMap;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
import org.springframework.web.server.ServerWebExchange;
|
||||
|
||||
/**
|
||||
* Specialized {@link org.springframework.validation.DataBinder} to perform data
|
||||
* binding from URL query params or form data in the request data to Java objects.
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
* @since 5.0
|
||||
*/
|
||||
public class WebExchangeDataBinder extends WebDataBinder {
|
||||
|
||||
private static final ResolvableType MULTIVALUE_MAP_TYPE = ResolvableType.forClass(MultiValueMap.class);
|
||||
|
||||
|
||||
private HttpMessageReader<MultiValueMap<String, String>> formReader = null;
|
||||
|
||||
|
||||
/**
|
||||
* Create a new instance, with default object name.
|
||||
* @param target the target object to bind onto (or {@code null} if the
|
||||
* binder is just used to convert a plain parameter value)
|
||||
* @see #DEFAULT_OBJECT_NAME
|
||||
*/
|
||||
public WebExchangeDataBinder(Object target) {
|
||||
super(target);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new instance.
|
||||
* @param target the target object to bind onto (or {@code null} if the
|
||||
* binder is just used to convert a plain parameter value)
|
||||
* @param objectName the name of the target object
|
||||
*/
|
||||
public WebExchangeDataBinder(Object target, String objectName) {
|
||||
super(target, objectName);
|
||||
}
|
||||
|
||||
|
||||
public void setFormReader(HttpMessageReader<MultiValueMap<String, String>> formReader) {
|
||||
this.formReader = formReader;
|
||||
}
|
||||
|
||||
public HttpMessageReader<MultiValueMap<String, String>> getFormReader() {
|
||||
return this.formReader;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Bind the URL query parameters or form data of the body of the given request
|
||||
* to this binder's target. The request body is parsed if the content-type
|
||||
* is "application/x-www-form-urlencoded".
|
||||
*
|
||||
* @param exchange the current exchange.
|
||||
* @return a {@code Mono<Void>} to indicate the result
|
||||
*/
|
||||
public Mono<Void> bind(ServerWebExchange exchange) {
|
||||
|
||||
ServerHttpRequest request = exchange.getRequest();
|
||||
Mono<MultiValueMap<String, String>> queryParams = Mono.just(request.getQueryParams());
|
||||
Mono<MultiValueMap<String, String>> formParams = getFormParams(exchange);
|
||||
|
||||
return Mono.zip(this::mergeParams, queryParams, formParams)
|
||||
.map(this::getParamsToBind)
|
||||
.doOnNext(values -> values.putAll(getMultipartFiles(exchange)))
|
||||
.doOnNext(values -> values.putAll(getExtraValuesToBind(exchange)))
|
||||
.then(values -> {
|
||||
doBind(new MutablePropertyValues(values));
|
||||
return Mono.empty();
|
||||
});
|
||||
}
|
||||
|
||||
private Mono<MultiValueMap<String, String>> getFormParams(ServerWebExchange exchange) {
|
||||
ServerHttpRequest request = exchange.getRequest();
|
||||
MediaType contentType = request.getHeaders().getContentType();
|
||||
if (this.formReader.canRead(MULTIVALUE_MAP_TYPE, contentType)) {
|
||||
return this.formReader.readMono(MULTIVALUE_MAP_TYPE, request, Collections.emptyMap());
|
||||
}
|
||||
else {
|
||||
return Mono.just(new LinkedMultiValueMap<>());
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private MultiValueMap<String, String> mergeParams(Object[] paramMaps) {
|
||||
MultiValueMap<String, String> result = new LinkedMultiValueMap<>();
|
||||
Arrays.stream(paramMaps).forEach(map -> result.putAll((MultiValueMap<String, String>) map));
|
||||
return result;
|
||||
}
|
||||
|
||||
private Map<String, Object> getParamsToBind(MultiValueMap<String, String> params) {
|
||||
Map<String, Object> valuesToBind = new TreeMap<>();
|
||||
for (Map.Entry<String, List<String>> entry : params.entrySet()) {
|
||||
String name = entry.getKey();
|
||||
List<String> values = entry.getValue();
|
||||
if (values == null || values.isEmpty()) {
|
||||
// Do nothing, no values found at all.
|
||||
}
|
||||
else {
|
||||
if (values.size() > 1) {
|
||||
valuesToBind.put(name, values);
|
||||
}
|
||||
else {
|
||||
valuesToBind.put(name, values.get(0));
|
||||
}
|
||||
}
|
||||
}
|
||||
return valuesToBind;
|
||||
}
|
||||
|
||||
/**
|
||||
* Bind all multipart files contained in the given request, if any (in case
|
||||
* of a multipart request).
|
||||
* <p>Multipart files will only be added to the property values if they
|
||||
* are not empty or if we're configured to bind empty multipart files too.
|
||||
* @param exchange the current exchange
|
||||
* @return Map of field name String to MultipartFile object
|
||||
*/
|
||||
protected Map<String, List<MultipartFile>> getMultipartFiles(ServerWebExchange exchange) {
|
||||
// TODO
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
|
||||
/**
|
||||
* Extension point that subclasses can use to add extra bind values for a
|
||||
* request. Invoked before {@link #doBind(MutablePropertyValues)}.
|
||||
* The default implementation is empty.
|
||||
* @param exchange the current exchange
|
||||
*/
|
||||
protected Map<String, ?> getExtraValuesToBind(ServerWebExchange exchange) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* 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.
|
||||
|
|
@ -22,7 +22,6 @@ import org.springframework.validation.BindingErrorProcessor;
|
|||
import org.springframework.validation.MessageCodesResolver;
|
||||
import org.springframework.validation.Validator;
|
||||
import org.springframework.web.bind.WebDataBinder;
|
||||
import org.springframework.web.context.request.WebRequest;
|
||||
|
||||
/**
|
||||
* Convenient {@link WebBindingInitializer} for declarative configuration
|
||||
|
|
@ -182,7 +181,7 @@ public class ConfigurableWebBindingInitializer implements WebBindingInitializer
|
|||
|
||||
|
||||
@Override
|
||||
public void initBinder(WebDataBinder binder, WebRequest request) {
|
||||
public void initBinder(WebDataBinder binder) {
|
||||
binder.setAutoGrowNestedPaths(this.autoGrowNestedPaths);
|
||||
if (this.directFieldAccess) {
|
||||
binder.initDirectFieldAccess();
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
* 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.
|
||||
|
|
@ -47,6 +47,7 @@ public class DefaultDataBinderFactory implements WebDataBinderFactory {
|
|||
* @throws Exception in case of invalid state or arguments
|
||||
*/
|
||||
@Override
|
||||
@SuppressWarnings("deprecation")
|
||||
public final WebDataBinder createBinder(NativeWebRequest webRequest, Object target, String objectName)
|
||||
throws Exception {
|
||||
|
||||
|
|
@ -74,7 +75,7 @@ public class DefaultDataBinderFactory implements WebDataBinderFactory {
|
|||
|
||||
/**
|
||||
* Extension point to further initialize the created data binder instance
|
||||
* (e.g. with {@code @InitBinder} methods) after "global" initializaton
|
||||
* (e.g. with {@code @InitBinder} methods) after "global" initialization
|
||||
* via {@link WebBindingInitializer}.
|
||||
* @param dataBinder the data binder instance to customize
|
||||
* @param webRequest the current request
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2007 the original author or authors.
|
||||
* 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.
|
||||
|
|
@ -20,19 +20,31 @@ import org.springframework.web.bind.WebDataBinder;
|
|||
import org.springframework.web.context.request.WebRequest;
|
||||
|
||||
/**
|
||||
* Callback interface for initializing a {@link org.springframework.web.bind.WebDataBinder}
|
||||
* for performing data binding in the context of a specific web request.
|
||||
* Callback interface for initializing a {@link WebDataBinder} for performing
|
||||
* data binding in the context of a specific web request.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @author Rossen Stoyanchev
|
||||
* @since 2.5
|
||||
*/
|
||||
public interface WebBindingInitializer {
|
||||
|
||||
/**
|
||||
* Initialize the given DataBinder for the given request.
|
||||
* Initialize the given DataBinder.
|
||||
* @param binder the DataBinder to initialize
|
||||
* @since 5.0
|
||||
*/
|
||||
void initBinder(WebDataBinder binder);
|
||||
|
||||
/**
|
||||
* Initialize the given DataBinder for the given (Servlet) request.
|
||||
* @param binder the DataBinder to initialize
|
||||
* @param request the web request that the data binding happens within
|
||||
* @deprecated as of 5.0 in favor of {@link #initBinder(WebDataBinder)}
|
||||
*/
|
||||
void initBinder(WebDataBinder binder, WebRequest request);
|
||||
@Deprecated
|
||||
default void initBinder(WebDataBinder binder, WebRequest request) {
|
||||
initBinder(binder);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,214 @@
|
|||
/*
|
||||
* 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.bind;
|
||||
|
||||
import java.beans.PropertyEditorSupport;
|
||||
import java.util.Collections;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import org.springframework.core.ResolvableType;
|
||||
import org.springframework.http.codec.HttpMessageReader;
|
||||
import org.springframework.mock.http.server.reactive.test.MockServerHttpRequest;
|
||||
import org.springframework.mock.http.server.reactive.test.MockServerHttpResponse;
|
||||
import org.springframework.tests.sample.beans.ITestBean;
|
||||
import org.springframework.tests.sample.beans.TestBean;
|
||||
import org.springframework.util.LinkedMultiValueMap;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
import org.springframework.web.server.ServerWebExchange;
|
||||
import org.springframework.web.server.adapter.DefaultServerWebExchange;
|
||||
import org.springframework.web.server.session.DefaultWebSessionManager;
|
||||
import org.springframework.web.server.session.WebSessionManager;
|
||||
|
||||
import static junit.framework.TestCase.assertFalse;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.Mockito.when;
|
||||
import static org.springframework.http.MediaType.APPLICATION_FORM_URLENCODED;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link WebExchangeDataBinder}.
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
*/
|
||||
public class WebExchangeDataBinderTests {
|
||||
|
||||
private static final ResolvableType ELEMENT_TYPE = ResolvableType.forClass(MultiValueMap.class);
|
||||
|
||||
|
||||
private WebExchangeDataBinder binder;
|
||||
|
||||
private TestBean testBean;
|
||||
|
||||
private ServerWebExchange exchange;
|
||||
|
||||
@Mock
|
||||
private HttpMessageReader<MultiValueMap<String, String>> formReader;
|
||||
|
||||
private MultiValueMap<String, String> formData;
|
||||
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
|
||||
this.testBean = new TestBean();
|
||||
this.binder = new WebExchangeDataBinder(this.testBean, "person");
|
||||
this.binder.registerCustomEditor(ITestBean.class, new TestBeanPropertyEditor());
|
||||
this.binder.setFormReader(this.formReader);
|
||||
|
||||
MockServerHttpRequest request = new MockServerHttpRequest();
|
||||
MockServerHttpResponse response = new MockServerHttpResponse();
|
||||
WebSessionManager sessionManager = new DefaultWebSessionManager();
|
||||
this.exchange = new DefaultServerWebExchange(request, response, sessionManager);
|
||||
|
||||
request.getHeaders().setContentType(APPLICATION_FORM_URLENCODED);
|
||||
|
||||
this.formData = new LinkedMultiValueMap<>();
|
||||
when(this.formReader.canRead(ELEMENT_TYPE, APPLICATION_FORM_URLENCODED)).thenReturn(true);
|
||||
when(this.formReader.readMono(ELEMENT_TYPE, request, Collections.emptyMap()))
|
||||
.thenReturn(Mono.just(formData));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testBindingWithNestedObjectCreation() throws Exception {
|
||||
this.formData.add("spouse", "someValue");
|
||||
this.formData.add("spouse.name", "test");
|
||||
this.binder.bind(this.exchange).blockMillis(5000);
|
||||
|
||||
assertNotNull(this.testBean.getSpouse());
|
||||
assertEquals("test", testBean.getSpouse().getName());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFieldPrefixCausesFieldReset() throws Exception {
|
||||
this.formData.add("_postProcessed", "visible");
|
||||
this.formData.add("postProcessed", "on");
|
||||
this.binder.bind(this.exchange).blockMillis(5000);
|
||||
assertTrue(this.testBean.isPostProcessed());
|
||||
|
||||
this.formData.remove("postProcessed");
|
||||
this.binder.bind(this.exchange).blockMillis(5000);
|
||||
assertFalse(this.testBean.isPostProcessed());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFieldPrefixCausesFieldResetWithIgnoreUnknownFields() throws Exception {
|
||||
this.binder.setIgnoreUnknownFields(false);
|
||||
|
||||
this.formData.add("_postProcessed", "visible");
|
||||
this.formData.add("postProcessed", "on");
|
||||
this.binder.bind(this.exchange).blockMillis(5000);
|
||||
assertTrue(this.testBean.isPostProcessed());
|
||||
|
||||
this.formData.remove("postProcessed");
|
||||
this.binder.bind(this.exchange).blockMillis(5000);
|
||||
assertFalse(this.testBean.isPostProcessed());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFieldDefault() throws Exception {
|
||||
this.formData.add("!postProcessed", "off");
|
||||
this.formData.add("postProcessed", "on");
|
||||
this.binder.bind(this.exchange).blockMillis(5000);
|
||||
assertTrue(this.testBean.isPostProcessed());
|
||||
|
||||
this.formData.remove("postProcessed");
|
||||
this.binder.bind(this.exchange).blockMillis(5000);
|
||||
assertFalse(this.testBean.isPostProcessed());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFieldDefaultPreemptsFieldMarker() throws Exception {
|
||||
this.formData.add("!postProcessed", "on");
|
||||
this.formData.add("_postProcessed", "visible");
|
||||
this.formData.add("postProcessed", "on");
|
||||
this.binder.bind(this.exchange).blockMillis(5000);
|
||||
assertTrue(this.testBean.isPostProcessed());
|
||||
|
||||
this.formData.remove("postProcessed");
|
||||
this.binder.bind(this.exchange).blockMillis(5000);
|
||||
assertTrue(this.testBean.isPostProcessed());
|
||||
|
||||
this.formData.remove("!postProcessed");
|
||||
this.binder.bind(this.exchange).blockMillis(5000);
|
||||
assertFalse(this.testBean.isPostProcessed());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFieldDefaultNonBoolean() throws Exception {
|
||||
this.formData.add("!name", "anonymous");
|
||||
this.formData.add("name", "Scott");
|
||||
this.binder.bind(this.exchange).blockMillis(5000);
|
||||
assertEquals("Scott", this.testBean.getName());
|
||||
|
||||
this.formData.remove("name");
|
||||
this.binder.bind(this.exchange).blockMillis(5000);
|
||||
assertEquals("anonymous", this.testBean.getName());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWithCommaSeparatedStringArray() throws Exception {
|
||||
this.formData.add("stringArray", "bar");
|
||||
this.formData.add("stringArray", "abc");
|
||||
this.formData.add("stringArray", "123,def");
|
||||
this.binder.bind(this.exchange).blockMillis(5000);
|
||||
assertEquals("Expected all three items to be bound", 3, this.testBean.getStringArray().length);
|
||||
|
||||
this.formData.remove("stringArray");
|
||||
this.formData.add("stringArray", "123,def");
|
||||
this.binder.bind(this.exchange).blockMillis(5000);
|
||||
assertEquals("Expected only 1 item to be bound", 1, this.testBean.getStringArray().length);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBindingWithNestedObjectCreationAndWrongOrder() throws Exception {
|
||||
this.formData.add("spouse.name", "test");
|
||||
this.formData.add("spouse", "someValue");
|
||||
this.binder.bind(this.exchange).blockMillis(5000);
|
||||
|
||||
assertNotNull(this.testBean.getSpouse());
|
||||
assertEquals("test", this.testBean.getSpouse().getName());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBindingWithQueryParams() throws Exception {
|
||||
MultiValueMap<String, String> queryParams = this.exchange.getRequest().getQueryParams();
|
||||
queryParams.add("spouse", "someValue");
|
||||
queryParams.add("spouse.name", "test");
|
||||
this.binder.bind(this.exchange).blockMillis(5000);
|
||||
|
||||
assertNotNull(this.testBean.getSpouse());
|
||||
assertEquals("test", this.testBean.getSpouse().getName());
|
||||
}
|
||||
|
||||
|
||||
|
||||
private static class TestBeanPropertyEditor extends PropertyEditorSupport {
|
||||
|
||||
@Override
|
||||
public void setAsText(String text) {
|
||||
setValue(new TestBean());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Loading…
Reference in New Issue