Browse Source

Data binding from pathvars and headers in fn handlers

Closes gh-35800
pull/35899/head
rstoyanchev 3 weeks ago
parent
commit
a9a404266c
  1. 3
      framework-docs/modules/ROOT/pages/web/webflux-functional.adoc
  2. 3
      framework-docs/modules/ROOT/pages/web/webmvc-functional.adoc
  3. 3
      spring-webflux/src/main/java/org/springframework/web/reactive/function/server/DefaultServerRequest.java
  4. 11
      spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/ExtendedWebExchangeDataBinder.java
  5. 10
      spring-webflux/src/test/java/org/springframework/web/reactive/function/server/BindingFunctionIntegrationTests.java
  6. 3
      spring-webmvc/src/main/java/org/springframework/web/servlet/function/DefaultServerRequest.java
  7. 9
      spring-webmvc/src/test/java/org/springframework/web/servlet/function/DefaultServerRequestTests.java

3
framework-docs/modules/ROOT/pages/web/webflux-functional.adoc

@ -296,7 +296,8 @@ allPartsEvents.windowUntil(PartEvent::isLast) @@ -296,7 +296,8 @@ allPartsEvents.windowUntil(PartEvent::isLast)
NOTE: The body contents of the `PartEvent` objects must be completely consumed, relayed, or released to avoid memory leaks.
The following shows how to bind request parameters, including an optional `DataBinder` customization:
The following shows how to bind request parameters, URI variables, or headers via `DataBinder`,
and also shows how to customize the `DataBinder`:
[tabs]
======

3
framework-docs/modules/ROOT/pages/web/webmvc-functional.adoc

@ -184,7 +184,8 @@ val map = request.params() @@ -184,7 +184,8 @@ val map = request.params()
----
======
The following shows how to bind request parameters, including an optional `DataBinder` customization:
The following shows how to bind request parameters, URI variables, or headers via `DataBinder`,
and also shows how to customize the `DataBinder`:
[tabs]
======

3
spring-webflux/src/main/java/org/springframework/web/reactive/function/server/DefaultServerRequest.java

@ -61,6 +61,7 @@ import org.springframework.web.reactive.accept.ApiVersionStrategy; @@ -61,6 +61,7 @@ import org.springframework.web.reactive.accept.ApiVersionStrategy;
import org.springframework.web.reactive.function.BodyExtractor;
import org.springframework.web.reactive.function.BodyExtractors;
import org.springframework.web.reactive.function.UnsupportedMediaTypeException;
import org.springframework.web.reactive.result.method.annotation.ExtendedWebExchangeDataBinder;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.ServerWebInputException;
import org.springframework.web.server.UnsupportedMediaTypeStatusException;
@ -244,7 +245,7 @@ class DefaultServerRequest implements ServerRequest { @@ -244,7 +245,7 @@ class DefaultServerRequest implements ServerRequest {
Assert.notNull(dataBinderCustomizer, "DataBinderCustomizer must not be null");
return Mono.defer(() -> {
WebExchangeDataBinder dataBinder = new WebExchangeDataBinder(null);
WebExchangeDataBinder dataBinder = new ExtendedWebExchangeDataBinder(null);
dataBinder.setTargetType(ResolvableType.forClass(bindType));
dataBinderCustomizer.accept(dataBinder);

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

@ -51,6 +51,17 @@ public class ExtendedWebExchangeDataBinder extends WebExchangeDataBinder { @@ -51,6 +51,17 @@ public class ExtendedWebExchangeDataBinder extends WebExchangeDataBinder {
private Predicate<String> headerPredicate = name -> !FILTERED_HEADER_NAMES.contains(name.toLowerCase(Locale.ROOT));
/**
* 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)
* @since 7.0.2
* @see #DEFAULT_OBJECT_NAME
*/
public ExtendedWebExchangeDataBinder(@Nullable Object target) {
super(target);
}
public ExtendedWebExchangeDataBinder(@Nullable Object target, String objectName) {
super(target, objectName);
}

10
spring-webflux/src/test/java/org/springframework/web/reactive/function/server/BindingFunctionIntegrationTests.java

@ -30,6 +30,7 @@ import org.springframework.web.testfixture.http.server.reactive.bootstrap.HttpSe @@ -30,6 +30,7 @@ import org.springframework.web.testfixture.http.server.reactive.bootstrap.HttpSe
import static org.springframework.web.reactive.function.server.RouterFunctions.route;
/**
* Integration tests with data binding in fn handlers.
* @author Arjen Poutsma
*/
class BindingFunctionIntegrationTests extends AbstractRouterFunctionIntegrationTests {
@ -65,7 +66,8 @@ class BindingFunctionIntegrationTests extends AbstractRouterFunctionIntegrationT @@ -65,7 +66,8 @@ class BindingFunctionIntegrationTests extends AbstractRouterFunctionIntegrationT
startServer(httpServer);
Mono<String> result = this.webClient.get()
.uri("/constructor?foo=FOO&bar=BAR")
.uri("/constructor?foo=FOO")
.header("bar", "BAR")
.retrieve()
.bodyToMono(String.class);
@ -80,7 +82,8 @@ class BindingFunctionIntegrationTests extends AbstractRouterFunctionIntegrationT @@ -80,7 +82,8 @@ class BindingFunctionIntegrationTests extends AbstractRouterFunctionIntegrationT
startServer(httpServer);
Mono<String> result = this.webClient.get()
.uri("/property?foo=FOO&bar=BAR")
.uri("/property?foo=FOO")
.header("bar", "BAR")
.retrieve()
.bodyToMono(String.class);
@ -95,7 +98,8 @@ class BindingFunctionIntegrationTests extends AbstractRouterFunctionIntegrationT @@ -95,7 +98,8 @@ class BindingFunctionIntegrationTests extends AbstractRouterFunctionIntegrationT
startServer(httpServer);
Mono<String> result = this.webClient.get()
.uri("/mixed?foo=FOO&bar=BAR")
.uri("/mixed?foo=FOO")
.header("bar", "BAR")
.retrieve()
.bodyToMono(String.class);

3
spring-webmvc/src/main/java/org/springframework/web/servlet/function/DefaultServerRequest.java

@ -76,6 +76,7 @@ import org.springframework.web.bind.ServletRequestDataBinder; @@ -76,6 +76,7 @@ import org.springframework.web.bind.ServletRequestDataBinder;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.context.request.ServletWebRequest;
import org.springframework.web.context.request.WebRequest;
import org.springframework.web.servlet.mvc.method.annotation.ExtendedServletRequestDataBinder;
import org.springframework.web.servlet.support.ServletUriComponentsBuilder;
import org.springframework.web.util.ServletRequestPathUtils;
import org.springframework.web.util.UriBuilder;
@ -258,7 +259,7 @@ class DefaultServerRequest implements ServerRequest { @@ -258,7 +259,7 @@ class DefaultServerRequest implements ServerRequest {
Assert.notNull(bindType, "BindType must not be null");
Assert.notNull(dataBinderCustomizer, "DataBinderCustomizer must not be null");
ServletRequestDataBinder dataBinder = new ServletRequestDataBinder(null);
ServletRequestDataBinder dataBinder = new ExtendedServletRequestDataBinder(null);
dataBinder.setTargetType(ResolvableType.forClass(bindType));
dataBinderCustomizer.accept(dataBinder);

9
spring-webmvc/src/test/java/org/springframework/web/servlet/function/DefaultServerRequestTests.java

@ -64,8 +64,7 @@ import static org.assertj.core.api.Assertions.assertThatExceptionOfType; @@ -64,8 +64,7 @@ import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
/**
* Tests for {@link DefaultServerRequest}.
*
* Unit tests for {@link DefaultServerRequest}.
* @author Arjen Poutsma
*/
class DefaultServerRequestTests {
@ -350,7 +349,7 @@ class DefaultServerRequestTests { @@ -350,7 +349,7 @@ class DefaultServerRequestTests {
void bindToConstructor() throws BindException {
MockHttpServletRequest servletRequest = PathPatternsTestUtils.initRequest("GET", "/", true);
servletRequest.addParameter("foo", "FOO");
servletRequest.addParameter("bar", "BAR");
servletRequest.addHeader("bar", "BAR");
DefaultServerRequest request = new DefaultServerRequest(servletRequest, this.messageConverters);
@ -363,7 +362,7 @@ class DefaultServerRequestTests { @@ -363,7 +362,7 @@ class DefaultServerRequestTests {
void bindToProperties() throws BindException {
MockHttpServletRequest servletRequest = PathPatternsTestUtils.initRequest("GET", "/", true);
servletRequest.addParameter("foo", "FOO");
servletRequest.addParameter("bar", "BAR");
servletRequest.addHeader("bar", "BAR");
DefaultServerRequest request = new DefaultServerRequest(servletRequest, this.messageConverters);
@ -376,7 +375,7 @@ class DefaultServerRequestTests { @@ -376,7 +375,7 @@ class DefaultServerRequestTests {
void bindToMixed() throws BindException {
MockHttpServletRequest servletRequest = PathPatternsTestUtils.initRequest("GET", "/", true);
servletRequest.addParameter("foo", "FOO");
servletRequest.addParameter("bar", "BAR");
servletRequest.addHeader("bar", "BAR");
DefaultServerRequest request = new DefaultServerRequest(servletRequest, this.messageConverters);

Loading…
Cancel
Save