OMG,到底在尋找什么..................
          (構(gòu)造一個(gè)完美的J2EE系統(tǒng)所需要的完整知識(shí)體系)
          posts - 198,  comments - 37,  trackbacks - 0
          ? BeanUtils:?威力和代價(jià)(轉(zhuǎn)載綜合)
          ?

          Apache Jakarta Commons項(xiàng)目非常有用。我曾在許多不同的項(xiàng)目上或直接或間接地使用各種流行的commons組件。其中的一個(gè)強(qiáng)大的組件就是BeanUtils。我將說明如何使用BeanUtils將local實(shí)體bean轉(zhuǎn)換為對(duì)應(yīng)的value 對(duì)象:


          BeanUtils.copyProperties(aValue, aLocal)

          上面的代碼從aLocal對(duì)象復(fù)制屬性到aValue對(duì)象。它相當(dāng)簡(jiǎn)單!它不管local(或?qū)?yīng)的value)對(duì)象有多少個(gè)屬性,只管進(jìn)行復(fù)制。我們假設(shè)local對(duì)象有100個(gè)屬性。上面的代碼使我們可以無需鍵入至少100行的冗長、容易出錯(cuò)和反復(fù)的get和set方法調(diào)用。這太棒了!太強(qiáng)大了!太有用了!

          現(xiàn)在,還有一個(gè)壞消息:使用BeanUtils的成本驚人地昂貴!我做了一個(gè)簡(jiǎn)單的測(cè)試,BeanUtils所花費(fèi)的時(shí)間要超過取數(shù)據(jù)、將其復(fù)制到對(duì)應(yīng)的value對(duì)象(通過手動(dòng)調(diào)用get和set方法),以及通過串行化將其返回到遠(yuǎn)程的客戶機(jī)的時(shí)間總和。所以要小心使用這種威力!

          • 如果您有BeanUtils和類似的實(shí)用程序方面的體驗(yàn),請(qǐng)與我交流分享。
            +prakash

          Beanutils用了魔術(shù)般的反射技術(shù),實(shí)現(xiàn)了很多夸張有用的功能,都是C/C++時(shí)代不敢想的。無論誰的項(xiàng)目,始終一天都會(huì)用得上它。我算是后知后覺了,第一回看到它的時(shí)候居然錯(cuò)過。

          1.屬性的動(dòng)態(tài)getter,setter

          在這框架滿天飛的年代,不能事事都保證執(zhí)行g(shù)etter,setter函數(shù)了,有時(shí)候?qū)傩允且枰鶕?jù)名字動(dòng)態(tài)取得的,就像這樣:  
          BeanUtils.getProperty(myBean,"code");
          而BeanUtils更強(qiáng)的功能是直接訪問內(nèi)嵌對(duì)象的屬性,只要使用點(diǎn)號(hào)分隔。
          BeanUtils.getProperty(orderBean, "address.city");
          相比之下其他類庫的BeanUtils通常都很簡(jiǎn)單,不能訪問內(nèi)嵌的對(duì)象,所以經(jīng)常要用Commons BeanUtils替換它們。
          BeanUtils還支持List和Map類型的屬性。如下面的語法即可取得顧客列表中第一個(gè)顧客的名字
          BeanUtils.getProperty(orderBean, "customers[1].name");
          其中BeanUtils會(huì)使用ConvertUtils類把字符串轉(zhuǎn)為Bean屬性的真正類型,方便從HttpServletRequest等對(duì)象中提取bean,或者把bean輸出到頁面。
          而PropertyUtils就會(huì)原色的保留Bean原來的類型。

          2.beanCompartor 動(dòng)態(tài)排序

          還是通過反射,動(dòng)態(tài)設(shè)定Bean按照哪個(gè)屬性來排序,而不再需要在bean的Compare接口進(jìn)行復(fù)雜的條件判斷。
          List peoples = ...; // Person對(duì)象的列表
          Collections.sort(peoples, new BeanComparator("age"));
          

          如果要支持多個(gè)屬性的復(fù)合排序,如"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屬性不是普通類型,構(gòu)造函數(shù)需要再傳入一個(gè)comparator對(duì)象為age變量排序。
          另外, BeanCompartor本身的ComparebleComparator, 遇到屬性為null就會(huì)拋出異常, 也不能設(shè)定升序還是降序。
          這個(gè)時(shí)候又要借助commons-collections包的ComparatorUtils.

          ?? Comparator mycmp = ComparableComparator.getInstance();
          ???mycmp = ComparatorUtils.nullLowComparator(mycmp);? //允許null
          ?? mycmp = ComparatorUtils.reversedComparator(mycmp); //逆序
          ?? Comparator cmp = new BeanComparator(sortColumn, mycmp);

          3.Converter 把Request或ResultSet中的字符串綁定到對(duì)象的屬性

          ?? 經(jīng)常要從request,resultSet等對(duì)象取出值來賦入bean中,下面的代碼誰都寫膩了,如果不用MVC框架的綁定功能的話。

             String a = request.getParameter("a");
             bean.setA(a);
             String b = ....
          

          不妨寫一個(gè)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方法其實(shí)都會(huì)調(diào)用convert進(jìn)行轉(zhuǎn)換。
          ????但Converter只支持一些基本的類型,甚至連java.util.Date類型也不支持。而且它比較笨的一個(gè)地方是當(dāng)遇到不認(rèn)識(shí)的類型時(shí),居然會(huì)拋出異常來。
          ??? 對(duì)于Date類型,我參考它的sqldate類型實(shí)現(xiàn)了一個(gè)Converter,而且添加了一個(gè)設(shè)置日期格式的函數(shù)。
          要把這個(gè)Converter注冊(cè),需要如下語句:

              ConvertUtilsBean convertUtils = new ConvertUtilsBean();
          ?? DateConverter dateConverter = new DateConverter();
          ?? convertUtils.register(dateConverter,Date.class);



          //因?yàn)橐?cè)converter,所以不能再使用BeanUtils的靜態(tài)方法了,必須創(chuàng)建BeanUtilsBean實(shí)例
          BeanUtilsBean beanUtils = new BeanUtilsBean(convertUtils,new PropertyUtilsBean());
          beanUtils.setProperty(bean, name, value);

          4 其他功能

          4.1 PropertyUtils,當(dāng)屬性為Collection,Map時(shí)的動(dòng)態(tài)讀取:
          ?
          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.2 PropertyUtils,獲取屬性的Class類型
          ???? public static Class getPropertyType(Object bean, String name)
          ?
          4.3 ConstructorUtils,動(dòng)態(tài)創(chuàng)建對(duì)象
          ????? public static Object invokeConstructor(Class klass, Object arg)
          4.4 MethodUtils,動(dòng)態(tài)調(diào)用方法
              MethodUtils.invokeMethod(bean, methodName, parameter);
          4.5 動(dòng)態(tài)Bean 用DynaBean減除不必要的VO和FormBean?
          一、概述
          第一次看到BeanUtils包,是在Struts項(xiàng)目中,作為Struts一個(gè)工具來使用的,
          估計(jì)功能越弄越強(qiáng),就移到Common項(xiàng)目中了吧。

          BeanUtils一共有四個(gè)package:
          org.apache.commons.beanutils
          org.apache.commons.beanutils.converters
          org.apache.commons.beanutils.locale
          org.apache.commons.beanutils.locale.converters
          后三個(gè)包主要是用于數(shù)據(jù)的轉(zhuǎn)換,圍繞著一個(gè)Converter接口,該接口只有一個(gè)方法:
          java.lang.Object convert(java.lang.Class type, java.lang.Object value) ,
          用于將一個(gè)value轉(zhuǎn)換成另一個(gè)類型為type的Object。在一些自動(dòng)化的應(yīng)用中應(yīng)該會(huì)有用。
          這里不作評(píng)論,以后有興趣了,或者覺得有用了,再行研究。
          這里只講第一個(gè)包。

          二、測(cè)試用的Bean
          在開始所有的測(cè)試之前,我寫了一個(gè)簡(jiǎn)單的Bean,以便于測(cè)試,代碼如下:
          package test.jakarta.commons.beanutils;

          /**
          ?* @author SonyMusic
          ?*
          ?*/
          public class Month {
          ?private int value;
          ?private String name;
          ?private int[] days={11,22,33,44,55};

          ?public Month(int v, String n){
          ? ?value=v;
          ? ?name=n;
          ?}
          ?
          ?/**
          ? * Returns the name.
          ? * @return String
          ? */
          ?public String getName() {
          ? ?return name;
          ?}

          ?/**
          ? * Returns the value.
          ? * @return int
          ? */
          ?public int getValue() {
          ? ?return value;
          ?}

          ?/**
          ? * Sets the name.
          ? * @param name The name to set
          ? */
          ?public void setName(String name) {
          ? ?this.name = name;
          ?}

          ?/**
          ? * Sets the value.
          ? * @param value The value to set
          ? */
          ?public void setValue(int value) {
          ? ?this.value = value;
          ?}

          ?/**
          ? * @see java.lang.Object#toString()
          ? */
          ?public String toString() {
          ? ?return value+"("+name+")";
          ?}

          ?public int[] getDays() {
          ? ?return days;
          ?}

          ?public void setDays(int[] is) {
          ? ?days = is;
          ?}

          }

          三、BeanUtils
          這是一個(gè)主要應(yīng)用于Bean的Util(呵呵,這個(gè)解釋很絕吧),以下是其中幾個(gè)方法的例子

          //static java.util.Map describe(java.lang.Object bean)
          //這個(gè)方法返回一個(gè)Object中所有的可讀屬性,并將屬性名/屬性值放入一個(gè)Map中,另外還有
          //一個(gè)名為class的屬性,屬性值是Object的類名,事實(shí)上class是java.lang.Object的一個(gè)屬性
          ?Month month=new Month(1, "Jan");
          ?
          ?try {
          ? ?Map map=BeanUtils.describe(month);
          ? ?Set keySet=map.keySet();
          ? ?for (Iterator iter = keySet.iterator(); iter.hasNext();) {
          ? ? ?Object element = (Object) iter.next();
          ? ? ?System.out.println("KeyClass:"+element.getClass().getName());
          ? ? ?System.out.println("ValueClass:"+map.get(element).getClass().getName());
          ? ? ?System.out.print(element+"\t");
          ? ? ?System.out.print(map.get(element));
          ? ? ?System.out.println();
          ? ?}
          ?} catch (IllegalAccessException e) {
          ? ?e.printStackTrace();
          ?} catch (InvocationTargetException e) {
          ? ?e.printStackTrace();
          ?} catch (NoSuchMethodException e) {
          ? ?e.printStackTrace();
          ?}
          輸出為:
          KeyClass:java.lang.String
          ValueClass:java.lang.String
          value ?1
          KeyClass:java.lang.String
          ValueClass:java.lang.String
          class ?class test.jakarta.commons.beanutils.Month
          KeyClass:java.lang.String
          ValueClass:java.lang.String
          name ?Jan
          注意到所有Map中的key/value都是String,而不管object中實(shí)際的值是多少。
          與此對(duì)應(yīng)的還有static void populate(java.lang.Object bean, java.util.Map properties)
          用于將剛才describe出的Map再裝配成一個(gè)對(duì)象。


          再看這樣一段代碼
          曹曉鋼也許還記得,為了取一個(gè)不確定對(duì)象的property,著實(shí)花了不少時(shí)間,
          難度不大,但要做到100%的正確,仍然需要付出很大的精力。
          //static java.lang.String getProperty(java.lang.Object bean, java.lang.String name)
          ?Month month=new Month(1, "Jan");
          ?
          ?try {
          ? ?System.out.println(BeanUtils.getProperty(month,"value"));
          ?} catch (Exception e) {
          ? ?e.printStackTrace();
          ?}
          //輸出是:1

          與getProperty類似的還有g(shù)etIndexedProperty, getMappedProperty,
          以getIndexedProperty為例:
          ?Month month=new Month(1, "Jan");
          ?
          ?try {
          ? ?System.out.println(BeanUtils.getIndexedProperty(month,"days",1));
          ? ?System.out.println(BeanUtils.getIndexedProperty(month,"days[1]"));
          ?} catch (Exception e) {
          ? ?e.printStackTrace();
          ?}
          這兩個(gè)調(diào)用是相同的。


          BeanUtils中還有一個(gè)方法:
          static void copyProperties(java.lang.Object dest, java.lang.Object orig)
          它真是太有用,還記得struts中滿天飛的都是copyProperties,我甚至懷疑整個(gè)BeanUtils最初
          是不是因?yàn)檫@個(gè)方法的需求才寫出來的。
          它將對(duì)象orig中的屬性復(fù)制到dest中去。


          四、PropertyUtils
          這個(gè)類和BeanUtils類很多的方法在參數(shù)上都是相同的,但返回值不同。
          BeanUtils著重于"Bean",返回值通常是String,而PropertyUtils著重于屬性,
          它的返回值通常是Object。


          五、ConstructorUtils
          這個(gè)類中的方法主要分成兩種,一種是得到構(gòu)造方法,一種是創(chuàng)建對(duì)象。
          事實(shí)上多數(shù)時(shí)候得到構(gòu)造方法的目的就是創(chuàng)建對(duì)象,這里只介紹一下創(chuàng)建對(duì)象。
          //static java.lang.Object ConstructorUtils.invokeConstructor
          //(java.lang.Class klass, java.lang.Object[] args)
          //根據(jù)一個(gè)java.lang.Class以及相應(yīng)的構(gòu)造方法的參數(shù),創(chuàng)建一個(gè)對(duì)象。
          ?Object obj=ConstructorUtils.invokeConstructor(Month.class, {new Integer(1), "Jan"});
          ?Month month=(Month)obj;
          ?try {
          ? ?System.out.println(BeanUtils.getProperty(month,"value"));
          ?} catch (Exception e) {
          ? ?e.printStackTrace();
          ?}
          輸出證明,構(gòu)造方法的調(diào)用是成功的。
          如果需要強(qiáng)制指定構(gòu)造方法的參數(shù)類型,可以這樣調(diào)用:
          ? ?Object[] args={new Integer(1), "Jan"};
          ? ?Class[] argsType={int.class, String.class};
          ? ?Object obj;
          ? ?obj = ConstructorUtils.invokeExactConstructor(Month.class, args, argsType);
          ? ?Month month=(Month)obj;
          ? ?System.out.println(BeanUtils.getProperty(month,"value"));
          argsType指定了參數(shù)的類型。
          ?
          六、ConstructorUtils補(bǔ)遺
          創(chuàng)建對(duì)象還有一個(gè)方法:invokeExactConstructor,該方法對(duì)參數(shù)要求
          更加嚴(yán)格,傳遞進(jìn)去的參數(shù)必須嚴(yán)格符合構(gòu)造方法的參數(shù)列表。
          例如:
          Object[] args={new Integer(1), "Jan"};
          Class[] argsType={int.class, String.class};
          Object obj;
          //下面這句調(diào)用將不會(huì)成功,因?yàn)閍rgs[0]的類型為Integer,而不是int
          //obj = ConstructorUtils.invokeExactConstructor(Month.class, args);

          //這一句就可以,因?yàn)閍rgsType指定了類型。
          obj = ConstructorUtils.invokeExactConstructor(Month.class, args, argsType);
          Month month=(Month)obj;
          System.out.println(BeanUtils.getProperty(month,"value"));


          七、MethodUtils
          與ConstructorUtils類似,不過調(diào)用的時(shí)候,通常需要再指定一個(gè)method name的參數(shù)。

          八、DynaClass/DynaBean
          這似乎是BeanUtils中最有趣的部分之一了,很簡(jiǎn)單,簡(jiǎn)單到光看這兩個(gè)接口中的方法會(huì)不明白
          為什么要設(shè)計(jì)這兩個(gè)接口。不過看到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();
          原來這是一個(gè)ResultSet的包裝器,ResultSetDynaClass實(shí)現(xiàn)了DynaClass,它的iterator方法返回一個(gè)
          ResultSetIterator,則是實(shí)現(xiàn)了DynaBean接口。
          在獲得一個(gè)DynaBean之后,我們就可以用
          ?????DynaBean row = (DynaBean) rows.next();
          ?????System.out.println(row.get("field1")); //field1是其中一個(gè)字段的名字

          再看另一個(gè)類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();
          //先打印一下,用于檢驗(yàn)后面的結(jié)果。
          while(rs.next()){
          System.out.println(rs.getString("name"));
          }
          rs.beforeFirst();//這里必須用beforeFirst,因?yàn)镽owSetDynaClass只從當(dāng)前位置向前滾動(dòng)

          RowSetDynaClass rsdc = new RowSetDynaClass(rs);
          rs.close();
          ps.close();
          List rows = rsdc.getRows();//返回一個(gè)標(biāo)準(zhǔn)的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的數(shù)據(jù),代價(jià)是占用內(nèi)存。如果一個(gè)表有10萬條記錄,rsdc.getRows()
          就會(huì)返回10萬個(gè)記錄。@_@

          需要注意的是ResultSetDynaClass和RowSetDynaClass的不同之處:
          1,ResultSetDynaClass是基于Iterator的,一次只返回一條記錄,而RowSetDynaClass是基于
          List的,一次性返回全部記錄。直接影響是在數(shù)據(jù)比較多時(shí)ResultSetDynaClass會(huì)比較的快速,
          而RowSetDynaClass需要將ResultSet中的全部數(shù)據(jù)都讀出來(并存儲(chǔ)在其內(nèi)部),會(huì)占用過多的
          內(nèi)存,并且速度也會(huì)比較慢。
          2,ResultSetDynaClass一次只處理一條記錄,在處理完成之前,ResultSet不可以關(guān)閉。
          3,ResultSetIterator的next()方法返回的DynaBean其實(shí)是指向其內(nèi)部的一個(gè)固定
          對(duì)象,在每次next()之后,內(nèi)部的值都會(huì)被改變。這樣做的目的是節(jié)約內(nèi)存,如果你需要保存每
          次生成的DynaBean,就需要?jiǎng)?chuàng)建另一個(gè)DynaBean,并將數(shù)據(jù)復(fù)制過去,下面也是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);
          ???}

          事實(shí)上DynaClass/DynaBean可以用于很多地方,存儲(chǔ)各種類型的數(shù)據(jù)。自己想吧。嘿嘿。


          九、自定義的CustomRowSetDynaClass
          兩年前寫過一個(gè)與RowSetDynaClass目標(biāo)相同的類,不過多一個(gè)功能,就是分頁,只取需要的數(shù)據(jù),
          這樣內(nèi)存占用就會(huì)減少。

          先看一段代碼:
          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();
          */

          //第二個(gè)參數(shù)表示第幾頁,第三個(gè)參數(shù)表示頁的大小
          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) {
          }
          }
          在這里用到了一個(gè)CustomRowSetDynaClass類,構(gòu)造方法中增加了page和pageSize兩個(gè)參數(shù),
          這樣,不管數(shù)據(jù)庫里有多少條記錄,最多只取pageSize條記錄,若pageSize==-1,則功能和
          RowSetDynaClass一樣。這在大多數(shù)情況下是適用的。該類的代碼如下:

          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的源碼中取得,只做了簡(jiǎn)單的修改,沒有加多余的注釋。如果要正式使用,
          需要再做精加工。
          原貼地址:http://www.54bk.com/user1/7053/archives/2006/200610269924.html
          posted on 2006-11-09 11:21 OMG 閱讀(2030) 評(píng)論(0)  編輯  收藏 所屬分類: Utils公用類/commons

          只有注冊(cè)用戶登錄后才能發(fā)表評(píng)論。


          網(wǎng)站導(dǎo)航:
           

          <2006年11月>
          2930311234
          567891011
          12131415161718
          19202122232425
          262728293012
          3456789

          常用鏈接

          留言簿(1)

          隨筆分類

          隨筆檔案

          IT風(fēng)云人物

          文檔

          朋友

          相冊(cè)

          經(jīng)典網(wǎng)站

          搜索

          •  

          最新評(píng)論

          閱讀排行榜

          評(píng)論排行榜

          主站蜘蛛池模板: 宁安市| 台江县| 屯昌县| 昌吉市| 嘉禾县| 高雄市| 西乌珠穆沁旗| 城口县| 嘉峪关市| 宝鸡市| 宜州市| 灵寿县| 信宜市| 嘉定区| 丰宁| 息烽县| 建德市| 绥中县| 兴安县| 达拉特旗| 滕州市| 资阳市| 博湖县| 阜宁县| 合川市| 永康市| 玉林市| 工布江达县| 清水县| 温泉县| 玉龙| 米泉市| 桓仁| 拉萨市| 汉阴县| 汉川市| 枞阳县| 镇江市| 黄龙县| 吉首市| 崇礼县|