diff --git a/spring-web/src/main/java/org/springframework/web/bind/support/WebExchangeDataBinder.java b/spring-web/src/main/java/org/springframework/web/bind/support/WebExchangeDataBinder.java index 10cc5a8b263..4bfeb063264 100644 --- a/spring-web/src/main/java/org/springframework/web/bind/support/WebExchangeDataBinder.java +++ b/spring-web/src/main/java/org/springframework/web/bind/support/WebExchangeDataBinder.java @@ -148,13 +148,19 @@ public class WebExchangeDataBinder extends WebDataBinder { protected static void addBindValue(Map params, String key, List values) { if (!CollectionUtils.isEmpty(values)) { - values = values.stream() - .map(value -> value instanceof FormFieldPart formFieldPart ? formFieldPart.value() : value) - .toList(); - params.put(key, values.size() == 1 ? values.get(0) : values); + if (values.size() == 1) { + params.put(key, adaptBindValue(values.get(0))); + } + else { + params.put(key, values.stream().map(WebExchangeDataBinder::adaptBindValue).toList()); + } } } + private static Object adaptBindValue(Object value) { + return (value instanceof FormFieldPart part ? part.value() : value); + } + /** * Resolve values from a map. diff --git a/spring-webflux/src/test/java/org/springframework/web/reactive/BindingContextTests.java b/spring-webflux/src/test/java/org/springframework/web/reactive/BindingContextTests.java index f244d9e6816..b058c03df7e 100644 --- a/spring-webflux/src/test/java/org/springframework/web/reactive/BindingContextTests.java +++ b/spring-webflux/src/test/java/org/springframework/web/reactive/BindingContextTests.java @@ -16,10 +16,11 @@ package org.springframework.web.reactive; +import java.lang.reflect.Method; + import jakarta.validation.Valid; import org.junit.jupiter.api.Test; -import org.springframework.core.MethodParameter; import org.springframework.core.ResolvableType; import org.springframework.validation.Errors; import org.springframework.validation.SmartValidator; @@ -27,7 +28,6 @@ import org.springframework.validation.Validator; import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean; import org.springframework.web.bind.WebDataBinder; import org.springframework.web.testfixture.http.server.reactive.MockServerHttpRequest; -import org.springframework.web.testfixture.method.ResolvableMethod; import org.springframework.web.testfixture.server.MockServerWebExchange; import static org.assertj.core.api.Assertions.assertThat; @@ -40,44 +40,37 @@ import static org.mockito.BDDMockito.when; class BindingContextTests { @Test - void jakartaValidatorExcludedWhenMethodValidationApplicable() { + void jakartaValidatorExcludedWhenMethodValidationApplicable() throws Exception { BindingContext bindingContext = new BindingContext(null); bindingContext.setMethodValidationApplicable(true); - MethodParameter parameter = ResolvableMethod.on(BindingContextTests.class) - .named("handle").build().annotPresent(Valid.class).arg(); + Method method = getClass().getDeclaredMethod("handleValidObject", Foo.class); + ResolvableType targetType = ResolvableType.forMethodParameter(method, 0); - WebDataBinder dataBinder = bindingContext.createDataBinder( - MockServerWebExchange.from(MockServerHttpRequest.get("")), new Foo(), "foo", - ResolvableType.forMethodParameter(parameter)); + WebDataBinder binder = bindingContext.createDataBinder( + MockServerWebExchange.from(MockServerHttpRequest.get("")), new Foo(), "foo", targetType); Validator springValidator = mock(Validator.class); when(springValidator.supports(Foo.class)).thenReturn(true); - dataBinder.addValidators(springValidator); + binder.addValidators(springValidator); LocalValidatorFactoryBean beanValidator = new LocalValidatorFactoryBean(); beanValidator.afterPropertiesSet(); - dataBinder.addValidators(beanValidator); + binder.addValidators(beanValidator); WrappedBeanValidator wrappedBeanValidator = new WrappedBeanValidator(beanValidator); - dataBinder.addValidators(wrappedBeanValidator); + binder.addValidators(wrappedBeanValidator); - assertThat(dataBinder.getValidatorsToApply()).containsExactly(springValidator); + assertThat(binder.getValidatorsToApply()).containsExactly(springValidator); } @SuppressWarnings("unused") - private void handle(@Valid Foo foo) { + private void handleValidObject(@Valid Foo foo) { } - private static class WrappedBeanValidator implements SmartValidator { - - private final jakarta.validation.Validator validator; - - private WrappedBeanValidator(jakarta.validation.Validator validator) { - this.validator = validator; - } + private record WrappedBeanValidator(jakarta.validation.Validator validator) implements SmartValidator { @Override public boolean supports(Class clazz) { @@ -100,6 +93,6 @@ class BindingContextTests { } - private static class Foo {} + private static final class Foo {} } diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/ExtendedServletRequestDataBinder.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/ExtendedServletRequestDataBinder.java index 12491972c26..f185f85a09e 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/ExtendedServletRequestDataBinder.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/ExtendedServletRequestDataBinder.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2023 the original author or authors. + * Copyright 2002-2024 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. @@ -81,24 +81,29 @@ public class ExtendedServletRequestDataBinder extends ServletRequestDataBinder { protected void addBindValues(MutablePropertyValues mpvs, ServletRequest request) { Map uriVars = getUriVars(request); if (uriVars != null) { - uriVars.forEach((name, value) -> { - if (mpvs.contains(name)) { - if (logger.isDebugEnabled()) { - logger.debug("URI variable '" + name + "' overridden by request bind value."); - } - } - else { - mpvs.addPropertyValue(name, value); - } - }); + uriVars.forEach((name, value) -> addValueIfNotPresent(mpvs, "URI variable", name, value)); } } @SuppressWarnings("unchecked") @Nullable private static Map getUriVars(ServletRequest request) { - String attr = HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE; - return (Map) request.getAttribute(attr); + return (Map) request.getAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE); + } + + private static void addValueIfNotPresent( + MutablePropertyValues mpvs, String label, String name, @Nullable Object value) { + + if (value != null) { + if (mpvs.contains(name)) { + if (logger.isDebugEnabled()) { + logger.debug(label + " '" + name + "' overridden by request bind value."); + } + } + else { + mpvs.addPropertyValue(name, value); + } + } } diff --git a/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/ExtendedServletRequestDataBinderTests.java b/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/ExtendedServletRequestDataBinderTests.java index b2295a12e72..f3cb0a903a4 100644 --- a/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/ExtendedServletRequestDataBinderTests.java +++ b/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/ExtendedServletRequestDataBinderTests.java @@ -45,10 +45,10 @@ class ExtendedServletRequestDataBinderTests { @Test void createBinder() { - Map uriTemplateVars = new HashMap<>(); - uriTemplateVars.put("name", "nameValue"); - uriTemplateVars.put("age", "25"); - request.setAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE, uriTemplateVars); + + this.request.setAttribute( + HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE, + Map.of("name", "nameValue", "age", "25")); TestBean target = new TestBean(); ServletRequestDataBinder binder = new ExtendedServletRequestDataBinder(target, "");