Efficient Kotlin metadata detection
Follow-up of 3991ab4a23.
Issue: SPR-15673
This commit is contained in:
@@ -71,16 +71,18 @@ public abstract class BeanUtils {
|
||||
Collections.newSetFromMap(new ConcurrentReferenceHashMap<>(64));
|
||||
|
||||
@Nullable
|
||||
private static Class<?> kotlinMetadata;
|
||||
private static final Class<?> kotlinMetadata;
|
||||
|
||||
static {
|
||||
Class<?> metadata;
|
||||
try {
|
||||
kotlinMetadata = ClassUtils.forName("kotlin.Metadata", BeanUtils.class.getClassLoader());
|
||||
metadata = ClassUtils.forName("kotlin.Metadata", BeanUtils.class.getClassLoader());
|
||||
}
|
||||
catch (ClassNotFoundException ex) {
|
||||
// Kotlin API not available - no special support for Kotlin class instantiation
|
||||
kotlinMetadata = null;
|
||||
metadata = null;
|
||||
}
|
||||
kotlinMetadata = metadata;
|
||||
}
|
||||
|
||||
|
||||
@@ -125,7 +127,7 @@ public abstract class BeanUtils {
|
||||
throw new BeanInstantiationException(clazz, "Specified class is an interface");
|
||||
}
|
||||
try {
|
||||
Constructor<T> ctor = (isKotlinClass(clazz) ?
|
||||
Constructor<T> ctor = (useKotlinSupport(clazz) ?
|
||||
KotlinDelegate.findPrimaryConstructor(clazz) : clazz.getDeclaredConstructor());
|
||||
if (ctor == null) {
|
||||
throw new BeanInstantiationException(clazz, "No default constructor found");
|
||||
@@ -172,7 +174,7 @@ public abstract class BeanUtils {
|
||||
Assert.notNull(ctor, "Constructor must not be null");
|
||||
try {
|
||||
ReflectionUtils.makeAccessible(ctor);
|
||||
return (isKotlinClass(ctor.getDeclaringClass()) ?
|
||||
return (useKotlinSupport(ctor.getDeclaringClass()) ?
|
||||
KotlinDelegate.instantiateClass(ctor, args) : ctor.newInstance(args));
|
||||
}
|
||||
catch (InstantiationException ex) {
|
||||
@@ -340,7 +342,7 @@ public abstract class BeanUtils {
|
||||
@Nullable
|
||||
public static <T> Constructor<T> findPrimaryConstructor(Class<T> clazz) {
|
||||
Assert.notNull(clazz, "Class must not be null");
|
||||
if (isKotlinClass(clazz)) {
|
||||
if (useKotlinSupport(clazz)) {
|
||||
return KotlinDelegate.findPrimaryConstructor(clazz);
|
||||
}
|
||||
else {
|
||||
@@ -707,10 +709,10 @@ public abstract class BeanUtils {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the specified class is a Kotlin one.
|
||||
* Return true if Kotlin is present and if the specified class is a Kotlin one.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
private static boolean isKotlinClass(Class<?> clazz) {
|
||||
private static boolean useKotlinSupport(Class<?> clazz) {
|
||||
return (kotlinMetadata != null &&
|
||||
clazz.getDeclaredAnnotation((Class<? extends Annotation>) kotlinMetadata) != null);
|
||||
}
|
||||
|
||||
@@ -26,7 +26,6 @@ import java.lang.reflect.Type;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
import kotlin.Metadata;
|
||||
import kotlin.reflect.KProperty;
|
||||
import kotlin.reflect.jvm.ReflectJvmMapping;
|
||||
|
||||
@@ -52,8 +51,20 @@ import org.springframework.util.ClassUtils;
|
||||
@SuppressWarnings("serial")
|
||||
public class DependencyDescriptor extends InjectionPoint implements Serializable {
|
||||
|
||||
private static final boolean kotlinPresent =
|
||||
ClassUtils.isPresent("kotlin.Metadata", DependencyDescriptor.class.getClassLoader());
|
||||
@Nullable
|
||||
private static final Class<?> kotlinMetadata;
|
||||
|
||||
static {
|
||||
Class<?> metadata;
|
||||
try {
|
||||
metadata = ClassUtils.forName("kotlin.Metadata", DependencyDescriptor.class.getClassLoader());
|
||||
}
|
||||
catch (ClassNotFoundException ex) {
|
||||
// Kotlin API not available - no Kotlin support
|
||||
metadata = null;
|
||||
}
|
||||
kotlinMetadata = metadata;
|
||||
}
|
||||
|
||||
|
||||
private final Class<?> declaringClass;
|
||||
@@ -172,13 +183,22 @@ public class DependencyDescriptor extends InjectionPoint implements Serializable
|
||||
|
||||
if (this.field != null) {
|
||||
return !(this.field.getType() == Optional.class || hasNullableAnnotation() ||
|
||||
(kotlinPresent && KotlinDelegate.isNullable(this.field)));
|
||||
(useKotlinSupport(this.field.getDeclaringClass()) && KotlinDelegate.isNullable(this.field)));
|
||||
}
|
||||
else {
|
||||
return !obtainMethodParameter().isOptional();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether the underlying field is annotated with any variant of a
|
||||
* {@code Nullable} annotation, e.g. {@code javax.annotation.Nullable} or
|
||||
@@ -435,11 +455,8 @@ public class DependencyDescriptor extends InjectionPoint implements Serializable
|
||||
* Check whether the specified {@link Field} represents a nullable Kotlin type or not.
|
||||
*/
|
||||
public static boolean isNullable(Field field) {
|
||||
if (field.getDeclaringClass().isAnnotationPresent(Metadata.class)) {
|
||||
KProperty<?> property = ReflectJvmMapping.getKotlinProperty(field);
|
||||
return (property != null && property.getReturnType().isMarkedNullable());
|
||||
}
|
||||
return false;
|
||||
KProperty<?> property = ReflectJvmMapping.getKotlinProperty(field);
|
||||
return (property != null && property.getReturnType().isMarkedNullable());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user