Conditional use of URI vars for data binding in WebFlux
This commit aligns Spring WebFlux with WebMvc in adding URI variables conditionally if not already in the map. The idea is that data binding is primarily through form data and query params, with URI variables, and request headers (to be implemented next) also made available but without shadowing existing values. See gh-32676
This commit is contained in:
parent
398aae2b9a
commit
23160a43dd
|
|
@ -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.
|
||||
|
|
@ -18,7 +18,6 @@ package org.springframework.web.reactive;
|
|||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
|
||||
import reactor.core.publisher.Mono;
|
||||
|
|
@ -29,6 +28,7 @@ import org.springframework.core.ReactiveAdapterRegistry;
|
|||
import org.springframework.core.ResolvableType;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.validation.BindingResult;
|
||||
import org.springframework.validation.DataBinder;
|
||||
import org.springframework.validation.SmartValidator;
|
||||
|
|
@ -209,10 +209,29 @@ public class BindingContext {
|
|||
|
||||
@Override
|
||||
public Mono<Map<String, Object>> getValuesToBind(ServerWebExchange exchange) {
|
||||
return super.getValuesToBind(exchange).doOnNext(map ->
|
||||
map.putAll(exchange.<Map<String, String>>getAttributeOrDefault(
|
||||
HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE, Collections.emptyMap())));
|
||||
return super.getValuesToBind(exchange).doOnNext(map -> {
|
||||
Map<String, String> vars = exchange.getAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE);
|
||||
if (!CollectionUtils.isEmpty(vars)) {
|
||||
vars.forEach((key, value) -> addValueIfNotPresent(map, "URI variable", key, value));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static void addValueIfNotPresent(
|
||||
Map<String, Object> map, String label, String name, @Nullable Object value) {
|
||||
|
||||
if (value != null) {
|
||||
if (map.containsKey(name)) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug(label + " '" + name + "' overridden by request bind value.");
|
||||
}
|
||||
}
|
||||
else {
|
||||
map.put(name, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -17,16 +17,20 @@
|
|||
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;
|
||||
|
||||
|
|
@ -64,6 +68,27 @@ class BindingContextTests {
|
|||
assertThat(binder.getValidatorsToApply()).containsExactly(springValidator);
|
||||
}
|
||||
|
||||
@Test
|
||||
void uriVariablesAddedConditionally() {
|
||||
|
||||
MockServerHttpRequest request = MockServerHttpRequest.post("/path")
|
||||
.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 testBean = new TestBean();
|
||||
|
||||
BindingContext bindingContext = new BindingContext(null);
|
||||
WebExchangeDataBinder binder = bindingContext.createDataBinder(exchange, testBean, "testBean", null);
|
||||
|
||||
binder.bind(exchange).block();
|
||||
|
||||
assertThat(testBean.getName()).isEqualTo("John");
|
||||
assertThat(testBean.getAge()).isEqualTo(25);
|
||||
}
|
||||
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private void handleValidObject(@Valid Foo foo) {
|
||||
|
|
|
|||
Loading…
Reference in New Issue