static class Foo {
private List<String> list;
public List<String> getList() {
return list;
}
public void setList(List<String> list) {
this.list = list;
}
}
static class Bar {
private List<Integer> list;
public List<Integer> getList() {
return list;
}
public void setList(List<Integer> list) {
this.list = list;
}
}
public static void main(String[] args) {
Foo foo = new Foo();
List<String> list = new ArrayList<>();
list.add("asdasd");
list.add("asdasd");
foo.setList(list);
Bar bar = new Bar();
// 重點
BeanUtils.copyProperties(foo, bar);
bar.getList().forEach(item -> {
System.out.println(item);
});
}
這個一看是不是沒有任何問題,java編譯器也過的去,運行會不會報錯呢?
答案就是會報錯!!!
Exception in thread "main" java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Integer
at java.util.ArrayList.forEach(ArrayList.java:1249)
at com.wuhulala.mybatis.BeanUtilsTest.main(BeanUtilsTest.java:49)
爲啥會報錯呢???
先看一下源碼
private static void copyProperties(Object source, Object target, Class<?> editable, String... ignoreProperties)
throws BeansException {
Assert.notNull(source, "Source must not be null");
Assert.notNull(target, "Target must not be null");
Class<?> actualEditable = target.getClass();
if (editable != null) {
if (!editable.isInstance(target)) {
throw new IllegalArgumentException("Target class [" + target.getClass().getName() +
"] not assignable to Editable class [" + editable.getName() + "]");
}
actualEditable = editable;
}
PropertyDescriptor[] targetPds = getPropertyDescriptors(actualEditable);
List<String> ignoreList = (ignoreProperties != null ? Arrays.asList(ignoreProperties) : 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 (sourcePd != null) {
Method readMethod = sourcePd.getReadMethod();
// 重點就是這裏裏面使用的ClassUtils.isAssignable裏面
if (readMethod != null &&
ClassUtils.isAssignable(writeMethod.getParameterTypes()[0], readMethod.getReturnType())) {
try {
if (!Modifier.isPublic(readMethod.getDeclaringClass().getModifiers())) {
readMethod.setAccessible(true);
}
Object value = readMethod.invoke(source);
if (!Modifier.isPublic(writeMethod.getDeclaringClass().getModifiers())) {
writeMethod.setAccessible(true);
}
writeMethod.invoke(target, value);
}
catch (Throwable ex) {
throw new FatalBeanException(
"Could not copy property '" + targetPd.getName() + "' from source to target", ex);
}
}
}
}
}
}
重點就是這裏裏面使用的ClassUtils.isAssignable,我們來看一下我們的bar的寫方法的參數類型和foo讀方法的返回類型
可以看到都是java.util.List。那麼這個也解釋的通了。
其實這裏就是因爲Java
的泛型擦除原理,所以在copyProperties
方法認爲他們兩個list
都是一致的,但是在實際應用的時候,卻是使用的Integer
,所以會導致類型不一致問題。
那麼如何可以解決這個問題呢?
- 不解決,在應用的時候注意一點