Efficient Kotlin metadata detection

Follow-up of 3991ab4a23.

Issue: SPR-15673
This commit is contained in:
Sebastien Deleuze
2017-08-22 14:38:24 +02:00
parent cea9d1db8e
commit ab6430569d
3 changed files with 83 additions and 54 deletions

View File

@@ -58,8 +58,20 @@ import org.springframework.util.ClassUtils;
*/
public class MethodParameter {
private static final boolean kotlinPresent =
ClassUtils.isPresent("kotlin.Metadata", MethodParameter.class.getClassLoader());
@Nullable
private static final Class<?> kotlinMetadata;
static {
Class<?> metadata;
try {
metadata = ClassUtils.forName("kotlin.Metadata", MethodParameter.class.getClassLoader());
}
catch (ClassNotFoundException ex) {
// Kotlin API not available - no Kotlin support
metadata = null;
}
kotlinMetadata = metadata;
}
private final Executable executable;
@@ -341,7 +353,16 @@ public class MethodParameter {
*/
public boolean isOptional() {
return (getParameterType() == Optional.class || hasNullableAnnotation() ||
(kotlinPresent && KotlinDelegate.isNullable(this)));
(useKotlinSupport(this.getContainingClass()) && KotlinDelegate.isNullable(this)));
}
/**
* Return true if Kotlin is present and if the specified class is a Kotlin one.
*/
@SuppressWarnings("unchecked")
private static boolean useKotlinSupport(Class<?> clazz) {
return (kotlinMetadata != null &&
clazz.getDeclaredAnnotation((Class<? extends Annotation>) kotlinMetadata) != null);
}
/**
@@ -736,41 +757,30 @@ public class MethodParameter {
* Check whether the specified {@link MethodParameter} represents a nullable Kotlin type or not.
*/
public static boolean isNullable(MethodParameter param) {
if (isKotlinClass(param.getContainingClass())) {
Method method = param.getMethod();
Constructor<?> ctor = param.getConstructor();
int index = param.getParameterIndex();
if (method != null && index == -1) {
KFunction<?> function = ReflectJvmMapping.getKotlinFunction(method);
return (function != null && function.getReturnType().isMarkedNullable());
}
else {
KFunction<?> function = null;
if (method != null) {
function = ReflectJvmMapping.getKotlinFunction(method);
}
else if (ctor != null) {
function = ReflectJvmMapping.getKotlinFunction(ctor);
}
if (function != null) {
List<KParameter> parameters = function.getParameters();
return parameters
.stream()
.filter(p -> KParameter.Kind.VALUE.equals(p.getKind()))
.collect(Collectors.toList())
.get(index)
.getType()
.isMarkedNullable();
}
}
Method method = param.getMethod();
Constructor<?> ctor = param.getConstructor();
int index = param.getParameterIndex();
if (method != null && index == -1) {
KFunction<?> function = ReflectJvmMapping.getKotlinFunction(method);
return (function != null && function.getReturnType().isMarkedNullable());
}
return false;
}
private static boolean isKotlinClass(Class<?> clazz) {
for (Annotation annotation : clazz.getDeclaredAnnotations()) {
if (annotation.annotationType().getName().equals("kotlin.Metadata")) {
return true;
else {
KFunction<?> function = null;
if (method != null) {
function = ReflectJvmMapping.getKotlinFunction(method);
}
else if (ctor != null) {
function = ReflectJvmMapping.getKotlinFunction(ctor);
}
if (function != null) {
List<KParameter> parameters = function.getParameters();
return parameters
.stream()
.filter(p -> KParameter.Kind.VALUE.equals(p.getKind()))
.collect(Collectors.toList())
.get(index)
.getType()
.isMarkedNullable();
}
}
return false;