|
|
|
|
@ -23,6 +23,7 @@ import java.lang.reflect.Constructor;
@@ -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 {
@@ -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 {
@@ -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 {
@@ -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 {
@@ -896,7 +905,6 @@ public abstract class BeanUtils {
|
|
|
|
|
} |
|
|
|
|
return kotlinConstructor.callBy(argParameters); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|