Handle parameters of Kotlin extension methods correctly

The EXTENSION_RECEIVER parameter of Kotlin's extension
methods appear as normal method parameters to Java and
thus require a name. The synthetic name "$receiver" is
used here, as it is not a valid Kotlin identifier,
but valid in Java.

Issue: SPR-16119
master
diesieben07 7 years ago committed by sdeleuze
parent 2be2aa7b96
commit 0e49e32188
  1. 8
      spring-core/src/main/java/org/springframework/core/KotlinReflectionParameterNameDiscoverer.java
  2. 11
      spring-core/src/test/kotlin/org/springframework/core/KotlinReflectionParameterNameDiscovererTests.kt

@ -75,11 +75,15 @@ public class KotlinReflectionParameterNameDiscoverer implements ParameterNameDis
private String[] getParameterNames(List<KParameter> parameters) { private String[] getParameterNames(List<KParameter> parameters) {
List<KParameter> filteredParameters = parameters List<KParameter> filteredParameters = parameters
.stream() .stream()
.filter(p -> KParameter.Kind.VALUE.equals(p.getKind())) // Extension receivers of extension methods must be included as they appear as normal method parameters in Java
.filter(p -> KParameter.Kind.VALUE.equals(p.getKind()) || KParameter.Kind.EXTENSION_RECEIVER.equals(p.getKind()))
.collect(Collectors.toList()); .collect(Collectors.toList());
String[] parameterNames = new String[filteredParameters.size()]; String[] parameterNames = new String[filteredParameters.size()];
for (int i = 0; i < filteredParameters.size(); i++) { for (int i = 0; i < filteredParameters.size(); i++) {
String name = filteredParameters.get(i).getName(); KParameter parameter = filteredParameters.get(i);
// extension receivers are not explicitly named, but require a name for Java interoperability
// $receiver is not a valid Kotlin identifier, but valid in Java, so it can be used here
String name = KParameter.Kind.EXTENSION_RECEIVER.equals(parameter.getKind()) ? "$receiver" : parameter.getName();
if (name == null) { if (name == null) {
return null; return null;
} }

@ -42,6 +42,13 @@ class KotlinReflectionParameterNameDiscovererTests {
assertThat(actualParams, `is`(arrayOf("message"))) assertThat(actualParams, `is`(arrayOf("message")))
} }
@Test
fun getParameterNamesOnExtensionMethod() {
val method = ReflectionUtils.findMethod(UtilityClass::class.java, "identity", String::class.java)!!
val actualParams = parameterNameDiscoverer.getParameterNames(method)!!
assertThat(actualParams, `is`(arrayOf("\$receiver")))
}
interface MessageService { interface MessageService {
fun sendMessage(message: String) fun sendMessage(message: String)
} }
@ -49,4 +56,8 @@ class KotlinReflectionParameterNameDiscovererTests {
class MessageServiceImpl { class MessageServiceImpl {
fun sendMessage(message: String) = message fun sendMessage(message: String) = message
} }
class UtilityClass {
fun String.identity() = this
}
} }

Loading…
Cancel
Save