用该方法复制时,只要属性名一样,属性类一样,就能复制成功,而不管泛型是否相同。比如下面这段代码:
public class Main {
public static void main(String[] args){
SourceClass source = new SourceClass();
source.getCollection.add("aaa");
TargetClass target = new TargetClass();
BeanUtils.copyProperties(source, target);
System.out.println(target.getCollection.size());
}
}
class SourceClass {
private Collection<String> collection = new ArrayList<>();
public Collection<String> getCollection() {
return collection;
}
public void setCollection(Collection<String> collection) {
this.collection = collection;
}
}
class TargetClass {
private Collection<Long> collection = new ArrayList<>();
public Collection<Long> getCollection() {
return collection;
}
public void setCollection(Collection<Long> collection) {
this.collection = collection;
}
}
输出将是1,因为复制成功了。这不是我们想要的结果,因为会导致类型错误。一种办法是通过多传一个String[]参数,忽略掉这个字段。但我想要的是彻底解决问题,所以写了写面的这个方法:
public class BeanUtils {
public static void copyProperties(Object source, Object target) {
copyProperties(source, target, null);
}
public static void copyProperties(Object source, Object target,
String[] ignoreProperties) {
Assert.notNull(source, "Source must not be null");
Assert.notNull(target, "Target must not be null");
Class<?> targetClass = target.getClass();
Field[] targetFields = targetClass.getDeclaredFields();
List<String> ignoreList = ignoreProperties == null ? null : Arrays
.asList(ignoreProperties);
for (Field targetField : targetFields) {
String targetFieldName = targetField.getName();
Method writeMethod = getWriteMethod(targetField);
if (writeMethod == null
|| (ignoreList != null && ignoreList.contains(targetFieldName))) {
continue;
}
Field sourceField = null;
try {
sourceField = source.getClass().getDeclaredField(targetFieldName);
} catch (NoSuchFieldException | SecurityException e1) {
continue;
}
ParameterizedType sourceGenericType = (ParameterizedType) sourceField
.getGenericType();
ParameterizedType targetGenericType = (ParameterizedType) targetField
.getGenericType();
if (!genericTypeEquals(sourceGenericType, targetGenericType)) {
continue;
}
Method readMethod = getReadMethod(sourceField);
if (sourceField == null || readMethod == null) {
continue;
}
Object value = null;
try {
value = readMethod.invoke(source);
writeMethod.invoke(target, value);
} catch (IllegalAccessException | IllegalArgumentException
| InvocationTargetException e) {}
}
}
// 判断字段泛型是否相同
private static boolean genericTypeEquals(ParameterizedType sourceGenericType,
ParameterizedType targetGenericType) {
Type[] sourceTypes = sourceGenericType.getActualTypeArguments();
Type[] targetTypes = targetGenericType.getActualTypeArguments();
if (sourceTypes == null) {
if (targetTypes == null) {
return true;
} else {
return false;
}
} else {
if (targetTypes == null) {
return false;
} else {
int lengthS = sourceTypes.length;
int lengthT = targetTypes.length;
if (lengthS != lengthT) {
return false;
} else {
for (int i = 0; i < lengthS; i++) {
if (!sourceTypes[i].equals(targetTypes[i])) {
return false;
}
}
return true;
}
}
}
}
// 获取get方法或者is方法(boolean)
private static Method getReadMethod(Field sourceField) {
Method method = null;
Class<?> declaringClass = sourceField.getDeclaringClass();
String fieldName = StringUtils.capitalize(sourceField.getName());
try {
method = declaringClass.getMethod("get" + fieldName);
} catch (NoSuchMethodException | SecurityException e) {}
try {
method = declaringClass.getMethod("is" + fieldName);
} catch (NoSuchMethodException | SecurityException e) {}
return method;
}
// 获取set方法
private static Method getWriteMethod(Field targetField) {
Method method = null;
Class<?> declaringClass = targetField.getDeclaringClass();
String fieldName = StringUtils.capitalize(targetField.getName());
try {
method = declaringClass.getMethod("set" + fieldName, targetField.getType());
} catch (NoSuchMethodException | SecurityException e) {}
return method;
}
}
彻底的解决了问题。