DATACMNS-1508 - Address review comments.

Added ClassUtils.ifPresent(…) to conditionally call back a Consumer<Class> if a class is available from the given ClassLoader. Extract isSuspend(…) method into KotlinReflectionUtils. Deprecate Kotlin-related methods in our ReflectionUtils as parts are available from Spring Framework directly.

Rename CoCrudRepository to CoroutineCrudRepository and CoroutineSortingRepository. Add tests for KotlinReflectionUtils to test calls without Kotlin dependencies.

Original pull request: #415.
This commit is contained in:
Mark Paluch
2020-01-10 10:55:35 +01:00
parent c945fa4f9a
commit 93c708379e
17 changed files with 425 additions and 254 deletions

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2019 the original author or authors.
* Copyright 2019-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -26,10 +26,13 @@ import kotlin.reflect.jvm.KTypesJvm;
import kotlin.reflect.jvm.ReflectJvmMapping;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Optional;
import java.util.stream.Stream;
import org.springframework.core.KotlinDetector;
import org.springframework.core.MethodParameter;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.lang.Nullable;
/**
@@ -38,11 +41,32 @@ import org.springframework.lang.Nullable;
*
* @author Mark Paluch
* @since 2.3
* @see org.springframework.core.KotlinDetector#isKotlinReflectPresent()
*/
public final class KotlinReflectionUtils {
private static final int KOTLIN_KIND_CLASS = 1;
private KotlinReflectionUtils() {}
/**
* Return {@literal true} if the specified class is a supported Kotlin class. Currently supported are only regular
* Kotlin classes. Other class types (synthetic, SAM, lambdas) are not supported via reflection.
*
* @return {@literal true} if {@code type} is a supported Kotlin class.
*/
public static boolean isSupportedKotlinClass(Class<?> type) {
if (!KotlinDetector.isKotlinType(type)) {
return false;
}
return Arrays.stream(type.getDeclaredAnnotations()) //
.filter(annotation -> annotation.annotationType().getName().equals("kotlin.Metadata")) //
.map(annotation -> AnnotationUtils.getValue(annotation, "k")) //
.anyMatch(it -> Integer.valueOf(KOTLIN_KIND_CLASS).equals(it));
}
/**
* Returns a {@link KFunction} instance corresponding to the given Java {@link Method} instance, or {@code null} if
* this method cannot be represented by a Kotlin function.
@@ -55,14 +79,24 @@ public final class KotlinReflectionUtils {
KFunction<?> kotlinFunction = ReflectJvmMapping.getKotlinFunction(method);
if (kotlinFunction == null) {
// 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.
return kotlinFunction == null ? findKFunction(method).orElse(null) : kotlinFunction;
}
// 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.
return findKFunction(method).orElse(null);
}
/**
* Returns whether the {@link Method} is declared as suspend (Kotlin Coroutine).
*
* @param method the method to inspect.
* @return {@literal true} if the method is declared as suspend.
* @see KFunction#isSuspend()
*/
public static boolean isSuspend(Method method) {
return kotlinFunction;
KFunction<?> invokedFunction = KotlinDetector.isKotlinType(method.getDeclaringClass()) ? findKotlinFunction(method)
: null;
return invokedFunction != null && invokedFunction.isSuspend();
}
/**

View File

@@ -31,6 +31,7 @@ import java.util.stream.IntStream;
import java.util.stream.Stream;
import org.springframework.beans.BeanUtils;
import org.springframework.core.KotlinDetector;
import org.springframework.core.MethodParameter;
import org.springframework.core.ResolvableType;
import org.springframework.core.annotation.AnnotationUtils;
@@ -51,10 +52,6 @@ import org.springframework.util.ReflectionUtils.FieldFilter;
@UtilityClass
public class ReflectionUtils {
private static final boolean KOTLIN_IS_PRESENT = ClassUtils.isPresent("kotlin.Unit",
BeanUtils.class.getClassLoader());
private static final int KOTLIN_KIND_CLASS = 1;
/**
* Creates an instance of the class with the given fully qualified name or returns the given default instance if the
* class cannot be loaded or instantiated.
@@ -350,12 +347,11 @@ public class ReflectionUtils {
*
* @return {@literal true} if {@code type} is a Kotlin class.
* @since 2.0
* @deprecated since 2.3, use {@link KotlinDetector#isKotlinType(Class)} instead.
*/
@Deprecated
public static boolean isKotlinClass(Class<?> type) {
return KOTLIN_IS_PRESENT && Arrays.stream(type.getDeclaredAnnotations()) //
.map(Annotation::annotationType) //
.anyMatch(annotation -> annotation.getName().equals("kotlin.Metadata"));
return KotlinDetector.isKotlinType(type);
}
/**
@@ -364,17 +360,11 @@ public class ReflectionUtils {
*
* @return {@literal true} if {@code type} is a supported Kotlin class.
* @since 2.0
* @deprecated since 2.3, use {@link KotlinReflectionUtils#isSupportedKotlinClass(Class)} instead.
*/
@Deprecated
public static boolean isSupportedKotlinClass(Class<?> type) {
if (!isKotlinClass(type)) {
return false;
}
return Arrays.stream(type.getDeclaredAnnotations()) //
.filter(annotation -> annotation.annotationType().getName().equals("kotlin.Metadata")) //
.map(annotation -> AnnotationUtils.getValue(annotation, "k")) //
.anyMatch(it -> Integer.valueOf(KOTLIN_KIND_CLASS).equals(it));
return KotlinReflectionUtils.isSupportedKotlinClass(type);
}
/**