DATACMNS-1197 - Resolve Kotlin interface properties for nullability inspection.
We now resolve Kotlin interface properties to inspect these for nullability. Kotlin-reflect does not resolve interface property accessors yet so we need to handle this aspect ourselves. Related ticket: https://youtrack.jetbrains.com/issue/KT-20768. Original pull request: #254.
This commit is contained in:
committed by
Oliver Gierke
parent
8ce79c1810
commit
634d8cbbd6
@@ -15,7 +15,12 @@
|
||||
*/
|
||||
package org.springframework.data.util;
|
||||
|
||||
import kotlin.jvm.JvmClassMappingKt;
|
||||
import kotlin.reflect.KCallable;
|
||||
import kotlin.reflect.KClass;
|
||||
import kotlin.reflect.KFunction;
|
||||
import kotlin.reflect.KMutableProperty;
|
||||
import kotlin.reflect.KProperty;
|
||||
import kotlin.reflect.KType;
|
||||
import kotlin.reflect.jvm.ReflectJvmMapping;
|
||||
import kotlin.reflect.jvm.internal.impl.load.kotlin.header.KotlinClassHeader;
|
||||
@@ -402,11 +407,37 @@ public class ReflectionUtils {
|
||||
}
|
||||
|
||||
if (isSupportedKotlinClass(parameter.getDeclaringClass())) {
|
||||
return KotlinReflectionUtils.isNullable(parameter);
|
||||
}
|
||||
|
||||
KFunction<?> kotlinFunction = ReflectJvmMapping.getKotlinFunction(parameter.getMethod());
|
||||
return !parameter.getParameterType().isPrimitive();
|
||||
}
|
||||
|
||||
/**
|
||||
* Reflection utility methods specific to Kotlin reflection.
|
||||
*/
|
||||
static class KotlinReflectionUtils {
|
||||
|
||||
/**
|
||||
* Returns {@literal} whether the given {@link MethodParameter} is nullable. Its declaring method can reference a
|
||||
* Kotlin function, property or interface property.
|
||||
*
|
||||
* @return {@literal true} if {@link MethodParameter} is nullable.
|
||||
* @since 2.0.1
|
||||
*/
|
||||
static boolean isNullable(MethodParameter parameter) {
|
||||
|
||||
Method method = parameter.getMethod();
|
||||
KFunction<?> kotlinFunction = ReflectJvmMapping.getKotlinFunction(method);
|
||||
|
||||
if (kotlinFunction == null) {
|
||||
throw new IllegalArgumentException(String.format("Cannot resolve %s to a Kotlin function!", parameter));
|
||||
|
||||
// Fallback to own lookup because there's no public Kotlin API for that kind of lookup until
|
||||
// https://youtrack.jetbrains.com/issue/KT-20768 gets resolved.
|
||||
Optional<? extends KFunction> first = findKFunction(method);
|
||||
|
||||
kotlinFunction = first.orElseThrow(
|
||||
() -> new IllegalArgumentException(String.format("Cannot resolve %s to a Kotlin function!", parameter)));
|
||||
}
|
||||
|
||||
KType type = parameter.getParameterIndex() == -1 ? kotlinFunction.getReturnType()
|
||||
@@ -415,6 +446,46 @@ public class ReflectionUtils {
|
||||
return type.isMarkedNullable();
|
||||
}
|
||||
|
||||
return !parameter.getParameterType().isPrimitive();
|
||||
/**
|
||||
* Lookup a {@link Method} to a {@link KFunction}.
|
||||
*
|
||||
* @param method the JVM {@link Method} to look up.
|
||||
* @return {@link Optional} wrapping a possibly existing {@link KFunction}.
|
||||
*/
|
||||
private static Optional<? extends KFunction> findKFunction(Method method) {
|
||||
|
||||
KClass<?> kotlinClass = JvmClassMappingKt.getKotlinClass(method.getDeclaringClass());
|
||||
|
||||
return kotlinClass.getMembers() //
|
||||
.stream() //
|
||||
.flatMap(KotlinReflectionUtils::toKFunctionStream) //
|
||||
.filter(it -> {
|
||||
|
||||
Method javaMethod = ReflectJvmMapping.getJavaMethod(it);
|
||||
return javaMethod != null && javaMethod.equals(method);
|
||||
}) //
|
||||
.findFirst();
|
||||
}
|
||||
|
||||
private static Stream<? extends KFunction> toKFunctionStream(KCallable<?> it) {
|
||||
|
||||
if (it instanceof KMutableProperty<?>) {
|
||||
|
||||
KMutableProperty property = (KMutableProperty<?>) it;
|
||||
return Stream.of(property.getGetter(), property.getSetter());
|
||||
}
|
||||
|
||||
if (it instanceof KProperty<?>) {
|
||||
|
||||
KProperty<?> property = (KProperty<?>) it;
|
||||
return Stream.of(property.getGetter());
|
||||
}
|
||||
|
||||
if (it instanceof KFunction<?>) {
|
||||
return Stream.of((KFunction<?>) it);
|
||||
}
|
||||
|
||||
return Stream.empty();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user