Avoid ResolvableType for simple assignability check in copyProperties
Closes gh-27246
This commit is contained in:
		
							parent
							
								
									7874a59771
								
							
						
					
					
						commit
						09aa59f9e7
					
				|  | @ -23,6 +23,7 @@ import java.lang.reflect.Constructor; | |||
| import java.lang.reflect.InvocationTargetException; | ||||
| import java.lang.reflect.Method; | ||||
| import java.lang.reflect.Modifier; | ||||
| import java.lang.reflect.Type; | ||||
| import java.net.URI; | ||||
| import java.net.URL; | ||||
| import java.time.temporal.Temporal; | ||||
|  | @ -615,8 +616,8 @@ public abstract class BeanUtils { | |||
| 	 * @return a corresponding MethodParameter object | ||||
| 	 */ | ||||
| 	public static MethodParameter getWriteMethodParameter(PropertyDescriptor pd) { | ||||
| 		if (pd instanceof GenericTypeAwarePropertyDescriptor typeAwarePd) { | ||||
| 			return new MethodParameter(typeAwarePd.getWriteMethodParameter()); | ||||
| 		if (pd instanceof GenericTypeAwarePropertyDescriptor gpd) { | ||||
| 			return new MethodParameter(gpd.getWriteMethodParameter()); | ||||
| 		} | ||||
| 		else { | ||||
| 			Method writeMethod = pd.getWriteMethod(); | ||||
|  | @ -787,38 +788,28 @@ public abstract class BeanUtils { | |||
| 		if (editable != null) { | ||||
| 			if (!editable.isInstance(target)) { | ||||
| 				throw new IllegalArgumentException("Target class [" + target.getClass().getName() + | ||||
| 						"] not assignable to Editable class [" + editable.getName() + "]"); | ||||
| 						"] not assignable to editable class [" + editable.getName() + "]"); | ||||
| 			} | ||||
| 			actualEditable = editable; | ||||
| 		} | ||||
| 		PropertyDescriptor[] targetPds = getPropertyDescriptors(actualEditable); | ||||
| 		Set<String> ignoredProps = (ignoreProperties != null ? new HashSet<>(Arrays.asList(ignoreProperties)) : null); | ||||
| 		CachedIntrospectionResults sourceResults = (actualEditable != source.getClass() ? | ||||
| 				CachedIntrospectionResults.forClass(source.getClass()) : null); | ||||
| 
 | ||||
| 		for (PropertyDescriptor targetPd : targetPds) { | ||||
| 			Method writeMethod = targetPd.getWriteMethod(); | ||||
| 			if (writeMethod != null && (ignoredProps == null || !ignoredProps.contains(targetPd.getName()))) { | ||||
| 				PropertyDescriptor sourcePd = getPropertyDescriptor(source.getClass(), targetPd.getName()); | ||||
| 				PropertyDescriptor sourcePd = (sourceResults != null ? | ||||
| 						sourceResults.getPropertyDescriptor(targetPd.getName()) : targetPd); | ||||
| 				if (sourcePd != null) { | ||||
| 					Method readMethod = sourcePd.getReadMethod(); | ||||
| 					if (readMethod != null) { | ||||
| 						ResolvableType sourceResolvableType = ResolvableType.forMethodReturnType(readMethod); | ||||
| 						ResolvableType targetResolvableType = ResolvableType.forMethodParameter(writeMethod, 0); | ||||
| 
 | ||||
| 						// Ignore generic types in assignable check if either ResolvableType has unresolvable generics. | ||||
| 						boolean isAssignable = | ||||
| 								(sourceResolvableType.hasUnresolvableGenerics() || targetResolvableType.hasUnresolvableGenerics() ? | ||||
| 										ClassUtils.isAssignable(writeMethod.getParameterTypes()[0], readMethod.getReturnType()) : | ||||
| 										targetResolvableType.isAssignableFrom(sourceResolvableType)); | ||||
| 
 | ||||
| 						if (isAssignable) { | ||||
| 						if (isAssignable(writeMethod, readMethod)) { | ||||
| 							try { | ||||
| 								if (!Modifier.isPublic(readMethod.getDeclaringClass().getModifiers())) { | ||||
| 									readMethod.setAccessible(true); | ||||
| 								} | ||||
| 								ReflectionUtils.makeAccessible(readMethod); | ||||
| 								Object value = readMethod.invoke(source); | ||||
| 								if (!Modifier.isPublic(writeMethod.getDeclaringClass().getModifiers())) { | ||||
| 									writeMethod.setAccessible(true); | ||||
| 								} | ||||
| 								ReflectionUtils.makeAccessible(writeMethod); | ||||
| 								writeMethod.invoke(target, value); | ||||
| 							} | ||||
| 							catch (Throwable ex) { | ||||
|  | @ -832,6 +823,24 @@ public abstract class BeanUtils { | |||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	private static boolean isAssignable(Method writeMethod, Method readMethod) { | ||||
| 		Type paramType = writeMethod.getGenericParameterTypes()[0]; | ||||
| 		if (paramType instanceof Class<?> clazz) { | ||||
| 			return ClassUtils.isAssignable(clazz, readMethod.getReturnType()); | ||||
| 		} | ||||
| 		else if (paramType.equals(readMethod.getGenericReturnType())) { | ||||
| 			return true; | ||||
| 		} | ||||
| 		else { | ||||
| 			ResolvableType sourceType = ResolvableType.forMethodReturnType(readMethod); | ||||
| 			ResolvableType targetType = ResolvableType.forMethodParameter(writeMethod, 0); | ||||
| 			// Ignore generic types in assignable check if either ResolvableType has unresolvable generics. | ||||
| 			return (sourceType.hasUnresolvableGenerics() || targetType.hasUnresolvableGenerics() ? | ||||
| 					ClassUtils.isAssignable(writeMethod.getParameterTypes()[0], readMethod.getReturnType()) : | ||||
| 					targetType.isAssignableFrom(sourceType)); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 
 | ||||
| 	/** | ||||
| 	 * Inner class to avoid a hard dependency on Kotlin at runtime. | ||||
|  | @ -896,7 +905,6 @@ public abstract class BeanUtils { | |||
| 			} | ||||
| 			return kotlinConstructor.callBy(argParameters); | ||||
| 		} | ||||
| 
 | ||||
| 	} | ||||
| 
 | ||||
| } | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue