|
|
@ -19,13 +19,16 @@ import java.lang.annotation.Annotation;
|
|
|
|
import java.lang.reflect.Constructor;
|
|
|
|
import java.lang.reflect.Constructor;
|
|
|
|
import java.lang.reflect.Modifier;
|
|
|
|
import java.lang.reflect.Modifier;
|
|
|
|
import java.lang.reflect.Parameter;
|
|
|
|
import java.lang.reflect.Parameter;
|
|
|
|
|
|
|
|
import java.lang.reflect.Type;
|
|
|
|
import java.util.ArrayList;
|
|
|
|
import java.util.ArrayList;
|
|
|
|
import java.util.Collections;
|
|
|
|
|
|
|
|
import java.util.HashMap;
|
|
|
|
|
|
|
|
import java.util.LinkedHashMap;
|
|
|
|
import java.util.LinkedHashMap;
|
|
|
|
import java.util.List;
|
|
|
|
import java.util.List;
|
|
|
|
import java.util.Map;
|
|
|
|
import java.util.Map;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
import kotlin.reflect.KFunction;
|
|
|
|
|
|
|
|
import kotlin.reflect.KParameter;
|
|
|
|
|
|
|
|
import kotlin.reflect.jvm.ReflectJvmMapping;
|
|
|
|
|
|
|
|
|
|
|
|
import org.springframework.beans.BeanUtils;
|
|
|
|
import org.springframework.beans.BeanUtils;
|
|
|
|
import org.springframework.boot.context.properties.ConfigurationPropertyDefaultValue;
|
|
|
|
import org.springframework.boot.context.properties.ConfigurationPropertyDefaultValue;
|
|
|
|
import org.springframework.boot.context.properties.source.ConfigurationPropertyName;
|
|
|
|
import org.springframework.boot.context.properties.source.ConfigurationPropertyName;
|
|
|
@ -42,18 +45,6 @@ class ConstructorParametersBinder implements BeanBinder {
|
|
|
|
|
|
|
|
|
|
|
|
private static boolean KOTLIN_PRESENT = KotlinDetector.isKotlinPresent();
|
|
|
|
private static boolean KOTLIN_PRESENT = KotlinDetector.isKotlinPresent();
|
|
|
|
|
|
|
|
|
|
|
|
private static final Map<Class<?>, Object> DEFAULT_TYPE_VALUES;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static {
|
|
|
|
|
|
|
|
Map<Class<?>, Object> values = new HashMap<>();
|
|
|
|
|
|
|
|
values.put(boolean.class, false);
|
|
|
|
|
|
|
|
values.put(byte.class, (byte) 0);
|
|
|
|
|
|
|
|
values.put(short.class, (short) 0);
|
|
|
|
|
|
|
|
values.put(int.class, 0);
|
|
|
|
|
|
|
|
values.put(long.class, (long) 0);
|
|
|
|
|
|
|
|
DEFAULT_TYPE_VALUES = Collections.unmodifiableMap(values);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
@Override
|
|
|
|
@SuppressWarnings("unchecked")
|
|
|
|
@SuppressWarnings("unchecked")
|
|
|
|
public <T> T bind(ConfigurationPropertyName name, Bindable<T> target,
|
|
|
|
public <T> T bind(ConfigurationPropertyName name, Bindable<T> target,
|
|
|
@ -72,14 +63,14 @@ class ConstructorParametersBinder implements BeanBinder {
|
|
|
|
for (ConstructorParameter parameter : bean.getParameters().values()) {
|
|
|
|
for (ConstructorParameter parameter : bean.getParameters().values()) {
|
|
|
|
Object bound = bind(parameter, propertyBinder);
|
|
|
|
Object bound = bind(parameter, propertyBinder);
|
|
|
|
if (bound == null) {
|
|
|
|
if (bound == null) {
|
|
|
|
bound = getDefaultValue(parameter, bean, converter);
|
|
|
|
bound = getDefaultValue(parameter, converter);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
boundParams.add(bound);
|
|
|
|
boundParams.add(bound);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return boundParams;
|
|
|
|
return boundParams;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private Object getDefaultValue(ConstructorParameter parameter, Bean bean,
|
|
|
|
private Object getDefaultValue(ConstructorParameter parameter,
|
|
|
|
BindConverter converter) {
|
|
|
|
BindConverter converter) {
|
|
|
|
if (parameter.getDefaultValue() != null) {
|
|
|
|
if (parameter.getDefaultValue() != null) {
|
|
|
|
return converter.convert(parameter.getDefaultValue(), parameter.getType(),
|
|
|
|
return converter.convert(parameter.getDefaultValue(), parameter.getType(),
|
|
|
@ -88,7 +79,7 @@ class ConstructorParametersBinder implements BeanBinder {
|
|
|
|
else {
|
|
|
|
else {
|
|
|
|
Class<?> resolve = parameter.getType().resolve();
|
|
|
|
Class<?> resolve = parameter.getType().resolve();
|
|
|
|
if (resolve != null && resolve.isPrimitive()) {
|
|
|
|
if (resolve != null && resolve.isPrimitive()) {
|
|
|
|
return (bean.kotlinType) ? null : DEFAULT_TYPE_VALUES.get(resolve);
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return null;
|
|
|
|
return null;
|
|
|
@ -103,15 +94,12 @@ class ConstructorParametersBinder implements BeanBinder {
|
|
|
|
|
|
|
|
|
|
|
|
private static final class Bean {
|
|
|
|
private static final class Bean {
|
|
|
|
|
|
|
|
|
|
|
|
private final boolean kotlinType;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private final Constructor<?> constructor;
|
|
|
|
private final Constructor<?> constructor;
|
|
|
|
|
|
|
|
|
|
|
|
private final Map<String, ConstructorParameter> parameters;
|
|
|
|
private final Map<String, ConstructorParameter> parameters;
|
|
|
|
|
|
|
|
|
|
|
|
private Bean(boolean kotlinType, Constructor<?> constructor,
|
|
|
|
private Bean(Constructor<?> constructor,
|
|
|
|
Map<String, ConstructorParameter> parameters) {
|
|
|
|
Map<String, ConstructorParameter> parameters) {
|
|
|
|
this.kotlinType = kotlinType;
|
|
|
|
|
|
|
|
this.constructor = constructor;
|
|
|
|
this.constructor = constructor;
|
|
|
|
this.parameters = parameters;
|
|
|
|
this.parameters = parameters;
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -129,20 +117,37 @@ class ConstructorParametersBinder implements BeanBinder {
|
|
|
|
.findPrimaryConstructor(type);
|
|
|
|
.findPrimaryConstructor(type);
|
|
|
|
if (primaryConstructor != null
|
|
|
|
if (primaryConstructor != null
|
|
|
|
&& primaryConstructor.getParameterCount() > 0) {
|
|
|
|
&& primaryConstructor.getParameterCount() > 0) {
|
|
|
|
return new Bean(true, primaryConstructor,
|
|
|
|
return KotlinBeanProvider.get(primaryConstructor);
|
|
|
|
parseParameters(primaryConstructor));
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
else {
|
|
|
|
Constructor<?>[] constructors = type.getDeclaredConstructors();
|
|
|
|
Constructor<?>[] constructors = type.getDeclaredConstructors();
|
|
|
|
if (constructors.length == 1 && constructors[0].getParameterCount() > 0) {
|
|
|
|
if (constructors.length == 1 && constructors[0].getParameterCount() > 0) {
|
|
|
|
Constructor<?> constructor = constructors[0];
|
|
|
|
return SimpleBeanProvider.get(constructors[0]);
|
|
|
|
return new Bean(false, constructor, parseParameters(constructor));
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return null;
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public Map<String, ConstructorParameter> getParameters() {
|
|
|
|
|
|
|
|
return this.parameters;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public Constructor<?> getConstructor() {
|
|
|
|
|
|
|
|
return this.constructor;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
|
|
* A simple bean provider that uses `-parameters` to extract the parameter names.
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
private static class SimpleBeanProvider {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public static Bean get(Constructor<?> constructor) {
|
|
|
|
|
|
|
|
return new Bean(constructor, parseParameters(constructor));
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private static Map<String, ConstructorParameter> parseParameters(
|
|
|
|
private static Map<String, ConstructorParameter> parseParameters(
|
|
|
|
Constructor<?> constructor) {
|
|
|
|
Constructor<?> constructor) {
|
|
|
|
Map<String, ConstructorParameter> parameters = new LinkedHashMap<>();
|
|
|
|
Map<String, ConstructorParameter> parameters = new LinkedHashMap<>();
|
|
|
@ -160,12 +165,37 @@ class ConstructorParametersBinder implements BeanBinder {
|
|
|
|
return parameters;
|
|
|
|
return parameters;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public Map<String, ConstructorParameter> getParameters() {
|
|
|
|
|
|
|
|
return this.parameters;
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public Constructor<?> getConstructor() {
|
|
|
|
/**
|
|
|
|
return this.constructor;
|
|
|
|
* A bean provider for a Kotlin class. Uses the Kotlin constructor to extract the
|
|
|
|
|
|
|
|
* parameter names.
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
private static class KotlinBeanProvider {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public static Bean get(Constructor<?> constructor) {
|
|
|
|
|
|
|
|
KFunction<?> kotlinConstructor = ReflectJvmMapping
|
|
|
|
|
|
|
|
.getKotlinFunction(constructor);
|
|
|
|
|
|
|
|
if (kotlinConstructor != null) {
|
|
|
|
|
|
|
|
return new Bean(constructor, parseParameters(kotlinConstructor));
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
else {
|
|
|
|
|
|
|
|
return SimpleBeanProvider.get(constructor);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private static Map<String, ConstructorParameter> parseParameters(
|
|
|
|
|
|
|
|
KFunction<?> constructor) {
|
|
|
|
|
|
|
|
Map<String, ConstructorParameter> parameters = new LinkedHashMap<>();
|
|
|
|
|
|
|
|
for (KParameter parameter : constructor.getParameters()) {
|
|
|
|
|
|
|
|
String name = parameter.getName();
|
|
|
|
|
|
|
|
Type type = ReflectJvmMapping.getJavaType(parameter.getType());
|
|
|
|
|
|
|
|
Annotation[] annotations = parameter.getAnnotations()
|
|
|
|
|
|
|
|
.toArray(new Annotation[0]);
|
|
|
|
|
|
|
|
parameters.computeIfAbsent(name, (s) -> new ConstructorParameter(name,
|
|
|
|
|
|
|
|
ResolvableType.forType(type), annotations, null));
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return parameters;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|