15
15
*/
16
16
package org .springframework .data .util ;
17
17
18
+ import kotlin .jvm .JvmClassMappingKt ;
19
+ import kotlin .reflect .KCallable ;
20
+ import kotlin .reflect .KClass ;
18
21
import kotlin .reflect .KFunction ;
22
+ import kotlin .reflect .KMutableProperty ;
23
+ import kotlin .reflect .KProperty ;
19
24
import kotlin .reflect .KType ;
20
25
import kotlin .reflect .jvm .ReflectJvmMapping ;
21
26
import kotlin .reflect .jvm .internal .impl .load .kotlin .header .KotlinClassHeader ;
@@ -402,11 +407,37 @@ public static boolean isNullable(MethodParameter parameter) {
402
407
}
403
408
404
409
if (isSupportedKotlinClass (parameter .getDeclaringClass ())) {
410
+ return KotlinReflectionUtils .isNullable (parameter );
411
+ }
412
+
413
+ return !parameter .getParameterType ().isPrimitive ();
414
+ }
415
+
416
+ /**
417
+ * Reflection utility methods specific to Kotlin reflection.
418
+ */
419
+ static class KotlinReflectionUtils {
420
+
421
+ /**
422
+ * Returns {@literal} whether the given {@link MethodParameter} is nullable. Its declaring method can reference a
423
+ * Kotlin function, property or interface property.
424
+ *
425
+ * @return {@literal true} if {@link MethodParameter} is nullable.
426
+ * @since 2.0.1
427
+ */
428
+ static boolean isNullable (MethodParameter parameter ) {
405
429
406
- KFunction <?> kotlinFunction = ReflectJvmMapping .getKotlinFunction (parameter .getMethod ());
430
+ Method method = parameter .getMethod ();
431
+ KFunction <?> kotlinFunction = ReflectJvmMapping .getKotlinFunction (method );
407
432
408
433
if (kotlinFunction == null ) {
409
- throw new IllegalArgumentException (String .format ("Cannot resolve %s to a Kotlin function!" , parameter ));
434
+
435
+ // Fallback to own lookup because there's no public Kotlin API for that kind of lookup until
436
+ // https://youtrack.jetbrains.com/issue/KT-20768 gets resolved.
437
+ Optional <? extends KFunction > first = findKFunction (method );
438
+
439
+ kotlinFunction = first .orElseThrow (
440
+ () -> new IllegalArgumentException (String .format ("Cannot resolve %s to a Kotlin function!" , parameter )));
410
441
}
411
442
412
443
KType type = parameter .getParameterIndex () == -1 ? kotlinFunction .getReturnType ()
@@ -415,6 +446,46 @@ public static boolean isNullable(MethodParameter parameter) {
415
446
return type .isMarkedNullable ();
416
447
}
417
448
418
- return !parameter .getParameterType ().isPrimitive ();
449
+ /**
450
+ * Lookup a {@link Method} to a {@link KFunction}.
451
+ *
452
+ * @param method the JVM {@link Method} to look up.
453
+ * @return {@link Optional} wrapping a possibly existing {@link KFunction}.
454
+ */
455
+ private static Optional <? extends KFunction > findKFunction (Method method ) {
456
+
457
+ KClass <?> kotlinClass = JvmClassMappingKt .getKotlinClass (method .getDeclaringClass ());
458
+
459
+ return kotlinClass .getMembers () //
460
+ .stream () //
461
+ .flatMap (KotlinReflectionUtils ::toKFunctionStream ) //
462
+ .filter (it -> {
463
+
464
+ Method javaMethod = ReflectJvmMapping .getJavaMethod (it );
465
+ return javaMethod != null && javaMethod .equals (method );
466
+ }) //
467
+ .findFirst ();
468
+ }
469
+
470
+ private static Stream <? extends KFunction > toKFunctionStream (KCallable <?> it ) {
471
+
472
+ if (it instanceof KMutableProperty <?>) {
473
+
474
+ KMutableProperty property = (KMutableProperty <?>) it ;
475
+ return Stream .of (property .getGetter (), property .getSetter ());
476
+ }
477
+
478
+ if (it instanceof KProperty <?>) {
479
+
480
+ KProperty <?> property = (KProperty <?>) it ;
481
+ return Stream .of (property .getGetter ());
482
+ }
483
+
484
+ if (it instanceof KFunction <?>) {
485
+ return Stream .of ((KFunction <?>) it );
486
+ }
487
+
488
+ return Stream .empty ();
489
+ }
419
490
}
420
491
}
0 commit comments