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:
Juergen Hoeller
2017-09-28 00:31:12 +02:00
parent d3129a8bd7
commit ec345bf162
14 changed files with 204 additions and 344 deletions

View File

@@ -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);
});