Use ResolvableType to create WebDataBinder

This provides more flexibility to pass a targetType even if
a MethodParameter is not available.

See gh-26721
This commit is contained in:
rstoyanchev
2023-06-26 13:11:05 +01:00
parent d37d6688d8
commit 11a416156b
10 changed files with 56 additions and 42 deletions

View File

@@ -81,19 +81,19 @@ public class DefaultDataBinderFactory implements WebDataBinderFactory {
@Override
public final WebDataBinder createBinder(
NativeWebRequest webRequest, @Nullable Object target, String objectName,
MethodParameter parameter) throws Exception {
ResolvableType type) throws Exception {
return createBinderInternal(webRequest, target, objectName, parameter);
return createBinderInternal(webRequest, target, objectName, type);
}
private WebDataBinder createBinderInternal(
NativeWebRequest webRequest, @Nullable Object target, String objectName,
@Nullable MethodParameter parameter) throws Exception {
@Nullable ResolvableType type) throws Exception {
WebDataBinder dataBinder = createBinderInstance(target, objectName, webRequest);
if (target == null && parameter != null) {
dataBinder.setTargetType(ResolvableType.forMethodParameter(parameter));
if (target == null && type != null) {
dataBinder.setTargetType(type);
}
if (this.initializer != null) {
@@ -101,8 +101,10 @@ public class DefaultDataBinderFactory implements WebDataBinderFactory {
}
initBinder(dataBinder, webRequest);
if (this.methodValidationApplicable && parameter != null) {
MethodValidationInitializer.initBinder(dataBinder, parameter);
if (this.methodValidationApplicable && type != null) {
if (type.getSource() instanceof MethodParameter parameter) {
MethodValidationInitializer.initBinder(dataBinder, parameter);
}
}
return dataBinder;

View File

@@ -16,7 +16,7 @@
package org.springframework.web.bind.support;
import org.springframework.core.MethodParameter;
import org.springframework.core.ResolvableType;
import org.springframework.lang.Nullable;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.context.request.NativeWebRequest;
@@ -44,13 +44,14 @@ public interface WebDataBinderFactory {
/**
* Variant of {@link #createBinder(NativeWebRequest, Object, String)} with a
* {@link MethodParameter} for which the {@code DataBinder} is created. This
* may provide more insight to initialize the {@link WebDataBinder}.
* {@link ResolvableType} for which the {@code DataBinder} is created.
* This may be used to construct the target, or otherwise provide more
* insight on how to initialize the binder.
* @since 6.1
*/
default WebDataBinder createBinder(
NativeWebRequest webRequest, @Nullable Object target, String objectName,
MethodParameter parameter) throws Exception {
ResolvableType targetType) throws Exception {
return createBinder(webRequest, target, objectName);
}

View File

@@ -148,13 +148,7 @@ public class WebExchangeDataBinder extends WebDataBinder {
/**
* Resolve values from a map.
*/
private static class MapValueResolver implements ValueResolver {
private final Map<String, Object> map;
private MapValueResolver(Map<String, Object> map) {
this.map = map;
}
private record MapValueResolver(Map<String, Object> map) implements ValueResolver {
@Override
public Object resolveValue(String name, Class<?> type) {
@@ -162,4 +156,4 @@ public class WebExchangeDataBinder extends WebDataBinder {
}
}
}
}

View File

@@ -26,6 +26,7 @@ import org.apache.commons.logging.LogFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.core.MethodParameter;
import org.springframework.core.ResolvableType;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;
@@ -142,7 +143,8 @@ public class ModelAttributeMethodProcessor implements HandlerMethodArgumentResol
// No BindingResult yet, proceed with binding and validation
if (bindingResult == null) {
WebDataBinder binder = binderFactory.createBinder(webRequest, attribute, name, parameter);
ResolvableType type = ResolvableType.forMethodParameter(parameter);
WebDataBinder binder = binderFactory.createBinder(webRequest, attribute, name, type);
if (attribute == null) {
constructAttribute(binder, webRequest);
attribute = wrapAsOptionalIfNecessary(parameter, binder.getTarget());