From 1763334180ece33aca8ff9d5a456563cb2eaffe3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Deleuze?= Date: Fri, 17 Jan 2025 16:21:50 +0100 Subject: [PATCH] Refine KotlinDetector usages and implementation This commit refines KotlinDetector usages and implementation in order to remove preliminary KotlinDetector#isKotlinReflectPresent invocations and to ensure that KotlinDetector methods are implemented safely and efficiently for such use case. Closes gh-34275 --- .../org/springframework/beans/BeanUtils.java | 4 +-- .../aot/InstanceSupplierCodeGenerator.java | 16 +++++----- .../factory/config/DependencyDescriptor.java | 6 ++-- .../factory/support/ConstructorResolver.java | 2 +- .../cache/interceptor/CacheAspectSupport.java | 2 +- .../ScheduledAnnotationReactiveSupport.java | 6 ++-- .../springframework/core/KotlinDetector.java | 29 ++++++++++++------- .../springframework/core/MethodParameter.java | 10 +++---- .../io/support/SpringFactoriesLoader.java | 8 ++--- .../support/ReflectivePropertyAccessor.java | 5 ++-- .../json/Jackson2ObjectMapperBuilder.java | 3 +- ...tractNamedValueMethodArgumentResolver.java | 7 ++--- .../support/InvocableHandlerMethod.java | 6 ++-- .../result/method/InvocableHandlerMethod.java | 11 +++---- .../AbstractNamedValueArgumentResolver.java | 7 ++--- 15 files changed, 56 insertions(+), 66 deletions(-) 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 79ca2a297dbd..0da9c8fd525f 100644 --- a/spring-beans/src/main/java/org/springframework/beans/BeanUtils.java +++ b/spring-beans/src/main/java/org/springframework/beans/BeanUtils.java @@ -186,7 +186,7 @@ public static T instantiateClass(Constructor ctor, @Nullable Object... ar Assert.notNull(ctor, "Constructor must not be null"); try { ReflectionUtils.makeAccessible(ctor); - if (KotlinDetector.isKotlinReflectPresent() && KotlinDetector.isKotlinType(ctor.getDeclaringClass())) { + if (KotlinDetector.isKotlinType(ctor.getDeclaringClass())) { return KotlinDelegate.instantiateClass(ctor, args); } else { @@ -279,7 +279,7 @@ else if (ctors.length == 0) { */ public static @Nullable Constructor findPrimaryConstructor(Class clazz) { Assert.notNull(clazz, "Class must not be null"); - if (KotlinDetector.isKotlinReflectPresent() && KotlinDetector.isKotlinType(clazz)) { + if (KotlinDetector.isKotlinType(clazz)) { return KotlinDelegate.findPrimaryConstructor(clazz); } if (clazz.isRecord()) { diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/aot/InstanceSupplierCodeGenerator.java b/spring-beans/src/main/java/org/springframework/beans/factory/aot/InstanceSupplierCodeGenerator.java index c331ce404938..a727980e191a 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/aot/InstanceSupplierCodeGenerator.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/aot/InstanceSupplierCodeGenerator.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2024 the original author or authors. + * Copyright 2002-2025 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. @@ -160,7 +160,7 @@ private CodeBlock generateCodeForConstructor(RegisteredBean registeredBean, Cons registeredBean.getBeanName(), constructor, registeredBean.getBeanClass()); Class publicType = descriptor.publicType(); - if (KotlinDetector.isKotlinReflectPresent() && KotlinDelegate.hasConstructorWithOptionalParameter(publicType)) { + if (KotlinDetector.isKotlinType(publicType) && KotlinDelegate.hasConstructorWithOptionalParameter(publicType)) { return generateCodeForInaccessibleConstructor(descriptor, hints -> hints.registerType(publicType, MemberCategory.INVOKE_DECLARED_CONSTRUCTORS)); } @@ -408,13 +408,11 @@ private boolean isThrowingCheckedException(Executable executable) { private static class KotlinDelegate { public static boolean hasConstructorWithOptionalParameter(Class beanClass) { - if (KotlinDetector.isKotlinType(beanClass)) { - KClass kClass = JvmClassMappingKt.getKotlinClass(beanClass); - for (KFunction constructor : kClass.getConstructors()) { - for (KParameter parameter : constructor.getParameters()) { - if (parameter.isOptional()) { - return true; - } + KClass kClass = JvmClassMappingKt.getKotlinClass(beanClass); + for (KFunction constructor : kClass.getConstructors()) { + for (KParameter parameter : constructor.getParameters()) { + if (parameter.isOptional()) { + return true; } } } 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 5084f049e890..41c8a815daab 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 @@ -1,5 +1,5 @@ /* - * Copyright 2002-2024 the original author or authors. + * Copyright 2002-2025 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. @@ -163,9 +163,7 @@ public boolean isRequired() { if (this.field != null) { return !(this.field.getType() == Optional.class || hasNullableAnnotation() || - (KotlinDetector.isKotlinReflectPresent() && - KotlinDetector.isKotlinType(this.field.getDeclaringClass()) && - KotlinDelegate.isNullable(this.field))); + (KotlinDetector.isKotlinType(this.field.getDeclaringClass()) && KotlinDelegate.isNullable(this.field))); } else { return !obtainMethodParameter().isOptional(); diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/support/ConstructorResolver.java b/spring-beans/src/main/java/org/springframework/beans/factory/support/ConstructorResolver.java index 742dbb869b58..d06454940847 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/support/ConstructorResolver.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/support/ConstructorResolver.java @@ -624,7 +624,7 @@ else if (void.class == factoryMethodToUse.getReturnType()) { "Invalid factory method '" + mbd.getFactoryMethodName() + "' on class [" + factoryClass.getName() + "]: needs to have a non-void return type!"); } - else if (KotlinDetector.isKotlinPresent() && KotlinDetector.isSuspendingFunction(factoryMethodToUse)) { + else if (KotlinDetector.isSuspendingFunction(factoryMethodToUse)) { throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Invalid factory method '" + mbd.getFactoryMethodName() + "' on class [" + factoryClass.getName() + "]: suspending functions are not supported!"); diff --git a/spring-context/src/main/java/org/springframework/cache/interceptor/CacheAspectSupport.java b/spring-context/src/main/java/org/springframework/cache/interceptor/CacheAspectSupport.java index 9ca44f16969f..9cad2635991c 100644 --- a/spring-context/src/main/java/org/springframework/cache/interceptor/CacheAspectSupport.java +++ b/spring-context/src/main/java/org/springframework/cache/interceptor/CacheAspectSupport.java @@ -1092,7 +1092,7 @@ private class ReactiveCachingHandler { () -> Mono.from(adapter.toPublisher(invokeOperation(invoker))).toFuture()))); } } - if (KotlinDetector.isKotlinReflectPresent() && KotlinDetector.isSuspendingFunction(method)) { + if (KotlinDetector.isSuspendingFunction(method)) { return Mono.fromFuture(cache.retrieve(key, () -> { Mono mono = ((Mono) invokeOperation(invoker)); if (mono == null) { diff --git a/spring-context/src/main/java/org/springframework/scheduling/annotation/ScheduledAnnotationReactiveSupport.java b/spring-context/src/main/java/org/springframework/scheduling/annotation/ScheduledAnnotationReactiveSupport.java index 6f2d2705da87..a99ecfedbfc8 100644 --- a/spring-context/src/main/java/org/springframework/scheduling/annotation/ScheduledAnnotationReactiveSupport.java +++ b/spring-context/src/main/java/org/springframework/scheduling/annotation/ScheduledAnnotationReactiveSupport.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2024 the original author or authors. + * Copyright 2002-2025 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. @@ -81,7 +81,7 @@ abstract class ScheduledAnnotationReactiveSupport { * Kotlin coroutines bridge are not present at runtime */ public static boolean isReactive(Method method) { - if (KotlinDetector.isKotlinPresent() && KotlinDetector.isSuspendingFunction(method)) { + if (KotlinDetector.isSuspendingFunction(method)) { // Note that suspending functions declared without args have a single Continuation // parameter in reflective inspection Assert.isTrue(method.getParameterCount() == 1, @@ -138,7 +138,7 @@ public static Runnable createSubscriptionRunnable(Method method, Object targetBe * to a {@code Flux} with a checkpoint String, allowing for better debugging. */ static Publisher getPublisherFor(Method method, Object bean) { - if (KotlinDetector.isKotlinPresent() && KotlinDetector.isSuspendingFunction(method)) { + if (KotlinDetector.isSuspendingFunction(method)) { return CoroutinesUtils.invokeSuspendingFunction(method, bean, (Object[]) method.getParameters()); } diff --git a/spring-core/src/main/java/org/springframework/core/KotlinDetector.java b/spring-core/src/main/java/org/springframework/core/KotlinDetector.java index ad9976ce931c..3e104670d007 100644 --- a/spring-core/src/main/java/org/springframework/core/KotlinDetector.java +++ b/spring-core/src/main/java/org/springframework/core/KotlinDetector.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2024 the original author or authors. + * Copyright 2002-2025 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. @@ -24,7 +24,8 @@ import org.springframework.util.ClassUtils; /** - * A common delegate for detecting Kotlin's presence and for identifying Kotlin types. + * A common delegate for detecting Kotlin's presence and for identifying Kotlin types. All the methods of this class + * can be safely used without any preliminary classpath checks. * * @author Juergen Hoeller * @author Sebastien Deleuze @@ -37,6 +38,8 @@ public abstract class KotlinDetector { private static final @Nullable Class kotlinJvmInline; + private static final @Nullable Class kotlinCoroutineContinuation; + // For ConstantFieldFeature compliance, otherwise could be deduced from kotlinMetadata private static final boolean kotlinPresent; @@ -46,6 +49,7 @@ public abstract class KotlinDetector { ClassLoader classLoader = KotlinDetector.class.getClassLoader(); Class metadata = null; Class jvmInline = null; + Class coroutineContinuation = null; try { metadata = ClassUtils.forName("kotlin.Metadata", classLoader); try { @@ -54,14 +58,21 @@ public abstract class KotlinDetector { catch (ClassNotFoundException ex) { // JVM inline support not available } + try { + coroutineContinuation = ClassUtils.forName("kotlin.coroutines.Continuation", classLoader); + } + catch (ClassNotFoundException ex) { + // Coroutines support not available + } } catch (ClassNotFoundException ex) { // Kotlin API not available - no Kotlin support } kotlinMetadata = (Class) metadata; kotlinPresent = (kotlinMetadata != null); - kotlinReflectPresent = kotlinPresent && ClassUtils.isPresent("kotlin.reflect.full.KClasses", classLoader); + kotlinReflectPresent = ClassUtils.isPresent("kotlin.reflect.full.KClasses", classLoader); kotlinJvmInline = (Class) jvmInline; + kotlinCoroutineContinuation = coroutineContinuation; } @@ -89,7 +100,7 @@ public static boolean isKotlinReflectPresent() { * as invokedynamic has become the default method for lambda generation. */ public static boolean isKotlinType(Class clazz) { - return (kotlinMetadata != null && clazz.getDeclaredAnnotation(kotlinMetadata) != null); + return (kotlinPresent && clazz.getDeclaredAnnotation(kotlinMetadata) != null); } /** @@ -97,13 +108,11 @@ public static boolean isKotlinType(Class clazz) { * @since 5.3 */ public static boolean isSuspendingFunction(Method method) { - if (KotlinDetector.isKotlinType(method.getDeclaringClass())) { - Class[] types = method.getParameterTypes(); - if (types.length > 0 && "kotlin.coroutines.Continuation".equals(types[types.length - 1].getName())) { - return true; - } + if (kotlinCoroutineContinuation == null) { + return false; } - return false; + int parameterCount = method.getParameterCount(); + return (parameterCount > 0 && method.getParameterTypes()[parameterCount - 1] == kotlinCoroutineContinuation); } /** 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 da0535ece0e8..f89f03b85546 100644 --- a/spring-core/src/main/java/org/springframework/core/MethodParameter.java +++ b/spring-core/src/main/java/org/springframework/core/MethodParameter.java @@ -396,9 +396,7 @@ private MethodParameter nested(int nestingLevel, @Nullable Integer typeIndex) { */ public boolean isOptional() { return (getParameterType() == Optional.class || hasNullableAnnotation() || - (KotlinDetector.isKotlinReflectPresent() && - KotlinDetector.isKotlinType(getContainingClass()) && - KotlinDelegate.isOptional(this))); + (KotlinDetector.isKotlinType(getContainingClass()) && KotlinDelegate.isOptional(this))); } /** @@ -508,8 +506,8 @@ public Type getGenericParameterType() { if (this.parameterIndex < 0) { Method method = getMethod(); paramType = (method != null ? - (KotlinDetector.isKotlinReflectPresent() && KotlinDetector.isKotlinType(getContainingClass()) ? - KotlinDelegate.getGenericReturnType(method) : method.getGenericReturnType()) : void.class); + (KotlinDetector.isKotlinType(getContainingClass()) ? + KotlinDelegate.getGenericReturnType(method) : method.getGenericReturnType()) : void.class); } else { Type[] genericParameterTypes = this.executable.getGenericParameterTypes(); @@ -536,7 +534,7 @@ private Class computeParameterType() { if (method == null) { return void.class; } - if (KotlinDetector.isKotlinReflectPresent() && KotlinDetector.isKotlinType(getContainingClass())) { + if (KotlinDetector.isKotlinType(getContainingClass())) { return KotlinDelegate.getReturnType(method); } return method.getReturnType(); diff --git a/spring-core/src/main/java/org/springframework/core/io/support/SpringFactoriesLoader.java b/spring-core/src/main/java/org/springframework/core/io/support/SpringFactoriesLoader.java index 94129a481aab..02f22d49e93c 100644 --- a/spring-core/src/main/java/org/springframework/core/io/support/SpringFactoriesLoader.java +++ b/spring-core/src/main/java/org/springframework/core/io/support/SpringFactoriesLoader.java @@ -374,7 +374,7 @@ private FactoryInstantiator(Constructor constructor) { T instantiate(@Nullable ArgumentResolver argumentResolver) throws Exception { Object[] args = resolveArgs(argumentResolver); - if (isKotlinType(this.constructor.getDeclaringClass())) { + if (KotlinDetector.isKotlinType(this.constructor.getDeclaringClass())) { return KotlinDelegate.instantiate(this.constructor, args); } return this.constructor.newInstance(args); @@ -408,14 +408,10 @@ static FactoryInstantiator forClass(Class factoryImplementationClass) } private static @Nullable Constructor findPrimaryKotlinConstructor(Class factoryImplementationClass) { - return (isKotlinType(factoryImplementationClass) ? + return (KotlinDetector.isKotlinType(factoryImplementationClass) ? KotlinDelegate.findPrimaryConstructor(factoryImplementationClass) : null); } - private static boolean isKotlinType(Class factoryImplementationClass) { - return KotlinDetector.isKotlinReflectPresent() && KotlinDetector.isKotlinType(factoryImplementationClass); - } - private static @Nullable Constructor findSingleConstructor(Constructor[] constructors) { return (constructors.length == 1 ? constructors[0] : null); } diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/support/ReflectivePropertyAccessor.java b/spring-expression/src/main/java/org/springframework/expression/spel/support/ReflectivePropertyAccessor.java index af16393aee6c..c3817c83b0d0 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/support/ReflectivePropertyAccessor.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/support/ReflectivePropertyAccessor.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2024 the original author or authors. + * Copyright 2002-2025 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. @@ -558,8 +558,7 @@ public PropertyAccessor createOptimalAccessor(EvaluationContext context, @Nullab private static boolean isKotlinProperty(Method method, String methodSuffix) { Class clazz = method.getDeclaringClass(); - return KotlinDetector.isKotlinReflectPresent() && - KotlinDetector.isKotlinType(clazz) && + return KotlinDetector.isKotlinType(clazz) && KotlinDelegate.isKotlinProperty(method, methodSuffix); } diff --git a/spring-web/src/main/java/org/springframework/http/converter/json/Jackson2ObjectMapperBuilder.java b/spring-web/src/main/java/org/springframework/http/converter/json/Jackson2ObjectMapperBuilder.java index 12c4bcbcca2b..a4eaa7ec5993 100644 --- a/spring-web/src/main/java/org/springframework/http/converter/json/Jackson2ObjectMapperBuilder.java +++ b/spring-web/src/main/java/org/springframework/http/converter/json/Jackson2ObjectMapperBuilder.java @@ -868,8 +868,7 @@ private void registerWellKnownModulesIfAvailable(MultiValueMap m // jackson-datatype-jsr310 not available } - // Kotlin present? - if (KotlinDetector.isKotlinPresent()) { + if (KotlinDetector.isKotlinReflectPresent()) { try { Class kotlinModuleClass = (Class) ClassUtils.forName("com.fasterxml.jackson.module.kotlin.KotlinModule", this.moduleClassLoader); diff --git a/spring-web/src/main/java/org/springframework/web/method/annotation/AbstractNamedValueMethodArgumentResolver.java b/spring-web/src/main/java/org/springframework/web/method/annotation/AbstractNamedValueMethodArgumentResolver.java index 017a42c3161d..4cee5a3cb206 100644 --- a/spring-web/src/main/java/org/springframework/web/method/annotation/AbstractNamedValueMethodArgumentResolver.java +++ b/spring-web/src/main/java/org/springframework/web/method/annotation/AbstractNamedValueMethodArgumentResolver.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2024 the original author or authors. + * Copyright 2002-2025 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. @@ -103,8 +103,7 @@ public AbstractNamedValueMethodArgumentResolver(@Nullable ConfigurableBeanFactor NamedValueInfo namedValueInfo = getNamedValueInfo(parameter); MethodParameter nestedParameter = parameter.nestedIfOptional(); - boolean hasDefaultValue = KotlinDetector.isKotlinReflectPresent() && - KotlinDetector.isKotlinType(parameter.getDeclaringClass()) && + boolean hasDefaultValue = KotlinDetector.isKotlinType(parameter.getDeclaringClass()) && KotlinDelegate.hasDefaultValue(nestedParameter); Object resolvedName = resolveEmbeddedValuesAndExpressions(namedValueInfo.name); @@ -276,7 +275,7 @@ else if (paramType.isPrimitive()) { WebDataBinder binder = binderFactory.createBinder(webRequest, null, namedValueInfo.name); Class parameterType = parameter.getParameterType(); - if (KotlinDetector.isKotlinPresent() && KotlinDetector.isInlineClass(parameterType)) { + if (KotlinDetector.isInlineClass(parameterType)) { Constructor ctor = BeanUtils.findPrimaryConstructor(parameterType); if (ctor != null) { parameterType = ctor.getParameterTypes()[0]; diff --git a/spring-web/src/main/java/org/springframework/web/method/support/InvocableHandlerMethod.java b/spring-web/src/main/java/org/springframework/web/method/support/InvocableHandlerMethod.java index bf17a15caf0b..78fa9e253530 100644 --- a/spring-web/src/main/java/org/springframework/web/method/support/InvocableHandlerMethod.java +++ b/spring-web/src/main/java/org/springframework/web/method/support/InvocableHandlerMethod.java @@ -242,13 +242,11 @@ public void setMethodValidator(@Nullable MethodValidator methodValidator) { protected @Nullable Object doInvoke(@Nullable Object... args) throws Exception { Method method = getBridgedMethod(); try { - if (KotlinDetector.isKotlinReflectPresent()) { + if (KotlinDetector.isKotlinType(method.getDeclaringClass())) { if (KotlinDetector.isSuspendingFunction(method)) { return invokeSuspendingFunction(method, getBean(), args); } - else if (KotlinDetector.isKotlinType(method.getDeclaringClass())) { - return KotlinDelegate.invokeFunction(method, getBean(), args); - } + return KotlinDelegate.invokeFunction(method, getBean(), args); } return method.invoke(getBean(), args); } diff --git a/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/InvocableHandlerMethod.java b/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/InvocableHandlerMethod.java index f6bc3fb54cc9..65c9d5a346f3 100644 --- a/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/InvocableHandlerMethod.java +++ b/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/InvocableHandlerMethod.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2024 the original author or authors. + * Copyright 2002-2025 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. @@ -191,12 +191,9 @@ public Mono invoke( Method method = getBridgedMethod(); boolean isSuspendingFunction = KotlinDetector.isSuspendingFunction(method); try { - if (KotlinDetector.isKotlinReflectPresent() && KotlinDetector.isKotlinType(method.getDeclaringClass())) { - value = KotlinDelegate.invokeFunction(method, getBean(), args, isSuspendingFunction, exchange); - } - else { - value = method.invoke(getBean(), args); - } + value = (KotlinDetector.isKotlinType(method.getDeclaringClass()) ? + KotlinDelegate.invokeFunction(method, getBean(), args, isSuspendingFunction, exchange) : + method.invoke(getBean(), args)); } catch (IllegalArgumentException ex) { assertTargetBean(getBridgedMethod(), getBean(), args); diff --git a/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/AbstractNamedValueArgumentResolver.java b/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/AbstractNamedValueArgumentResolver.java index 0f7989209695..776f232f0d88 100644 --- a/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/AbstractNamedValueArgumentResolver.java +++ b/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/AbstractNamedValueArgumentResolver.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2024 the original author or authors. + * Copyright 2002-2025 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. @@ -195,7 +195,7 @@ private NamedValueInfo updateNamedValueInfo(MethodParameter parameter, NamedValu WebDataBinder binder = bindingContext.createDataBinder(exchange, namedValueInfo.name); Class parameterType = parameter.getParameterType(); - if (KotlinDetector.isKotlinPresent() && KotlinDetector.isInlineClass(parameterType)) { + if (KotlinDetector.isInlineClass(parameterType)) { Constructor ctor = BeanUtils.findPrimaryConstructor(parameterType); if (ctor != null) { parameterType = ctor.getParameterTypes()[0]; @@ -222,8 +222,7 @@ private Mono getDefaultValue(NamedValueInfo namedValueInfo, String resol return Mono.fromSupplier(() -> { Object value = null; - boolean hasDefaultValue = KotlinDetector.isKotlinReflectPresent() && - KotlinDetector.isKotlinType(parameter.getDeclaringClass()) && + boolean hasDefaultValue = KotlinDetector.isKotlinType(parameter.getDeclaringClass()) && KotlinDelegate.hasDefaultValue(parameter); if (namedValueInfo.defaultValue != null) { value = resolveEmbeddedValuesAndExpressions(namedValueInfo.defaultValue);