Merge branch '6.1.x'

This commit is contained in:
Sébastien Deleuze
2024-02-28 17:24:08 +01:00
6 changed files with 108 additions and 21 deletions

View File

@@ -32,11 +32,9 @@ import java.util.Map;
import java.util.Set;
import kotlin.jvm.JvmClassMappingKt;
import kotlin.jvm.JvmInline;
import kotlin.reflect.KClass;
import kotlin.reflect.KFunction;
import kotlin.reflect.KParameter;
import kotlin.reflect.full.KAnnotatedElements;
import kotlin.reflect.full.KClasses;
import kotlin.reflect.jvm.KCallablesJvm;
import kotlin.reflect.jvm.ReflectJvmMapping;
@@ -874,8 +872,7 @@ public abstract class BeanUtils {
if (primaryCtor == null) {
return null;
}
if (kClass.isValue() && !KAnnotatedElements
.findAnnotations(kClass, JvmClassMappingKt.getKotlinClass(JvmInline.class)).isEmpty()) {
if (KotlinDetector.isInlineClass(clazz)) {
Constructor<?>[] constructors = clazz.getDeclaredConstructors();
Assert.state(constructors.length == 1,
"Kotlin value classes annotated with @JvmInline are expected to have a single JVM constructor");

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 the original author or authors.
* Copyright 2002-2024 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.
@@ -120,11 +120,17 @@ public abstract class CoroutinesUtils {
case INSTANCE -> argMap.put(parameter, target);
case VALUE, EXTENSION_RECEIVER -> {
if (!parameter.isOptional() || args[index] != null) {
if (parameter.getType().getClassifier() instanceof KClass<?> kClass && kClass.isValue()) {
if (parameter.getType().getClassifier() instanceof KClass<?> kClass) {
Class<?> javaClass = JvmClassMappingKt.getJavaClass(kClass);
Method[] methods = ReflectionUtils.getUniqueDeclaredMethods(javaClass, boxImplFilter);
Assert.state(methods.length == 1, "Unable to find a single box-impl synthetic static method in " + javaClass.getName());
argMap.put(parameter, ReflectionUtils.invokeMethod(methods[0], null, args[index]));
if (KotlinDetector.isInlineClass(javaClass)) {
Method[] methods = ReflectionUtils.getUniqueDeclaredMethods(javaClass, boxImplFilter);
Assert.state(methods.length == 1,
"Unable to find a single box-impl synthetic static method in " + javaClass.getName());
argMap.put(parameter, ReflectionUtils.invokeMethod(methods[0], null, args[index]));
}
else {
argMap.put(parameter, args[index]);
}
}
else {
argMap.put(parameter, args[index]);

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 the original author or authors.
* Copyright 2002-2024 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.
@@ -35,24 +35,34 @@ public abstract class KotlinDetector {
@Nullable
private static final Class<? extends Annotation> kotlinMetadata;
@Nullable
private static final Class<? extends Annotation> kotlinJvmInline;
// For ConstantFieldFeature compliance, otherwise could be deduced from kotlinMetadata
private static final boolean kotlinPresent;
private static final boolean kotlinReflectPresent;
static {
Class<?> metadata;
ClassLoader classLoader = KotlinDetector.class.getClassLoader();
Class<?> metadata = null;
Class<?> jvmInline = null;
try {
metadata = ClassUtils.forName("kotlin.Metadata", classLoader);
try {
jvmInline = ClassUtils.forName("kotlin.jvm.JvmInline", classLoader);
}
catch (ClassNotFoundException ex) {
// JVM inline support not available
}
}
catch (ClassNotFoundException ex) {
// Kotlin API not available - no Kotlin support
metadata = null;
}
kotlinMetadata = (Class<? extends Annotation>) metadata;
kotlinPresent = (kotlinMetadata != null);
kotlinReflectPresent = ClassUtils.isPresent("kotlin.reflect.full.KClasses", classLoader);
kotlinReflectPresent = kotlinPresent && ClassUtils.isPresent("kotlin.reflect.full.KClasses", classLoader);
kotlinJvmInline = (Class<? extends Annotation>) jvmInline;
}
@@ -93,4 +103,14 @@ public abstract class KotlinDetector {
return false;
}
/**
* Determine whether the given {@code Class} is an inline class
* (annotated with {@code @JvmInline}).
* @since 6.1.5
* @see <a href="https://kotlinlang.org/docs/inline-classes.html">Kotlin inline value classes</a>
*/
public static boolean isInlineClass(Class<?> clazz) {
return (kotlinJvmInline != null && clazz.getDeclaredAnnotation(kotlinJvmInline) != null);
}
}

View File

@@ -0,0 +1,52 @@
/*
* Copyright 2002-2024 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.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.core
import org.assertj.core.api.Assertions
import org.junit.jupiter.api.Test
/**
* Kotlin tests for [KotlinDetector].
*
* @author Sebastien Deleuze
*/
class KotlinDetectorTests {
@Test
fun isKotlinType() {
Assertions.assertThat(KotlinDetector.isKotlinType(KotlinDetectorTests::class.java)).isTrue()
}
@Test
fun isNotKotlinType() {
Assertions.assertThat(KotlinDetector.isKotlinType(KotlinDetector::class.java)).isFalse()
}
@Test
fun isInlineClass() {
Assertions.assertThat(KotlinDetector.isInlineClass(ValueClass::class.java)).isTrue()
}
@Test
fun isNotInlineClass() {
Assertions.assertThat(KotlinDetector.isInlineClass(KotlinDetector::class.java)).isFalse()
Assertions.assertThat(KotlinDetector.isInlineClass(KotlinDetectorTests::class.java)).isFalse()
}
@JvmInline
value class ValueClass(val value: String)
}

View File

@@ -319,11 +319,17 @@ public class InvocableHandlerMethod extends HandlerMethod {
case INSTANCE -> argMap.put(parameter, target);
case VALUE, EXTENSION_RECEIVER -> {
if (!parameter.isOptional() || args[index] != null) {
if (parameter.getType().getClassifier() instanceof KClass<?> kClass && kClass.isValue()) {
if (parameter.getType().getClassifier() instanceof KClass<?> kClass) {
Class<?> javaClass = JvmClassMappingKt.getJavaClass(kClass);
Method[] methods = ReflectionUtils.getUniqueDeclaredMethods(javaClass, boxImplFilter);
Assert.state(methods.length == 1, "Unable to find a single box-impl synthetic static method in " + javaClass.getName());
argMap.put(parameter, ReflectionUtils.invokeMethod(methods[0], null, args[index]));
if (KotlinDetector.isInlineClass(javaClass)) {
Method[] methods = ReflectionUtils.getUniqueDeclaredMethods(javaClass, boxImplFilter);
Assert.state(methods.length == 1,
"Unable to find a single box-impl synthetic static method in " + javaClass.getName());
argMap.put(parameter, ReflectionUtils.invokeMethod(methods[0], null, args[index]));
}
else {
argMap.put(parameter, args[index]);
}
}
else {
argMap.put(parameter, args[index]);

View File

@@ -330,11 +330,17 @@ public class InvocableHandlerMethod extends HandlerMethod {
case INSTANCE -> argMap.put(parameter, target);
case VALUE, EXTENSION_RECEIVER -> {
if (!parameter.isOptional() || args[index] != null) {
if (parameter.getType().getClassifier() instanceof KClass<?> kClass && kClass.isValue()) {
if (parameter.getType().getClassifier() instanceof KClass<?> kClass) {
Class<?> javaClass = JvmClassMappingKt.getJavaClass(kClass);
Method[] methods = ReflectionUtils.getUniqueDeclaredMethods(javaClass, boxImplFilter);
Assert.state(methods.length == 1, "Unable to find a single box-impl synthetic static method in " + javaClass.getName());
argMap.put(parameter, ReflectionUtils.invokeMethod(methods[0], null, args[index]));
if (KotlinDetector.isInlineClass(javaClass)) {
Method[] methods = ReflectionUtils.getUniqueDeclaredMethods(javaClass, boxImplFilter);
Assert.state(methods.length == 1,
"Unable to find a single box-impl synthetic static method in " + javaClass.getName());
argMap.put(parameter, ReflectionUtils.invokeMethod(methods[0], null, args[index]));
}
else {
argMap.put(parameter, args[index]);
}
}
else {
argMap.put(parameter, args[index]);