Skip to content

Commit 1881727

Browse files
committed
Remove ServerWebExchange#getRequestParams
Issue: SPR-15508
1 parent 7f19e57 commit 1881727

16 files changed

+110
-309
lines changed

spring-web/src/main/java/org/springframework/web/bind/support/WebExchangeDataBinder.java

Lines changed: 35 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -16,18 +16,17 @@
1616

1717
package org.springframework.web.bind.support;
1818

19-
import java.util.Collections;
2019
import java.util.List;
2120
import java.util.Map;
2221
import java.util.TreeMap;
2322

2423
import reactor.core.publisher.Mono;
2524

2625
import org.springframework.beans.MutablePropertyValues;
26+
import org.springframework.http.codec.multipart.Part;
2727
import org.springframework.util.CollectionUtils;
2828
import org.springframework.util.MultiValueMap;
2929
import org.springframework.web.bind.WebDataBinder;
30-
import org.springframework.web.multipart.MultipartFile;
3130
import org.springframework.web.server.ServerWebExchange;
3231

3332
/**
@@ -39,6 +38,7 @@
3938
*/
4039
public class WebExchangeDataBinder extends WebDataBinder {
4140

41+
4242
/**
4343
* Create a new instance, with default object name.
4444
* @param target the target object to bind onto (or {@code null} if the
@@ -61,62 +61,52 @@ public WebExchangeDataBinder(Object target, String objectName) {
6161

6262

6363
/**
64-
* Bind the URL query parameters or form data of the body of the given request
65-
* to this binder's target. The request body is parsed if the Content-Type
66-
* is {@code "application/x-www-form-urlencoded"}.
64+
* Bind query params, form data, and or multipart form data to the binder target.
6765
* @param exchange the current exchange.
6866
* @return a {@code Mono<Void>} when binding is complete
6967
*/
7068
public Mono<Void> bind(ServerWebExchange exchange) {
71-
return exchange.getRequestParams()
72-
.map(this::getParamsToBind)
73-
.doOnNext(values -> values.putAll(getMultipartFiles(exchange)))
74-
.doOnNext(values -> values.putAll(getExtraValuesToBind(exchange)))
75-
.flatMap(values -> {
76-
doBind(new MutablePropertyValues(values));
77-
return Mono.empty();
78-
});
79-
}
80-
81-
private Map<String, Object> getParamsToBind(MultiValueMap<String, String> params) {
82-
Map<String, Object> result = new TreeMap<>();
83-
for (Map.Entry<String, List<String>> entry : params.entrySet()) {
84-
String name = entry.getKey();
85-
List<String> values = entry.getValue();
86-
if (CollectionUtils.isEmpty(values)) {
87-
// Do nothing, no values found at all.
88-
}
89-
else if (values.size() == 1) {
90-
result.put(name, values.get(0));
91-
}
92-
else {
93-
result.put(name, values);
94-
}
95-
}
96-
return result;
69+
return getValuesToBind(exchange)
70+
.doOnNext(values -> doBind(new MutablePropertyValues(values)))
71+
.then();
9772
}
9873

9974
/**
100-
* Bind all multipart files contained in the given request, if any (in case
101-
* of a multipart request).
102-
* <p>Multipart files will only be added to the property values if they
103-
* are not empty or if we're configured to bind empty multipart files too.
104-
* @param exchange the current exchange
105-
* @return Map of field name String to MultipartFile object
75+
* Protected method to obtain the values for data binding. By default this
76+
* method delegates to {@link #extractValuesToBind(ServerWebExchange)}.
10677
*/
107-
protected Map<String, List<MultipartFile>> getMultipartFiles(ServerWebExchange exchange) {
108-
// TODO
109-
return Collections.emptyMap();
78+
protected Mono<Map<String, Object>> getValuesToBind(ServerWebExchange exchange) {
79+
return extractValuesToBind(exchange);
11080
}
11181

11282
/**
113-
* Extension point that subclasses can use to add extra bind values for a
114-
* request. Invoked before {@link #doBind(MutablePropertyValues)}.
115-
* <p>The default implementation is empty.
83+
* Combine query params and form data for multipart form data from the body
84+
* of the request into a {@code Map<String, Object>} of values to use for
85+
* data binding purposes.
86+
*
11687
* @param exchange the current exchange
88+
* @return a {@code Mono} with the values to bind
11789
*/
118-
protected Map<String, ?> getExtraValuesToBind(ServerWebExchange exchange) {
119-
return Collections.emptyMap();
90+
public static Mono<Map<String, Object>> extractValuesToBind(ServerWebExchange exchange) {
91+
92+
MultiValueMap<String, String> queryParams = exchange.getRequest().getQueryParams();
93+
Mono<MultiValueMap<String, String>> formData = exchange.getFormData();
94+
Mono<MultiValueMap<String, Part>> multipartData = exchange.getMultipartData();
95+
96+
return Mono.when(Mono.just(queryParams), formData, multipartData)
97+
.map(tuple -> {
98+
Map<String, Object> result = new TreeMap<>();
99+
tuple.getT1().forEach((key, values) -> addBindValue(result, key, values));
100+
tuple.getT2().forEach((key, values) -> addBindValue(result, key, values));
101+
tuple.getT3().forEach((key, values) -> addBindValue(result, key, values));
102+
return result;
103+
});
104+
}
105+
106+
private static void addBindValue(Map<String, Object> params, String key, List<?> values) {
107+
if (!CollectionUtils.isEmpty(values)) {
108+
params.put(key, values.size() == 1 ? values.get(0) : values);
109+
}
120110
}
121111

122112
}

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

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2015 the original author or authors.
2+
* Copyright 2002-2017 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -80,24 +80,23 @@ public interface ServerWebExchange {
8080
/**
8181
* Return the form data from the body of the request if the Content-Type is
8282
* {@code "application/x-www-form-urlencoded"} or an empty map otherwise.
83-
* This method may be called multiple times.
83+
*
84+
* <p><strong>Note:</strong> calling this method causes the request body to
85+
* be read and parsed in full and the resulting {@code MultiValueMap} is
86+
* cached so that this method is safe to call more than once.
8487
*/
8588
Mono<MultiValueMap<String, String>> getFormData();
8689

8790
/**
8891
* Return the parts of a multipart request if the Content-Type is
8992
* {@code "multipart/form-data"} or an empty map otherwise.
90-
* This method may be called multiple times.
93+
*
94+
* <p><strong>Note:</strong> calling this method causes the request body to
95+
* be read and parsed in full and the resulting {@code MultiValueMap} is
96+
* cached so that this method is safe to call more than once.
9197
*/
9298
Mono<MultiValueMap<String, Part>> getMultipartData();
9399

94-
/**
95-
* Return a combined map that represents both
96-
* {@link ServerHttpRequest#getQueryParams()} and {@link #getFormData()}
97-
* or an empty map.
98-
*/
99-
Mono<MultiValueMap<String, String>> getRequestParams();
100-
101100
/**
102101
* Returns {@code true} if the one of the {@code checkNotModified} methods
103102
* in this contract were used and they returned true.

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

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -99,11 +99,6 @@ public Mono<MultiValueMap<String, Part>> getMultipartData() {
9999
return getDelegate().getMultipartData();
100100
}
101101

102-
@Override
103-
public Mono<MultiValueMap<String, String>> getRequestParams() {
104-
return getDelegate().getRequestParams();
105-
}
106-
107102
@Override
108103
public boolean isNotModified() {
109104
return getDelegate().isNotModified();

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

Lines changed: 1 addition & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2016 the original author or authors.
2+
* Copyright 2002-2017 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -88,8 +88,6 @@ public class DefaultServerWebExchange implements ServerWebExchange {
8888

8989
private final Mono<MultiValueMap<String, Part>> multipartDataMono;
9090

91-
private final Mono<MultiValueMap<String, String>> requestParamsMono;
92-
9391
private volatile boolean notModified;
9492

9593

@@ -109,8 +107,6 @@ public DefaultServerWebExchange(ServerHttpRequest request, ServerHttpResponse re
109107
this.sessionMono = sessionManager.getSession(this).cache();
110108
this.formDataMono = initFormData(request, codecConfigurer);
111109
this.multipartDataMono = initMultipartData(request, codecConfigurer);
112-
this.requestParamsMono = initRequestParams(request, this.formDataMono);
113-
114110
}
115111

116112
@SuppressWarnings("unchecked")
@@ -165,20 +161,6 @@ private static Mono<MultiValueMap<String, Part>> initMultipartData(
165161
return EMPTY_MULTIPART_DATA;
166162
}
167163

168-
private static Mono<MultiValueMap<String, String>> initRequestParams(
169-
ServerHttpRequest request, Mono<MultiValueMap<String, String>> formDataMono) {
170-
171-
return formDataMono
172-
.map(formData -> {
173-
MultiValueMap<String, String> result = new LinkedMultiValueMap<>();
174-
result.putAll(request.getQueryParams());
175-
result.putAll(formData);
176-
return CollectionUtils.unmodifiableMultiValueMap(result);
177-
})
178-
.defaultIfEmpty(request.getQueryParams())
179-
.cache();
180-
}
181-
182164

183165
@Override
184166
public ServerHttpRequest getRequest() {
@@ -228,11 +210,6 @@ public Mono<MultiValueMap<String, Part>> getMultipartData() {
228210
return this.multipartDataMono;
229211
}
230212

231-
@Override
232-
public Mono<MultiValueMap<String, String>> getRequestParams() {
233-
return this.requestParamsMono;
234-
}
235-
236213
@Override
237214
public boolean isNotModified() {
238215
return this.notModified;

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

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,6 @@
2121
import java.util.LinkedHashSet;
2222
import java.util.Set;
2323

24-
import org.springframework.util.Assert;
25-
import org.springframework.util.MultiValueMap;
2624
import org.springframework.web.bind.annotation.RequestMapping;
2725
import org.springframework.web.server.ServerWebExchange;
2826

@@ -143,18 +141,12 @@ protected String parseValue(String valueExpression) {
143141

144142
@Override
145143
protected boolean matchName(ServerWebExchange exchange) {
146-
return getRequestParams(exchange).containsKey(this.name);
144+
return exchange.getRequest().getQueryParams().containsKey(this.name);
147145
}
148146

149147
@Override
150148
protected boolean matchValue(ServerWebExchange exchange) {
151-
return this.value.equals(getRequestParams(exchange).getFirst(this.name));
152-
}
153-
154-
private MultiValueMap<String, String> getRequestParams(ServerWebExchange exchange) {
155-
MultiValueMap<String, String> params = exchange.getRequestParams().subscribe().peek();
156-
Assert.notNull(params, "Expected form data (if any) to be parsed.");
157-
return params;
149+
return this.value.equals(exchange.getRequest().getQueryParams().getFirst(this.name));
158150
}
159151
}
160152

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

Lines changed: 19 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -258,32 +258,26 @@ public Mono<HandlerMethod> getHandlerInternal(ServerWebExchange exchange) {
258258
logger.debug("Looking up handler method for path " + lookupPath);
259259
}
260260
this.mappingRegistry.acquireReadLock();
261-
262261
try {
263-
// Ensure form data is parsed for "params" conditions...
264-
return exchange.getRequestParams()
265-
.then(exchange.getMultipartData())
266-
.then(Mono.defer(() -> {
267-
HandlerMethod handlerMethod = null;
268-
try {
269-
handlerMethod = lookupHandlerMethod(lookupPath, exchange);
270-
}
271-
catch (Exception ex) {
272-
return Mono.error(ex);
273-
}
274-
if (logger.isDebugEnabled()) {
275-
if (handlerMethod != null) {
276-
logger.debug("Returning handler method [" + handlerMethod + "]");
277-
}
278-
else {
279-
logger.debug("Did not find handler method for [" + lookupPath + "]");
280-
}
281-
}
282-
if (handlerMethod != null) {
283-
handlerMethod = handlerMethod.createWithResolvedBean();
284-
}
285-
return Mono.justOrEmpty(handlerMethod);
286-
}));
262+
HandlerMethod handlerMethod;
263+
try {
264+
handlerMethod = lookupHandlerMethod(lookupPath, exchange);
265+
}
266+
catch (Exception ex) {
267+
return Mono.error(ex);
268+
}
269+
if (logger.isDebugEnabled()) {
270+
if (handlerMethod != null) {
271+
logger.debug("Returning handler method [" + handlerMethod + "]");
272+
}
273+
else {
274+
logger.debug("Did not find handler method for [" + lookupPath + "]");
275+
}
276+
}
277+
if (handlerMethod != null) {
278+
handlerMethod = handlerMethod.createWithResolvedBean();
279+
}
280+
return Mono.justOrEmpty(handlerMethod);
287281
}
288282
finally {
289283
this.mappingRegistry.releaseReadLock();

spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/ControllerMethodResolver.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,8 +133,8 @@ private void addResolversTo(ArgumentResolverRegistrar registrar,
133133

134134
// Annotation-based...
135135
registrar.add(new RequestParamMethodArgumentResolver(beanFactory, reactiveRegistry, false));
136-
registrar.add(new RequestPartMethodArgumentResolver(beanFactory, reactiveRegistry, false));
137136
registrar.add(new RequestParamMapMethodArgumentResolver(reactiveRegistry));
137+
registrar.add(new RequestPartMethodArgumentResolver(reactiveRegistry));
138138
registrar.add(new PathVariableMethodArgumentResolver(beanFactory, reactiveRegistry));
139139
registrar.add(new PathVariableMapMethodArgumentResolver(reactiveRegistry));
140140
registrar.addIfRequestBody(readers -> new RequestBodyArgumentResolver(readers, reactiveRegistry));

spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/ModelAttributeMethodArgumentResolver.java

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -216,7 +216,7 @@ private Mono<?> createAttribute(
216216
}
217217

218218
// A single data class constructor -> resolve constructor arguments from request parameters.
219-
return exchange.getRequestParams().map(requestParams -> {
219+
return WebExchangeDataBinder.extractValuesToBind(exchange).map(bindValues -> {
220220
ConstructorProperties cp = ctor.getAnnotation(ConstructorProperties.class);
221221
String[] paramNames = (cp != null ? cp.value() : parameterNameDiscoverer.getParameterNames(ctor));
222222
Assert.state(paramNames != null, () -> "Cannot resolve parameter names for constructor " + ctor);
@@ -226,13 +226,9 @@ private Mono<?> createAttribute(
226226
Object[] args = new Object[paramTypes.length];
227227
WebDataBinder binder = context.createDataBinder(exchange, null, attributeName);
228228
for (int i = 0; i < paramNames.length; i++) {
229-
List<String> paramValues = requestParams.get(paramNames[i]);
230-
Object paramValue = null;
231-
if (paramValues != null) {
232-
paramValue = (paramValues.size() == 1 ? paramValues.get(0) :
233-
paramValues.toArray(new String[paramValues.size()]));
234-
}
235-
args[i] = binder.convertIfNecessary(paramValue, paramTypes[i], new MethodParameter(ctor, i));
229+
Object value = bindValues.get(paramNames[i]);
230+
value = (value != null && value instanceof List ? ((List<?>) value).toArray() : value);
231+
args[i] = binder.convertIfNecessary(value, paramTypes[i], new MethodParameter(ctor, i));
236232
}
237233
return BeanUtils.instantiateClass(ctor, args);
238234
});

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

Lines changed: 5 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,6 @@
2121

2222
import org.springframework.core.MethodParameter;
2323
import org.springframework.core.ReactiveAdapterRegistry;
24-
import org.springframework.core.ResolvableType;
25-
import org.springframework.http.codec.multipart.Part;
26-
import org.springframework.util.Assert;
2724
import org.springframework.util.MultiValueMap;
2825
import org.springframework.util.StringUtils;
2926
import org.springframework.web.bind.annotation.RequestParam;
@@ -51,6 +48,7 @@
5148
public class RequestParamMapMethodArgumentResolver extends HandlerMethodArgumentResolverSupport
5249
implements SyncHandlerMethodArgumentResolver {
5350

51+
5452
public RequestParamMapMethodArgumentResolver(ReactiveAdapterRegistry adapterRegistry) {
5553
super(adapterRegistry);
5654
}
@@ -70,18 +68,10 @@ private boolean allParams(RequestParam requestParam, Class<?> type) {
7068
public Optional<Object> resolveArgumentValue(MethodParameter methodParameter,
7169
BindingContext context, ServerWebExchange exchange) {
7270

73-
ResolvableType paramType = ResolvableType.forType(methodParameter.getGenericParameterType());
74-
boolean isMultiValueMap = MultiValueMap.class.isAssignableFrom(paramType.getRawClass());
75-
76-
77-
if (paramType.getGeneric(1).getRawClass() == Part.class) {
78-
MultiValueMap<String, Part> requestParts = exchange.getMultipartData().subscribe().peek();
79-
Assert.notNull(requestParts, "Expected multipart data (if any) to be parsed.");
80-
return Optional.of(isMultiValueMap ? requestParts : requestParts.toSingleValueMap());
81-
}
82-
MultiValueMap<String, String> requestParams = exchange.getRequestParams().subscribe().peek();
83-
Assert.notNull(requestParams, "Expected form data (if any) to be parsed.");
84-
return Optional.of(isMultiValueMap ? requestParams : requestParams.toSingleValueMap());
71+
boolean isMultiValueMap = MultiValueMap.class.isAssignableFrom(methodParameter.getParameterType());
72+
MultiValueMap<String, String> queryParams = exchange.getRequest().getQueryParams();
73+
Object value = isMultiValueMap ? queryParams : queryParams.toSingleValueMap();
74+
return Optional.of(value);
8575
}
8676

8777
}

0 commit comments

Comments
 (0)