Browse Source

Support for "request parameters"

ServerWebExchange now provides access to "requestParams" as a
MulitValueMap with query parameters and form data combined.

The combined map is then used for the params condition of
@RequestMapping purposes () and also for @RequestParam arguments.

Issue: SPR-15000
pull/1270/merge
Rossen Stoyanchev 8 years ago
parent
commit
6119415427
  1. 12
      spring-web-reactive/src/main/java/org/springframework/web/reactive/result/condition/ParamsRequestCondition.java
  2. 43
      spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/AbstractHandlerMethodMapping.java
  3. 12
      spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/RequestParamMapMethodArgumentResolver.java
  4. 10
      spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/RequestParamMethodArgumentResolver.java
  5. 68
      spring-web-reactive/src/test/java/org/springframework/web/reactive/result/condition/ParamsRequestConditionTests.java
  6. 70
      spring-web-reactive/src/test/java/org/springframework/web/reactive/result/method/annotation/RequestParamMapMethodArgumentResolverTests.java
  7. 132
      spring-web-reactive/src/test/java/org/springframework/web/reactive/result/method/annotation/RequestParamMethodArgumentResolverTests.java
  8. 11
      spring-web/src/main/java/org/springframework/web/server/ServerWebExchange.java
  9. 5
      spring-web/src/main/java/org/springframework/web/server/ServerWebExchangeDecorator.java
  10. 36
      spring-web/src/main/java/org/springframework/web/server/adapter/DefaultServerWebExchange.java
  11. 3
      spring-web/src/test/java/org/springframework/web/server/adapter/DefaultServerWebExchangeCheckNotModifiedTests.java
  12. 39
      spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/condition/ParamsRequestConditionTests.java

12
spring-web-reactive/src/main/java/org/springframework/web/reactive/result/condition/ParamsRequestCondition.java

@ -21,6 +21,8 @@ import java.util.Collections; @@ -21,6 +21,8 @@ import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.Set;
import org.springframework.util.Assert;
import org.springframework.util.MultiValueMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.server.ServerWebExchange;
@ -141,12 +143,18 @@ public final class ParamsRequestCondition extends AbstractRequestCondition<Param @@ -141,12 +143,18 @@ public final class ParamsRequestCondition extends AbstractRequestCondition<Param
@Override
protected boolean matchName(ServerWebExchange exchange) {
return exchange.getRequest().getQueryParams().containsKey(this.name);
return getRequestParams(exchange).containsKey(this.name);
}
@Override
protected boolean matchValue(ServerWebExchange exchange) {
return this.value.equals(exchange.getRequest().getQueryParams().getFirst(this.name));
return this.value.equals(getRequestParams(exchange).getFirst(this.name));
}
private MultiValueMap<String, String> getRequestParams(ServerWebExchange exchange) {
MultiValueMap<String, String> params = exchange.getRequestParams().subscribe().peek();
Assert.notNull(params, "Expected form data (if any) to be parsed.");
return params;
}
}

43
spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/AbstractHandlerMethodMapping.java

@ -260,26 +260,31 @@ public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMap @@ -260,26 +260,31 @@ public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMap
logger.debug("Looking up handler method for path " + lookupPath);
}
this.mappingRegistry.acquireReadLock();
try {
HandlerMethod handlerMethod = null;
try {
handlerMethod = lookupHandlerMethod(lookupPath, exchange);
}
catch (Exception ex) {
return Mono.error(ex);
}
if (logger.isDebugEnabled()) {
if (handlerMethod != null) {
logger.debug("Returning handler method [" + handlerMethod + "]");
}
else {
logger.debug("Did not find handler method for [" + lookupPath + "]");
}
}
if (handlerMethod != null) {
handlerMethod = handlerMethod.createWithResolvedBean();
}
return Mono.justOrEmpty(handlerMethod);
// Ensure form data is parsed for "params" conditions...
return exchange.getRequestParams()
.then(() -> {
HandlerMethod handlerMethod = null;
try {
handlerMethod = lookupHandlerMethod(lookupPath, exchange);
}
catch (Exception ex) {
return Mono.error(ex);
}
if (logger.isDebugEnabled()) {
if (handlerMethod != null) {
logger.debug("Returning handler method [" + handlerMethod + "]");
}
else {
logger.debug("Did not find handler method for [" + lookupPath + "]");
}
}
if (handlerMethod != null) {
handlerMethod = handlerMethod.createWithResolvedBean();
}
return Mono.justOrEmpty(handlerMethod);
});
}
finally {
this.mappingRegistry.releaseReadLock();

12
spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/RequestParamMapMethodArgumentResolver.java

@ -20,6 +20,8 @@ import java.util.Map; @@ -20,6 +20,8 @@ import java.util.Map;
import java.util.Optional;
import org.springframework.core.MethodParameter;
import org.springframework.util.Assert;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestParam;
@ -59,11 +61,17 @@ public class RequestParamMapMethodArgumentResolver implements SyncHandlerMethodA @@ -59,11 +61,17 @@ public class RequestParamMapMethodArgumentResolver implements SyncHandlerMethodA
public Optional<Object> resolveArgumentValue(MethodParameter parameter, BindingContext context,
ServerWebExchange exchange) {
MultiValueMap<String, String> queryParams = exchange.getRequest().getQueryParams();
Object value = (isMultiValueMap(parameter) ? queryParams : queryParams.toSingleValueMap());
MultiValueMap<String, String> requestParams = getRequestParams(exchange);
Object value = (isMultiValueMap(parameter) ? requestParams : requestParams.toSingleValueMap());
return Optional.of(value);
}
private MultiValueMap<String, String> getRequestParams(ServerWebExchange exchange) {
MultiValueMap<String, String> params = exchange.getRequestParams().subscribe().peek();
Assert.notNull(params, "Expected form data (if any) to be parsed.");
return params;
}
private boolean isMultiValueMap(MethodParameter parameter) {
Class<?> paramType = parameter.getParameterType();
return MultiValueMap.class.isAssignableFrom(paramType);

10
spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/RequestParamMethodArgumentResolver.java

@ -24,6 +24,8 @@ import org.springframework.beans.BeanUtils; @@ -24,6 +24,8 @@ import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.core.MethodParameter;
import org.springframework.core.convert.converter.Converter;
import org.springframework.util.Assert;
import org.springframework.util.MultiValueMap;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ValueConstants;
@ -106,7 +108,7 @@ public class RequestParamMethodArgumentResolver extends AbstractNamedValueSyncAr @@ -106,7 +108,7 @@ public class RequestParamMethodArgumentResolver extends AbstractNamedValueSyncAr
protected Optional<Object> resolveNamedValue(String name, MethodParameter parameter,
ServerWebExchange exchange) {
List<String> paramValues = exchange.getRequest().getQueryParams().get(name);
List<String> paramValues = getRequestParams(exchange).get(name);
Object result = null;
if (paramValues != null) {
result = (paramValues.size() == 1 ? paramValues.get(0) : paramValues);
@ -114,6 +116,12 @@ public class RequestParamMethodArgumentResolver extends AbstractNamedValueSyncAr @@ -114,6 +116,12 @@ public class RequestParamMethodArgumentResolver extends AbstractNamedValueSyncAr
return Optional.ofNullable(result);
}
private MultiValueMap<String, String> getRequestParams(ServerWebExchange exchange) {
MultiValueMap<String, String> params = exchange.getRequestParams().subscribe().peek();
Assert.notNull(params, "Expected form data (if any) to be parsed.");
return params;
}
@Override
protected void handleMissingValue(String name, MethodParameter parameter, ServerWebExchange exchange) {
String type = parameter.getNestedParameterType().getSimpleName();

68
spring-web-reactive/src/test/java/org/springframework/web/reactive/result/condition/ParamsRequestConditionTests.java

@ -22,9 +22,11 @@ import java.util.Collection; @@ -22,9 +22,11 @@ import java.util.Collection;
import org.junit.Test;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.mock.http.server.reactive.test.MockServerHttpRequest;
import org.springframework.mock.http.server.reactive.test.MockServerHttpResponse;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.util.MultiValueMap;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.adapter.DefaultServerWebExchange;
import org.springframework.web.server.session.MockWebSessionManager;
@ -35,9 +37,11 @@ import static org.junit.Assert.assertFalse; @@ -35,9 +37,11 @@ import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.springframework.web.util.UriComponentsBuilder.fromPath;
/**
* @author Arjen Poutsma
* Unit tests for {@link ParamsRequestCondition}.
* @author Rossen Stoyanchev
*/
public class ParamsRequestConditionTests {
@ -52,47 +56,45 @@ public class ParamsRequestConditionTests { @@ -52,47 +56,45 @@ public class ParamsRequestConditionTests {
@Test
public void paramPresent() throws Exception {
ServerWebExchange exchange = createExchange("foo", "");
ParamsRequestCondition condition = new ParamsRequestCondition("foo");
assertNotNull(condition.getMatchingCondition(exchange));
assertNotNull(condition.getMatchingCondition(exchangeWithQuery("foo=")));
assertNotNull(condition.getMatchingCondition(exchangeWithFormData("foo=")));
}
@Test
public void paramPresentNoMatch() throws Exception {
ServerWebExchange exchange = createExchange("bar", "");
ParamsRequestCondition condition = new ParamsRequestCondition("foo");
assertNull(condition.getMatchingCondition(exchange));
assertNull(condition.getMatchingCondition(exchangeWithQuery("bar=")));
assertNull(condition.getMatchingCondition(exchangeWithFormData("bar=")));
}
@Test
public void paramNotPresent() throws Exception {
ServerWebExchange exchange = createExchange();
ParamsRequestCondition condition = new ParamsRequestCondition("!foo");
assertNotNull(condition.getMatchingCondition(exchange));
ServerWebExchange exchange = exchange();
assertNotNull(new ParamsRequestCondition("!foo").getMatchingCondition(exchange));
}
@Test
public void paramValueMatch() throws Exception {
ServerWebExchange exchange = createExchange("foo", "bar");
ParamsRequestCondition condition = new ParamsRequestCondition("foo=bar");
assertNotNull(condition.getMatchingCondition(exchange));
assertNotNull(condition.getMatchingCondition(exchangeWithQuery("foo=bar")));
assertNotNull(condition.getMatchingCondition(exchangeWithFormData("foo=bar")));
}
@Test
public void paramValueNoMatch() throws Exception {
ServerWebExchange exchange = createExchange("foo", "bazz");
ParamsRequestCondition condition = new ParamsRequestCondition("foo=bar");
assertNull(condition.getMatchingCondition(exchange));
assertNull(condition.getMatchingCondition(exchangeWithQuery("foo=bazz")));
assertNull(condition.getMatchingCondition(exchangeWithFormData("foo=bazz")));
}
@Test
public void compareTo() throws Exception {
ServerWebExchange exchange = createExchange();
ServerWebExchange exchange = exchange(new MockServerHttpRequest(HttpMethod.GET, "/"));
ParamsRequestCondition condition1 = new ParamsRequestCondition("foo", "bar", "baz");
ParamsRequestCondition condition2 = new ParamsRequestCondition("foo", "bar");
@ -114,31 +116,29 @@ public class ParamsRequestConditionTests { @@ -114,31 +116,29 @@ public class ParamsRequestConditionTests {
assertEquals(2, conditions.size());
}
@Test
public void getMatchingCondition() throws Exception {
ServerWebExchange exchange = createExchange("foo", "bar");
ParamsRequestCondition condition = new ParamsRequestCondition("foo");
ParamsRequestCondition result = condition.getMatchingCondition(exchange);
assertEquals(condition, result);
condition = new ParamsRequestCondition("bar");
private ServerWebExchange exchangeWithQuery(String query) throws URISyntaxException {
MockServerHttpRequest request = new MockServerHttpRequest(HttpMethod.GET, "/");
MultiValueMap<String, String> params = fromPath("/").query(query).build().getQueryParams();
request.getQueryParams().putAll(params);
return exchange(request);
}
result = condition.getMatchingCondition(exchange);
assertNull(result);
private ServerWebExchange exchangeWithFormData(String formData) throws URISyntaxException {
MockServerHttpRequest request = new MockServerHttpRequest(HttpMethod.GET, "/");
request.getHeaders().setContentType(MediaType.APPLICATION_FORM_URLENCODED);
request.setBody(formData);
return exchange(request);
}
private ServerWebExchange createExchange() throws URISyntaxException {
return createExchange(null, null);
private ServerWebExchange exchange() {
return exchange(new MockServerHttpRequest(HttpMethod.GET, "/"));
}
private ServerWebExchange createExchange(String paramName, String paramValue) throws URISyntaxException {
ServerHttpRequest request = new MockServerHttpRequest(HttpMethod.GET, "/");
if (paramName != null) {
request.getQueryParams().add(paramName, paramValue);
}
WebSessionManager sessionManager = new MockWebSessionManager();
return new DefaultServerWebExchange(request, new MockServerHttpResponse(), sessionManager);
private ServerWebExchange exchange(ServerHttpRequest request) {
MockServerHttpResponse response = new MockServerHttpResponse();
WebSessionManager manager = new MockWebSessionManager();
return new DefaultServerWebExchange(request, response, manager);
}
}

70
spring-web-reactive/src/test/java/org/springframework/web/reactive/result/method/annotation/RequestParamMapMethodArgumentResolverTests.java

@ -17,21 +17,21 @@ @@ -17,21 +17,21 @@
package org.springframework.web.reactive.result.method.annotation;
import java.lang.reflect.Method;
import java.net.URISyntaxException;
import java.util.Arrays;
import java.util.Collections;
import java.util.Map;
import org.junit.Before;
import org.junit.Test;
import reactor.core.publisher.Mono;
import org.springframework.core.MethodParameter;
import org.springframework.core.annotation.SynthesizingMethodParameter;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.mock.http.server.reactive.test.MockServerHttpRequest;
import org.springframework.mock.http.server.reactive.test.MockServerHttpResponse;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.server.ServerWebExchange;
@ -42,18 +42,16 @@ import org.springframework.web.server.session.WebSessionManager; @@ -42,18 +42,16 @@ import org.springframework.web.server.session.WebSessionManager;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.springframework.web.util.UriComponentsBuilder.fromPath;
/**
* Unit tests for {@link RequestParamMapMethodArgumentResolver}.
*
* @author Rossen Stoyanchev
*/
public class RequestParamMapMethodArgumentResolverTests {
private RequestParamMapMethodArgumentResolver resolver;
private ServerWebExchange exchange;
private MethodParameter paramMap;
private MethodParameter paramMultiValueMap;
private MethodParameter paramNamedMap;
@ -65,10 +63,6 @@ public class RequestParamMapMethodArgumentResolverTests { @@ -65,10 +63,6 @@ public class RequestParamMapMethodArgumentResolverTests {
public void setUp() throws Exception {
this.resolver = new RequestParamMapMethodArgumentResolver();
ServerHttpRequest request = new MockServerHttpRequest(HttpMethod.GET, "/");
WebSessionManager sessionManager = new MockWebSessionManager();
this.exchange = new DefaultServerWebExchange(request, new MockServerHttpResponse(), sessionManager);
Method method = getClass().getMethod("params", Map.class, MultiValueMap.class, Map.class, Map.class);
this.paramMap = new SynthesizingMethodParameter(method, 0);
this.paramMultiValueMap = new SynthesizingMethodParameter(method, 1);
@ -86,35 +80,51 @@ public class RequestParamMapMethodArgumentResolverTests { @@ -86,35 +80,51 @@ public class RequestParamMapMethodArgumentResolverTests {
}
@Test
public void resolveMapArgument() throws Exception {
String name = "foo";
String value = "bar";
this.exchange.getRequest().getQueryParams().set(name, value);
Map<String, String> expected = Collections.singletonMap(name, value);
Mono<Object> mono = resolver.resolveArgument(paramMap, null, exchange);
Object result = mono.block();
public void resolveMapArgumentWithQueryString() throws Exception {
Object result= resolve(this.paramMap, exchangeWithQuery("foo=bar"));
assertTrue(result instanceof Map);
assertEquals(Collections.singletonMap("foo", "bar"), result);
}
@Test
public void resolveMapArgumentWithFormData() throws Exception {
Object result= resolve(this.paramMap, exchangeWithFormData("foo=bar"));
assertTrue(result instanceof Map);
assertEquals(expected, result);
assertEquals(Collections.singletonMap("foo", "bar"), result);
}
@Test
public void resolveMultiValueMapArgument() throws Exception {
String name = "foo";
String value1 = "bar";
String value2 = "baz";
this.exchange.getRequest().getQueryParams().put(name, Arrays.asList(value1, value2));
ServerWebExchange exchange = exchangeWithQuery("foo=bar&foo=baz");
Object result= resolve(this.paramMultiValueMap, exchange);
MultiValueMap<String, String> expected = new LinkedMultiValueMap<>(1);
expected.add(name, value1);
expected.add(name, value2);
assertTrue(result instanceof MultiValueMap);
assertEquals(Collections.singletonMap("foo", Arrays.asList("bar", "baz")), result);
}
Mono<Object> mono = this.resolver.resolveArgument(this.paramMultiValueMap, null, this.exchange);
Object result = mono.block();
assertTrue(result instanceof MultiValueMap);
assertEquals(expected, result);
private ServerWebExchange exchangeWithQuery(String query) throws URISyntaxException {
MockServerHttpRequest request = new MockServerHttpRequest(HttpMethod.GET, "/");
MultiValueMap<String, String> params = fromPath("/").query(query).build().getQueryParams();
request.getQueryParams().putAll(params);
return exchange(request);
}
private ServerWebExchange exchangeWithFormData(String formData) throws URISyntaxException {
MockServerHttpRequest request = new MockServerHttpRequest(HttpMethod.GET, "/");
request.getHeaders().setContentType(MediaType.APPLICATION_FORM_URLENCODED);
request.setBody(formData);
return exchange(request);
}
private ServerWebExchange exchange(ServerHttpRequest request) {
MockServerHttpResponse response = new MockServerHttpResponse();
WebSessionManager manager = new MockWebSessionManager();
return new DefaultServerWebExchange(request, response, manager);
}
private Object resolve(MethodParameter parameter, ServerWebExchange exchange) {
return this.resolver.resolveArgument(parameter, null, exchange).blockMillis(0);
}

132
spring-web-reactive/src/test/java/org/springframework/web/reactive/result/method/annotation/RequestParamMethodArgumentResolverTests.java

@ -17,7 +17,7 @@ @@ -17,7 +17,7 @@
package org.springframework.web.reactive.result.method.annotation;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.net.URISyntaxException;
import java.util.Map;
import java.util.Optional;
@ -32,9 +32,11 @@ import org.springframework.core.ParameterNameDiscoverer; @@ -32,9 +32,11 @@ import org.springframework.core.ParameterNameDiscoverer;
import org.springframework.core.annotation.SynthesizingMethodParameter;
import org.springframework.format.support.DefaultFormattingConversionService;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.mock.http.server.reactive.test.MockServerHttpRequest;
import org.springframework.mock.http.server.reactive.test.MockServerHttpResponse;
import org.springframework.util.MultiValueMap;
import org.springframework.util.ReflectionUtils;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.support.ConfigurableWebBindingInitializer;
@ -45,7 +47,12 @@ import org.springframework.web.server.adapter.DefaultServerWebExchange; @@ -45,7 +47,12 @@ import org.springframework.web.server.adapter.DefaultServerWebExchange;
import org.springframework.web.server.session.MockWebSessionManager;
import org.springframework.web.server.session.WebSessionManager;
import static org.junit.Assert.*;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.springframework.web.util.UriComponentsBuilder.fromPath;
/**
* Unit tests for {@link RequestParamMethodArgumentResolver}.
@ -56,8 +63,6 @@ public class RequestParamMethodArgumentResolverTests { @@ -56,8 +63,6 @@ public class RequestParamMethodArgumentResolverTests {
private RequestParamMethodArgumentResolver resolver;
private ServerWebExchange exchange;
private MethodParameter paramNamedDefaultValueString;
private MethodParameter paramNamedStringArray;
private MethodParameter paramNamedMap;
@ -67,7 +72,7 @@ public class RequestParamMethodArgumentResolverTests { @@ -67,7 +72,7 @@ public class RequestParamMethodArgumentResolverTests {
private MethodParameter paramNotRequired;
private MethodParameter paramOptional;
private BindingContext bindingContext;
private BindingContext bindContext;
@Before @SuppressWarnings("ConfusingArgumentToVarargsMethod")
@ -77,10 +82,6 @@ public class RequestParamMethodArgumentResolverTests { @@ -77,10 +82,6 @@ public class RequestParamMethodArgumentResolverTests {
ParameterNameDiscoverer paramNameDiscoverer = new LocalVariableTableParameterNameDiscoverer();
Method method = ReflectionUtils.findMethod(getClass(), "handle", (Class<?>[]) null);
ServerHttpRequest request = new MockServerHttpRequest(HttpMethod.GET, "/");
WebSessionManager sessionManager = new MockWebSessionManager();
this.exchange = new DefaultServerWebExchange(request, new MockServerHttpResponse(), sessionManager);
this.paramNamedDefaultValueString = new SynthesizingMethodParameter(method, 0);
this.paramNamedStringArray = new SynthesizingMethodParameter(method, 1);
this.paramNamedMap = new SynthesizingMethodParameter(method, 2);
@ -94,7 +95,7 @@ public class RequestParamMethodArgumentResolverTests { @@ -94,7 +95,7 @@ public class RequestParamMethodArgumentResolverTests {
ConfigurableWebBindingInitializer initializer = new ConfigurableWebBindingInitializer();
initializer.setConversionService(new DefaultFormattingConversionService());
this.bindingContext = new BindingContext(initializer);
this.bindContext = new BindingContext(initializer);
}
@ -115,45 +116,33 @@ public class RequestParamMethodArgumentResolverTests { @@ -115,45 +116,33 @@ public class RequestParamMethodArgumentResolverTests {
}
@Test
public void resolveString() throws Exception {
String expected = "foo";
this.exchange.getRequest().getQueryParams().set("name", expected);
Mono<Object> mono = this.resolver.resolveArgument(
this.paramNamedDefaultValueString, this.bindingContext, this.exchange);
public void resolveWithQueryString() throws Exception {
assertEquals("foo", resolve(this.paramNamedDefaultValueString, exchangeWithQuery("name=foo")));
}
Object result = mono.block();
assertTrue(result instanceof String);
assertEquals("Invalid result", expected, result);
@Test
public void resolveWithFormData() throws Exception {
assertEquals("foo", resolve(this.paramNamedDefaultValueString, exchangeWithFormData("name=foo")));
}
@Test
public void resolveStringArray() throws Exception {
String[] expected = {"foo", "bar"};
this.exchange.getRequest().getQueryParams().put("name", Arrays.asList(expected));
Mono<Object> mono = this.resolver.resolveArgument(
this.paramNamedStringArray, this.bindingContext, this.exchange);
Object result = mono.block();
Object result = resolve(this.paramNamedStringArray, exchangeWithQuery("name=foo&name=bar"));
assertTrue(result instanceof String[]);
assertArrayEquals(expected, (String[]) result);
assertArrayEquals(new String[] {"foo", "bar"}, (String[]) result);
}
@Test
public void resolveDefaultValue() throws Exception {
Mono<Object> mono = this.resolver.resolveArgument(
this.paramNamedDefaultValueString, this.bindingContext, this.exchange);
Object result = mono.block();
assertTrue(result instanceof String);
assertEquals("Invalid result", "bar", result);
Object result = resolve(this.paramNamedDefaultValueString, exchange());
assertEquals("bar", result);
}
@Test
public void missingRequestParam() throws Exception {
Mono<Object> mono = this.resolver.resolveArgument(
this.paramNamedStringArray, this.bindingContext, this.exchange);
this.paramNamedStringArray, this.bindContext, exchange());
StepVerifier.create(mono)
.expectNextCount(0)
@ -163,65 +152,41 @@ public class RequestParamMethodArgumentResolverTests { @@ -163,65 +152,41 @@ public class RequestParamMethodArgumentResolverTests {
@Test
public void resolveSimpleTypeParam() throws Exception {
this.exchange.getRequest().getQueryParams().set("stringNotAnnot", "plainValue");
Mono<Object> mono = this.resolver.resolveArgument(
this.paramStringNotAnnot, this.bindingContext, this.exchange);
Object result = mono.block();
assertTrue(result instanceof String);
ServerWebExchange exchange = exchangeWithQuery("stringNotAnnot=plainValue");
Object result = resolve(this.paramStringNotAnnot, exchange);
assertEquals("plainValue", result);
}
@Test // SPR-8561
public void resolveSimpleTypeParamToNull() throws Exception {
Mono<Object> mono = this.resolver.resolveArgument(
this.paramStringNotAnnot, this.bindingContext, this.exchange);
Object result = mono.block();
assertNull(result);
assertNull(resolve(this.paramStringNotAnnot, exchange()));
}
@Test // SPR-10180
public void resolveEmptyValueToDefault() throws Exception {
this.exchange.getRequest().getQueryParams().set("name", "");
Mono<Object> mono = this.resolver.resolveArgument(
this.paramNamedDefaultValueString, this.bindingContext, this.exchange);
Object result = mono.block();
ServerWebExchange exchange = exchangeWithQuery("name=");
Object result = resolve(this.paramNamedDefaultValueString, exchange);
assertEquals("bar", result);
}
@Test
public void resolveEmptyValueWithoutDefault() throws Exception {
this.exchange.getRequest().getQueryParams().set("stringNotAnnot", "");
Mono<Object> mono = this.resolver.resolveArgument(
this.paramStringNotAnnot, this.bindingContext, this.exchange);
Object result = mono.block();
assertEquals("", result);
assertEquals("", resolve(this.paramStringNotAnnot, exchangeWithQuery("stringNotAnnot=")));
}
@Test
public void resolveEmptyValueRequiredWithoutDefault() throws Exception {
this.exchange.getRequest().getQueryParams().set("name", "");
Mono<Object> mono = this.resolver.resolveArgument(
this.paramRequired, this.bindingContext, this.exchange);
Object result = mono.block();
assertEquals("", result);
assertEquals("", resolve(this.paramRequired, exchangeWithQuery("name=")));
}
@Test
public void resolveOptionalParamValue() throws Exception {
Mono<Object> mono = this.resolver.resolveArgument(
this.paramOptional, this.bindingContext, this.exchange);
Object result = mono.block();
ServerWebExchange exchange = exchange();
Object result = resolve(this.paramOptional, exchange);
assertEquals(Optional.empty(), result);
this.exchange.getRequest().getQueryParams().set("name", "123");
mono = this.resolver.resolveArgument(this.paramOptional, this.bindingContext, this.exchange);
result = mono.block();
exchange = exchangeWithQuery("name=123");
result = resolve(this.paramOptional, exchange);
assertEquals(Optional.class, result.getClass());
Optional<?> value = (Optional<?>) result;
@ -230,6 +195,35 @@ public class RequestParamMethodArgumentResolverTests { @@ -230,6 +195,35 @@ public class RequestParamMethodArgumentResolverTests {
}
private ServerWebExchange exchangeWithQuery(String query) throws URISyntaxException {
MockServerHttpRequest request = new MockServerHttpRequest(HttpMethod.GET, "/");
MultiValueMap<String, String> params = fromPath("/").query(query).build().getQueryParams();
request.getQueryParams().putAll(params);
return exchange(request);
}
private ServerWebExchange exchangeWithFormData(String formData) throws URISyntaxException {
MockServerHttpRequest request = new MockServerHttpRequest(HttpMethod.GET, "/");
request.getHeaders().setContentType(MediaType.APPLICATION_FORM_URLENCODED);
request.setBody(formData);
return exchange(request);
}
private ServerWebExchange exchange() {
return exchange(new MockServerHttpRequest(HttpMethod.GET, "/"));
}
private ServerWebExchange exchange(ServerHttpRequest request) {
MockServerHttpResponse response = new MockServerHttpResponse();
WebSessionManager manager = new MockWebSessionManager();
return new DefaultServerWebExchange(request, response, manager);
}
private Object resolve(MethodParameter parameter, ServerWebExchange exchange) {
return this.resolver.resolveArgument(parameter, this.bindContext, exchange).blockMillis(0);
}
@SuppressWarnings({"unused", "OptionalUsedAsFieldOrParameterType"})
public void handle(
@RequestParam(name = "name", defaultValue = "bar") String param1,

11
spring-web/src/main/java/org/springframework/web/server/ServerWebExchange.java

@ -76,11 +76,18 @@ public interface ServerWebExchange { @@ -76,11 +76,18 @@ public interface ServerWebExchange {
<T extends Principal> Mono<T> getPrincipal();
/**
* Return the form data from the body of the request or an empty {@code Mono}
* if the Content-Type is not "application/x-www-form-urlencoded".
* Return the form data from the body of the request if the Content-Type is
* {@code "application/x-www-form-urlencoded"} or an empty map.
*/
Mono<MultiValueMap<String, String>> getFormData();
/**
* Return a combined map that represents both
* {@link ServerHttpRequest#getQueryParams()} and {@link #getFormData()}
* or an empty map.
*/
Mono<MultiValueMap<String, String>> getRequestParams();
/**
* Returns {@code true} if the one of the {@code checkNotModified} methods
* in this contract were used and they returned true.

5
spring-web/src/main/java/org/springframework/web/server/ServerWebExchangeDecorator.java

@ -93,6 +93,11 @@ public class ServerWebExchangeDecorator implements ServerWebExchange { @@ -93,6 +93,11 @@ public class ServerWebExchangeDecorator implements ServerWebExchange {
return getDelegate().getFormData();
}
@Override
public Mono<MultiValueMap<String, String>> getRequestParams() {
return getDelegate().getRequestParams();
}
@Override
public boolean isNotModified() {
return getDelegate().isNotModified();

36
spring-web/src/main/java/org/springframework/web/server/adapter/DefaultServerWebExchange.java

@ -38,6 +38,8 @@ import org.springframework.http.codec.FormHttpMessageReader; @@ -38,6 +38,8 @@ import org.springframework.http.codec.FormHttpMessageReader;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.util.StringUtils;
import org.springframework.web.server.ServerWebExchange;
@ -56,9 +58,13 @@ public class DefaultServerWebExchange implements ServerWebExchange { @@ -56,9 +58,13 @@ public class DefaultServerWebExchange implements ServerWebExchange {
private static final FormHttpMessageReader FORM_READER = new FormHttpMessageReader();
private static final ResolvableType MULTIVALUE_TYPE =
private static final ResolvableType FORM_DATA_VALUE_TYPE =
ResolvableType.forClassWithGenerics(MultiValueMap.class, String.class, String.class);
private static final Mono<MultiValueMap<String, String>> EMPTY_FORM_DATA =
Mono.just(CollectionUtils.unmodifiableMultiValueMap(new LinkedMultiValueMap<String, String>(0)))
.cache();
private final ServerHttpRequest request;
@ -70,6 +76,8 @@ public class DefaultServerWebExchange implements ServerWebExchange { @@ -70,6 +76,8 @@ public class DefaultServerWebExchange implements ServerWebExchange {
private final Mono<MultiValueMap<String, String>> formDataMono;
private final Mono<MultiValueMap<String, String>> requestParamsMono;
private volatile boolean notModified;
@ -80,10 +88,12 @@ public class DefaultServerWebExchange implements ServerWebExchange { @@ -80,10 +88,12 @@ public class DefaultServerWebExchange implements ServerWebExchange {
Assert.notNull(response, "'response' is required");
Assert.notNull(response, "'sessionManager' is required");
Assert.notNull(response, "'formReader' is required");
this.request = request;
this.response = response;
this.sessionMono = sessionManager.getSession(this).cache();
this.formDataMono = initFormData(request);
this.requestParamsMono = initRequestParams(request, this.formDataMono);
}
private static Mono<MultiValueMap<String, String>> initFormData(ServerHttpRequest request) {
@ -91,13 +101,28 @@ public class DefaultServerWebExchange implements ServerWebExchange { @@ -91,13 +101,28 @@ public class DefaultServerWebExchange implements ServerWebExchange {
try {
contentType = request.getHeaders().getContentType();
if (MediaType.APPLICATION_FORM_URLENCODED.isCompatibleWith(contentType)) {
return FORM_READER.readMono(MULTIVALUE_TYPE, request, Collections.emptyMap()).cache();
Map<String, Object> hints = Collections.emptyMap();
return FORM_READER.readMono(FORM_DATA_VALUE_TYPE, request, hints).cache();
}
}
catch (InvalidMediaTypeException ex) {
// Ignore
}
return Mono.empty();
return EMPTY_FORM_DATA;
}
private static Mono<MultiValueMap<String, String>> initRequestParams(
ServerHttpRequest request, Mono<MultiValueMap<String, String>> formDataMono) {
return formDataMono
.map(formData -> {
MultiValueMap<String, String> result = new LinkedMultiValueMap<>();
result.putAll(request.getQueryParams());
result.putAll(formData);
return CollectionUtils.unmodifiableMultiValueMap(result);
})
.defaultIfEmpty(request.getQueryParams())
.cache();
}
@ -144,6 +169,11 @@ public class DefaultServerWebExchange implements ServerWebExchange { @@ -144,6 +169,11 @@ public class DefaultServerWebExchange implements ServerWebExchange {
return this.formDataMono;
}
@Override
public Mono<MultiValueMap<String, String>> getRequestParams() {
return this.requestParamsMono;
}
@Override
public boolean isNotModified() {
return this.notModified;

3
spring-web/src/test/java/org/springframework/web/server/adapter/DefaultServerWebExchangeCheckNotModifiedTests.java

@ -43,7 +43,8 @@ import static org.junit.Assert.assertNull; @@ -43,7 +43,8 @@ import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
/**
* Parameterized tests for ServletWebRequest
* "checkNotModified" unit tests for {@link DefaultServerWebExchange}.
*
* @author Rossen Stoyanchev
*/
@RunWith(Parameterized.class)

39
spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/condition/ParamsRequestConditionTests.java

@ -1,5 +1,5 @@ @@ -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.
@ -26,6 +26,7 @@ import org.springframework.web.servlet.mvc.condition.ParamsRequestCondition.Para @@ -26,6 +26,7 @@ import org.springframework.web.servlet.mvc.condition.ParamsRequestCondition.Para
import static org.junit.Assert.*;
/**
* Unit tests for {@link ParamsRequestCondition}.
* @author Arjen Poutsma
*/
public class ParamsRequestConditionTests {
@ -36,34 +37,28 @@ public class ParamsRequestConditionTests { @@ -36,34 +37,28 @@ public class ParamsRequestConditionTests {
assertFalse(new ParamsRequestCondition("foo").equals(new ParamsRequestCondition("bar")));
assertFalse(new ParamsRequestCondition("foo").equals(new ParamsRequestCondition("FOO")));
assertEquals(new ParamsRequestCondition("foo=bar"), new ParamsRequestCondition("foo=bar"));
assertFalse(
new ParamsRequestCondition("foo=bar").equals(new ParamsRequestCondition("FOO=bar")));
assertFalse(new ParamsRequestCondition("foo=bar").equals(new ParamsRequestCondition("FOO=bar")));
}
@Test
public void paramPresent() {
ParamsRequestCondition condition = new ParamsRequestCondition("foo");
MockHttpServletRequest request = new MockHttpServletRequest();
request.addParameter("foo", "");
assertNotNull(condition.getMatchingCondition(request));
assertNotNull(new ParamsRequestCondition("foo").getMatchingCondition(request));
}
@Test
public void paramPresentNoMatch() {
ParamsRequestCondition condition = new ParamsRequestCondition("foo");
MockHttpServletRequest request = new MockHttpServletRequest();
request.addHeader("bar", "");
assertNull(condition.getMatchingCondition(request));
assertNull(new ParamsRequestCondition("foo").getMatchingCondition(request));
}
@Test
public void paramNotPresent() {
ParamsRequestCondition condition = new ParamsRequestCondition("!foo");
MockHttpServletRequest request = new MockHttpServletRequest();
assertNotNull(condition.getMatchingCondition(request));
@ -71,22 +66,18 @@ public class ParamsRequestConditionTests { @@ -71,22 +66,18 @@ public class ParamsRequestConditionTests {
@Test
public void paramValueMatch() {
ParamsRequestCondition condition = new ParamsRequestCondition("foo=bar");
MockHttpServletRequest request = new MockHttpServletRequest();
request.addParameter("foo", "bar");
assertNotNull(condition.getMatchingCondition(request));
assertNotNull(new ParamsRequestCondition("foo=bar").getMatchingCondition(request));
}
@Test
public void paramValueNoMatch() {
ParamsRequestCondition condition = new ParamsRequestCondition("foo=bar");
MockHttpServletRequest request = new MockHttpServletRequest();
request.addParameter("foo", "bazz");
assertNull(condition.getMatchingCondition(request));
assertNull(new ParamsRequestCondition("foo=bar").getMatchingCondition(request));
}
@Test
@ -113,20 +104,4 @@ public class ParamsRequestConditionTests { @@ -113,20 +104,4 @@ public class ParamsRequestConditionTests {
assertEquals(2, conditions.size());
}
@Test
public void getMatchingCondition() {
MockHttpServletRequest request = new MockHttpServletRequest();
request.addParameter("foo", "bar");
ParamsRequestCondition condition = new ParamsRequestCondition("foo");
ParamsRequestCondition result = condition.getMatchingCondition(request);
assertEquals(condition, result);
condition = new ParamsRequestCondition("bar");
result = condition.getMatchingCondition(request);
assertNull(result);
}
}

Loading…
Cancel
Save