BeanUtils.copyProperties 導致的 ClassCastException

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,所以會導致類型不一致問題。

那麼如何可以解決這個問題呢?

  1. 不解決,在應用的時候注意一點
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章