|
|
|
|
@ -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; |
|
|
|
|
@ -30,6 +31,7 @@ import java.util.Arrays;
@@ -30,6 +31,7 @@ import java.util.Arrays;
|
|
|
|
|
import java.util.Collections; |
|
|
|
|
import java.util.Date; |
|
|
|
|
import java.util.HashMap; |
|
|
|
|
import java.util.HashSet; |
|
|
|
|
import java.util.List; |
|
|
|
|
import java.util.Locale; |
|
|
|
|
import java.util.Map; |
|
|
|
|
@ -787,38 +789,28 @@ public abstract class BeanUtils {
@@ -787,38 +789,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); |
|
|
|
|
List<String> ignoreList = (ignoreProperties != null ? Arrays.asList(ignoreProperties) : null); |
|
|
|
|
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 && (ignoreList == null || !ignoreList.contains(targetPd.getName()))) { |
|
|
|
|
PropertyDescriptor sourcePd = getPropertyDescriptor(source.getClass(), targetPd.getName()); |
|
|
|
|
if (writeMethod != null && (ignoredProps == null || !ignoredProps.contains(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 +824,24 @@ public abstract class BeanUtils {
@@ -832,6 +824,24 @@ public abstract class BeanUtils {
|
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
private static boolean isAssignable(Method writeMethod, Method readMethod) { |
|
|
|
|
Type paramType = writeMethod.getGenericParameterTypes()[0]; |
|
|
|
|
if (paramType instanceof Class) { |
|
|
|
|
return ClassUtils.isAssignable((Class<?>) paramType, 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. |
|
|
|
|
@ -892,7 +902,6 @@ public abstract class BeanUtils {
@@ -892,7 +902,6 @@ public abstract class BeanUtils {
|
|
|
|
|
} |
|
|
|
|
return kotlinConstructor.callBy(argParameters); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|