Ignore DefaultConstructorMarker in BeanUtils#getParameterNames

Closes gh-34760
This commit is contained in:
Sébastien Deleuze 2025-05-28 10:12:09 +02:00
parent 472c4012ca
commit d777b70889
2 changed files with 55 additions and 3 deletions

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2024 the original author or authors. * Copyright 2002-2025 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -33,6 +33,7 @@ import java.util.Map;
import java.util.Set; import java.util.Set;
import kotlin.jvm.JvmClassMappingKt; import kotlin.jvm.JvmClassMappingKt;
import kotlin.jvm.internal.DefaultConstructorMarker;
import kotlin.reflect.KClass; import kotlin.reflect.KClass;
import kotlin.reflect.KFunction; import kotlin.reflect.KFunction;
import kotlin.reflect.KParameter; import kotlin.reflect.KParameter;
@ -669,7 +670,9 @@ public abstract class BeanUtils {
ConstructorProperties cp = ctor.getAnnotation(ConstructorProperties.class); ConstructorProperties cp = ctor.getAnnotation(ConstructorProperties.class);
String[] paramNames = (cp != null ? cp.value() : parameterNameDiscoverer.getParameterNames(ctor)); String[] paramNames = (cp != null ? cp.value() : parameterNameDiscoverer.getParameterNames(ctor));
Assert.state(paramNames != null, () -> "Cannot resolve parameter names for constructor " + ctor); Assert.state(paramNames != null, () -> "Cannot resolve parameter names for constructor " + ctor);
Assert.state(paramNames.length == ctor.getParameterCount(), int parameterCount = (KotlinDetector.isKotlinReflectPresent() && KotlinDelegate.hasDefaultConstructorMarker(ctor) ?
ctor.getParameterCount() - 1 : ctor.getParameterCount());
Assert.state(paramNames.length == parameterCount,
() -> "Invalid number of parameter names: " + paramNames.length + " for constructor " + ctor); () -> "Invalid number of parameter names: " + paramNames.length + " for constructor " + ctor);
return paramNames; return paramNames;
} }
@ -939,6 +942,11 @@ public abstract class BeanUtils {
} }
return kotlinConstructor.callBy(argParameters); return kotlinConstructor.callBy(argParameters);
} }
public static boolean hasDefaultConstructorMarker(Constructor<?> ctor) {
int parameterCount = ctor.getParameterCount();
return parameterCount > 0 && ctor.getParameters()[parameterCount -1].getType() == DefaultConstructorMarker.class;
}
} }
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2023 the original author or authors. * Copyright 2002-2025 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -157,6 +157,48 @@ class BeanUtilsKotlinTests {
assertThat(instance).isEqualTo(ConstructorWithNullablePrimitiveValueClass(null)) assertThat(instance).isEqualTo(ConstructorWithNullablePrimitiveValueClass(null))
} }
@Test
fun `Get parameter names with Foo`() {
val ctor = BeanUtils.findPrimaryConstructor(Foo::class.java)!!
val names = BeanUtils.getParameterNames(ctor)
assertThat(names).containsExactly("param1", "param2")
}
@Test
fun `Get parameter names filters out DefaultConstructorMarker with ConstructorWithValueClass`() {
val ctor = BeanUtils.findPrimaryConstructor(ConstructorWithValueClass::class.java)!!
val names = BeanUtils.getParameterNames(ctor)
assertThat(names).containsExactly("value")
}
@Test
fun `getParameterNames filters out DefaultConstructorMarker with ConstructorWithNullableValueClass`() {
val ctor = BeanUtils.findPrimaryConstructor(ConstructorWithNullableValueClass::class.java)!!
val names = BeanUtils.getParameterNames(ctor)
assertThat(names).containsExactly("value")
}
@Test
fun `getParameterNames filters out DefaultConstructorMarker with ConstructorWithPrimitiveValueClass`() {
val ctor = BeanUtils.findPrimaryConstructor(ConstructorWithPrimitiveValueClass::class.java)!!
val names = BeanUtils.getParameterNames(ctor)
assertThat(names).containsExactly("value")
}
@Test
fun `getParameterNames filters out DefaultConstructorMarker with ConstructorWithNullablePrimitiveValueClass`() {
val ctor = BeanUtils.findPrimaryConstructor(ConstructorWithNullablePrimitiveValueClass::class.java)!!
val names = BeanUtils.getParameterNames(ctor)
assertThat(names).containsExactly("value")
}
@Test
fun `getParameterNames with ClassWithZeroParameterCtor`() {
val ctor = BeanUtils.findPrimaryConstructor(ClassWithZeroParameterCtor::class.java)!!
val names = BeanUtils.getParameterNames(ctor)
assertThat(names).isEmpty()
}
class Foo(val param1: String, val param2: Int) class Foo(val param1: String, val param2: Int)
@ -216,4 +258,6 @@ class BeanUtilsKotlinTests {
data class ConstructorWithNullablePrimitiveValueClass(val value: PrimitiveValueClass?) data class ConstructorWithNullablePrimitiveValueClass(val value: PrimitiveValueClass?)
class ClassWithZeroParameterCtor()
} }