diff --git a/spring-beans/src/main/java/org/springframework/beans/BeanUtils.java b/spring-beans/src/main/java/org/springframework/beans/BeanUtils.java index c0ab530a40..a6730b3243 100644 --- a/spring-beans/src/main/java/org/springframework/beans/BeanUtils.java +++ b/spring-beans/src/main/java/org/springframework/beans/BeanUtils.java @@ -19,6 +19,7 @@ package org.springframework.beans; import java.beans.PropertyDescriptor; import java.beans.PropertyEditor; import java.lang.reflect.Constructor; +import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Modifier; @@ -45,6 +46,7 @@ import org.apache.commons.logging.LogFactory; import org.springframework.core.KotlinDetector; import org.springframework.core.MethodParameter; +import org.springframework.core.convert.TypeDescriptor; import org.springframework.lang.Nullable; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; @@ -681,7 +683,8 @@ public abstract class BeanUtils { } /** - * Copy the property values of the given source bean into the given target bean. + * Copy the property values of the given source bean into the given target bean + * and ignored if *
Note: The source and target classes do not have to match or even be derived
* from each other, as long as the properties match. Any bean properties that the
* source bean exposes but the target bean does not will silently be ignored.
@@ -714,9 +717,17 @@ public abstract class BeanUtils {
if (writeMethod != null && (ignoreList == null || !ignoreList.contains(targetPd.getName()))) {
PropertyDescriptor sourcePd = getPropertyDescriptor(source.getClass(), targetPd.getName());
if (sourcePd != null) {
+ Field sourcefield = ReflectionUtils.findField(source.getClass(), sourcePd.getName());
+ Field targetfield = ReflectionUtils.findField(target.getClass(), targetPd.getName());
+
+ TypeDescriptor sourceTypeDescriptor = new TypeDescriptor(sourcefield);
+ TypeDescriptor targetTypeDescriptor = new TypeDescriptor(targetfield);
+
Method readMethod = sourcePd.getReadMethod();
+
if (readMethod != null &&
- ClassUtils.isAssignable(writeMethod.getParameterTypes()[0], readMethod.getReturnType())) {
+ ClassUtils.isAssignable(writeMethod.getParameterTypes()[0], readMethod.getReturnType()) &&
+ sourceTypeDescriptor.getResolvableType().equals(targetTypeDescriptor.getResolvableType())) {
try {
if (!Modifier.isPublic(readMethod.getDeclaringClass().getModifiers())) {
readMethod.setAccessible(true);
@@ -724,7 +735,7 @@ public abstract class BeanUtils {
Object value = readMethod.invoke(source);
if (!Modifier.isPublic(writeMethod.getDeclaringClass().getModifiers())) {
writeMethod.setAccessible(true);
- }
+ }
writeMethod.invoke(target, value);
}
catch (Throwable ex) {
diff --git a/spring-beans/src/test/java/org/springframework/beans/BeanUtilsTests.java b/spring-beans/src/test/java/org/springframework/beans/BeanUtilsTests.java
index 907cbbb9b2..50dd7a3c74 100644
--- a/spring-beans/src/test/java/org/springframework/beans/BeanUtilsTests.java
+++ b/spring-beans/src/test/java/org/springframework/beans/BeanUtilsTests.java
@@ -24,6 +24,7 @@ import java.net.URI;
import java.net.URL;
import java.time.DayOfWeek;
import java.time.LocalDateTime;
+import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Locale;
@@ -336,6 +337,49 @@ class BeanUtilsTests {
private void assertSignatureEquals(Method desiredMethod, String signature) {
assertThat(BeanUtils.resolveSignature(signature, MethodSignatureBean.class)).isEqualTo(desiredMethod);
}
+
+ @Test
+ void testCopiedParametersType() {
+
+ A a = new A();
+ a.getList().add(42);
+ B b = new B();
+
+ BeanUtils.copyProperties(a, b);
+
+ assertThat(a.getList()).containsOnly(42);
+
+ b.getList().forEach(n -> assertThat(n).isInstanceOf(Long.class));
+ assertThat(b.getList()).isEmpty();
+
+ }
+
+ class A {
+
+ private List