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 5d8d01eef33..495acb6710c 100644 --- a/spring-beans/src/main/java/org/springframework/beans/BeanUtils.java +++ b/spring-beans/src/main/java/org/springframework/beans/BeanUtils.java @@ -88,6 +88,8 @@ public abstract class BeanUtils { double.class, 0D, char.class, '\0'); + private static final boolean KOTLIN_REFLECT_PRESENT = KotlinDetector.isKotlinReflectPresent(); + /** * Convenience method to instantiate a class using its no-arg constructor. @@ -186,7 +188,7 @@ public abstract class BeanUtils { Assert.notNull(ctor, "Constructor must not be null"); try { ReflectionUtils.makeAccessible(ctor); - if (KotlinDetector.isKotlinType(ctor.getDeclaringClass())) { + if (KOTLIN_REFLECT_PRESENT && KotlinDetector.isKotlinType(ctor.getDeclaringClass())) { return KotlinDelegate.instantiateClass(ctor, args); } else { @@ -279,7 +281,7 @@ public abstract class BeanUtils { */ public static @Nullable Constructor findPrimaryConstructor(Class clazz) { Assert.notNull(clazz, "Class must not be null"); - if (KotlinDetector.isKotlinType(clazz)) { + if (KOTLIN_REFLECT_PRESENT && KotlinDetector.isKotlinType(clazz)) { return KotlinDelegate.findPrimaryConstructor(clazz); } if (clazz.isRecord()) { @@ -659,7 +661,7 @@ public abstract class BeanUtils { ConstructorProperties cp = ctor.getAnnotation(ConstructorProperties.class); @Nullable String[] paramNames = (cp != null ? cp.value() : parameterNameDiscoverer.getParameterNames(ctor)); Assert.state(paramNames != null, () -> "Cannot resolve parameter names for constructor " + ctor); - int parameterCount = (KotlinDetector.isKotlinReflectPresent() && KotlinDelegate.hasDefaultConstructorMarker(ctor) ? + int parameterCount = (KOTLIN_REFLECT_PRESENT && KotlinDelegate.hasDefaultConstructorMarker(ctor) ? ctor.getParameterCount() - 1 : ctor.getParameterCount()); Assert.state(paramNames.length == parameterCount, () -> "Invalid number of parameter names: " + paramNames.length + " for constructor " + ctor); 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 61f2738cb7b..ff978aabc45 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 @@ -88,6 +88,8 @@ public class InstanceSupplierCodeGenerator { private static final CodeBlock NO_ARGS = CodeBlock.of(""); + private static final boolean KOTLIN_REFLECT_PRESENT = KotlinDetector.isKotlinReflectPresent(); + private final GenerationContext generationContext; @@ -161,7 +163,7 @@ public class InstanceSupplierCodeGenerator { registeredBean.getBeanName(), constructor, registeredBean.getBeanClass()); Class publicType = descriptor.publicType(); - if (KotlinDetector.isKotlinType(publicType) && KotlinDelegate.hasConstructorWithOptionalParameter(publicType)) { + if (KOTLIN_REFLECT_PRESENT && KotlinDetector.isKotlinType(publicType) && KotlinDelegate.hasConstructorWithOptionalParameter(publicType)) { return generateCodeForInaccessibleConstructor(descriptor, hints -> hints.registerType(publicType, MemberCategory.INVOKE_DECLARED_CONSTRUCTORS)); } diff --git a/spring-core/src/main/java/org/springframework/core/DefaultParameterNameDiscoverer.java b/spring-core/src/main/java/org/springframework/core/DefaultParameterNameDiscoverer.java index 67a65727f13..77cd4320cf5 100644 --- a/spring-core/src/main/java/org/springframework/core/DefaultParameterNameDiscoverer.java +++ b/spring-core/src/main/java/org/springframework/core/DefaultParameterNameDiscoverer.java @@ -35,8 +35,11 @@ package org.springframework.core; */ public class DefaultParameterNameDiscoverer extends PrioritizedParameterNameDiscoverer { + private static final boolean KOTLIN_REFLECT_PRESENT = KotlinDetector.isKotlinReflectPresent(); + + public DefaultParameterNameDiscoverer() { - if (KotlinDetector.isKotlinReflectPresent()) { + if (KOTLIN_REFLECT_PRESENT) { addDiscoverer(new KotlinReflectionParameterNameDiscoverer()); } 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 1d5e2a484c3..397c027e4f9 100644 --- a/spring-core/src/main/java/org/springframework/core/MethodParameter.java +++ b/spring-core/src/main/java/org/springframework/core/MethodParameter.java @@ -66,6 +66,8 @@ public class MethodParameter { private static final Annotation[] EMPTY_ANNOTATION_ARRAY = new Annotation[0]; + private static final boolean KOTLIN_REFLECT_PRESENT = KotlinDetector.isKotlinReflectPresent(); + private final Executable executable; @@ -396,7 +398,8 @@ public class MethodParameter { */ public boolean isOptional() { return (getParameterType() == Optional.class || Nullness.forMethodParameter(this) == Nullness.NULLABLE || - (KotlinDetector.isKotlinType(getContainingClass()) && KotlinDelegate.isOptional(this))); + (KOTLIN_REFLECT_PRESENT && KotlinDetector.isKotlinType(getContainingClass()) && + KotlinDelegate.isOptional(this))); } /** @@ -484,7 +487,7 @@ public class MethodParameter { if (this.parameterIndex < 0) { Method method = getMethod(); paramType = (method != null ? - (KotlinDetector.isKotlinType(getContainingClass()) ? + (KOTLIN_REFLECT_PRESENT && KotlinDetector.isKotlinType(getContainingClass()) ? KotlinDelegate.getGenericReturnType(method) : method.getGenericReturnType()) : void.class); } else { @@ -512,7 +515,7 @@ public class MethodParameter { if (method == null) { return void.class; } - if (KotlinDetector.isKotlinType(getContainingClass())) { + if (KOTLIN_REFLECT_PRESENT && KotlinDetector.isKotlinType(getContainingClass())) { return KotlinDelegate.getReturnType(method); } return method.getReturnType(); diff --git a/spring-core/src/main/java/org/springframework/core/Nullness.java b/spring-core/src/main/java/org/springframework/core/Nullness.java index 29382aac665..2644fc2d640 100644 --- a/spring-core/src/main/java/org/springframework/core/Nullness.java +++ b/spring-core/src/main/java/org/springframework/core/Nullness.java @@ -77,6 +77,8 @@ public enum Nullness { */ NON_NULL; + private static final boolean KOTLIN_REFLECT_PRESENT = KotlinDetector.isKotlinReflectPresent(); + /** * Return the nullness of the return type for the given method. @@ -84,7 +86,7 @@ public enum Nullness { * @return the corresponding nullness */ public static Nullness forMethodReturnType(Method method) { - if (KotlinDetector.isKotlinType(method.getDeclaringClass())) { + if (KOTLIN_REFLECT_PRESENT && KotlinDetector.isKotlinType(method.getDeclaringClass())) { return KotlinDelegate.forMethodReturnType(method); } return (hasNullableAnnotation(method) ? Nullness.NULLABLE : @@ -97,7 +99,7 @@ public enum Nullness { * @return the corresponding nullness */ public static Nullness forParameter(Parameter parameter) { - if (KotlinDetector.isKotlinType(parameter.getDeclaringExecutable().getDeclaringClass())) { + if (KOTLIN_REFLECT_PRESENT && KotlinDetector.isKotlinType(parameter.getDeclaringExecutable().getDeclaringClass())) { // TODO Optimize when kotlin-reflect provide a more direct Parameter to KParameter resolution MethodParameter methodParameter = MethodParameter.forParameter(parameter); return KotlinDelegate.forParameter(methodParameter.getExecutable(), methodParameter.getParameterIndex()); @@ -124,7 +126,7 @@ public enum Nullness { * @return the corresponding nullness */ public static Nullness forField(Field field) { - if (KotlinDetector.isKotlinType(field.getDeclaringClass())) { + if (KOTLIN_REFLECT_PRESENT && KotlinDetector.isKotlinType(field.getDeclaringClass())) { return KotlinDelegate.forField(field); } return (hasNullableAnnotation(field) ? Nullness.NULLABLE : 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 09eea12323a..96b55761ac7 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 @@ -360,8 +360,11 @@ public class SpringFactoriesLoader { */ static final class FactoryInstantiator { + private static final boolean KOTLIN_REFLECT_PRESENT = KotlinDetector.isKotlinReflectPresent(); + private final Constructor constructor; + private FactoryInstantiator(Constructor constructor) { ReflectionUtils.makeAccessible(constructor); this.constructor = constructor; @@ -369,7 +372,7 @@ public class SpringFactoriesLoader { T instantiate(@Nullable ArgumentResolver argumentResolver) throws Exception { Object[] args = resolveArgs(argumentResolver); - if (KotlinDetector.isKotlinType(this.constructor.getDeclaringClass())) { + if (KOTLIN_REFLECT_PRESENT && KotlinDetector.isKotlinType(this.constructor.getDeclaringClass())) { return KotlinDelegate.instantiate(this.constructor, args); } return this.constructor.newInstance(args); 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 b5f051359ce..06f93226093 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 @@ -75,6 +75,9 @@ public class ReflectivePropertyAccessor implements PropertyAccessor { private static final Set> BOOLEAN_TYPES = Set.of(Boolean.class, boolean.class); + private static final boolean KOTLIN_REFLECT_PRESENT = KotlinDetector.isKotlinReflectPresent(); + + private final boolean allowWrite; private final Map readerCache = new ConcurrentHashMap<>(64); @@ -558,7 +561,7 @@ public class ReflectivePropertyAccessor implements PropertyAccessor { private static boolean isKotlinProperty(Method method, String methodSuffix) { Class clazz = method.getDeclaringClass(); - return KotlinDetector.isKotlinType(clazz) && + return KOTLIN_REFLECT_PRESENT && KotlinDetector.isKotlinType(clazz) && KotlinDelegate.isKotlinProperty(method, methodSuffix); } 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 d9c393e9a18..22b2762047e 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 @@ -72,6 +72,8 @@ import org.springframework.web.method.support.ModelAndViewContainer; */ public abstract class AbstractNamedValueMethodArgumentResolver implements HandlerMethodArgumentResolver { + private static final boolean KOTLIN_REFLECT_PRESENT = KotlinDetector.isKotlinReflectPresent(); + private final @Nullable ConfigurableBeanFactory configurableBeanFactory; private final @Nullable BeanExpressionContext expressionContext; @@ -103,7 +105,7 @@ public abstract class AbstractNamedValueMethodArgumentResolver implements Handle NamedValueInfo namedValueInfo = getNamedValueInfo(parameter); MethodParameter nestedParameter = parameter.nestedIfOptional(); - boolean hasDefaultValue = KotlinDetector.isKotlinType(parameter.getDeclaringClass()) && + boolean hasDefaultValue = KOTLIN_REFLECT_PRESENT && KotlinDetector.isKotlinType(parameter.getDeclaringClass()) && KotlinDelegate.hasDefaultValue(nestedParameter); Object resolvedName = resolveEmbeddedValuesAndExpressions(namedValueInfo.name); 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 c87cc74729a..2963783a4d6 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 @@ -66,6 +66,8 @@ public class InvocableHandlerMethod extends HandlerMethod { private static final Class[] EMPTY_GROUPS = new Class[0]; + private static final boolean KOTLIN_REFLECT_PRESENT = KotlinDetector.isKotlinReflectPresent(); + private HandlerMethodArgumentResolverComposite resolvers = new HandlerMethodArgumentResolverComposite(); @@ -247,7 +249,7 @@ public class InvocableHandlerMethod extends HandlerMethod { protected @Nullable Object doInvoke(@Nullable Object... args) throws Exception { Method method = getBridgedMethod(); try { - if (KotlinDetector.isKotlinType(method.getDeclaringClass())) { + if (KOTLIN_REFLECT_PRESENT && KotlinDetector.isKotlinType(method.getDeclaringClass())) { if (KotlinDetector.isSuspendingFunction(method)) { return invokeSuspendingFunction(method, 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 ce7e2c08822..4f77b6a0c4d 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 @@ -85,6 +85,8 @@ public class InvocableHandlerMethod extends HandlerMethod { private static final Object NO_ARG_VALUE = new Object(); + private static final boolean KOTLIN_REFLECT_PRESENT = KotlinDetector.isKotlinReflectPresent(); + private final HandlerMethodArgumentResolverComposite resolvers = new HandlerMethodArgumentResolverComposite(); @@ -197,12 +199,17 @@ public class InvocableHandlerMethod extends HandlerMethod { } } Object value; + boolean isSuspendingFunction; Method method = getBridgedMethod(); - boolean isSuspendingFunction = KotlinDetector.isSuspendingFunction(method); try { - value = (KotlinDetector.isKotlinType(method.getDeclaringClass()) ? - KotlinDelegate.invokeFunction(method, getBean(), args, isSuspendingFunction, exchange) : - method.invoke(getBean(), args)); + if (KOTLIN_REFLECT_PRESENT && KotlinDetector.isKotlinType(method.getDeclaringClass())) { + isSuspendingFunction = KotlinDetector.isSuspendingFunction(method); + value = KotlinDelegate.invokeFunction(method, getBean(), args, isSuspendingFunction, exchange); + } + else { + isSuspendingFunction = false; + value = 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 bf026785e70..a04ea841451 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 @@ -69,6 +69,8 @@ import org.springframework.web.server.ServerWebInputException; */ public abstract class AbstractNamedValueArgumentResolver extends HandlerMethodArgumentResolverSupport { + private static final boolean KOTLIN_REFLECT_PRESENT = KotlinDetector.isKotlinReflectPresent(); + private final @Nullable ConfigurableBeanFactory configurableBeanFactory; private final @Nullable BeanExpressionContext expressionContext; @@ -222,7 +224,7 @@ public abstract class AbstractNamedValueArgumentResolver extends HandlerMethodAr return Mono.fromSupplier(() -> { Object value = null; - boolean hasDefaultValue = KotlinDetector.isKotlinType(parameter.getDeclaringClass()) && + boolean hasDefaultValue = KOTLIN_REFLECT_PRESENT && KotlinDetector.isKotlinType(parameter.getDeclaringClass()) && KotlinDelegate.hasDefaultValue(parameter); if (namedValueInfo.defaultValue != null) { value = resolveEmbeddedValuesAndExpressions(namedValueInfo.defaultValue); diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/config/annotation/WebMvcConfigurationSupport.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/config/annotation/WebMvcConfigurationSupport.java index e6c3d3ce9a5..650b9884ed6 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/config/annotation/WebMvcConfigurationSupport.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/config/annotation/WebMvcConfigurationSupport.java @@ -36,6 +36,7 @@ import org.springframework.context.ApplicationContextAware; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Lazy; +import org.springframework.core.KotlinDetector; import org.springframework.core.convert.converter.Converter; import org.springframework.format.Formatter; import org.springframework.format.FormatterRegistry; @@ -184,6 +185,8 @@ public class WebMvcConfigurationSupport implements ApplicationContextAware, Serv private static final boolean JACKSON_2_PRESENT; + private static final boolean KOTLIN_REFLECT_PRESENT; + private static final boolean KOTLIN_SERIALIZATION_PRESENT; @@ -192,6 +195,7 @@ public class WebMvcConfigurationSupport implements ApplicationContextAware, Serv JACKSON_PRESENT = ClassUtils.isPresent("tools.jackson.databind.ObjectMapper", classLoader); JACKSON_2_PRESENT = ClassUtils.isPresent("com.fasterxml.jackson.databind.ObjectMapper", classLoader) && ClassUtils.isPresent("com.fasterxml.jackson.core.JsonGenerator", classLoader); + KOTLIN_REFLECT_PRESENT = KotlinDetector.isKotlinReflectPresent(); KOTLIN_SERIALIZATION_PRESENT = ClassUtils.isPresent("kotlinx.serialization.Serializable", classLoader); } @@ -659,7 +663,7 @@ public class WebMvcConfigurationSupport implements ApplicationContextAware, Serv requestBodyAdvices.add(new JsonViewRequestBodyAdvice()); responseBodyAdvices.add(new JsonViewResponseBodyAdvice()); } - if (KOTLIN_SERIALIZATION_PRESENT) { + if (KOTLIN_REFLECT_PRESENT && KOTLIN_SERIALIZATION_PRESENT) { requestBodyAdvices.add(new KotlinRequestBodyAdvice()); responseBodyAdvices.add(new KotlinResponseBodyAdvice()); }