Revised handling of missing data class arguments
Includes unified detection of Kotlin's optional parameters in MethodParameter.isOptional(), reduces BeanUtils.findPrimaryConstructor to Kotlin semantics (for reuse in AutowiredAnnotationBeanPostProcessor), and finally introduces a common KotlinDetector delegate with an isKotlinType(Class) check. Issue: SPR-15877 Issue: SPR-16020
This commit is contained in:
@@ -21,6 +21,7 @@ import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
import reactor.core.publisher.Mono;
|
||||
import reactor.core.publisher.MonoProcessor;
|
||||
@@ -196,15 +197,29 @@ public class ModelAttributeMethodArgumentResolver extends HandlerMethodArgumentR
|
||||
}
|
||||
|
||||
private Mono<?> createAttribute(
|
||||
String attributeName, Class<?> attributeType, BindingContext context, ServerWebExchange exchange) {
|
||||
String attributeName, Class<?> clazz, BindingContext context, ServerWebExchange exchange) {
|
||||
|
||||
Constructor<?>[] ctors = attributeType.getConstructors();
|
||||
if (ctors.length != 1) {
|
||||
// No standard data class or standard JavaBeans arrangement ->
|
||||
// defensively go with default constructor, expecting regular bean property bindings.
|
||||
return Mono.just(BeanUtils.instantiateClass(attributeType));
|
||||
Constructor<?> ctor = BeanUtils.findPrimaryConstructor(clazz);
|
||||
if (ctor == null) {
|
||||
Constructor<?>[] ctors = clazz.getConstructors();
|
||||
if (ctors.length == 1) {
|
||||
ctor = ctors[0];
|
||||
}
|
||||
else {
|
||||
try {
|
||||
ctor = clazz.getDeclaredConstructor();
|
||||
}
|
||||
catch (NoSuchMethodException ex) {
|
||||
throw new IllegalStateException("No primary or default constructor found for " + clazz, ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
Constructor<?> ctor = ctors[0];
|
||||
return constructAttribute(ctor, attributeName, context, exchange);
|
||||
}
|
||||
|
||||
private Mono<?> constructAttribute(Constructor<?> ctor, String attributeName,
|
||||
BindingContext context, ServerWebExchange exchange) {
|
||||
|
||||
if (ctor.getParameterCount() == 0) {
|
||||
// A single default constructor -> clearly a standard JavaBeans arrangement.
|
||||
return Mono.just(BeanUtils.instantiateClass(ctor));
|
||||
@@ -237,7 +252,13 @@ public class ModelAttributeMethodArgumentResolver extends HandlerMethodArgumentR
|
||||
}
|
||||
}
|
||||
value = (value instanceof List ? ((List<?>) value).toArray() : value);
|
||||
args[i] = binder.convertIfNecessary(value, paramTypes[i], new MethodParameter(ctor, i));
|
||||
MethodParameter methodParam = new MethodParameter(ctor, i);
|
||||
if (value == null && methodParam.isOptional()) {
|
||||
args[i] = (methodParam.getParameterType() == Optional.class ? Optional.empty() : null);
|
||||
}
|
||||
else {
|
||||
args[i] = binder.convertIfNecessary(value, paramTypes[i], methodParam);
|
||||
}
|
||||
}
|
||||
return BeanUtils.instantiateClass(ctor, args);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user