diff --git a/spring-beans/src/main/java/org/springframework/beans/BeanUtils.java b/spring-beans/src/main/java/org/springframework/beans/BeanUtils.java index e1683e7086..73e358c0d7 100644 --- a/spring-beans/src/main/java/org/springframework/beans/BeanUtils.java +++ b/spring-beans/src/main/java/org/springframework/beans/BeanUtils.java @@ -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 ctor = (isKotlinClass(clazz) ? + Constructor 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 Constructor findPrimaryConstructor(Class 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) kotlinMetadata) != null); } diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/config/DependencyDescriptor.java b/spring-beans/src/main/java/org/springframework/beans/factory/config/DependencyDescriptor.java index 16581caf42..4da1bb2ca2 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/config/DependencyDescriptor.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/config/DependencyDescriptor.java @@ -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) 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()); } } diff --git a/spring-core/src/main/java/org/springframework/core/MethodParameter.java b/spring-core/src/main/java/org/springframework/core/MethodParameter.java index 35fdb07d85..6660b56f5f 100644 --- a/spring-core/src/main/java/org/springframework/core/MethodParameter.java +++ b/spring-core/src/main/java/org/springframework/core/MethodParameter.java @@ -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) 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()); + 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 { - KFunction function = null; - if (method != null) { - function = ReflectJvmMapping.getKotlinFunction(method); - } - else if (ctor != null) { - function = ReflectJvmMapping.getKotlinFunction(ctor); - } - if (function != null) { - List parameters = function.getParameters(); - return parameters - .stream() - .filter(p -> KParameter.Kind.VALUE.equals(p.getKind())) - .collect(Collectors.toList()) - .get(index) - .getType() - .isMarkedNullable(); - } + else if (ctor != null) { + function = ReflectJvmMapping.getKotlinFunction(ctor); } - } - return false; - } - - private static boolean isKotlinClass(Class clazz) { - for (Annotation annotation : clazz.getDeclaredAnnotations()) { - if (annotation.annotationType().getName().equals("kotlin.Metadata")) { - return true; + if (function != null) { + List parameters = function.getParameters(); + return parameters + .stream() + .filter(p -> KParameter.Kind.VALUE.equals(p.getKind())) + .collect(Collectors.toList()) + .get(index) + .getType() + .isMarkedNullable(); } } return false;