Apache Commons Beanutils 二 (动态Bean - DynaBeans)
2017-05-30 13:09
543 查看
相关背景
上一篇介绍了PropertyUtils的用法,PropertyUtils主要是在不修改bean结构的前提下,动态访问bean的属性;
但是有时候,我们会经常希望能够在不定义一个Java类的前提下,动态决定这个类中包含哪些属性,并动态访问它们的属性值,比较典型的使用场景是作为SQL查询的结果集的bean;
为了支持以上特性,Apache Commons Beanutils包为我们提供了
DynaBean接口、DynaClass接口;
举个简单例子如下:
[code] DynaProperty[] props = new DynaProperty[]{
new DynaProperty("address", java.util.Map.class),
new DynaProperty("subordinate", mypackage.Employee[].class),
new DynaProperty("firstName", String.class),
new DynaProperty("lastName", String.class)
};
BasicDynaClass dynaClass = new BasicDynaClass("employee", null, props);
DynaBean employee = dynaClass.newInstance();
employee.set("address", new HashMap());
employee.set("subordinate", new Employee[]{...});
employee.set("firstName", "Fred");
employee.set("lastName", "Flintstone");
DynaBean employee = ...; // 具体的DynaBean实现类
String firstName = (String) employee.get("firstName");
Address homeAddress = (Address) employee.get("address", "home");
Object subordinate = employee.get("subordinate", 2);
由于DynaBean和DynaClass都是接口,它们可以有多种实现形式,应用于多种场景。
接下来,会介绍在Apache Commons Beanutils包下,DynaBean和DynaClass接口不同的实现类;
当然,我们也可以自定义实现类来满足我们特定的需求;
基础实现类:BasicDynaBean和BasicDynaClass
先了解下这两个重要的实现,这两个类为DynaBean和DynaClass接口的基础实现类;首先,我们可以这样创建一个DynaClass实例,其中类的成员属性是用
DynaProperty类来描述的:
DynaProperty[] props = new DynaProperty[] { new DynaProperty("address", java.util.Map.class), new DynaProperty("subordinate", Employee[].class), new DynaProperty("firstName", String.class), new DynaProperty("lastName", String.class) }; BasicDynaClass dynaClass = new BasicDynaClass("employee", null, props);
注意这里的Class<?> dynaBeanClass参数为空,看下源码就发现,如果为null的话,默认会使用BasicDynaBean.class;
有了BasicDynaClass实例后,我们就可以开始创建DynaBean实例了,并且可以调用DynaBean接口中定义的方法,如get和set来读写属性值,如下所示:
DynaBean employee = dynaClass.newInstance(); employee.set("address", new HashMap<String, Object>()); employee.set("subordinate", new Employee[0]); employee.set("firstName", "Fred"); employee.set("lastName", "Flintstone");
System.out.println(employee.get("firstName"));
实现类:ResultSetDynaClass,处理数据库查询结果集
ResultSetDynaClass主要用于包装java.sql.ResultSet,即SQL查询时候返回的结果集;不使用DynaBean的话,通常我们是这样处理的:
String sql = "SELECT id, name, address, state FROM user"; stmt = conn.prepareStatement(sql); ResultSet rs = stmt.executeQuery(sql); while (rs.next()) { Long id = rs.getLong("id"); String name = rs.getString("name"); String address = rs.getString("address"); boolean state = rs.getBoolean("state"); System.out.print("id: " + id); System.out.print(", name: " + name); System.out.print(", address: " + address); System.out.println(", state: " + state); }
使用ResultSetDynaClass的话,我们可以这样做:
String sql = "SELECT id, name, address, state FROM user"; stmt = conn.prepareStatement(sql); ResultSet rs = stmt.executeQuery(sql); Iterator<DynaBean> rows = (new ResultSetDynaClass(rs)).iterator(); while (rows.hasNext()) { DynaBean row = rows.next(); System.out.print("id: " + row.get("id")); System.out.print(", name: " + row.get("name")); System.out.print(", address: " + row.get("address")); System.out.println(", state: " + row.get("state")); }
完整示例:
/* * File Name: ResultSetDyna.java * Description: * Author: PiChen * Create Date: 2017年5月30日 */ package apache.commons.beanutils.example.dynabeans; import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.util.List; import org.apache.commons.beanutils.DynaBean; import org.apache.commons.beanutils.RowSetDynaClass; /** * * @author PiChen * @version 2017年5月30日 */ public class RowSetDyna { static final String JDBC_DRIVER = "com.mysql.jdbc.Driver"; static final String DB_URL = "jdbc:mysql://localhost/demo"; static final String USER = "root"; static final String PASS = "root"; public static void main(String[] args) { Connection conn = null; PreparedStatement stmt = null; try { Class.forName("com.mysql.jdbc.Driver"); conn = DriverManager.getConnection(DB_URL, USER, PASS); String sql = "SELECT id, name, address, state FROM user"; stmt = conn.prepareStatement(sql); ResultSet rs = stmt.executeQuery(sql); RowSetDynaClass rowSet = new RowSetDynaClass(rs); rs.close(); stmt.close(); conn.close(); List<DynaBean> rowlist = rowSet.getRows(); for (DynaBean row : rowlist) { System.out.print("id: " + row.get("id")); System.out.print(", name: " + row.get("name")); System.out.print(", address: " + row.get("address")); System.out.println(", state: " + row.get("state")); } } catch (SQLException se) { se.printStackTrace(); } catch (Exception e) { e.printStackTrace(); } finally { try { if (stmt != null) stmt.close(); } catch (SQLException se2) { } try { if (conn != null) conn.close(); } catch (SQLException se) { se.printStackTrace(); } } } }
View Code
实现类:WrapDynaBean和WrapDynaClass,包装普通bean
使用WrapDynaBean,我们可以将普通的javabean包装成DynaBean,并非常简便的使用DynaBean提供的API方法来访问bean成员属性示例:
Employee e = new Employee(); e.setFirstName("hello"); DynaBean wrapper = new WrapDynaBean(e); String firstName = (String) wrapper.get("firstName"); System.out.println(firstName);
注意,以上代码中,会间接的创建了
WrapDynaClass实例,我们不需要直接处理它;
实现类:Lazy DynaBeans,简单易用的DynaBean实现
Lazy DynaBeans,正如其名,可以让我们省去很多工作,更加人性化的去使用DynaBean,Lazy DynaBeans有如下特性:
1、自动添加bean属性,当我们调用
set(name, value)方法时,如果属性不存在,会自动添加该属性;
2、List、Array属性自动扩容,
3、List、Array属性里的内部元素可以自动创建,实例化
4、Map属性也可以自动创建,实例化
5、...
简单的说,使用Lazy DynaBeans的话,你可以大胆调用DynaBean的set、get方法,而不必担心没有属性不存在,集合数组空间不够等问题,Lazy DynaBeans会帮我们自动处理;
如下是一个
LazyDynaBean
例子:
DynaBean dynaBean = new LazyDynaBean(); dynaBean.set("foo", "bar"); // simple dynaBean.set("customer", "title", "Mr"); // mapped dynaBean.set("customer", "surname", "Smith"); // mapped dynaBean.set("users", 0, new User()); // indexed dynaBean.set("users", 1, new User()); // indexed dynaBean.set("users", 2, new User()); // indexed System.out.println(dynaBean.get("customer", "title"));
如下是一个
LazyDynaMap
例子:
DynaBean dynaBean = new LazyDynaMap(); dynaBean.set("foo", "bar"); // simple dynaBean.set("customer", "title", "Mr"); // mapped dynaBean.set("customer", "surname", "Smith"); // mapped dynaBean.set("users", 0, new User()); // indexed dynaBean.set("users", 1, new User()); // indexed dynaBean.set("users", 2, new User()); // indexed System.out.println(dynaBean.get("customer", "title")); //转成Map对象 Map<String, Object> myMap = ((LazyDynaBean) dynaBean).getMap(); System.out.println(myMap);
LazyDynaList例子,详见API文档
LazyDynaList dynaBean = new LazyDynaList(); dynaBean.setElementType(User.class); User u = new User(); u.setName("hello"); dynaBean.add(1, u); System.out.println(dynaBean.size()); User[] users = (User[])dynaBean.toArray();//转化为数组 System.out.println(users[1].getName()); WrapDynaBean w = (WrapDynaBean) dynaBean.get(1); System.out.println(w.get("name"));
LazyDynaClass
示例:
Lazy DynaBeans可以让我们不受控制的添加任意类型的bean属性,但是有时候,我们还是希望能控制某个bean属性的数据类型,如下,是一个示例:
MutableDynaClass dynaClass = new LazyDynaClass(); // create DynaClass dynaClass.add("amount", java.lang.Integer.class); // add property dynaClass.add("users", User[].class); // add indexed property dynaClass.add("orders", TreeMap.class); // add mapped property DynaBean dynaBean = new LazyDynaBean(dynaClass); dynaBean.set("amount_", "s"); dynaBean.set("amount", "s");//报错,需要为整型 dynaBean.set("users", 1);//报错,需要维数组 System.out.println(dynaBean.get("amount"));
参考资料
http://commons.apache.org/proper/commons-beanutils/javadocs/v1.9.3/apidocs/org/apache/commons/beanutils/package-summary.html源码
https://github.com/peterchenhdu/apache-commons-beanutils-example相关文章推荐
- Caused by: java.lang.ClassNotFoundException: org.apache.commons.beanutils.DynaBean
- Apache Commons Beanutils 一 (使用PropertyUtils访问Bean属性)
- java.lang.ClassNotFoundException: org.apache.commons.beanutils.DynaBean
- java.lang.ClassNotFoundException: org.apache.commons.beanutils.DynaBean
- org.apache.commons.beanutils.DynaBean
- VerifyError: org/apache/commons/beanutils/PropertyUtilsBean
- 初用org.apache.commons.beanutils.DynaBean
- Commons-BeanUtils动态bean在项目中的应用
- Bean复制的几种框架性能比较(Apache BeanUtils、PropertyUtils,Spring BeanUtils,Cglib BeanCopier)
- Bean复制的几种框架性能比较(Apache BeanUtils、PropertyUtils,Spring BeanUtils,Cglib BeanCopier)
- 对apache.commons.beanutils.BeanUtils的源码解读
- org.apache.commons.beanutils.ConversionException: DateConverter does not support default String to '
- com.qsoft.commons.beanutils源代码(.net版本的org.apache.commons.beanutils)
- com.qsoft.commons.beanutils源代码(.net版本的org.apache.commons.beanutils)
- com.qsoft.commons.beanutils源代码(.net版本的org.apache.commons.beanutils)
- 再续前缘-apache.commons.beanutils的补充
- org.apache.commons.beanutils.ConversionException:
- com.sun.org.apache.commons.beanutils.BeanUtils的用法简介
- org.apache.commons.beanutils.BeanUtils 简介
- 初用apache.commons.beanutils.BeanUtils