commons - BeanUtils 使用

来源:互联网 发布:淘宝一元夺宝虚假发货 编辑:程序博客网 时间:2024/06/11 09:52

 

commons-beanutilsjakarta 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,例如TeacherTeacherForm。我们一般会在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);

如果TeacherTeacherForm间存在名称不相同的属性,则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
还支持ListMap类型的属性,如下面的语法即可取得Order的顾客列表中第一个顾客的名字BeanUtils.getProperty(orderBean,"customers[1].name");
其中BeanUtils会使用ConvertUtils类把字符串转为Bean属性的真正类型,方便从HttpServletRequest等对象中提取bean,或者把bean输出到页面。
PropertyUtils就会原色的保留Bean原来的类型。
2.BeanCompartor动态排序
还是通过反射,动态设定Bean按照哪个属性来排序,而不再需要在实现beanCompare接口进行复杂的条件判断。 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属于jakatacommons-collections包。
如果age属性不是普通类型,构造函数需要再传入一个comparator对象为age变量排序。
另外, BeanCompartor本身的ComparebleComparator,遇到属性为null就会抛出异常, 也不能设定升序还是降序。这个时候又要借助commons-collections包的ComparatorUtils.
   Comparator mycmp = ComparableComparator.getInstance();
   mycmp = ComparatorUtils.nullLowComparator(mycmp);  //
允许null
   mycmp = ComparatorUtils.rever
sedComparator(mycmp); //逆序
   Comparator cmp = new BeanComparator(sortColumn, mycmp);
3.ConverterRequestResultSet中的字符串绑定到对象的属性
   
经常要从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);
   
其中BeanUtilspopulate方法或者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,newPropertyUtilsBean());
   beanUtils.setProperty(bean, name, value);
4 其他功能
4.1ConstructorUtils,动态创建对象
     public static Object invokeConstructor(Class klass,Object arg)
4.2 MethodUtils,动态调用方法    MethodUtils.invokeMethod(bean, methodName, parameter);
4.3PropertyUtils,当属性为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.4PropertyUtils,直接获取属性的Class类型     public static ClassgetPropertyType(Object bean, String name)4.5 动态Bean
DynaBean减除不必要的VOFormBean 

 

 

BeanUtils.populate(java.lang.Objectbean, java.util.Map properties)

使用一个mapbean赋值,map中的key的名称与bean中的成员变量名称相对应.注意:只有在key和成员变量名称完全对应的时候,populate机制才发生作用;但是在数量上没有任何要求,map中的key如果是成员变量名称的子集,那么成员变量中有的而map中不包含的项将会保留默认值;同样,如果成员变量是mapkey的子集,那么多余的key不会对populate的结果产生任何影响.,结果就是populate只针对mapkey名称集合与bean中成员变量名称集合的交集产生作用.(很饶口啊)
正常用法很简单,这里略掉.
同样,这个方法也支持对数组中单个元素,map中单个元素和嵌套属性的赋值,具体做法和copyProperty()方法类似,具体如下:
values.put("words[1]","U");
values.put("map(home)","remote");
values.put("sample.display",new Double(5.0));
注意:apachejavadoc,明确指明这个方法是为解析http请求参数特别定义和使用的,在正常的使用中不推荐使用.他们推荐使用BeanUtils.copyProperties()方法.(struts中的FormBean应该是用这个方法装配的) ...

 

原创粉丝点击