|
27 | 27 | import java.util.Set;
|
28 | 28 | import java.util.concurrent.ConcurrentHashMap;
|
29 | 29 |
|
| 30 | +import kotlin.jvm.JvmClassMappingKt; |
| 31 | +import kotlin.reflect.KClass; |
| 32 | +import kotlin.reflect.KMutableProperty; |
| 33 | +import kotlin.reflect.KProperty; |
| 34 | +import kotlin.reflect.full.KClasses; |
| 35 | +import kotlin.reflect.jvm.ReflectJvmMapping; |
| 36 | + |
30 | 37 | import org.springframework.asm.MethodVisitor;
|
| 38 | +import org.springframework.core.KotlinDetector; |
31 | 39 | import org.springframework.core.MethodParameter;
|
32 | 40 | import org.springframework.core.convert.Property;
|
33 | 41 | import org.springframework.core.convert.TypeDescriptor;
|
|
55 | 63 | * @author Juergen Hoeller
|
56 | 64 | * @author Phillip Webb
|
57 | 65 | * @author Sam Brannen
|
| 66 | + * @author Sebastien Deleuze |
58 | 67 | * @since 3.0
|
59 | 68 | * @see StandardEvaluationContext
|
60 | 69 | * @see SimpleEvaluationContext
|
@@ -401,7 +410,8 @@ private Method findMethodForProperty(String[] methodSuffixes, String prefix, Cla
|
401 | 410 | Method[] methods = getSortedMethods(clazz);
|
402 | 411 | for (String methodSuffix : methodSuffixes) {
|
403 | 412 | for (Method method : methods) {
|
404 |
| - if (isCandidateForProperty(method, clazz) && method.getName().equals(prefix + methodSuffix) && |
| 413 | + if (isCandidateForProperty(method, clazz) && |
| 414 | + (method.getName().equals(prefix + methodSuffix) || isKotlinProperty(method, methodSuffix)) && |
405 | 415 | method.getParameterCount() == numberOfParams &&
|
406 | 416 | (!mustBeStatic || Modifier.isStatic(method.getModifiers())) &&
|
407 | 417 | (requiredReturnTypes.isEmpty() || requiredReturnTypes.contains(method.getReturnType()))) {
|
@@ -557,6 +567,13 @@ public PropertyAccessor createOptimalAccessor(EvaluationContext context, @Nullab
|
557 | 567 | return this;
|
558 | 568 | }
|
559 | 569 |
|
| 570 | + private static boolean isKotlinProperty(Method method, String methodSuffix) { |
| 571 | + Class<?> clazz = method.getDeclaringClass(); |
| 572 | + return KotlinDetector.isKotlinReflectPresent() && |
| 573 | + KotlinDetector.isKotlinType(clazz) && |
| 574 | + KotlinDelegate.isKotlinProperty(method, methodSuffix); |
| 575 | + } |
| 576 | + |
560 | 577 |
|
561 | 578 | /**
|
562 | 579 | * Captures the member (method/field) to call reflectively to access a property value
|
@@ -755,4 +772,24 @@ public void generateCode(String propertyName, MethodVisitor mv, CodeFlow cf) {
|
755 | 772 | }
|
756 | 773 | }
|
757 | 774 |
|
| 775 | + /** |
| 776 | + * Inner class to avoid a hard dependency on Kotlin at runtime. |
| 777 | + */ |
| 778 | + private static class KotlinDelegate { |
| 779 | + |
| 780 | + public static boolean isKotlinProperty(Method method, String methodSuffix) { |
| 781 | + KClass<?> kClass = JvmClassMappingKt.getKotlinClass(method.getDeclaringClass()); |
| 782 | + for (KProperty<?> property : KClasses.getMemberProperties(kClass)) { |
| 783 | + if (methodSuffix.equalsIgnoreCase(property.getName()) && |
| 784 | + (method.equals(ReflectJvmMapping.getJavaGetter(property)) || |
| 785 | + property instanceof KMutableProperty<?> mutableProperty && |
| 786 | + method.equals(ReflectJvmMapping.getJavaSetter(mutableProperty)))) { |
| 787 | + return true; |
| 788 | + } |
| 789 | + } |
| 790 | + return false; |
| 791 | + } |
| 792 | + |
| 793 | + } |
| 794 | + |
758 | 795 | }
|
0 commit comments