diff --git a/build.gradle b/build.gradle index b073919aa7c0..f7c185bd956f 100644 --- a/build.gradle +++ b/build.gradle @@ -62,7 +62,8 @@ configure([rootProject] + javaProjects) { project -> kotlinOptions { languageVersion = "1.7" apiVersion = "1.7" - freeCompilerArgs = ["-Xjsr305=strict", "-Xsuppress-version-warnings", "-opt-in=kotlin.RequiresOptIn"] + freeCompilerArgs = ["-Xjsr305=strict", "-Xsuppress-version-warnings", + "-opt-in=kotlin.RequiresOptIn", "-no-reflect"] allWarningsAsErrors = true } } diff --git a/framework-platform/framework-platform.gradle b/framework-platform/framework-platform.gradle index e6d2bb7a9f85..0a27481082e0 100644 --- a/framework-platform/framework-platform.gradle +++ b/framework-platform/framework-platform.gradle @@ -124,6 +124,7 @@ dependencies { api("org.hibernate:hibernate-validator:7.0.4.Final") api("org.hsqldb:hsqldb:2.5.2") api("org.javamoney:moneta:1.4.2") + api("org.jetbrains.kotlinx:kotlinx.reflect.lite:1.1.0") api("org.jruby:jruby:9.3.4.0") api("org.junit.support:testng-engine:1.0.4") api("org.mozilla:rhino:1.7.11") diff --git a/spring-beans/spring-beans.gradle b/spring-beans/spring-beans.gradle index 877d28852dc0..592aa68f072a 100644 --- a/spring-beans/spring-beans.gradle +++ b/spring-beans/spring-beans.gradle @@ -7,9 +7,10 @@ dependencies { optional("jakarta.inject:jakarta.inject-api") optional("org.yaml:snakeyaml") optional("org.apache.groovy:groovy-xml") - optional("org.jetbrains.kotlin:kotlin-reflect") + optional("org.jetbrains.kotlinx:kotlinx.reflect.lite") optional("org.jetbrains.kotlin:kotlin-stdlib") testImplementation(testFixtures(project(":spring-core"))) + testImplementation("org.jetbrains.kotlin:kotlin-reflect") testImplementation(project(":spring-core-test")) testImplementation("jakarta.annotation:jakarta.annotation-api") testFixturesApi("org.junit.jupiter:junit-jupiter-api") 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 aa38a0e2ab3b..6f62e5a4e6d5 100644 --- a/spring-beans/src/main/java/org/springframework/beans/BeanUtils.java +++ b/spring-beans/src/main/java/org/springframework/beans/BeanUtils.java @@ -34,12 +34,12 @@ import java.util.Map; import java.util.Set; -import kotlin.jvm.JvmClassMappingKt; -import kotlin.reflect.KFunction; -import kotlin.reflect.KParameter; -import kotlin.reflect.full.KClasses; -import kotlin.reflect.jvm.KCallablesJvm; -import kotlin.reflect.jvm.ReflectJvmMapping; +import kotlinx.reflect.lite.KFunction; +import kotlinx.reflect.lite.KParameter; +import kotlinx.reflect.lite.full.KCallablesJvm; +import kotlinx.reflect.lite.full.KClasses; +import kotlinx.reflect.lite.jvm.JvmClassMappingKt; +import kotlinx.reflect.lite.jvm.ReflectJvmMapping; import org.springframework.core.DefaultParameterNameDiscoverer; import org.springframework.core.KotlinDetector; @@ -187,7 +187,7 @@ public static T instantiateClass(Constructor ctor, Object... args) throws Assert.notNull(ctor, "Constructor must not be null"); try { ReflectionUtils.makeAccessible(ctor); - if (KotlinDetector.isKotlinReflectPresent() && KotlinDetector.isKotlinType(ctor.getDeclaringClass())) { + if (KotlinDetector.isKotlinReflectLitePresent() && KotlinDetector.isKotlinType(ctor.getDeclaringClass())) { return KotlinDelegate.instantiateClass(ctor, args); } else { @@ -274,7 +274,7 @@ else if (ctors.length == 0){ @Nullable public static Constructor findPrimaryConstructor(Class clazz) { Assert.notNull(clazz, "Class must not be null"); - if (KotlinDetector.isKotlinReflectPresent() && KotlinDetector.isKotlinType(clazz)) { + if (KotlinDetector.isKotlinReflectLitePresent() && KotlinDetector.isKotlinType(clazz)) { return KotlinDelegate.findPrimaryConstructor(clazz); } return null; @@ -841,7 +841,7 @@ private static class KotlinDelegate { @Nullable public static Constructor findPrimaryConstructor(Class clazz) { try { - KFunction primaryCtor = KClasses.getPrimaryConstructor(JvmClassMappingKt.getKotlinClass(clazz)); + KFunction primaryCtor = KClasses.getPrimaryConstructor(JvmClassMappingKt.getLiteKClass(clazz)); if (primaryCtor == null) { return 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 4825563735ff..36b0658d5540 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 @@ -24,8 +24,8 @@ import java.util.Map; import java.util.Optional; -import kotlin.reflect.KProperty; -import kotlin.reflect.jvm.ReflectJvmMapping; +import kotlinx.reflect.lite.KProperty; +import kotlinx.reflect.lite.jvm.ReflectJvmMapping; import org.springframework.beans.BeansException; import org.springframework.beans.factory.BeanFactory; @@ -169,7 +169,7 @@ public boolean isRequired() { if (this.field != null) { return !(this.field.getType() == Optional.class || hasNullableAnnotation() || - (KotlinDetector.isKotlinReflectPresent() && + (KotlinDetector.isKotlinReflectLitePresent() && KotlinDetector.isKotlinType(this.field.getDeclaringClass()) && KotlinDelegate.isNullable(this.field))); } diff --git a/spring-context/spring-context.gradle b/spring-context/spring-context.gradle index 5f5ac1001ec7..da3cd4932f72 100644 --- a/spring-context/spring-context.gradle +++ b/spring-context/spring-context.gradle @@ -23,7 +23,7 @@ dependencies { optional("org.apache.groovy:groovy") optional("org.apache-extras.beanshell:bsh") optional("org.hibernate:hibernate-validator") - optional("org.jetbrains.kotlin:kotlin-reflect") + optional("org.jetbrains.kotlinx:kotlinx.reflect.lite") optional("org.jetbrains.kotlin:kotlin-stdlib") optional("org.reactivestreams:reactive-streams") testImplementation(project(":spring-core-test")) diff --git a/spring-core/spring-core.gradle b/spring-core/spring-core.gradle index 25c6f7ce78ef..db1de64f0b78 100644 --- a/spring-core/spring-core.gradle +++ b/spring-core/spring-core.gradle @@ -65,7 +65,7 @@ dependencies { compileOnly("io.projectreactor.tools:blockhound") optional("net.sf.jopt-simple:jopt-simple") optional("org.aspectj:aspectjweaver") - optional("org.jetbrains.kotlin:kotlin-reflect") + optional("org.jetbrains.kotlinx:kotlinx.reflect.lite") optional("org.jetbrains.kotlin:kotlin-stdlib") optional("org.jetbrains.kotlinx:kotlinx-coroutines-core") optional("org.jetbrains.kotlinx:kotlinx-coroutines-reactor") diff --git a/spring-core/src/main/java/org/springframework/core/CoroutinesUtils.java b/spring-core/src/main/java/org/springframework/core/CoroutinesUtils.java index c2724b507824..e088c8914c2c 100644 --- a/spring-core/src/main/java/org/springframework/core/CoroutinesUtils.java +++ b/spring-core/src/main/java/org/springframework/core/CoroutinesUtils.java @@ -21,13 +21,6 @@ import java.util.Objects; import kotlin.Unit; -import kotlin.jvm.JvmClassMappingKt; -import kotlin.reflect.KClass; -import kotlin.reflect.KClassifier; -import kotlin.reflect.KFunction; -import kotlin.reflect.full.KCallables; -import kotlin.reflect.jvm.KCallablesJvm; -import kotlin.reflect.jvm.ReflectJvmMapping; import kotlinx.coroutines.BuildersKt; import kotlinx.coroutines.CoroutineStart; import kotlinx.coroutines.Deferred; @@ -36,6 +29,13 @@ import kotlinx.coroutines.flow.Flow; import kotlinx.coroutines.reactor.MonoKt; import kotlinx.coroutines.reactor.ReactorFlowKt; +import kotlinx.reflect.lite.KClass; +import kotlinx.reflect.lite.KClassifier; +import kotlinx.reflect.lite.KFunction; +import kotlinx.reflect.lite.full.KCallables; +import kotlinx.reflect.lite.full.KCallablesJvm; +import kotlinx.reflect.lite.jvm.JvmClassMappingKt; +import kotlinx.reflect.lite.jvm.ReflectJvmMapping; import org.reactivestreams.Publisher; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; @@ -83,10 +83,10 @@ public static Publisher invokeSuspendingFunction(Method method, Object target KClassifier returnType = function.getReturnType().getClassifier(); if (returnType != null) { - if (returnType.equals(JvmClassMappingKt.getKotlinClass(Flow.class))) { + if (returnType.equals(JvmClassMappingKt.getLiteKClass(Flow.class))) { return mono.flatMapMany(CoroutinesUtils::asFlux); } - else if (returnType.equals(JvmClassMappingKt.getKotlinClass(Mono.class))) { + else if (returnType.equals(JvmClassMappingKt.getLiteKClass(Mono.class))) { return mono.flatMap(o -> ((Mono)o)); } else if (returnType instanceof KClass kClass && 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 746599542c57..da97c3d03a21 100644 --- a/spring-core/src/main/java/org/springframework/core/DefaultParameterNameDiscoverer.java +++ b/spring-core/src/main/java/org/springframework/core/DefaultParameterNameDiscoverer.java @@ -40,7 +40,7 @@ public class DefaultParameterNameDiscoverer extends PrioritizedParameterNameDiscoverer { public DefaultParameterNameDiscoverer() { - if (KotlinDetector.isKotlinReflectPresent()) { + if (KotlinDetector.isKotlinReflectLitePresent()) { addDiscoverer(new KotlinReflectionParameterNameDiscoverer()); } addDiscoverer(new StandardReflectionParameterNameDiscoverer()); 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 fde4e10a6c91..154fe38d1956 100644 --- a/spring-core/src/main/java/org/springframework/core/KotlinDetector.java +++ b/spring-core/src/main/java/org/springframework/core/KotlinDetector.java @@ -40,6 +40,8 @@ public abstract class KotlinDetector { private static final boolean kotlinReflectPresent; + private static final boolean kotlinReflectLitePresent; + static { Class metadata; ClassLoader classLoader = KotlinDetector.class.getClassLoader(); @@ -53,6 +55,7 @@ public abstract class KotlinDetector { kotlinMetadata = (Class) metadata; kotlinPresent = (kotlinMetadata != null); kotlinReflectPresent = ClassUtils.isPresent("kotlin.reflect.full.KClasses", classLoader); + kotlinReflectLitePresent = ClassUtils.isPresent("kotlinx.reflect.lite.full.KCallables", classLoader); } @@ -64,13 +67,25 @@ public static boolean isKotlinPresent() { } /** - * Determine whether Kotlin reflection is present. + * Determine whether the Kotlin reflection API is present. * @since 5.1 + * @deprecated as of 6.0, in favor of {@link #isKotlinReflectLitePresent()}, + * as Spring Framework does not require the "full" Kotlin reflection API + * anymore */ + @Deprecated public static boolean isKotlinReflectPresent() { return kotlinReflectPresent; } + /** + * Determine whether the Kotlin "light" reflection API is present. + * @since 6.0 + */ + public static boolean isKotlinReflectLitePresent() { + return kotlinReflectLitePresent; + } + /** * Determine whether the given {@code Class} is a Kotlin type * (with Kotlin metadata present on it). diff --git a/spring-core/src/main/java/org/springframework/core/KotlinReflectionParameterNameDiscoverer.java b/spring-core/src/main/java/org/springframework/core/KotlinReflectionParameterNameDiscoverer.java index 01700431612d..4552267a2e27 100644 --- a/spring-core/src/main/java/org/springframework/core/KotlinReflectionParameterNameDiscoverer.java +++ b/spring-core/src/main/java/org/springframework/core/KotlinReflectionParameterNameDiscoverer.java @@ -21,9 +21,9 @@ import java.util.List; import java.util.stream.Collectors; -import kotlin.reflect.KFunction; -import kotlin.reflect.KParameter; -import kotlin.reflect.jvm.ReflectJvmMapping; +import kotlinx.reflect.lite.KFunction; +import kotlinx.reflect.lite.KParameter; +import kotlinx.reflect.lite.jvm.ReflectJvmMapping; import org.springframework.lang.Nullable; 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 268184eab88a..ec503de62c84 100644 --- a/spring-core/src/main/java/org/springframework/core/MethodParameter.java +++ b/spring-core/src/main/java/org/springframework/core/MethodParameter.java @@ -31,9 +31,9 @@ import java.util.function.Predicate; import kotlin.Unit; -import kotlin.reflect.KFunction; -import kotlin.reflect.KParameter; -import kotlin.reflect.jvm.ReflectJvmMapping; +import kotlinx.reflect.lite.KFunction; +import kotlinx.reflect.lite.KParameter; +import kotlinx.reflect.lite.jvm.ReflectJvmMapping; import org.springframework.lang.Nullable; import org.springframework.util.Assert; @@ -402,7 +402,7 @@ private MethodParameter nested(int nestingLevel, @Nullable Integer typeIndex) { */ public boolean isOptional() { return (getParameterType() == Optional.class || hasNullableAnnotation() || - (KotlinDetector.isKotlinReflectPresent() && + (KotlinDetector.isKotlinReflectLitePresent() && KotlinDetector.isKotlinType(getContainingClass()) && KotlinDelegate.isOptional(this))); } @@ -506,7 +506,7 @@ public Type getGenericParameterType() { if (this.parameterIndex < 0) { Method method = getMethod(); paramType = (method != null ? - (KotlinDetector.isKotlinReflectPresent() && KotlinDetector.isKotlinType(getContainingClass()) ? + (KotlinDetector.isKotlinReflectLitePresent() && KotlinDetector.isKotlinType(getContainingClass()) ? KotlinDelegate.getGenericReturnType(method) : method.getGenericReturnType()) : void.class); } else { @@ -534,7 +534,7 @@ private Class computeParameterType() { if (method == null) { return void.class; } - if (KotlinDetector.isKotlinReflectPresent() && KotlinDetector.isKotlinType(getContainingClass())) { + if (KotlinDetector.isKotlinReflectLitePresent() && 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 550f3c770f59..4945669f188f 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 @@ -33,12 +33,12 @@ import java.util.function.Function; import java.util.function.Supplier; -import kotlin.jvm.JvmClassMappingKt; -import kotlin.reflect.KFunction; -import kotlin.reflect.KParameter; -import kotlin.reflect.full.KClasses; -import kotlin.reflect.jvm.KCallablesJvm; -import kotlin.reflect.jvm.ReflectJvmMapping; +import kotlinx.reflect.lite.KFunction; +import kotlinx.reflect.lite.KParameter; +import kotlinx.reflect.lite.full.KCallablesJvm; +import kotlinx.reflect.lite.full.KClasses; +import kotlinx.reflect.lite.jvm.JvmClassMappingKt; +import kotlinx.reflect.lite.jvm.ReflectJvmMapping; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -420,7 +420,7 @@ private static Constructor findPrimaryKotlinConstructor(Class factoryImple } private static boolean isKotlinType(Class factoryImplementationClass) { - return KotlinDetector.isKotlinReflectPresent() && KotlinDetector.isKotlinType(factoryImplementationClass); + return KotlinDetector.isKotlinReflectLitePresent() && KotlinDetector.isKotlinType(factoryImplementationClass); } @Nullable @@ -450,7 +450,7 @@ private static class KotlinDelegate { @Nullable static Constructor findPrimaryConstructor(Class clazz) { try { - KFunction primaryConstructor = KClasses.getPrimaryConstructor(JvmClassMappingKt.getKotlinClass(clazz)); + KFunction primaryConstructor = KClasses.getPrimaryConstructor(JvmClassMappingKt.getLiteKClass(clazz)); if (primaryConstructor != null) { Constructor constructor = ReflectJvmMapping.getJavaConstructor( primaryConstructor); diff --git a/spring-core/src/test/kotlin/org/springframework/core/KotlinMethodParameterTests.kt b/spring-core/src/test/kotlin/org/springframework/core/KotlinMethodParameterTests.kt index 419698d2ff6c..ca28b229d7ea 100644 --- a/spring-core/src/test/kotlin/org/springframework/core/KotlinMethodParameterTests.kt +++ b/spring-core/src/test/kotlin/org/springframework/core/KotlinMethodParameterTests.kt @@ -16,13 +16,14 @@ package org.springframework.core +import kotlinx.reflect.lite.KFunction +import kotlinx.reflect.lite.jvm.javaMethod +import kotlinx.reflect.lite.jvm.kotlin import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test import java.lang.reflect.Method import java.lang.reflect.TypeVariable import kotlin.coroutines.Continuation -import kotlin.reflect.full.declaredFunctions -import kotlin.reflect.jvm.javaMethod /** * Tests for Kotlin support in [MethodParameter]. @@ -115,7 +116,7 @@ class KotlinMethodParameterTests { private fun returnGenericParameterTypeBoundName(funName: String) = (returnGenericParameterType(funName) as TypeVariable<*>).bounds[0].typeName private fun returnMethodParameter(funName: String) = - MethodParameter(this::class.declaredFunctions.first { it.name == funName }.javaMethod!!, -1) + MethodParameter((this::class.java).kotlin.members.filterIsInstance>().first { it.name == funName }.javaMethod!!, -1) @Suppress("unused_parameter") fun nullable(nullable: String?): Int? = 42 diff --git a/spring-core/src/test/kotlin/org/springframework/core/KotlinReactiveAdapterRegistryTests.kt b/spring-core/src/test/kotlin/org/springframework/core/KotlinReactiveAdapterRegistryTests.kt index d74b6e20e7da..ff142d22a89a 100644 --- a/spring-core/src/test/kotlin/org/springframework/core/KotlinReactiveAdapterRegistryTests.kt +++ b/spring-core/src/test/kotlin/org/springframework/core/KotlinReactiveAdapterRegistryTests.kt @@ -24,6 +24,9 @@ import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.flow import kotlinx.coroutines.flow.toList import kotlinx.coroutines.runBlocking +import kotlinx.reflect.lite.KClass +import kotlinx.reflect.lite.jvm.java +import kotlinx.reflect.lite.jvm.kotlin import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test import org.reactivestreams.Publisher @@ -31,7 +34,6 @@ import reactor.core.publisher.Flux import reactor.core.publisher.Mono import reactor.test.StepVerifier import java.time.Duration -import kotlin.reflect.KClass @OptIn(DelicateCoroutinesApi::class) class KotlinReactiveAdapterRegistryTests { @@ -41,7 +43,7 @@ class KotlinReactiveAdapterRegistryTests { @Test fun deferredToPublisher() { val source = GlobalScope.async { 1 } - val target: Publisher = getAdapter(Deferred::class).toPublisher(source) + val target: Publisher = getAdapter((Deferred::class.java).kotlin).toPublisher(source) assertThat(target).isInstanceOf(Mono::class.java) assertThat((target as Mono).block(Duration.ofMillis(1000))).isEqualTo(1) } @@ -49,7 +51,7 @@ class KotlinReactiveAdapterRegistryTests { @Test fun publisherToDeferred() { val source = Mono.just(1) - val target = getAdapter(Deferred::class).fromPublisher(source) + val target = getAdapter((Deferred::class.java).kotlin).fromPublisher(source) assertThat(target).isInstanceOf(Deferred::class.java) assertThat(runBlocking { (target as Deferred<*>).await() }).isEqualTo(1) } @@ -61,7 +63,7 @@ class KotlinReactiveAdapterRegistryTests { emit(2) emit(3) } - val target: Publisher = getAdapter(Flow::class).toPublisher(source) + val target: Publisher = getAdapter((Flow::class.java).kotlin).toPublisher(source) assertThat(target).isInstanceOf(Flux::class.java) StepVerifier.create(target) .expectNext(1) @@ -73,7 +75,7 @@ class KotlinReactiveAdapterRegistryTests { @Test fun publisherToFlow() { val source = Flux.just(1, 2, 3) - val target = getAdapter(Flow::class).fromPublisher(source) + val target = getAdapter((Flow::class.java).kotlin).fromPublisher(source) assertThat(target).isInstanceOf(Flow::class.java) assertThat(runBlocking { (target as Flow<*>).toList() }).contains(1, 2, 3) } diff --git a/spring-jdbc/spring-jdbc.gradle b/spring-jdbc/spring-jdbc.gradle index 389462f3bb41..c8836af8f944 100644 --- a/spring-jdbc/spring-jdbc.gradle +++ b/spring-jdbc/spring-jdbc.gradle @@ -12,7 +12,7 @@ dependencies { optional("com.h2database:h2") optional("org.apache.derby:derby") optional("org.apache.derby:derbyclient") - optional("org.jetbrains.kotlin:kotlin-reflect") + optional("org.jetbrains.kotlinx:kotlinx.reflect.lite") optional("org.jetbrains.kotlin:kotlin-stdlib") testImplementation(testFixtures(project(":spring-beans"))) testImplementation(testFixtures(project(":spring-core"))) diff --git a/spring-messaging/spring-messaging.gradle b/spring-messaging/spring-messaging.gradle index 61554bc71839..fa16061d911a 100644 --- a/spring-messaging/spring-messaging.gradle +++ b/spring-messaging/spring-messaging.gradle @@ -28,7 +28,7 @@ dependencies { testImplementation("org.apache.activemq:activemq-stomp") testImplementation("io.projectreactor:reactor-test") testImplementation("io.reactivex.rxjava3:rxjava") - testImplementation("org.jetbrains.kotlin:kotlin-reflect") + testImplementation("org.jetbrains.kotlinx:kotlinx.reflect.lite") testImplementation("org.jetbrains.kotlin:kotlin-stdlib") testImplementation("org.xmlunit:xmlunit-assertj") testImplementation("org.xmlunit:xmlunit-matchers") diff --git a/spring-r2dbc/spring-r2dbc.gradle b/spring-r2dbc/spring-r2dbc.gradle index 75611a947eaf..828de998fe8e 100644 --- a/spring-r2dbc/spring-r2dbc.gradle +++ b/spring-r2dbc/spring-r2dbc.gradle @@ -8,7 +8,7 @@ dependencies { api(project(":spring-tx")) api("io.r2dbc:r2dbc-spi") api("io.projectreactor:reactor-core") - optional("org.jetbrains.kotlin:kotlin-reflect") + optional("org.jetbrains.kotlinx:kotlinx.reflect.lite") optional("org.jetbrains.kotlin:kotlin-stdlib") optional("org.jetbrains.kotlinx:kotlinx-coroutines-core") optional("org.jetbrains.kotlinx:kotlinx-coroutines-reactor") diff --git a/spring-tx/spring-tx.gradle b/spring-tx/spring-tx.gradle index 17c9ce146a3d..37be5ff308f7 100644 --- a/spring-tx/spring-tx.gradle +++ b/spring-tx/spring-tx.gradle @@ -13,7 +13,7 @@ dependencies { optional("jakarta.transaction:jakarta.transaction-api") optional("io.projectreactor:reactor-core") optional("io.vavr:vavr") - optional("org.jetbrains.kotlin:kotlin-reflect") + optional("org.jetbrains.kotlinx:kotlinx.reflect.lite") optional("org.jetbrains.kotlin:kotlin-stdlib") optional("org.jetbrains.kotlinx:kotlinx-coroutines-core") optional("org.jetbrains.kotlinx:kotlinx-coroutines-reactor") diff --git a/spring-web/spring-web.gradle b/spring-web/spring-web.gradle index 9e8c1511be83..138a22e50b75 100644 --- a/spring-web/spring-web.gradle +++ b/spring-web/spring-web.gradle @@ -50,7 +50,7 @@ dependencies { optional("com.googlecode.protobuf-java-format:protobuf-java-format") optional("com.rometools:rome") optional("org.apache.groovy:groovy") - optional("org.jetbrains.kotlin:kotlin-reflect") + optional("org.jetbrains.kotlinx:kotlinx.reflect.lite") optional("org.jetbrains.kotlin:kotlin-stdlib") optional("org.jetbrains.kotlinx:kotlinx-serialization-json") testImplementation(testFixtures(project(":spring-beans"))) @@ -65,7 +65,6 @@ dependencies { testImplementation("org.eclipse.jetty:jetty-server") testImplementation("org.eclipse.jetty:jetty-servlet") testImplementation("com.squareup.okhttp3:mockwebserver") - testImplementation("org.jetbrains.kotlin:kotlin-reflect") testImplementation("org.skyscreamer:jsonassert") testImplementation("org.xmlunit:xmlunit-assertj") testImplementation("org.xmlunit:xmlunit-matchers") diff --git a/spring-webflux/spring-webflux.gradle b/spring-webflux/spring-webflux.gradle index dad4a490b6b6..ab8e46948d9e 100644 --- a/spring-webflux/spring-webflux.gradle +++ b/spring-webflux/spring-webflux.gradle @@ -28,7 +28,7 @@ dependencies { optional("org.apache.httpcomponents:httpclient") { exclude group: "commons-logging", module: "commons-logging" } - optional("org.jetbrains.kotlin:kotlin-reflect") + optional("org.jetbrains.kotlinx:kotlinx.reflect.lite") optional("org.jetbrains.kotlin:kotlin-stdlib") optional("com.google.protobuf:protobuf-java-util") optional("org.jetbrains.kotlinx:kotlinx-coroutines-reactor") diff --git a/spring-webflux/src/main/kotlin/org/springframework/web/reactive/function/client/ClientResponseExtensions.kt b/spring-webflux/src/main/kotlin/org/springframework/web/reactive/function/client/ClientResponseExtensions.kt index b922a0aaf801..bfd8680122e2 100644 --- a/spring-webflux/src/main/kotlin/org/springframework/web/reactive/function/client/ClientResponseExtensions.kt +++ b/spring-webflux/src/main/kotlin/org/springframework/web/reactive/function/client/ClientResponseExtensions.kt @@ -17,14 +17,15 @@ package org.springframework.web.reactive.function.client import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.reactor.awaitSingleOrNull -import kotlinx.coroutines.reactive.awaitSingle import kotlinx.coroutines.reactive.asFlow +import kotlinx.coroutines.reactive.awaitSingle +import kotlinx.coroutines.reactor.awaitSingleOrNull +import kotlinx.reflect.lite.KClass +import kotlinx.reflect.lite.jvm.java import org.springframework.core.ParameterizedTypeReference import org.springframework.http.ResponseEntity import reactor.core.publisher.Flux import reactor.core.publisher.Mono -import kotlin.reflect.KClass /** * Extension for [ClientResponse.bodyToMono] providing a `bodyToMono()` variant diff --git a/spring-webflux/src/main/kotlin/org/springframework/web/reactive/function/server/ServerRequestExtensions.kt b/spring-webflux/src/main/kotlin/org/springframework/web/reactive/function/server/ServerRequestExtensions.kt index e446d51bfb3c..397b343d84ae 100644 --- a/spring-webflux/src/main/kotlin/org/springframework/web/reactive/function/server/ServerRequestExtensions.kt +++ b/spring-webflux/src/main/kotlin/org/springframework/web/reactive/function/server/ServerRequestExtensions.kt @@ -17,9 +17,11 @@ package org.springframework.web.reactive.function.server import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.reactor.awaitSingleOrNull -import kotlinx.coroutines.reactive.awaitSingle import kotlinx.coroutines.reactive.asFlow +import kotlinx.coroutines.reactive.awaitSingle +import kotlinx.coroutines.reactor.awaitSingleOrNull +import kotlinx.reflect.lite.KClass +import kotlinx.reflect.lite.jvm.java import org.springframework.core.ParameterizedTypeReference import org.springframework.http.MediaType import org.springframework.http.codec.multipart.Part @@ -30,7 +32,6 @@ import reactor.core.publisher.Flux import reactor.core.publisher.Mono import java.net.InetSocketAddress import java.security.Principal -import kotlin.reflect.KClass /** * Extension for [ServerRequest.bodyToMono] providing a `bodyToMono()` variant diff --git a/spring-webflux/src/test/kotlin/org/springframework/web/reactive/function/client/ClientResponseExtensionsTests.kt b/spring-webflux/src/test/kotlin/org/springframework/web/reactive/function/client/ClientResponseExtensionsTests.kt index 1819e1dd6ec3..c9f4091eb144 100644 --- a/spring-webflux/src/test/kotlin/org/springframework/web/reactive/function/client/ClientResponseExtensionsTests.kt +++ b/spring-webflux/src/test/kotlin/org/springframework/web/reactive/function/client/ClientResponseExtensionsTests.kt @@ -20,6 +20,7 @@ import io.mockk.every import io.mockk.mockk import io.mockk.verify import kotlinx.coroutines.runBlocking +import kotlinx.reflect.lite.jvm.kotlin import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test import org.springframework.core.ParameterizedTypeReference @@ -57,7 +58,7 @@ class ClientResponseExtensionsTests { @Test fun `bodyToFlow with KClass parameter`() { - response.bodyToFlow(Foo::class) + response.bodyToFlow(Foo::class.java.kotlin) verify { response.bodyToFlux(Foo::class.java) } } @@ -87,7 +88,7 @@ class ClientResponseExtensionsTests { val response = mockk() every { response.bodyToMono(String::class.java) } returns Mono.just("foo") runBlocking { - assertThat(response.awaitBody(String::class)).isEqualTo("foo") + assertThat(response.awaitBody(String::class.java.kotlin)).isEqualTo("foo") } } @@ -105,7 +106,7 @@ class ClientResponseExtensionsTests { val response = mockk() every { response.bodyToMono(String::class.java) } returns Mono.empty() runBlocking { - assertThat(response.awaitBodyOrNull(String::class)).isNull() + assertThat(response.awaitBodyOrNull(String::class.java.kotlin)).isNull() } } @@ -125,7 +126,7 @@ class ClientResponseExtensionsTests { val entity = ResponseEntity("foo", HttpStatus.OK) every { response.toEntity(String::class.java) } returns Mono.just(entity) runBlocking { - assertThat(response.awaitEntity(String::class)).isEqualTo(entity) + assertThat(response.awaitEntity(String::class.java.kotlin)).isEqualTo(entity) } } @@ -145,7 +146,7 @@ class ClientResponseExtensionsTests { val entity = ResponseEntity(listOf("foo"), HttpStatus.OK) every { response.toEntityList(String::class.java) } returns Mono.just(entity) runBlocking { - assertThat(response.awaitEntityList(String::class)).isEqualTo(entity) + assertThat(response.awaitEntityList(String::class.java.kotlin)).isEqualTo(entity) } } diff --git a/spring-webflux/src/test/kotlin/org/springframework/web/reactive/function/server/ServerRequestExtensionsTests.kt b/spring-webflux/src/test/kotlin/org/springframework/web/reactive/function/server/ServerRequestExtensionsTests.kt index 5406a6883c6e..baba742dddc0 100644 --- a/spring-webflux/src/test/kotlin/org/springframework/web/reactive/function/server/ServerRequestExtensionsTests.kt +++ b/spring-webflux/src/test/kotlin/org/springframework/web/reactive/function/server/ServerRequestExtensionsTests.kt @@ -20,6 +20,7 @@ import io.mockk.every import io.mockk.mockk import io.mockk.verify import kotlinx.coroutines.runBlocking +import kotlinx.reflect.lite.jvm.kotlin import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test import org.springframework.core.ParameterizedTypeReference @@ -31,7 +32,8 @@ import org.springframework.web.server.WebSession import reactor.core.publisher.Mono import java.net.InetSocketAddress import java.security.Principal -import java.util.* +import java.util.Optional +import java.util.OptionalLong /** * Mock object based tests for [ServerRequest] Kotlin extensions. @@ -65,7 +67,7 @@ class ServerRequestExtensionsTests { @Test fun `bodyToFlow with KClass parameters`() { - request.bodyToFlow(String::class) + request.bodyToFlow(String::class.java.kotlin) verify { request.bodyToFlux(String::class.java) } } @@ -81,7 +83,7 @@ class ServerRequestExtensionsTests { fun `awaitBody with KClass parameters`() { every { request.bodyToMono(String::class.java) } returns Mono.just("foo") runBlocking { - assertThat(request.awaitBody(String::class)).isEqualTo("foo") + assertThat(request.awaitBody(String::class.java.kotlin)).isEqualTo("foo") } } @@ -97,7 +99,7 @@ class ServerRequestExtensionsTests { fun `awaitBodyOrNull with KClass parameters`() { every { request.bodyToMono(String::class.java) } returns Mono.empty() runBlocking { - assertThat(request.awaitBodyOrNull(String::class)).isNull() + assertThat(request.awaitBodyOrNull(String::class.java.kotlin)).isNull() } } diff --git a/spring-webflux/src/test/kotlin/org/springframework/web/reactive/result/KotlinInvocableHandlerMethodTests.kt b/spring-webflux/src/test/kotlin/org/springframework/web/reactive/result/KotlinInvocableHandlerMethodTests.kt index 133046955275..1dbb47f5e511 100644 --- a/spring-webflux/src/test/kotlin/org/springframework/web/reactive/result/KotlinInvocableHandlerMethodTests.kt +++ b/spring-webflux/src/test/kotlin/org/springframework/web/reactive/result/KotlinInvocableHandlerMethodTests.kt @@ -19,22 +19,24 @@ package org.springframework.web.reactive.result import io.mockk.every import io.mockk.mockk import kotlinx.coroutines.delay +import kotlinx.reflect.lite.KFunction +import kotlinx.reflect.lite.jvm.javaMethod +import kotlinx.reflect.lite.jvm.kotlin import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test import org.springframework.http.HttpStatus import org.springframework.http.server.reactive.ServerHttpResponse -import org.springframework.web.testfixture.http.server.reactive.MockServerHttpRequest.get -import org.springframework.web.testfixture.server.MockServerWebExchange import org.springframework.web.bind.annotation.ResponseStatus import org.springframework.web.reactive.BindingContext import org.springframework.web.reactive.HandlerResult import org.springframework.web.reactive.result.method.HandlerMethodArgumentResolver import org.springframework.web.reactive.result.method.InvocableHandlerMethod import org.springframework.web.reactive.result.method.annotation.ContinuationHandlerMethodArgumentResolver +import org.springframework.web.testfixture.http.server.reactive.MockServerHttpRequest.get +import org.springframework.web.testfixture.server.MockServerWebExchange import reactor.core.publisher.Mono import reactor.test.StepVerifier import java.lang.reflect.Method -import kotlin.reflect.jvm.javaMethod class KotlinInvocableHandlerMethodTests { @@ -45,7 +47,7 @@ class KotlinInvocableHandlerMethodTests { @Test fun resolveNoArg() { this.resolvers.add(stubResolver(Mono.empty())) - val method = CoroutinesController::singleArg.javaMethod!! + val method = ((CoroutinesController::class.java.kotlin).members.single { it.name == "singleArg" } as KFunction<*>).javaMethod!! val result = invoke(CoroutinesController(), method, null) assertHandlerResultValue(result, "success:null") } @@ -53,21 +55,21 @@ class KotlinInvocableHandlerMethodTests { @Test fun resolveArg() { this.resolvers.add(stubResolver("foo")) - val method = CoroutinesController::singleArg.javaMethod!! + val method = ((CoroutinesController::class.java.kotlin).members.single { it.name == "singleArg" } as KFunction<*>).javaMethod!! val result = invoke(CoroutinesController(), method,"foo") assertHandlerResultValue(result, "success:foo") } @Test fun resolveNoArgs() { - val method = CoroutinesController::noArgs.javaMethod!! + val method = ((CoroutinesController::class.java.kotlin).members.single { it.name == "noArgs" } as KFunction<*>).javaMethod!! val result = invoke(CoroutinesController(), method) assertHandlerResultValue(result, "success") } @Test fun invocationTargetException() { - val method = CoroutinesController::exceptionMethod.javaMethod!! + val method = ((CoroutinesController::class.java.kotlin).members.single { it.name == "exceptionMethod" } as KFunction<*>).javaMethod!! val result = invoke(CoroutinesController(), method) StepVerifier.create(result) @@ -77,7 +79,7 @@ class KotlinInvocableHandlerMethodTests { @Test fun responseStatusAnnotation() { - val method = CoroutinesController::created.javaMethod!! + val method = ((CoroutinesController::class.java.kotlin).members.single { it.name == "created" } as KFunction<*>).javaMethod!! val result = invoke(CoroutinesController(), method) assertHandlerResultValue(result, "created") @@ -88,7 +90,7 @@ class KotlinInvocableHandlerMethodTests { fun voidMethodWithResponseArg() { val response = this.exchange.response this.resolvers.add(stubResolver(response)) - val method = CoroutinesController::response.javaMethod!! + val method = ((CoroutinesController::class.java.kotlin).members.single { it.name == "response" } as KFunction<*>).javaMethod!! val result = invoke(CoroutinesController(), method) StepVerifier.create(result) @@ -100,7 +102,7 @@ class KotlinInvocableHandlerMethodTests { @Test fun privateController() { this.resolvers.add(stubResolver("foo")) - val method = PrivateCoroutinesController::singleArg.javaMethod!! + val method = ((PrivateCoroutinesController::class.java.kotlin).members.single { it.name == "singleArg" } as KFunction<*>).javaMethod!! val result = invoke(PrivateCoroutinesController(), method,"foo") assertHandlerResultValue(result, "success:foo") } diff --git a/spring-webmvc/spring-webmvc.gradle b/spring-webmvc/spring-webmvc.gradle index 585eba2915ac..f27ec3113686 100644 --- a/spring-webmvc/spring-webmvc.gradle +++ b/spring-webmvc/spring-webmvc.gradle @@ -29,7 +29,7 @@ dependencies { optional("com.fasterxml.jackson.dataformat:jackson-dataformat-smile") optional("com.fasterxml.jackson.dataformat:jackson-dataformat-cbor") optional("org.apache.groovy:groovy-templates") - optional("org.jetbrains.kotlin:kotlin-reflect") + optional("org.jetbrains.kotlinx:kotlinx.reflect.lite") optional("org.jetbrains.kotlin:kotlin-stdlib") optional("org.reactivestreams:reactive-streams") optional("org.jetbrains.kotlinx:kotlinx-coroutines-reactor")