Skip to content

Commit 7c5bcbc

Browse files
committed
Merge branch '6.1.x'
2 parents 3477738 + 45c2104 commit 7c5bcbc

File tree

6 files changed

+108
-21
lines changed

6 files changed

+108
-21
lines changed

spring-beans/src/main/java/org/springframework/beans/BeanUtils.java

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,11 +32,9 @@
3232
import java.util.Set;
3333

3434
import kotlin.jvm.JvmClassMappingKt;
35-
import kotlin.jvm.JvmInline;
3635
import kotlin.reflect.KClass;
3736
import kotlin.reflect.KFunction;
3837
import kotlin.reflect.KParameter;
39-
import kotlin.reflect.full.KAnnotatedElements;
4038
import kotlin.reflect.full.KClasses;
4139
import kotlin.reflect.jvm.KCallablesJvm;
4240
import kotlin.reflect.jvm.ReflectJvmMapping;
@@ -874,8 +872,7 @@ public static <T> Constructor<T> findPrimaryConstructor(Class<T> clazz) {
874872
if (primaryCtor == null) {
875873
return null;
876874
}
877-
if (kClass.isValue() && !KAnnotatedElements
878-
.findAnnotations(kClass, JvmClassMappingKt.getKotlinClass(JvmInline.class)).isEmpty()) {
875+
if (KotlinDetector.isInlineClass(clazz)) {
879876
Constructor<?>[] constructors = clazz.getDeclaredConstructors();
880877
Assert.state(constructors.length == 1,
881878
"Kotlin value classes annotated with @JvmInline are expected to have a single JVM constructor");

spring-core/src/main/java/org/springframework/core/CoroutinesUtils.java

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2023 the original author or authors.
2+
* Copyright 2002-2024 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -120,11 +120,17 @@ public static Publisher<?> invokeSuspendingFunction(CoroutineContext context, Me
120120
case INSTANCE -> argMap.put(parameter, target);
121121
case VALUE, EXTENSION_RECEIVER -> {
122122
if (!parameter.isOptional() || args[index] != null) {
123-
if (parameter.getType().getClassifier() instanceof KClass<?> kClass && kClass.isValue()) {
123+
if (parameter.getType().getClassifier() instanceof KClass<?> kClass) {
124124
Class<?> javaClass = JvmClassMappingKt.getJavaClass(kClass);
125-
Method[] methods = ReflectionUtils.getUniqueDeclaredMethods(javaClass, boxImplFilter);
126-
Assert.state(methods.length == 1, "Unable to find a single box-impl synthetic static method in " + javaClass.getName());
127-
argMap.put(parameter, ReflectionUtils.invokeMethod(methods[0], null, args[index]));
125+
if (KotlinDetector.isInlineClass(javaClass)) {
126+
Method[] methods = ReflectionUtils.getUniqueDeclaredMethods(javaClass, boxImplFilter);
127+
Assert.state(methods.length == 1,
128+
"Unable to find a single box-impl synthetic static method in " + javaClass.getName());
129+
argMap.put(parameter, ReflectionUtils.invokeMethod(methods[0], null, args[index]));
130+
}
131+
else {
132+
argMap.put(parameter, args[index]);
133+
}
128134
}
129135
else {
130136
argMap.put(parameter, args[index]);

spring-core/src/main/java/org/springframework/core/KotlinDetector.java

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2022 the original author or authors.
2+
* Copyright 2002-2024 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -35,24 +35,34 @@ public abstract class KotlinDetector {
3535
@Nullable
3636
private static final Class<? extends Annotation> kotlinMetadata;
3737

38+
@Nullable
39+
private static final Class<? extends Annotation> kotlinJvmInline;
40+
3841
// For ConstantFieldFeature compliance, otherwise could be deduced from kotlinMetadata
3942
private static final boolean kotlinPresent;
4043

4144
private static final boolean kotlinReflectPresent;
4245

4346
static {
44-
Class<?> metadata;
4547
ClassLoader classLoader = KotlinDetector.class.getClassLoader();
48+
Class<?> metadata = null;
49+
Class<?> jvmInline = null;
4650
try {
4751
metadata = ClassUtils.forName("kotlin.Metadata", classLoader);
52+
try {
53+
jvmInline = ClassUtils.forName("kotlin.jvm.JvmInline", classLoader);
54+
}
55+
catch (ClassNotFoundException ex) {
56+
// JVM inline support not available
57+
}
4858
}
4959
catch (ClassNotFoundException ex) {
5060
// Kotlin API not available - no Kotlin support
51-
metadata = null;
5261
}
5362
kotlinMetadata = (Class<? extends Annotation>) metadata;
5463
kotlinPresent = (kotlinMetadata != null);
55-
kotlinReflectPresent = ClassUtils.isPresent("kotlin.reflect.full.KClasses", classLoader);
64+
kotlinReflectPresent = kotlinPresent && ClassUtils.isPresent("kotlin.reflect.full.KClasses", classLoader);
65+
kotlinJvmInline = (Class<? extends Annotation>) jvmInline;
5666
}
5767

5868

@@ -93,4 +103,14 @@ public static boolean isSuspendingFunction(Method method) {
93103
return false;
94104
}
95105

106+
/**
107+
* Determine whether the given {@code Class} is an inline class
108+
* (annotated with {@code @JvmInline}).
109+
* @since 6.1.5
110+
* @see <a href="https://kotlinlang.org/docs/inline-classes.html">Kotlin inline value classes</a>
111+
*/
112+
public static boolean isInlineClass(Class<?> clazz) {
113+
return (kotlinJvmInline != null && clazz.getDeclaredAnnotation(kotlinJvmInline) != null);
114+
}
115+
96116
}
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
/*
2+
* Copyright 2002-2024 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.springframework.core
17+
18+
import org.assertj.core.api.Assertions
19+
import org.junit.jupiter.api.Test
20+
21+
/**
22+
* Kotlin tests for [KotlinDetector].
23+
*
24+
* @author Sebastien Deleuze
25+
*/
26+
class KotlinDetectorTests {
27+
28+
@Test
29+
fun isKotlinType() {
30+
Assertions.assertThat(KotlinDetector.isKotlinType(KotlinDetectorTests::class.java)).isTrue()
31+
}
32+
33+
@Test
34+
fun isNotKotlinType() {
35+
Assertions.assertThat(KotlinDetector.isKotlinType(KotlinDetector::class.java)).isFalse()
36+
}
37+
38+
@Test
39+
fun isInlineClass() {
40+
Assertions.assertThat(KotlinDetector.isInlineClass(ValueClass::class.java)).isTrue()
41+
}
42+
43+
@Test
44+
fun isNotInlineClass() {
45+
Assertions.assertThat(KotlinDetector.isInlineClass(KotlinDetector::class.java)).isFalse()
46+
Assertions.assertThat(KotlinDetector.isInlineClass(KotlinDetectorTests::class.java)).isFalse()
47+
}
48+
49+
@JvmInline
50+
value class ValueClass(val value: String)
51+
52+
}

spring-web/src/main/java/org/springframework/web/method/support/InvocableHandlerMethod.java

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -319,11 +319,17 @@ public static Object invokeFunction(Method method, Object target, Object[] args)
319319
case INSTANCE -> argMap.put(parameter, target);
320320
case VALUE, EXTENSION_RECEIVER -> {
321321
if (!parameter.isOptional() || args[index] != null) {
322-
if (parameter.getType().getClassifier() instanceof KClass<?> kClass && kClass.isValue()) {
322+
if (parameter.getType().getClassifier() instanceof KClass<?> kClass) {
323323
Class<?> javaClass = JvmClassMappingKt.getJavaClass(kClass);
324-
Method[] methods = ReflectionUtils.getUniqueDeclaredMethods(javaClass, boxImplFilter);
325-
Assert.state(methods.length == 1, "Unable to find a single box-impl synthetic static method in " + javaClass.getName());
326-
argMap.put(parameter, ReflectionUtils.invokeMethod(methods[0], null, args[index]));
324+
if (KotlinDetector.isInlineClass(javaClass)) {
325+
Method[] methods = ReflectionUtils.getUniqueDeclaredMethods(javaClass, boxImplFilter);
326+
Assert.state(methods.length == 1,
327+
"Unable to find a single box-impl synthetic static method in " + javaClass.getName());
328+
argMap.put(parameter, ReflectionUtils.invokeMethod(methods[0], null, args[index]));
329+
}
330+
else {
331+
argMap.put(parameter, args[index]);
332+
}
327333
}
328334
else {
329335
argMap.put(parameter, args[index]);

spring-webflux/src/main/java/org/springframework/web/reactive/result/method/InvocableHandlerMethod.java

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -330,11 +330,17 @@ public static Object invokeFunction(Method method, Object target, Object[] args,
330330
case INSTANCE -> argMap.put(parameter, target);
331331
case VALUE, EXTENSION_RECEIVER -> {
332332
if (!parameter.isOptional() || args[index] != null) {
333-
if (parameter.getType().getClassifier() instanceof KClass<?> kClass && kClass.isValue()) {
333+
if (parameter.getType().getClassifier() instanceof KClass<?> kClass) {
334334
Class<?> javaClass = JvmClassMappingKt.getJavaClass(kClass);
335-
Method[] methods = ReflectionUtils.getUniqueDeclaredMethods(javaClass, boxImplFilter);
336-
Assert.state(methods.length == 1, "Unable to find a single box-impl synthetic static method in " + javaClass.getName());
337-
argMap.put(parameter, ReflectionUtils.invokeMethod(methods[0], null, args[index]));
335+
if (KotlinDetector.isInlineClass(javaClass)) {
336+
Method[] methods = ReflectionUtils.getUniqueDeclaredMethods(javaClass, boxImplFilter);
337+
Assert.state(methods.length == 1,
338+
"Unable to find a single box-impl synthetic static method in " + javaClass.getName());
339+
argMap.put(parameter, ReflectionUtils.invokeMethod(methods[0], null, args[index]));
340+
}
341+
else {
342+
argMap.put(parameter, args[index]);
343+
}
338344
}
339345
else {
340346
argMap.put(parameter, args[index]);

0 commit comments

Comments
 (0)