您的位置:首页 > 运维架构 > Apache

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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: