Make ExtendedServletRequestDataBinder public

Make it public and move it down to the annotations package alongside
InitBinderBindingContext. This is mirrors the hierarchy in Spring MVC
with the ExtendedServletRequestDataBinder. The change will allow
customization of the header names to include/exclude in data binding.

See gh-34039
This commit is contained in:
rstoyanchev
2024-12-11 14:23:41 +00:00
parent 3b95d2c449
commit 7b4e19c69b
5 changed files with 156 additions and 104 deletions

View File

@@ -17,20 +17,16 @@
package org.springframework.web.reactive;
import java.lang.reflect.Method;
import java.util.Map;
import jakarta.validation.Valid;
import org.junit.jupiter.api.Test;
import org.springframework.beans.testfixture.beans.TestBean;
import org.springframework.core.ResolvableType;
import org.springframework.http.MediaType;
import org.springframework.validation.Errors;
import org.springframework.validation.SmartValidator;
import org.springframework.validation.Validator;
import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.support.WebExchangeDataBinder;
import org.springframework.web.testfixture.http.server.reactive.MockServerHttpRequest;
import org.springframework.web.testfixture.server.MockServerWebExchange;
@@ -68,54 +64,6 @@ class BindingContextTests {
assertThat(binder.getValidatorsToApply()).containsExactly(springValidator);
}
@Test
void bindUriVariablesAndHeaders() {
MockServerHttpRequest request = MockServerHttpRequest.get("/path")
.header("Some-Int-Array", "1")
.header("Some-Int-Array", "2")
.build();
MockServerWebExchange exchange = MockServerWebExchange.from(request);
exchange.getAttributes().put(
HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE,
Map.of("name", "John", "age", "25"));
TestBean target = new TestBean();
BindingContext bindingContext = new BindingContext(null);
WebExchangeDataBinder binder = bindingContext.createDataBinder(exchange, target, "testBean", null);
binder.bind(exchange).block();
assertThat(target.getName()).isEqualTo("John");
assertThat(target.getAge()).isEqualTo(25);
assertThat(target.getSomeIntArray()).containsExactly(1, 2);
}
@Test
void bindUriVarsAndHeadersAddedConditionally() {
MockServerHttpRequest request = MockServerHttpRequest.post("/path")
.header("name", "Johnny")
.contentType(MediaType.APPLICATION_FORM_URLENCODED)
.body("name=John&age=25");
MockServerWebExchange exchange = MockServerWebExchange.from(request);
exchange.getAttributes().put(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE, Map.of("age", "26"));
TestBean target = new TestBean();
BindingContext bindingContext = new BindingContext(null);
WebExchangeDataBinder binder = bindingContext.createDataBinder(exchange, target, "testBean", null);
binder.bind(exchange).block();
assertThat(target.getName()).isEqualTo("John");
assertThat(target.getAge()).isEqualTo(25);
}
@SuppressWarnings("unused")
private void handleValidObject(@Valid Foo foo) {
}

View File

@@ -20,18 +20,23 @@ import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import org.junit.jupiter.api.Test;
import org.springframework.beans.testfixture.beans.TestBean;
import org.springframework.core.DefaultParameterNameDiscoverer;
import org.springframework.core.ReactiveAdapterRegistry;
import org.springframework.core.convert.ConversionService;
import org.springframework.format.support.DefaultFormattingConversionService;
import org.springframework.http.MediaType;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.support.ConfigurableWebBindingInitializer;
import org.springframework.web.bind.support.WebExchangeDataBinder;
import org.springframework.web.reactive.BindingContext;
import org.springframework.web.reactive.HandlerMapping;
import org.springframework.web.reactive.result.method.SyncHandlerMethodArgumentResolver;
import org.springframework.web.reactive.result.method.SyncInvocableHandlerMethod;
import org.springframework.web.testfixture.http.server.reactive.MockServerHttpRequest;
@@ -123,6 +128,52 @@ class InitBinderBindingContextTests {
assertThat(dataBinder.getDisallowedFields()[0]).isEqualToIgnoringCase("requestParam-22");
}
@Test
void bindUriVariablesAndHeaders() throws Exception {
MockServerHttpRequest request = MockServerHttpRequest.get("/path")
.header("Some-Int-Array", "1")
.header("Some-Int-Array", "2")
.build();
MockServerWebExchange exchange = MockServerWebExchange.from(request);
exchange.getAttributes().put(
HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE,
Map.of("name", "John", "age", "25"));
TestBean target = new TestBean();
BindingContext context = createBindingContext("initBinderWithAttributeName", WebDataBinder.class);
WebExchangeDataBinder binder = context.createDataBinder(exchange, target, "testBean", null);
binder.bind(exchange).block();
assertThat(target.getName()).isEqualTo("John");
assertThat(target.getAge()).isEqualTo(25);
assertThat(target.getSomeIntArray()).containsExactly(1, 2);
}
@Test
void bindUriVarsAndHeadersAddedConditionally() throws Exception {
MockServerHttpRequest request = MockServerHttpRequest.post("/path")
.header("name", "Johnny")
.contentType(MediaType.APPLICATION_FORM_URLENCODED)
.body("name=John&age=25");
MockServerWebExchange exchange = MockServerWebExchange.from(request);
exchange.getAttributes().put(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE, Map.of("age", "26"));
TestBean target = new TestBean();
BindingContext context = createBindingContext("initBinderWithAttributeName", WebDataBinder.class);
WebExchangeDataBinder binder = context.createDataBinder(exchange, target, "testBean", null);
binder.bind(exchange).block();
assertThat(target.getName()).isEqualTo("John");
assertThat(target.getAge()).isEqualTo(25);
}
private BindingContext createBindingContext(String methodName, Class<?>... parameterTypes) throws Exception {
Object handler = new InitBinderHandler();