|
19 | 19 | import java.beans.PropertyDescriptor;
|
20 | 20 | import java.beans.PropertyEditor;
|
21 | 21 | import java.lang.reflect.Constructor;
|
22 |
| -import java.lang.reflect.Field; |
23 | 22 | import java.lang.reflect.InvocationTargetException;
|
24 | 23 | import java.lang.reflect.Method;
|
25 | 24 | import java.lang.reflect.Modifier;
|
|
46 | 45 |
|
47 | 46 | import org.springframework.core.KotlinDetector;
|
48 | 47 | import org.springframework.core.MethodParameter;
|
49 |
| -import org.springframework.core.convert.TypeDescriptor; |
| 48 | +import org.springframework.core.ResolvableType; |
50 | 49 | import org.springframework.lang.Nullable;
|
51 | 50 | import org.springframework.util.Assert;
|
52 | 51 | import org.springframework.util.ClassUtils;
|
@@ -683,11 +682,12 @@ public static void copyProperties(Object source, Object target, String... ignore
|
683 | 682 | }
|
684 | 683 |
|
685 | 684 | /**
|
686 |
| - * Copy the property values of the given source bean into the given target bean |
687 |
| - * and ignored if |
| 685 | + * Copy the property values of the given source bean into the given target bean. |
688 | 686 | * <p>Note: The source and target classes do not have to match or even be derived
|
689 | 687 | * from each other, as long as the properties match. Any bean properties that the
|
690 | 688 | * source bean exposes but the target bean does not will silently be ignored.
|
| 689 | + * <p>As of Spring Framework 5.3, this method honors generic type information |
| 690 | + * when matching properties in the source and target objects. |
691 | 691 | * @param source the source bean
|
692 | 692 | * @param target the target bean
|
693 | 693 | * @param editable the class (or interface) to restrict property setting to
|
@@ -717,30 +717,25 @@ private static void copyProperties(Object source, Object target, @Nullable Class
|
717 | 717 | if (writeMethod != null && (ignoreList == null || !ignoreList.contains(targetPd.getName()))) {
|
718 | 718 | PropertyDescriptor sourcePd = getPropertyDescriptor(source.getClass(), targetPd.getName());
|
719 | 719 | if (sourcePd != null) {
|
720 |
| - Field sourcefield = ReflectionUtils.findField(source.getClass(), sourcePd.getName()); |
721 |
| - Field targetfield = ReflectionUtils.findField(target.getClass(), targetPd.getName()); |
722 |
| - |
723 |
| - TypeDescriptor sourceTypeDescriptor = new TypeDescriptor(sourcefield); |
724 |
| - TypeDescriptor targetTypeDescriptor = new TypeDescriptor(targetfield); |
725 |
| - |
726 | 720 | Method readMethod = sourcePd.getReadMethod();
|
727 |
| - |
728 |
| - if (readMethod != null && |
729 |
| - ClassUtils.isAssignable(writeMethod.getParameterTypes()[0], readMethod.getReturnType()) && |
730 |
| - sourceTypeDescriptor.getResolvableType().equals(targetTypeDescriptor.getResolvableType())) { |
731 |
| - try { |
732 |
| - if (!Modifier.isPublic(readMethod.getDeclaringClass().getModifiers())) { |
733 |
| - readMethod.setAccessible(true); |
| 721 | + if (readMethod != null) { |
| 722 | + ResolvableType sourceResolvableType = ResolvableType.forMethodReturnType(readMethod); |
| 723 | + ResolvableType targetResolvableType = ResolvableType.forMethodParameter(writeMethod, 0); |
| 724 | + if (targetResolvableType.isAssignableFrom(sourceResolvableType)) { |
| 725 | + try { |
| 726 | + if (!Modifier.isPublic(readMethod.getDeclaringClass().getModifiers())) { |
| 727 | + readMethod.setAccessible(true); |
| 728 | + } |
| 729 | + Object value = readMethod.invoke(source); |
| 730 | + if (!Modifier.isPublic(writeMethod.getDeclaringClass().getModifiers())) { |
| 731 | + writeMethod.setAccessible(true); |
| 732 | + } |
| 733 | + writeMethod.invoke(target, value); |
| 734 | + } |
| 735 | + catch (Throwable ex) { |
| 736 | + throw new FatalBeanException( |
| 737 | + "Could not copy property '" + targetPd.getName() + "' from source to target", ex); |
734 | 738 | }
|
735 |
| - Object value = readMethod.invoke(source); |
736 |
| - if (!Modifier.isPublic(writeMethod.getDeclaringClass().getModifiers())) { |
737 |
| - writeMethod.setAccessible(true); |
738 |
| - } |
739 |
| - writeMethod.invoke(target, value); |
740 |
| - } |
741 |
| - catch (Throwable ex) { |
742 |
| - throw new FatalBeanException( |
743 |
| - "Could not copy property '" + targetPd.getName() + "' from source to target", ex); |
744 | 739 | }
|
745 | 740 | }
|
746 | 741 | }
|
|
0 commit comments