Polishing in data binding tests

See gh-32676
This commit is contained in:
rstoyanchev 2024-06-04 09:55:09 +01:00
parent 36b0702c0b
commit 398aae2b9a
4 changed files with 46 additions and 42 deletions

View File

@ -148,13 +148,19 @@ public class WebExchangeDataBinder extends WebDataBinder {
protected static void addBindValue(Map<String, Object> params, String key, List<?> values) { protected static void addBindValue(Map<String, Object> params, String key, List<?> values) {
if (!CollectionUtils.isEmpty(values)) { if (!CollectionUtils.isEmpty(values)) {
values = values.stream() if (values.size() == 1) {
.map(value -> value instanceof FormFieldPart formFieldPart ? formFieldPart.value() : value) params.put(key, adaptBindValue(values.get(0)));
.toList(); }
params.put(key, values.size() == 1 ? values.get(0) : values); 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. * Resolve values from a map.

View File

@ -16,10 +16,11 @@
package org.springframework.web.reactive; package org.springframework.web.reactive;
import java.lang.reflect.Method;
import jakarta.validation.Valid; import jakarta.validation.Valid;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.springframework.core.MethodParameter;
import org.springframework.core.ResolvableType; import org.springframework.core.ResolvableType;
import org.springframework.validation.Errors; import org.springframework.validation.Errors;
import org.springframework.validation.SmartValidator; import org.springframework.validation.SmartValidator;
@ -27,7 +28,6 @@ import org.springframework.validation.Validator;
import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean; import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;
import org.springframework.web.bind.WebDataBinder; import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.testfixture.http.server.reactive.MockServerHttpRequest; import org.springframework.web.testfixture.http.server.reactive.MockServerHttpRequest;
import org.springframework.web.testfixture.method.ResolvableMethod;
import org.springframework.web.testfixture.server.MockServerWebExchange; import org.springframework.web.testfixture.server.MockServerWebExchange;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
@ -40,44 +40,37 @@ import static org.mockito.BDDMockito.when;
class BindingContextTests { class BindingContextTests {
@Test @Test
void jakartaValidatorExcludedWhenMethodValidationApplicable() { void jakartaValidatorExcludedWhenMethodValidationApplicable() throws Exception {
BindingContext bindingContext = new BindingContext(null); BindingContext bindingContext = new BindingContext(null);
bindingContext.setMethodValidationApplicable(true); bindingContext.setMethodValidationApplicable(true);
MethodParameter parameter = ResolvableMethod.on(BindingContextTests.class) Method method = getClass().getDeclaredMethod("handleValidObject", Foo.class);
.named("handle").build().annotPresent(Valid.class).arg(); ResolvableType targetType = ResolvableType.forMethodParameter(method, 0);
WebDataBinder dataBinder = bindingContext.createDataBinder( WebDataBinder binder = bindingContext.createDataBinder(
MockServerWebExchange.from(MockServerHttpRequest.get("")), new Foo(), "foo", MockServerWebExchange.from(MockServerHttpRequest.get("")), new Foo(), "foo", targetType);
ResolvableType.forMethodParameter(parameter));
Validator springValidator = mock(Validator.class); Validator springValidator = mock(Validator.class);
when(springValidator.supports(Foo.class)).thenReturn(true); when(springValidator.supports(Foo.class)).thenReturn(true);
dataBinder.addValidators(springValidator); binder.addValidators(springValidator);
LocalValidatorFactoryBean beanValidator = new LocalValidatorFactoryBean(); LocalValidatorFactoryBean beanValidator = new LocalValidatorFactoryBean();
beanValidator.afterPropertiesSet(); beanValidator.afterPropertiesSet();
dataBinder.addValidators(beanValidator); binder.addValidators(beanValidator);
WrappedBeanValidator wrappedBeanValidator = new WrappedBeanValidator(beanValidator); WrappedBeanValidator wrappedBeanValidator = new WrappedBeanValidator(beanValidator);
dataBinder.addValidators(wrappedBeanValidator); binder.addValidators(wrappedBeanValidator);
assertThat(dataBinder.getValidatorsToApply()).containsExactly(springValidator); assertThat(binder.getValidatorsToApply()).containsExactly(springValidator);
} }
@SuppressWarnings("unused") @SuppressWarnings("unused")
private void handle(@Valid Foo foo) { private void handleValidObject(@Valid Foo foo) {
} }
private static class WrappedBeanValidator implements SmartValidator { private record WrappedBeanValidator(jakarta.validation.Validator validator) implements SmartValidator {
private final jakarta.validation.Validator validator;
private WrappedBeanValidator(jakarta.validation.Validator validator) {
this.validator = validator;
}
@Override @Override
public boolean supports(Class<?> clazz) { public boolean supports(Class<?> clazz) {
@ -100,6 +93,6 @@ class BindingContextTests {
} }
private static class Foo {} private static final class Foo {}
} }

View File

@ -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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with 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) { protected void addBindValues(MutablePropertyValues mpvs, ServletRequest request) {
Map<String, String> uriVars = getUriVars(request); Map<String, String> uriVars = getUriVars(request);
if (uriVars != null) { if (uriVars != null) {
uriVars.forEach((name, value) -> { uriVars.forEach((name, value) -> addValueIfNotPresent(mpvs, "URI variable", name, value));
if (mpvs.contains(name)) {
if (logger.isDebugEnabled()) {
logger.debug("URI variable '" + name + "' overridden by request bind value.");
}
}
else {
mpvs.addPropertyValue(name, value);
}
});
} }
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@Nullable @Nullable
private static Map<String, String> getUriVars(ServletRequest request) { private static Map<String, String> getUriVars(ServletRequest request) {
String attr = HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE; return (Map<String, String>) request.getAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE);
return (Map<String, String>) request.getAttribute(attr); }
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);
}
}
} }

View File

@ -45,10 +45,10 @@ class ExtendedServletRequestDataBinderTests {
@Test @Test
void createBinder() { void createBinder() {
Map<String, String> uriTemplateVars = new HashMap<>();
uriTemplateVars.put("name", "nameValue"); this.request.setAttribute(
uriTemplateVars.put("age", "25"); HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE,
request.setAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE, uriTemplateVars); Map.of("name", "nameValue", "age", "25"));
TestBean target = new TestBean(); TestBean target = new TestBean();
ServletRequestDataBinder binder = new ExtendedServletRequestDataBinder(target, ""); ServletRequestDataBinder binder = new ExtendedServletRequestDataBinder(target, "");