王朝网络
分享
 
 
 

Jakarta-Common-BeanUtils研究心得(2)[转载]

王朝java/jsp·作者佚名  2006-01-09
宽屏版  字体: |||超大  

作者 :SonyMusic 2003.05.13

六、ConstructorUtils补遗

创建对象还有一个方法:invokeExactConstructor,该方法对参数要求

更加严格,传递进去的参数必须严格符合构造方法的参数列表。

例如:

Object[] args={new Integer(1), "Jan"};

Class[] argsType={int.class, String.class};

Object obj;

//下面这句调用将不会成功,因为args[0]的类型为Integer,而不是int

//obj = ConstructorUtils.invokeExactConstructor(Month.class, args);

//这一句就可以,因为argsType指定了类型。

obj = ConstructorUtils.invokeExactConstructor(Month.class, args, argsType);

Month month=(Month)obj;

System.out.println(BeanUtils.getProperty(month,"value"));

七、MethodUtils

与ConstructorUtils类似,不过调用的时候,通常需要再指定一个method name的参数。

八、DynaClass/DynaBean

这似乎是BeanUtils中最有趣的部分之一了,很简单,简单到光看这两个接口中的方法会不明白

为什么要设计这两个接口。不过看到ResultSetDynaClass后,就明白了。下面是java doc中的代码:

ResultSet rs = ...;

ResultSetDynaClass rsdc = new ResultSetDynaClass(rs);

Iterator rows = rsdc.iterator();

while (rows.hasNext()) {

DynaBean row = (DynaBean) rows.next();

... process this row ...

}

rs.close();

原来这是一个ResultSet的包装器,ResultSetDynaClass实现了DynaClass,它的iterator方法返回一个

ResultSetIterator,则是实现了DynaBean接口。

在获得一个DynaBean之后,我们就可以用

DynaBean row = (DynaBean) rows.next();

System.out.println(row.get("field1")); //field1是其中一个字段的名字

再看另一个类RowSetDynaClass的用法,代码如下:

String driver="com.mysql.jdbc.Driver";

String url="jdbc:mysql://localhost/2hu?useUnicode=true&characterEncoding=GBK";

String username="root";

String password="";

java.sql.Connection con=null;

PreparedStatement ps=null;

ResultSet rs=null;

try {

Class.forName(driver).newInstance();

con = DriverManager.getConnection(url);

ps=con.prepareStatement("select * from forumlist");

rs=ps.executeQuery();

//先打印一下,用于检验后面的结果。

while(rs.next()){

System.out.println(rs.getString("name"));

}

rs.beforeFirst();//这里必须用beforeFirst,因为RowSetDynaClass只从当前位置向前滚动

RowSetDynaClass rsdc = new RowSetDynaClass(rs);

rs.close();

ps.close();

List rows = rsdc.getRows();//返回一个标准的List,存放的是DynaBean

for (int i = 0; i <rows.size(); i++) {

DynaBean b=(DynaBean)rows.get(i);

System.out.println(b.get("name"));

}

} catch (Exception e) {

e.printStackTrace();

}

finally{

try {

con.close();

} catch (Exception e) {

}

}

是不是很有趣?封装了ResultSet的数据,代价是占用内存。如果一个表有10万条记录,rsdc.getRows()

就会返回10万个记录。@_@

需要注意的是ResultSetDynaClass和RowSetDynaClass的不同之处:

1,ResultSetDynaClass是基于Iterator的,一次只返回一条记录,而RowSetDynaClass是基于

List的,一次性返回全部记录。直接影响是在数据比较多时ResultSetDynaClass会比较的快速,

而RowSetDynaClass需要将ResultSet中的全部数据都读出来(并存储在其内部),会占用过多的

内存,并且速度也会比较慢。

2,ResultSetDynaClass一次只处理一条记录,在处理完成之前,ResultSet不可以关闭。

3,ResultSetIterator的next()方法返回的DynaBean其实是指向其内部的一个固定

对象,在每次next()之后,内部的值都会被改变。这样做的目的是节约内存,如果你需要保存每

次生成的DynaBean,就需要创建另一个DynaBean,并将数据复制过去,下面也是java doc中的代码:

ArrayList results = new ArrayList(); // To hold copied list

ResultSetDynaClass rsdc = ...;

DynaProperty properties[] = rsdc.getDynaProperties();

BasicDynaClass bdc =

new BasicDynaClass("foo", BasicDynaBean.class,

rsdc.getDynaProperties());

Iterator rows = rsdc.iterator();

while (rows.hasNext()) {

DynaBean oldRow = (DynaBean) rows.next();

DynaBean newRow = bdc.newInstance();

PropertyUtils.copyProperties(newRow, oldRow);

results.add(newRow);

}

事实上DynaClass/DynaBean可以用于很多地方,存储各种类型的数据。自己想吧。嘿嘿。

九、自定义的CustomRowSetDynaClass

两年前写过一个与RowSetDynaClass目标相同的类,不过多一个功能,就是分页,只取需要的数据,

这样内存占用就会减少。

先看一段代码:

String driver="com.mysql.jdbc.Driver";

String url="jdbc:mysql://localhost/2hu?useUnicode=true&characterEncoding=GBK";

String username="root";

String password="";

java.sql.Connection con=null;

PreparedStatement ps=null;

ResultSet rs=null;

try {

Class.forName(driver).newInstance();

con = DriverManager.getConnection(url);

ps=con.prepareStatement("select * from forumlist order by name");

rs=ps.executeQuery();

/*

while(rs.next()){

System.out.println(rs.getString("name"));

}

rs.beforeFirst();

*/

//第二个参数表示第几页,第三个参数表示页的大小

CustomRowSetDynaClass rsdc = new CustomRowSetDynaClass(rs, 2, 5);

//RowSetDynaClass rsdc = new RowSetDynaClass(rs);

rs.close();

ps.close();

List rows = rsdc.getRows();

for (int i = 0; i <rows.size(); i++) {

DynaBean b=(DynaBean)rows.get(i);

System.out.println(b.get("name"));

}

} catch (Exception e) {

e.printStackTrace();

}

finally{

try {

con.close();

} catch (Exception e) {

}

}

在这里用到了一个CustomRowSetDynaClass类,构造方法中增加了page和pageSize两个参数,

这样,不管数据库里有多少条记录,最多只取pageSize条记录,若pageSize==-1,则功能和

RowSetDynaClass一样。这在大多数情况下是适用的。该类的代码如下:

package test.jakarta.commons.beanutils;

import java.io.*;

import java.sql.*;

import java.util.*;

import org.apache.commons.beanutils.*;

/**

* @author SonyMusic

*

* To change this generated comment edit the template variable "typecomment":

* Window>Preferences>Java>Templates.

* To enable and disable the creation of type comments go to

* Window>Preferences>Java>Code Generation.

*/

public class CustomRowSetDynaClass implements DynaClass, Serializable {

// ----------------------------------------------------------- Constructors

/**

* <p>Construct a new {@link RowSetDynaClass} for the specified

* <code>ResultSet</code>. The property names corresponding

* to column names in the result set will be lower cased.</p>

*

* @param resultSet The result set to be wrapped

*

* @exception NullPointerException if <code>resultSet</code>

* is <code>null</code>

* @exception SQLException if the metadata for this result set

* cannot be introspected

*/

public CustomRowSetDynaClass(ResultSet resultSet) throws SQLException {

this(resultSet, true);

}

/**

* <p>Construct a new {@link RowSetDynaClass} for the specified

* <code>ResultSet</code>. The property names corresponding

* to the column names in the result set will be lower cased or not,

* depending on the specified <code>lowerCase</code> value.</p>

*

* <p><strong>WARNING</strong> - If you specify <code>false</code>

* for <code>lowerCase</code>, the returned property names will

* exactly match the column names returned by your JDBC driver.

* Because different drivers might return column names in different

* cases, the property names seen by your application will vary

* depending on which JDBC driver you are using.</p>

*

* @param resultSet The result set to be wrapped

* @param lowerCase Should property names be lower cased?

*

* @exception NullPointerException if <code>resultSet</code>

* is <code>null</code>

* @exception SQLException if the metadata for this result set

* cannot be introspected

*/

public CustomRowSetDynaClass(ResultSet resultSet, boolean lowerCase)

throws SQLException {

this(resultSet, 1, -1, lowerCase);

}

public CustomRowSetDynaClass(

ResultSet resultSet,

int page,

int pageSize,

boolean lowerCase)

throws SQLException {

if (resultSet == null) {

throw new NullPointerException();

}

this.lowerCase = lowerCase;

this.page = page;

this.pageSize = pageSize;

introspect(resultSet);

copy(resultSet);

}

public CustomRowSetDynaClass(ResultSet resultSet, int page, int pageSize)

throws SQLException {

this(resultSet, page, pageSize, true);

}

// ----------------------------------------------------- Instance Variables

/**

* <p>Flag defining whether column names should be lower cased when

* converted to property names.</p>

*/

protected boolean lowerCase = true;

protected int page = 1;

protected int pageSize = -1;

/**

* <p>The set of dynamic properties that are part of this

* {@link DynaClass}.</p>

*/

protected DynaProperty properties[] = null;

/**

* <p>The set of dynamic properties that are part of this

* {@link DynaClass}, keyed by the property name. Individual descriptor

* instances will be the same instances as those in the

* <code>properties</code> list.</p>

*/

protected Map propertiesMap = new HashMap();

/**

* <p>The list of {@link DynaBean}s representing the contents of

* the original <code>ResultSet</code> on which this

* {@link RowSetDynaClass} was based.</p>

*/

protected List rows = new ArrayList();

// ------------------------------------------------------ DynaClass Methods

/**

* <p>Return the name of this DynaClass (analogous to the

* <code>getName()</code> method of <code>java.lang.Class</code), which

* allows the same <code>DynaClass</code> implementation class to support

* different dynamic classes, with different sets of properties.</p>

*/

public String getName() {

return (this.getClass().getName());

}

/**

* <p>Return a property descriptor for the specified property, if it

* exists; otherwise, return <code>null</code>.</p>

*

* @param name Name of the dynamic property for which a descriptor

* is requested

*

* @exception IllegalArgumentException if no property name is specified

*/

public DynaProperty getDynaProperty(String name) {

if (name == null) {

throw new IllegalArgumentException("No property name specified");

}

return ((DynaProperty) propertiesMap.get(name));

}

/**

* <p>Return an array of <code>ProperyDescriptors</code> for the properties

* currently defined in this DynaClass. If no properties are defined, a

* zero-length array will be returned.</p>

*/

public DynaProperty[] getDynaProperties() {

return (properties);

}

/**

* <p>Instantiate and return a new DynaBean instance, associated

* with this DynaClass. <strong>NOTE</strong> - This operation is not

* supported, and throws an exception.</p>

*

* @exception IllegalAccessException if the Class or the appropriate

* constructor is not accessible

* @exception InstantiationException if this Class represents an abstract

* class, an array class, a primitive type, or void; or if instantiation

* fails for some other reason

*/

public DynaBean newInstance()

throws IllegalAccessException, InstantiationException {

throw new UnsupportedOperationException("newInstance() not supported");

}

// --------------------------------------------------------- Public Methods

/**

* <p>Return a <code>List</code> containing the {@link DynaBean}s that

* represent the contents of each <code>Row</code> from the

* <code>ResultSet</code> that was the basis of this

* {@link RowSetDynaClass} instance. These {@link DynaBean}s are

* disconnected from the database itself, so there is no problem with

* modifying the contents of the list, or the values of the properties

* of these {@link DynaBean}s. However, it is the application's

* responsibility to persist any such changes back to the database,

* if it so desires.</p>

*/

public List getRows() {

return (this.rows);

}

// ------------------------------------------------------ Protected Methods

/**

* <p>Copy the column values for each row in the specified

* <code>ResultSet</code> into a newly created {@link DynaBean}, and add

* this bean to the list of {@link DynaBean}s that will later by

* returned by a call to <code>getRows()</code>.</p>

*

* @param resultSet The <code>ResultSet</code> whose data is to be

* copied

*

* @exception SQLException if an error is encountered copying the data

*/

protected void copy(ResultSet resultSet) throws SQLException {

int abs = 0;

int rowsCount = 0;

int currentPageRows = 0;

resultSet.last();

rowsCount = resultSet.getRow();

if (pageSize != -1) {

int totalPages = (int) Math.ceil(((double) rowsCount) / pageSize);

if (page > totalPages)

page = totalPages;

if (page < 1)

page = 1;

abs = (page - 1) * pageSize;

//currentPageRows=(page==totalPages?rowsCount-pageSize*(totalPages-1):pageSize);

} else

pageSize = rowsCount;

if (abs == 0)

resultSet.beforeFirst();

else

resultSet.absolute(abs);

//int

while (resultSet.next() && ++currentPageRows <= pageSize) {

DynaBean bean = new BasicDynaBean(this);

for (int i = 0; i < properties.length; i++) {

String name = properties[i].getName();

bean.set(name, resultSet.getObject(name));

}

rows.add(bean);

}

}

/**

* <p>Introspect the metadata associated with our result set, and populate

* the <code>properties</code> and <code>propertiesMap</code> instance

* variables.</p>

*

* @param resultSet The <code>resultSet</code> whose metadata is to

* be introspected

*

* @exception SQLException if an error is encountered processing the

* result set metadata

*/

protected void introspect(ResultSet resultSet) throws SQLException {

// Accumulate an ordered list of DynaProperties

ArrayList list = new ArrayList();

ResultSetMetaData metadata = resultSet.getMetaData();

int n = metadata.getColumnCount();

for (int i = 1; i <= n; i++) { // JDBC is one-relative!

DynaProperty dynaProperty = createDynaProperty(metadata, i);

if (dynaProperty != null) {

list.add(dynaProperty);

}

}

// Convert this list into the internal data structures we need

properties =

(DynaProperty[]) list.toArray(new DynaProperty[list.size()]);

for (int i = 0; i < properties.length; i++) {

propertiesMap.put(properties[i].getName(), properties[i]);

}

}

/**

* <p>Factory method to create a new DynaProperty for the given index

* into the result set metadata.</p>

*

* @param metadata is the result set metadata

* @param i is the column index in the metadata

* @return the newly created DynaProperty instance

*/

protected DynaProperty createDynaProperty(

ResultSetMetaData metadata,

int i)

throws SQLException {

String name = null;

if (lowerCase) {

name = metadata.getColumnName(i).toLowerCase();

} else {

name = metadata.getColumnName(i);

}

String className = null;

try {

className = metadata.getColumnClassName(i);

} catch (SQLException e) {

// this is a patch for HsqlDb to ignore exceptions

// thrown by its metadata implementation

}

// Default to Object type if no class name could be retrieved

// from the metadata

Class clazz = Object.class;

if (className != null) {

clazz = loadClass(className);

}

return new DynaProperty(name, clazz);

}

/**

* <p>Loads and returns the <code>Class</code> of the given name.

* By default, a load from the thread context class loader is attempted.

* If there is no such class loader, the class loader used to load this

* class will be utilized.</p>

*

* @exception SQLException if an exception was thrown trying to load

* the specified class

*/

protected Class loadClass(String className) throws SQLException {

try {

ClassLoader cl = Thread.currentThread().getContextClassLoader();

if (cl == null) {

cl = this.getClass().getClassLoader();

}

return (cl.loadClass(className));

} catch (Exception e) {

throw new SQLException(

"Cannot load column class '" + className + "': " + e);

}

}

}

大部分代码从BeanUtils的源码中取得,只做了简单的修改,没有加多余的注释。如果要正式使用,

需要再做精加工。

========================================

关于这个包,只准备测试到这里了,不过已经有了大概的印象了,至少,知道这个包可以做些什么。

其实这个笔记也只是起到这个作用。@_@

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
>>返回首页<<
推荐阅读
 
 
频道精选
 
静静地坐在废墟上,四周的荒凉一望无际,忽然觉得,凄凉也很美
© 2005- 王朝网络 版权所有