论坛首页 Java企业应用论坛

BeanUtils.copyProperties在一个java源文件有多个类的情况下失败的原因

浏览 4497 次
精华帖 (1) :: 良好帖 (1) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2009-05-27   最后修改:2009-05-27
最近在copybean时,无意中遇到一个问题,一个java源文件中存在几个类的情况下,BeanUtils.copyProperties不能成功,整理如下,供大家探讨。

情况1(copy失败)、(一个java源文件中存在3个类),如下:

BeanCopy.java
package com.hp9016.test.copyBean;

import java.lang.reflect.InvocationTargetException;

import org.apache.commons.beanutils.BeanUtils;

public class BeanCopy {

    public static void main( String[] args ) {
        BeanFrom from = new BeanFrom();
        from.setTestString( "testString" );
        BeanTo to = new BeanTo();
        
        try {
            BeanUtils.copyProperties( to, from );
        } catch ( IllegalAccessException e ) {
            e.printStackTrace();
        } catch ( InvocationTargetException e ) {
            e.printStackTrace();
        }

        System.out.println( to.getTestString() );
    }
}

class BeanFrom {

    private String _testString;

    public String getTestString() {
        return _testString;
    }

    public void setTestString( String testString ) {
        this._testString = testString;
    }
}

class BeanTo {

    private String _testString;

    public String getTestString() {
        return _testString;
    }

    public void setTestString( String testString ) {
        this._testString = testString;
    }
}

输出的是:null!

但是把这三个类分别写在三个源文件中就没有关系,像这样
情况2(copy成功)、

BeanCopy.java
package com.hp9016.test.copyBean;

import java.lang.reflect.InvocationTargetException;

import org.apache.commons.beanutils.BeanUtils;

public class BeanCopy {

    public static void main( String[] args ) {
        ...代码同上
    }
}

BeanFrom.java
package com.hp9016.test.copyBean;

public class BeanFrom {
    ...代码同上
}


BeanTo.java
package com.hp9016.test.copyBean;

public class BeanTo {
    ...代码同上
}

输出:testString
正确。


我又试了下,
情况3(出现异常)
入口类和源类(即BeanCopy和BeanFrom类)写在一个源文件(即BeanCopy.java)中,则会抛出
[java.lang.reflect.InvocationTargetException: Cannot set testString]的异常。

情况4(copy失败)
入口类和目标类(即BeanCopy和BeanTo类)写在一个源文件(即BeanCopy.java)中,输出的结果仍然是null

用的是1.7的jar包,commons-beanutils-1.7.0-src.zip
http://archive.apache.org/dist/commons/beanutils/source/
看来面前只能先慢慢看源码了,有科学解释的别憋着啊
   发表时间:2009-05-27  
用PropertyUtils试一下。
记得有一次遇到这个问题,用PropertyUtils解决了。
没深究什么原因,没精力啊。
0 请登录后投票
   发表时间:2009-05-27   最后修改:2009-05-27
OK,知道了,分享一下。
根本原因是BeanUtils.copyProperties在复制bean的属性时对类与方法的可见性做了限制,即只能够copy拥有public修饰符的类和方法。

    研究源码我们可以发现,org.apache.commons.beanutils.PropertyUtilsBean这个类主要就是通过java的反射机制来获得bean属性,当然这个过程会检查bean可见性和命名合法性的问题,这以前本来是BeanUtils应该做的事情,参见http://commons.apache.org/beanutils/api/org/apache/commons/beanutils/PropertyUtilsBean.html。
    而上面出现错误的原因就出在这里。在方法getSimpleProperty中,上面的情况除了情况2之外,method都不能正常获得,是null(第1125行)。原来在通过MethodUtils获得method的可见性时出现了问题,如下(MethodUtils,getAccessibleMethod,415行):
        // If the declaring class is public, we are done
        Class clazz = method.getDeclaringClass();
        if (Modifier.isPublic(clazz.getModifiers())) {
            return (method);
        }

由于在一个源文件中只能有一个类是public的,而在上面的情况中,这个类只可能是入口类。所以没有修饰符的类BeanFrom与类BeanTo的getModifiers只能为0,因为它既不是public也不是final或者其他,参见[http://java.sun.com/docs/books/jvms/second_edition/html/ClassFile.doc.html#75734]
Table 4.1
如此一来,就不能正常地返回method,导致属性的值不能被正常copy。

结论:使用BeanUtils.copyProperties作copybean的时候要注意源与目标的修饰符。为public。
0 请登录后投票
   发表时间:2009-05-27  
jander 写道
用PropertyUtils试一下。
记得有一次遇到这个问题,用PropertyUtils解决了。
没深究什么原因,没精力啊。

哎,都下班了,整天做些无脑的活,好久没有研究这样的问题了。
看来我们遇到的情况不一样,不过没有精力倒是一样呀。
ok,我把题目改了,结贴了。
0 请登录后投票
   发表时间:2010-01-08  
顶一个楼主,有次面试,我也被问到相关的问题.
by the way,BeanUtils中有直接打印出某BEAN所有属性的方法吗?暂不考虑复杂对象属性.
0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics