Support headers in DataBinding via constructor args
Closes gh-34073
This commit is contained in:
@@ -24,6 +24,7 @@ import reactor.core.publisher.Mono;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.bind.support.WebExchangeDataBinder;
|
||||
import org.springframework.web.reactive.HandlerMapping;
|
||||
import org.springframework.web.server.ServerWebExchange;
|
||||
@@ -57,7 +58,11 @@ public class ExtendedWebExchangeDataBinder extends WebExchangeDataBinder {
|
||||
for (Map.Entry<String, List<String>> entry : headers.entrySet()) {
|
||||
List<String> values = entry.getValue();
|
||||
if (!CollectionUtils.isEmpty(values)) {
|
||||
String name = entry.getKey().replace("-", "");
|
||||
// For constructor args with @BindParam mapped to the actual header name
|
||||
String name = entry.getKey();
|
||||
addValueIfNotPresent(map, "Header", name, (values.size() == 1 ? values.get(0) : values));
|
||||
// Also adapt to Java conventions for setters
|
||||
name = StringUtils.uncapitalize(entry.getKey().replace("-", ""));
|
||||
addValueIfNotPresent(map, "Header", name, (values.size() == 1 ? values.get(0) : values));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,10 +27,12 @@ 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.ResolvableType;
|
||||
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.BindParam;
|
||||
import org.springframework.web.bind.annotation.InitBinder;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.support.ConfigurableWebBindingInitializer;
|
||||
@@ -129,7 +131,7 @@ class InitBinderBindingContextTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
void bindUriVariablesAndHeaders() throws Exception {
|
||||
void bindUriVariablesAndHeadersViaSetters() throws Exception {
|
||||
|
||||
MockServerHttpRequest request = MockServerHttpRequest.get("/path")
|
||||
.header("Some-Int-Array", "1")
|
||||
@@ -153,6 +155,31 @@ class InitBinderBindingContextTests {
|
||||
assertThat(target.getSomeIntArray()).containsExactly(1, 2);
|
||||
}
|
||||
|
||||
@Test
|
||||
void bindUriVariablesAndHeadersViaConstructor() 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"));
|
||||
|
||||
BindingContext context = createBindingContext("initBinderWithAttributeName", WebDataBinder.class);
|
||||
WebExchangeDataBinder binder = context.createDataBinder(exchange, null, "dataBean", null);
|
||||
binder.setTargetType(ResolvableType.forClass(DataBean.class));
|
||||
binder.construct(exchange).block();
|
||||
|
||||
DataBean bean = (DataBean) binder.getTarget();
|
||||
|
||||
assertThat(bean.name()).isEqualTo("John");
|
||||
assertThat(bean.age()).isEqualTo(25);
|
||||
assertThat(bean.someIntArray()).containsExactly(1, 2);
|
||||
}
|
||||
|
||||
@Test
|
||||
void bindUriVarsAndHeadersAddedConditionally() throws Exception {
|
||||
|
||||
@@ -212,4 +239,8 @@ class InitBinderBindingContextTests {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private record DataBean(String name, int age, @BindParam("Some-Int-Array") Integer[] someIntArray) {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -156,6 +156,9 @@ public class ExtendedServletRequestDataBinder extends ServletRequestDataBinder {
|
||||
if (uriVars != null) {
|
||||
value = uriVars.get(name);
|
||||
}
|
||||
if (value == null && getRequest() instanceof HttpServletRequest httpServletRequest) {
|
||||
value = getHeaderValue(httpServletRequest, name);
|
||||
}
|
||||
}
|
||||
return value;
|
||||
}
|
||||
@@ -167,6 +170,13 @@ public class ExtendedServletRequestDataBinder extends ServletRequestDataBinder {
|
||||
if (uriVars != null) {
|
||||
set.addAll(uriVars.keySet());
|
||||
}
|
||||
if (request instanceof HttpServletRequest httpServletRequest) {
|
||||
Enumeration<String> enumeration = httpServletRequest.getHeaderNames();
|
||||
while (enumeration.hasMoreElements()) {
|
||||
String headerName = enumeration.nextElement();
|
||||
set.add(headerName.replaceAll("-", ""));
|
||||
}
|
||||
}
|
||||
return set;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,7 +22,10 @@ import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.beans.testfixture.beans.TestBean;
|
||||
import org.springframework.core.ResolvableType;
|
||||
import org.springframework.web.bind.ServletRequestDataBinder;
|
||||
import org.springframework.web.bind.annotation.BindParam;
|
||||
import org.springframework.web.bind.support.BindParamNameResolver;
|
||||
import org.springframework.web.servlet.HandlerMapping;
|
||||
import org.springframework.web.testfixture.servlet.MockHttpServletRequest;
|
||||
|
||||
@@ -45,7 +48,7 @@ class ExtendedServletRequestDataBinderTests {
|
||||
|
||||
|
||||
@Test
|
||||
void createBinder() {
|
||||
void createBinderViaSetters() {
|
||||
request.setAttribute(
|
||||
HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE,
|
||||
Map.of("name", "John", "age", "25"));
|
||||
@@ -62,6 +65,27 @@ class ExtendedServletRequestDataBinderTests {
|
||||
assertThat(target.getSomeIntArray()).containsExactly(1, 2);
|
||||
}
|
||||
|
||||
@Test
|
||||
void createBinderViaConstructor() {
|
||||
request.setAttribute(
|
||||
HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE,
|
||||
Map.of("name", "John", "age", "25"));
|
||||
|
||||
request.addHeader("Some-Int-Array", "1");
|
||||
request.addHeader("Some-Int-Array", "2");
|
||||
|
||||
ServletRequestDataBinder binder = new ExtendedServletRequestDataBinder(null);
|
||||
binder.setTargetType(ResolvableType.forClass(DataBean.class));
|
||||
binder.setNameResolver(new BindParamNameResolver());
|
||||
binder.construct(request);
|
||||
|
||||
DataBean bean = (DataBean) binder.getTarget();
|
||||
|
||||
assertThat(bean.name()).isEqualTo("John");
|
||||
assertThat(bean.age()).isEqualTo(25);
|
||||
assertThat(bean.someIntArray()).containsExactly(1, 2);
|
||||
}
|
||||
|
||||
@Test
|
||||
void uriVarsAndHeadersAddedConditionally() {
|
||||
request.addParameter("name", "John");
|
||||
@@ -88,4 +112,8 @@ class ExtendedServletRequestDataBinderTests {
|
||||
assertThat(target.getAge()).isEqualTo(0);
|
||||
}
|
||||
|
||||
|
||||
private record DataBean(String name, int age, @BindParam("Some-Int-Array") Integer[] someIntArray) {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user