|
|
|
|
@ -34,6 +34,7 @@ import java.util.Locale;
@@ -34,6 +34,7 @@ import java.util.Locale;
|
|
|
|
|
import java.util.UUID; |
|
|
|
|
|
|
|
|
|
import org.jspecify.annotations.Nullable; |
|
|
|
|
import org.junit.jupiter.api.Nested; |
|
|
|
|
import org.junit.jupiter.api.Test; |
|
|
|
|
import org.junit.jupiter.params.ParameterizedTest; |
|
|
|
|
import org.junit.jupiter.params.provider.ValueSource; |
|
|
|
|
@ -67,14 +68,14 @@ class BeanUtilsTests {
@@ -67,14 +68,14 @@ class BeanUtilsTests {
|
|
|
|
|
|
|
|
|
|
@Test |
|
|
|
|
void instantiateClassGivenInterface() { |
|
|
|
|
assertThatExceptionOfType(FatalBeanException.class).isThrownBy(() -> |
|
|
|
|
BeanUtils.instantiateClass(List.class)); |
|
|
|
|
assertThatExceptionOfType(FatalBeanException.class) |
|
|
|
|
.isThrownBy(() -> BeanUtils.instantiateClass(List.class)); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@Test |
|
|
|
|
void instantiateClassGivenClassWithoutDefaultConstructor() { |
|
|
|
|
assertThatExceptionOfType(FatalBeanException.class).isThrownBy(() -> |
|
|
|
|
BeanUtils.instantiateClass(CustomDateEditor.class)); |
|
|
|
|
assertThatExceptionOfType(FatalBeanException.class) |
|
|
|
|
.isThrownBy(() -> BeanUtils.instantiateClass(CustomDateEditor.class)); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@Test // gh-22531
|
|
|
|
|
@ -91,16 +92,16 @@ class BeanUtilsTests {
@@ -91,16 +92,16 @@ class BeanUtilsTests {
|
|
|
|
|
void instantiateClassWithFewerArgsThanParameters() throws NoSuchMethodException { |
|
|
|
|
Constructor<BeanWithPrimitiveTypes> constructor = getBeanWithPrimitiveTypesConstructor(); |
|
|
|
|
|
|
|
|
|
assertThatExceptionOfType(BeanInstantiationException.class).isThrownBy(() -> |
|
|
|
|
BeanUtils.instantiateClass(constructor, null, null, "foo")); |
|
|
|
|
assertThatExceptionOfType(BeanInstantiationException.class) |
|
|
|
|
.isThrownBy(() -> BeanUtils.instantiateClass(constructor, null, null, "foo")); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@Test // gh-22531
|
|
|
|
|
void instantiateClassWithMoreArgsThanParameters() throws NoSuchMethodException { |
|
|
|
|
Constructor<BeanWithPrimitiveTypes> constructor = getBeanWithPrimitiveTypesConstructor(); |
|
|
|
|
|
|
|
|
|
assertThatExceptionOfType(BeanInstantiationException.class).isThrownBy(() -> |
|
|
|
|
BeanUtils.instantiateClass(constructor, null, null, null, null, null, null, null, null, "foo", null)); |
|
|
|
|
assertThatExceptionOfType(BeanInstantiationException.class) |
|
|
|
|
.isThrownBy(() -> BeanUtils.instantiateClass(constructor, null, null, null, null, null, null, null, null, "foo", null)); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@Test // gh-22531, gh-27390
|
|
|
|
|
@ -157,6 +158,129 @@ class BeanUtilsTests {
@@ -157,6 +158,129 @@ class BeanUtilsTests {
|
|
|
|
|
assertThat(BeanUtils.findEditorByConvention(Resource.class).getClass()).isEqualTo(ResourceEditor.class); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@Test |
|
|
|
|
void resolveSimpleSignature() throws Exception { |
|
|
|
|
Method desiredMethod = MethodSignatureBean.class.getMethod("doSomething"); |
|
|
|
|
assertSignatureEquals(desiredMethod, "doSomething"); |
|
|
|
|
assertSignatureEquals(desiredMethod, "doSomething()"); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@Test |
|
|
|
|
void resolveInvalidSignatureEndParen() { |
|
|
|
|
assertThatIllegalArgumentException() |
|
|
|
|
.isThrownBy(() -> BeanUtils.resolveSignature("doSomething(", MethodSignatureBean.class)); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@Test |
|
|
|
|
void resolveInvalidSignatureStartParen() { |
|
|
|
|
assertThatIllegalArgumentException() |
|
|
|
|
.isThrownBy(() -> BeanUtils.resolveSignature("doSomething)", MethodSignatureBean.class)); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@Test |
|
|
|
|
void resolveWithAndWithoutArgList() throws Exception { |
|
|
|
|
Method desiredMethod = MethodSignatureBean.class.getMethod("doSomethingElse", String.class, int.class); |
|
|
|
|
assertSignatureEquals(desiredMethod, "doSomethingElse"); |
|
|
|
|
assertThat(BeanUtils.resolveSignature("doSomethingElse()", MethodSignatureBean.class)).isNull(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@Test |
|
|
|
|
void resolveTypedSignature() throws Exception { |
|
|
|
|
Method desiredMethod = MethodSignatureBean.class.getMethod("doSomethingElse", String.class, int.class); |
|
|
|
|
assertSignatureEquals(desiredMethod, "doSomethingElse(java.lang.String, int)"); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@Test |
|
|
|
|
void resolveOverloadedSignature() throws Exception { |
|
|
|
|
// test resolve with no args
|
|
|
|
|
Method desiredMethod = MethodSignatureBean.class.getMethod("overloaded"); |
|
|
|
|
assertSignatureEquals(desiredMethod, "overloaded()"); |
|
|
|
|
|
|
|
|
|
// resolve with single arg
|
|
|
|
|
desiredMethod = MethodSignatureBean.class.getMethod("overloaded", String.class); |
|
|
|
|
assertSignatureEquals(desiredMethod, "overloaded(java.lang.String)"); |
|
|
|
|
|
|
|
|
|
// resolve with two args
|
|
|
|
|
desiredMethod = MethodSignatureBean.class.getMethod("overloaded", String.class, BeanFactory.class); |
|
|
|
|
assertSignatureEquals(desiredMethod, "overloaded(java.lang.String, org.springframework.beans.factory.BeanFactory)"); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@Test |
|
|
|
|
void resolveSignatureWithArray() throws Exception { |
|
|
|
|
Method desiredMethod = MethodSignatureBean.class.getMethod("doSomethingWithAnArray", String[].class); |
|
|
|
|
assertSignatureEquals(desiredMethod, "doSomethingWithAnArray(java.lang.String[])"); |
|
|
|
|
|
|
|
|
|
desiredMethod = MethodSignatureBean.class.getMethod("doSomethingWithAMultiDimensionalArray", String[][].class); |
|
|
|
|
assertSignatureEquals(desiredMethod, "doSomethingWithAMultiDimensionalArray(java.lang.String[][])"); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@Test // gh-10731
|
|
|
|
|
void propertyDescriptorShouldMatchWithCachedDescriptors() { |
|
|
|
|
PropertyDescriptor[] descrs = BeanUtils.getPropertyDescriptors(Bean.class); |
|
|
|
|
|
|
|
|
|
PropertyDescriptor keyDescr = BeanUtils.getPropertyDescriptor(Bean.class, "value"); |
|
|
|
|
assertThat(keyDescr.getPropertyType()).isEqualTo(String.class); |
|
|
|
|
for (PropertyDescriptor propertyDescriptor : descrs) { |
|
|
|
|
if (propertyDescriptor.getName().equals(keyDescr.getName())) { |
|
|
|
|
assertThat(propertyDescriptor.getPropertyType()).as(propertyDescriptor.getName() + " has unexpected type").isEqualTo(keyDescr.getPropertyType()); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@ParameterizedTest |
|
|
|
|
@ValueSource(classes = { |
|
|
|
|
boolean.class, char.class, byte.class, short.class, int.class, long.class, float.class, double.class, |
|
|
|
|
Boolean.class, Character.class, Byte.class, Short.class, Integer.class, Long.class, Float.class, Double.class, |
|
|
|
|
DayOfWeek.class, String.class, LocalDateTime.class, Date.class, UUID.class, URI.class, URL.class, |
|
|
|
|
Locale.class, Class.class |
|
|
|
|
}) |
|
|
|
|
void isSimpleValueType(Class<?> type) { |
|
|
|
|
assertThat(BeanUtils.isSimpleValueType(type)).as("Type [" + type.getName() + "] should be a simple value type").isTrue(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@ParameterizedTest |
|
|
|
|
@ValueSource(classes = { int[].class, Object.class, List.class, void.class, Void.class }) |
|
|
|
|
void isNotSimpleValueType(Class<?> type) { |
|
|
|
|
assertThat(BeanUtils.isSimpleValueType(type)).as("Type [" + type.getName() + "] should not be a simple value type").isFalse(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@ParameterizedTest |
|
|
|
|
@ValueSource(classes = { |
|
|
|
|
boolean.class, char.class, byte.class, short.class, int.class, long.class, float.class, double.class, |
|
|
|
|
Boolean.class, Character.class, Byte.class, Short.class, Integer.class, Long.class, Float.class, Double.class, |
|
|
|
|
DayOfWeek.class, String.class, LocalDateTime.class, Date.class, UUID.class, URI.class, URL.class, |
|
|
|
|
Locale.class, Class.class, boolean[].class, Boolean[].class, LocalDateTime[].class, Date[].class |
|
|
|
|
}) |
|
|
|
|
void isSimpleProperty(Class<?> type) { |
|
|
|
|
assertThat(BeanUtils.isSimpleProperty(type)).as("Type [" + type.getName() + "] should be a simple property").isTrue(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@ParameterizedTest |
|
|
|
|
@ValueSource(classes = { Object.class, List.class, void.class, Void.class }) |
|
|
|
|
void isNotSimpleProperty(Class<?> type) { |
|
|
|
|
assertThat(BeanUtils.isSimpleProperty(type)).as("Type [" + type.getName() + "] should not be a simple property").isFalse(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@Test |
|
|
|
|
void resolveMultipleRecordPublicConstructor() throws NoSuchMethodException { |
|
|
|
|
assertThat(BeanUtils.getResolvableConstructor(RecordWithMultiplePublicConstructors.class)) |
|
|
|
|
.isEqualTo(RecordWithMultiplePublicConstructors.class.getDeclaredConstructor(String.class, String.class)); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@Test |
|
|
|
|
void resolveMultipleRecordePackagePrivateConstructor() throws NoSuchMethodException { |
|
|
|
|
assertThat(BeanUtils.getResolvableConstructor(RecordWithMultiplePackagePrivateConstructors.class)) |
|
|
|
|
.isEqualTo(RecordWithMultiplePackagePrivateConstructors.class.getDeclaredConstructor(String.class, String.class)); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
private void assertSignatureEquals(Method desiredMethod, String signature) { |
|
|
|
|
assertThat(BeanUtils.resolveSignature(signature, MethodSignatureBean.class)).isEqualTo(desiredMethod); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@Nested |
|
|
|
|
class CopyPropertiesTests { |
|
|
|
|
|
|
|
|
|
@Test |
|
|
|
|
void copyProperties() throws Exception { |
|
|
|
|
TestBean tb = new TestBean(); |
|
|
|
|
@ -344,7 +468,7 @@ class BeanUtilsTests {
@@ -344,7 +468,7 @@ class BeanUtilsTests {
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@Test // gh-32888
|
|
|
|
|
public void copyPropertiesWithGenericCglibClass() { |
|
|
|
|
void copyPropertiesWithGenericCglibClass() { |
|
|
|
|
Enhancer enhancer = new Enhancer(); |
|
|
|
|
enhancer.setSuperclass(User.class); |
|
|
|
|
enhancer.setCallback((MethodInterceptor) (obj, method, args, proxy) -> proxy.invokeSuper(obj, args)); |
|
|
|
|
@ -417,124 +541,6 @@ class BeanUtilsTests {
@@ -417,124 +541,6 @@ class BeanUtilsTests {
|
|
|
|
|
assertThat((boolean) target.getFlag1()).isTrue(); |
|
|
|
|
assertThat(target.getFlag2()).isTrue(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@Test |
|
|
|
|
void resolveSimpleSignature() throws Exception { |
|
|
|
|
Method desiredMethod = MethodSignatureBean.class.getMethod("doSomething"); |
|
|
|
|
assertSignatureEquals(desiredMethod, "doSomething"); |
|
|
|
|
assertSignatureEquals(desiredMethod, "doSomething()"); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@Test |
|
|
|
|
void resolveInvalidSignatureEndParen() { |
|
|
|
|
assertThatIllegalArgumentException().isThrownBy(() -> |
|
|
|
|
BeanUtils.resolveSignature("doSomething(", MethodSignatureBean.class)); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@Test |
|
|
|
|
void resolveInvalidSignatureStartParen() { |
|
|
|
|
assertThatIllegalArgumentException().isThrownBy(() -> |
|
|
|
|
BeanUtils.resolveSignature("doSomething)", MethodSignatureBean.class)); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@Test |
|
|
|
|
void resolveWithAndWithoutArgList() throws Exception { |
|
|
|
|
Method desiredMethod = MethodSignatureBean.class.getMethod("doSomethingElse", String.class, int.class); |
|
|
|
|
assertSignatureEquals(desiredMethod, "doSomethingElse"); |
|
|
|
|
assertThat(BeanUtils.resolveSignature("doSomethingElse()", MethodSignatureBean.class)).isNull(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@Test |
|
|
|
|
void resolveTypedSignature() throws Exception { |
|
|
|
|
Method desiredMethod = MethodSignatureBean.class.getMethod("doSomethingElse", String.class, int.class); |
|
|
|
|
assertSignatureEquals(desiredMethod, "doSomethingElse(java.lang.String, int)"); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@Test |
|
|
|
|
void resolveOverloadedSignature() throws Exception { |
|
|
|
|
// test resolve with no args
|
|
|
|
|
Method desiredMethod = MethodSignatureBean.class.getMethod("overloaded"); |
|
|
|
|
assertSignatureEquals(desiredMethod, "overloaded()"); |
|
|
|
|
|
|
|
|
|
// resolve with single arg
|
|
|
|
|
desiredMethod = MethodSignatureBean.class.getMethod("overloaded", String.class); |
|
|
|
|
assertSignatureEquals(desiredMethod, "overloaded(java.lang.String)"); |
|
|
|
|
|
|
|
|
|
// resolve with two args
|
|
|
|
|
desiredMethod = MethodSignatureBean.class.getMethod("overloaded", String.class, BeanFactory.class); |
|
|
|
|
assertSignatureEquals(desiredMethod, "overloaded(java.lang.String, org.springframework.beans.factory.BeanFactory)"); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@Test |
|
|
|
|
void resolveSignatureWithArray() throws Exception { |
|
|
|
|
Method desiredMethod = MethodSignatureBean.class.getMethod("doSomethingWithAnArray", String[].class); |
|
|
|
|
assertSignatureEquals(desiredMethod, "doSomethingWithAnArray(java.lang.String[])"); |
|
|
|
|
|
|
|
|
|
desiredMethod = MethodSignatureBean.class.getMethod("doSomethingWithAMultiDimensionalArray", String[][].class); |
|
|
|
|
assertSignatureEquals(desiredMethod, "doSomethingWithAMultiDimensionalArray(java.lang.String[][])"); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@Test // gh-10731
|
|
|
|
|
void propertyDescriptorShouldMatchWithCachedDescriptors() { |
|
|
|
|
PropertyDescriptor[] descrs = BeanUtils.getPropertyDescriptors(Bean.class); |
|
|
|
|
|
|
|
|
|
PropertyDescriptor keyDescr = BeanUtils.getPropertyDescriptor(Bean.class, "value"); |
|
|
|
|
assertThat(keyDescr.getPropertyType()).isEqualTo(String.class); |
|
|
|
|
for (PropertyDescriptor propertyDescriptor : descrs) { |
|
|
|
|
if (propertyDescriptor.getName().equals(keyDescr.getName())) { |
|
|
|
|
assertThat(propertyDescriptor.getPropertyType()).as(propertyDescriptor.getName() + " has unexpected type").isEqualTo(keyDescr.getPropertyType()); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@ParameterizedTest |
|
|
|
|
@ValueSource(classes = { |
|
|
|
|
boolean.class, char.class, byte.class, short.class, int.class, long.class, float.class, double.class, |
|
|
|
|
Boolean.class, Character.class, Byte.class, Short.class, Integer.class, Long.class, Float.class, Double.class, |
|
|
|
|
DayOfWeek.class, String.class, LocalDateTime.class, Date.class, UUID.class, URI.class, URL.class, |
|
|
|
|
Locale.class, Class.class |
|
|
|
|
}) |
|
|
|
|
void isSimpleValueType(Class<?> type) { |
|
|
|
|
assertThat(BeanUtils.isSimpleValueType(type)).as("Type [" + type.getName() + "] should be a simple value type").isTrue(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@ParameterizedTest |
|
|
|
|
@ValueSource(classes = { int[].class, Object.class, List.class, void.class, Void.class }) |
|
|
|
|
void isNotSimpleValueType(Class<?> type) { |
|
|
|
|
assertThat(BeanUtils.isSimpleValueType(type)).as("Type [" + type.getName() + "] should not be a simple value type").isFalse(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@ParameterizedTest |
|
|
|
|
@ValueSource(classes = { |
|
|
|
|
boolean.class, char.class, byte.class, short.class, int.class, long.class, float.class, double.class, |
|
|
|
|
Boolean.class, Character.class, Byte.class, Short.class, Integer.class, Long.class, Float.class, Double.class, |
|
|
|
|
DayOfWeek.class, String.class, LocalDateTime.class, Date.class, UUID.class, URI.class, URL.class, |
|
|
|
|
Locale.class, Class.class, boolean[].class, Boolean[].class, LocalDateTime[].class, Date[].class |
|
|
|
|
}) |
|
|
|
|
void isSimpleProperty(Class<?> type) { |
|
|
|
|
assertThat(BeanUtils.isSimpleProperty(type)).as("Type [" + type.getName() + "] should be a simple property").isTrue(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@ParameterizedTest |
|
|
|
|
@ValueSource(classes = { Object.class, List.class, void.class, Void.class }) |
|
|
|
|
void isNotSimpleProperty(Class<?> type) { |
|
|
|
|
assertThat(BeanUtils.isSimpleProperty(type)).as("Type [" + type.getName() + "] should not be a simple property").isFalse(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@Test |
|
|
|
|
void resolveMultipleRecordPublicConstructor() throws NoSuchMethodException { |
|
|
|
|
assertThat(BeanUtils.getResolvableConstructor(RecordWithMultiplePublicConstructors.class)) |
|
|
|
|
.isEqualTo(RecordWithMultiplePublicConstructors.class.getDeclaredConstructor(String.class, String.class)); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@Test |
|
|
|
|
void resolveMultipleRecordePackagePrivateConstructor() throws NoSuchMethodException { |
|
|
|
|
assertThat(BeanUtils.getResolvableConstructor(RecordWithMultiplePackagePrivateConstructors.class)) |
|
|
|
|
.isEqualTo(RecordWithMultiplePackagePrivateConstructors.class.getDeclaredConstructor(String.class, String.class)); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
private void assertSignatureEquals(Method desiredMethod, String signature) { |
|
|
|
|
assertThat(BeanUtils.resolveSignature(signature, MethodSignatureBean.class)).isEqualTo(desiredMethod); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|