您的位置:首页 > 其它

commons - BeanUtils 使用

2010-03-29 15:02 260 查看
commons-beanutils是jakarta commons子项目中的一个软件包,其主要目的是利用反射机制对JavaBean的属性进行处理。我们知道,一个JavaBean通常包含了大量的属性,很多情况下,对JavaBean的处理导致大量get/set代码堆积,增加了代码长度和阅读代码的难度(你的薪水按代码行数计算?那千万别让老板看到此帖哦





BeanUtils是这个包里比较常用的一个工具类,这里只介绍它的copyProperties()方法。该方法定义如下:


public static void copyProperties(java.lang.Object dest,java.lang.Object orig)


throws java.lang.IllegalAccessException,


java.lang.reflect.InvocationTargetException



如果你有两个具有很多相同属性的JavaBean,一个很常见的情况就是Struts里的PO对象(持久对象)和对应的ActionForm,例如Teacher和TeacherForm。我们一般会在Action里从ActionForm构造一个PO对象,传统的方式是使用类似下面的语句对属性逐个赋值:


//得到TeacherForm


TeacherForm teacherForm=(TeacherForm)form;


//构造Teacher对象


Teacher teacher=new Teacher();


//赋值


teacher.setName(teacherForm.getName());


teacher.setAge(teacherForm.getAge());


teacher.setGender(teacherForm.getGender());


teacher.setMajor(teacherForm.getMajor());


teacher.setDepartment(teacherForm.getDepartment());






//持久化Teacher对象到数据库


HibernateDAO=

;


HibernateDAO.save(teacher);
而使用BeanUtils后,代码就大大改观了,如下所示:


//得到TeacherForm


TeacherForm teacherForm=(TeacherForm)form;


//构造Teacher对象


Teacher teacher=new Teacher();


//赋值


BeanUtils.copyProperties(teacher,teacherForm);


//持久化Teacher对象到数据库


HibernateDAO=

;


HibernateDAO.save(teacher);
如果Teacher和TeacherForm间存在名称不相同的属性,则BeanUtils不对这些属性进行处理,需要程序员手动处理。例如Teacher包含modifyDate(该属性记录最后修改日期,不需要用户在界面中输入)属性而TeacherForm无此属性,那么在上面代码的copyProperties()后还要加上一句:


teacher.setModifyDate(new Date());
怎么样,很方便吧!除BeanUtils外还有一个名为PropertyUtils的工具类,它也提供copyProperties()方法,作用与BeanUtils的同名方法十分相似,主要的区别在于前者提供类型转换功能,即发现两个JavaBean的同名属性为不同类型时,在支持的数据类型范围内进行转换,而前者不支持这个功能,但是速度会更快一些

。BeanUtils支持的转换类型如下:

java.lang.BigDecimal

java.lang.BigInteger

boolean and java.lang.Boolean

byte and java.lang.Byte

char and java.lang.Character

java.lang.Class

double and java.lang.Double

float and java.lang.Float

int and java.lang.Integer

long and java.lang.Long

short and java.lang.Short

java.lang.String

java.sql.Date

java.sql.Time

java.sql.Timestamp

这里要注意一点,java.util.Date是不被支持的,而它的子类java.sql.Date是被支持的。因此如果对象包含时间类型的属性,且希望被转换的时候,一定要使用java.sql.Date类型。否则在转换时会提示argument mistype异常。

Beanutils用了魔术般的反射技术,实现了很多夸张有用的功能,都是C/C++时代不敢想的。无论谁的项目,始终一天都会用得上它。我算是后知后觉了,第一回看到它的时候居然错过。

1.属性的动态gettersetter

在这框架满天飞的年代,不能事事都保证执行getter,setter函数了,有时候属性是要根据名字动态取得的,就像这样:  BeanUtils.getProperty(myBean,"code");

而Common BeanUtils的更强功能在于可以直接访问内嵌对象的属性,只要使用点号分隔。BeanUtils.getProperty(orderBean,
"address.city");

相比之下其他类库的BeanUtils通常都很简单,不能访问内嵌的对象,所以有时要用Commons BeanUtils来替换它们。

BeanUtils还支持List和Map类型的属性,如下面的语法即可取得Order的顾客列表中第一个顾客的名字BeanUtils.getProperty(orderBean,
"customers[1].name");

其中BeanUtils会使用ConvertUtils类把字符串转为Bean属性的真正类型,方便从HttpServletRequest等对象中提取bean,或者把bean输出到页面。

而PropertyUtils就会原色的保留Bean原来的类型。

2.BeanCompartor
动态排序

还是通过反射,动态设定Bean按照哪个属性来排序,而不再需要在实现bean的Compare接口进行复杂的条件判断。 List peoples = ...; // Person对象的列表

Collections.sort(peoples, new BeanComparator("age"));

如果要支持多个属性的复合排序,如"Order By lastName,firstName"

ArrayList sortFields = new ArrayList();

sortFields.add(new BeanComparator("lastName"));

sortFields.add(new BeanComparator("firstName"));

ComparatorChain multiSort = new ComparatorChain(sortFields);

Collections.sort(rows,multiSort);

其中ComparatorChain属于jakata
commons-collections包。

如果age属性不是普通类型,构造函数需要再传入一个comparator对象为age变量排序。

另外, BeanCompartor本身的ComparebleComparator,
遇到属性为null就会抛出异常, 也不能设定升序还是降序。这个时候又要借助commons-collections包的ComparatorUtils.

Comparator mycmp = ComparableComparator.getInstance();

mycmp = ComparatorUtils.nullLowComparator(mycmp); //允许null

mycmp = ComparatorUtils.reversedComparator(mycmp); //逆序

Comparator cmp = new BeanComparator(sortColumn, mycmp);

3.Converter
RequestResultSet中的字符串绑定到对象的属性

经常要从request,resultSet等对象取出值来赋入bean中,如果不用MVC框架的绑定功能的话,下面的代码谁都写腻了。

String a = request.getParameter("a");

bean.setA(a);

String b = ....

bean.setB(b);

......

不妨写一个Binder自动绑定所有属性:

MyBean bean = ...;

HashMap map = new HashMap();

Enumeration names = request.getParameterNames();

while (names.hasMoreElements())

{

String name = (String) names.nextElement();

map.put(name, request.getParameterValues(name));

}

BeanUtils.populate(bean, map);

其中BeanUtils的populate方法或者getProperty,setProperty方法其实都会调用convert进行转换。

但Converter只支持一些基本的类型,甚至连java.util.Date类型也不支持。而且它比较笨的一个地方是当遇到不认识的类型时,居然会抛出异常来。 对于Date类型,我参考它的sqldate类型实现了一个Converter,而且添加了一个设置日期格式的函数。

要把这个Converter注册,需要如下语句:

ConvertUtilsBean convertUtils = new ConvertUtilsBean();

DateConverter dateConverter = new DateConverter();

convertUtils.register(dateConverter,Date.class);

//因为要注册converter,所以不能再使用BeanUtils的静态方法了,必须创建BeanUtilsBean实例

BeanUtilsBean beanUtils = new BeanUtilsBean(convertUtils,new
PropertyUtilsBean());

beanUtils.setProperty(bean, name, value);

4 其他功能

4.1
ConstructorUtils
,动态创建对象

public static Object invokeConstructor(Class klass,
Object arg)4.2 MethodUtils,动态调用方法
MethodUtils.invokeMethod(bean, methodName, parameter);

4.3
PropertyUtils
,当属性为Collection,Map时的动态读取:Collection: 提供index

BeanUtils.getIndexedProperty(orderBean,"items",1);

或者

BeanUtils.getIndexedProperty(orderBean,"items[1]");

Map: 提供Key Value

BeanUtils.getMappedProperty(orderBean,
"items","111");//key-value goods_no=111

或者

BeanUtils.getMappedProperty(orderBean, "items(111)")

4.4
PropertyUtils
,直接获取属性的Class类型 public static Class
getPropertyType(Object bean, String name)4.5 动态Bean

用DynaBean减除不必要的VO和FormBean

BeanUtils.populate(java.lang.Object
bean, java.util.Map properties)

使用一个map为bean赋值,该map中的key的名称与bean中的成员变量名称相对应.注意:只有在key和成员变量名称完全对应的时候,populate机制才发生作用;但是在数量上没有任何要求,如map中的key如果是成员变量名称的子集,那么成员变量中有的而map中不包含的项将会保留默认值;同样,如果成员变量是map中key的子集,那么多余的key不会对populate的结果产生任何影响.恩,结果就是populate只针对map中key名称集合与bean中成员变量名称集合的交集产生作用.(很饶口啊)

正常用法很简单,这里略掉.

同样,这个方法也支持对数组中单个元素,map中单个元素和嵌套属性的赋值,具体做法和copyProperty()方法类似,具体如下:

values.put("words[1]","U");

values.put("map(home)","remote");

values.put("sample.display",new Double(5.0));

注意:apache的javadoc中,明确指明这个方法是为解析http请求参数特别定义和使用的,在正常的使用中不推荐使用.他们推荐使用BeanUtils.copyProperties()方法.(struts中的FormBean应该是用这个方法装配的) ...
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: