23
23
import java .lang .reflect .InvocationTargetException ;
24
24
import java .lang .reflect .Method ;
25
25
import java .lang .reflect .Modifier ;
26
+ import java .lang .reflect .Type ;
26
27
import java .net .URI ;
27
28
import java .net .URL ;
28
29
import java .time .temporal .Temporal ;
@@ -615,8 +616,8 @@ public static Class<?> findPropertyType(String propertyName, @Nullable Class<?>.
615
616
* @return a corresponding MethodParameter object
616
617
*/
617
618
public static MethodParameter getWriteMethodParameter (PropertyDescriptor pd ) {
618
- if (pd instanceof GenericTypeAwarePropertyDescriptor typeAwarePd ) {
619
- return new MethodParameter (typeAwarePd .getWriteMethodParameter ());
619
+ if (pd instanceof GenericTypeAwarePropertyDescriptor gpd ) {
620
+ return new MethodParameter (gpd .getWriteMethodParameter ());
620
621
}
621
622
else {
622
623
Method writeMethod = pd .getWriteMethod ();
@@ -787,38 +788,28 @@ private static void copyProperties(Object source, Object target, @Nullable Class
787
788
if (editable != null ) {
788
789
if (!editable .isInstance (target )) {
789
790
throw new IllegalArgumentException ("Target class [" + target .getClass ().getName () +
790
- "] not assignable to Editable class [" + editable .getName () + "]" );
791
+ "] not assignable to editable class [" + editable .getName () + "]" );
791
792
}
792
793
actualEditable = editable ;
793
794
}
794
795
PropertyDescriptor [] targetPds = getPropertyDescriptors (actualEditable );
795
796
Set <String > ignoredProps = (ignoreProperties != null ? new HashSet <>(Arrays .asList (ignoreProperties )) : null );
797
+ CachedIntrospectionResults sourceResults = (actualEditable != source .getClass () ?
798
+ CachedIntrospectionResults .forClass (source .getClass ()) : null );
796
799
797
800
for (PropertyDescriptor targetPd : targetPds ) {
798
801
Method writeMethod = targetPd .getWriteMethod ();
799
802
if (writeMethod != null && (ignoredProps == null || !ignoredProps .contains (targetPd .getName ()))) {
800
- PropertyDescriptor sourcePd = getPropertyDescriptor (source .getClass (), targetPd .getName ());
803
+ PropertyDescriptor sourcePd = (sourceResults != null ?
804
+ sourceResults .getPropertyDescriptor (targetPd .getName ()) : targetPd );
801
805
if (sourcePd != null ) {
802
806
Method readMethod = sourcePd .getReadMethod ();
803
807
if (readMethod != null ) {
804
- ResolvableType sourceResolvableType = ResolvableType .forMethodReturnType (readMethod );
805
- ResolvableType targetResolvableType = ResolvableType .forMethodParameter (writeMethod , 0 );
806
-
807
- // Ignore generic types in assignable check if either ResolvableType has unresolvable generics.
808
- boolean isAssignable =
809
- (sourceResolvableType .hasUnresolvableGenerics () || targetResolvableType .hasUnresolvableGenerics () ?
810
- ClassUtils .isAssignable (writeMethod .getParameterTypes ()[0 ], readMethod .getReturnType ()) :
811
- targetResolvableType .isAssignableFrom (sourceResolvableType ));
812
-
813
- if (isAssignable ) {
808
+ if (isAssignable (writeMethod , readMethod )) {
814
809
try {
815
- if (!Modifier .isPublic (readMethod .getDeclaringClass ().getModifiers ())) {
816
- readMethod .setAccessible (true );
817
- }
810
+ ReflectionUtils .makeAccessible (readMethod );
818
811
Object value = readMethod .invoke (source );
819
- if (!Modifier .isPublic (writeMethod .getDeclaringClass ().getModifiers ())) {
820
- writeMethod .setAccessible (true );
821
- }
812
+ ReflectionUtils .makeAccessible (writeMethod );
822
813
writeMethod .invoke (target , value );
823
814
}
824
815
catch (Throwable ex ) {
@@ -832,6 +823,24 @@ private static void copyProperties(Object source, Object target, @Nullable Class
832
823
}
833
824
}
834
825
826
+ private static boolean isAssignable (Method writeMethod , Method readMethod ) {
827
+ Type paramType = writeMethod .getGenericParameterTypes ()[0 ];
828
+ if (paramType instanceof Class <?> clazz ) {
829
+ return ClassUtils .isAssignable (clazz , readMethod .getReturnType ());
830
+ }
831
+ else if (paramType .equals (readMethod .getGenericReturnType ())) {
832
+ return true ;
833
+ }
834
+ else {
835
+ ResolvableType sourceType = ResolvableType .forMethodReturnType (readMethod );
836
+ ResolvableType targetType = ResolvableType .forMethodParameter (writeMethod , 0 );
837
+ // Ignore generic types in assignable check if either ResolvableType has unresolvable generics.
838
+ return (sourceType .hasUnresolvableGenerics () || targetType .hasUnresolvableGenerics () ?
839
+ ClassUtils .isAssignable (writeMethod .getParameterTypes ()[0 ], readMethod .getReturnType ()) :
840
+ targetType .isAssignableFrom (sourceType ));
841
+ }
842
+ }
843
+
835
844
836
845
/**
837
846
* Inner class to avoid a hard dependency on Kotlin at runtime.
@@ -896,7 +905,6 @@ public static <T> T instantiateClass(Constructor<T> ctor, Object... args)
896
905
}
897
906
return kotlinConstructor .callBy (argParameters );
898
907
}
899
-
900
908
}
901
909
902
910
}
0 commit comments