Support running Kotlin apps without kotlin-reflect
This commit includes an optimization of BeansUtils#instantiateClass that favors Java reflection for default constructors before leveraging Kotlin one for finding primary constructors and avoids Kotlin related conditions when running in Java. Issue: SPR-17069
This commit is contained in:
@@ -16,17 +16,16 @@
|
||||
|
||||
package org.springframework.core;
|
||||
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
/**
|
||||
* Default implementation of the {@link ParameterNameDiscoverer} strategy interface,
|
||||
* using the Java 8 standard reflection mechanism (if available), and falling back
|
||||
* to the ASM-based {@link LocalVariableTableParameterNameDiscoverer} for checking
|
||||
* debug information in the class file.
|
||||
*
|
||||
* <p>If Kotlin is present, {@link KotlinReflectionParameterNameDiscoverer} is added first
|
||||
* in the list and used for Kotlin classes and interfaces. When compiling or running as
|
||||
* a Graal native image, no {@link ParameterNameDiscoverer} is used.
|
||||
* <p>If a Kotlin reflection implementation is present,
|
||||
* {@link KotlinReflectionParameterNameDiscoverer} is added first in the list and used
|
||||
* for Kotlin classes and interfaces. When compiling or running as a Graal native image,
|
||||
* no {@link ParameterNameDiscoverer} is used.
|
||||
*
|
||||
* <p>Further discoverers may be added through {@link #addDiscoverer(ParameterNameDiscoverer)}.
|
||||
*
|
||||
@@ -39,16 +38,13 @@ import org.springframework.util.ClassUtils;
|
||||
*/
|
||||
public class DefaultParameterNameDiscoverer extends PrioritizedParameterNameDiscoverer {
|
||||
|
||||
private static final boolean kotlinPresent =
|
||||
ClassUtils.isPresent("kotlin.Unit", DefaultParameterNameDiscoverer.class.getClassLoader());
|
||||
|
||||
// See https://github.com/oracle/graal/blob/master/sdk/src/org.graalvm.nativeimage/src/org/graalvm/nativeimage/ImageInfo.java
|
||||
private static final boolean inImageCode = (System.getProperty("org.graalvm.nativeimage.imagecode") != null);
|
||||
|
||||
|
||||
public DefaultParameterNameDiscoverer() {
|
||||
if (!inImageCode) {
|
||||
if (kotlinPresent) {
|
||||
if (KotlinDetector.isKotlinReflectPresent()) {
|
||||
addDiscoverer(new KotlinReflectionParameterNameDiscoverer());
|
||||
}
|
||||
addDiscoverer(new StandardReflectionParameterNameDiscoverer());
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2017 the original author or authors.
|
||||
* Copyright 2002-2018 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.
|
||||
@@ -18,6 +18,9 @@ package org.springframework.core;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
@@ -31,19 +34,28 @@ import org.springframework.util.ClassUtils;
|
||||
@SuppressWarnings("unchecked")
|
||||
public abstract class KotlinDetector {
|
||||
|
||||
private static final Log logger = LogFactory.getLog(KotlinDetector.class);
|
||||
|
||||
@Nullable
|
||||
private static final Class<? extends Annotation> kotlinMetadata;
|
||||
|
||||
private static final boolean kotlinReflectPresent;
|
||||
|
||||
static {
|
||||
Class<?> metadata;
|
||||
ClassLoader classLoader = KotlinDetector.class.getClassLoader();
|
||||
try {
|
||||
metadata = ClassUtils.forName("kotlin.Metadata", KotlinDetector.class.getClassLoader());
|
||||
metadata = ClassUtils.forName("kotlin.Metadata", classLoader);
|
||||
}
|
||||
catch (ClassNotFoundException ex) {
|
||||
// Kotlin API not available - no Kotlin support
|
||||
metadata = null;
|
||||
}
|
||||
kotlinMetadata = (Class<? extends Annotation>) metadata;
|
||||
kotlinReflectPresent = ClassUtils.isPresent("kotlin.reflect.full.KClasses", classLoader);
|
||||
if (kotlinMetadata != null && !kotlinReflectPresent) {
|
||||
logger.info("Kotlin reflection implementation not found at runtime, related features won't be available.");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -54,6 +66,14 @@ public abstract class KotlinDetector {
|
||||
return (kotlinMetadata != null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether Kotlin reflection is present.
|
||||
* @since 5.1
|
||||
*/
|
||||
public static boolean isKotlinReflectPresent() {
|
||||
return kotlinReflectPresent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the given {@code Class} is a Kotlin type
|
||||
* (with Kotlin metadata present on it).
|
||||
|
||||
@@ -342,7 +342,9 @@ public class MethodParameter {
|
||||
*/
|
||||
public boolean isOptional() {
|
||||
return (getParameterType() == Optional.class || hasNullableAnnotation() ||
|
||||
(KotlinDetector.isKotlinType(getContainingClass()) && KotlinDelegate.isOptional(this)));
|
||||
(KotlinDetector.isKotlinReflectPresent() &&
|
||||
KotlinDetector.isKotlinType(getContainingClass()) &&
|
||||
KotlinDelegate.isOptional(this)));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user