选择显示字体大小

struts源代码阅读(commons-beanutils包)

    既然是说struts源代码,为什么要讲commons-beanutils包呢?原因很简单,struts的dynaformbean就是通过这个包里的相关类实现的。同样,留下我的邮箱,方便和大家共同交流。我的邮箱是:mariah_fan@hotmail.com。

commons-beanutils(一)

    commons-beanutils 这个是jakarta commons项目中的一个子项目。这个项目开发的目的是帮助开发者动态的获取/设值java bean的属性,同时解决每次都要写getxxx和setxxx的麻烦。

一、xxxconvert
    这些类都实现converter接口,提供把value值转化成为相应xxx类的实现。现在只针对四种类型:数字,时间,boolean和string。在converter 接口中只有一个方法convert(class type, object value),把value对象转换为type所要求的类。xxxconvert类中这个方法的思路是:
    1、如果value==null,并且自己内部有缺省的值那么就返回这个缺省的值。如果没有缺省值,就抛出conversionexception异常。
    2、如果value instanceof xxx类,那么就直接返回value。
    3、如果上面的都不行,那么调用new xxx(value.tostring())或者xxx.valueof(value.tostring())方法来返回。转化失败时,抛出conversionexception异常。

二、特殊的实现
1、对于classconverter类,当进入第三种情形的时候,实际执行的是
  

classloader classloader =thread.currentthread().getcontextclassloader();
   if (classloader == null) {
       classloader = classconverter.class.getclassloader();
   }
   return (classloader.loadclass(value.tostring()));


2、对于booleanconverter类,当进入第三种情形的时候,实际执行的是,根据value.tostring()的值:yes,y,true, on, 1 返回true;no,n,false,off,0 返回false。如果这些情形都不符合,并且有缺省值的时候则返回缺省值。否则抛出conversionexception;

三、xxxarrayconverter
    这些类继承自abstractarrayconverter类。 abstractarrayconverter 实际只实现了一个list parseelements(string svalue)方法。这个方法接受的是{value1, value2,...}格式的字符串,逐个解析出来后,放入一个arraylist中。它通过streamtokenizer解析字符串:streamtokenizer是用来分离input stream中读取的字符串,并且可以根据标记区分不同的内容,比如数字,字符或者注释。xxxarrayconverter由于要转换的是一个数组,所以convert(....)方法的实现过程有所不同。
    1、如果value==null,并且自己内部有缺省的值那么就返回这个缺省的值。如果没有缺省值,就抛出conversionexception异常。
    2、如果model.getclass() == value.getclass(),那么就直接返回value。
    3、如果上面的都不行,那么就通过parseelements(value.tostring())生成一个数组,再对数组的元素逐个调用new xxx(list.get(i))或者xxx.valueof(list.get(i))方法,转换成为数组对元素要求的类型。转化失败时,抛出conversionexception异常。

commons-beanutils(二)

一、localeconverter 与 baselocaleconverter
    localeconverter继承自 converter接口,定义了一个新方法convert(class type, object value, string pattern)。
    抽象类baselocaleconverter实现了localeconverter接口。它的locpattern属性用来表示这个对象的pattern是否是本地化的格式。patttern 是指把何种格式的时间或者数字值转换成标准值。convert(...)的执行过程是:
    1、如果value==null,并且自己内部有缺省的值那么就返回这个缺省的值。如果没有缺省值,就抛出conversionexception异常。
   2、根据参数pattern值是否为null,调用parse(object value, string pattern)方法:如果这个参数不为null那么就使用这个参数的值,否则使用对象预存的pattern值。如果这
样做引起了异常,会首先判断是否能够返回缺省的值,不能则抛出conversionexception异常。
   3、parse(object value, string
pattern)方法的实现被抛至继承了它的类具体实现。这个方法虽然把value值表述为object类型,但是最后都是通过强制转换,转换成为string类型。也就是说它实际上需要的
是string类型的value。

二、 xxxlocaleconverter
   把pattern格式的value转换成标准格式的相应的xxx类。这些类可以分为两大类:一类为时间,一类为数值。
1、时间类最后都会通过simpledateformat类对值进行转换,程序如下:
  
 if(pattern == null) {      
       pattern = locpattern ? new simpledateformat().tolocalizedpattern() :
                 new simpledateformat().topattern();
   }
   simpledateformat format = new simpledateformat(pattern, locale);
   if (locpattern) {
       formatter.applylocalizedpattern(pattern);
   }else {
       formatter.applypattern(pattern);
   }
   return formatter.parse((string) value);


2、数值类最后都会通过decimalformat类对值进行转换,程序如下:
  
decimalformat formatter = (decimalformat) decimalformat.getinstance(locale);
   if (pattern != null) {
       if (locpattern) {
           formatter.applylocalizedpattern(pattern);
       } else {
           formatter.applypattern(pattern);
       }
   }
   return formatter.parse((string) value);

   这个转化过程要注意精度的问题。由于number类是所有的数值类的父类,所以转换完成后要检查最后的结果是否是当前要求的精度:如果大于所要求的精度,则抛出conversionexception异常。

commons-beanutils(三)

dyna开头的类,是专门为dynaformbean而设计的。

一、dynabean,dynaclass 与 dynaproperty
    dynabean并不是java中所定义的bean,而是一种“假”的bean。因为它并不是通过getxxx和setxxx方法,对xxx属性进行取值和设值的。它通过一个实现了dynaclass接口的类,帮助管理其所有的属性的类别,而自己则管理对xxx属性值的设定和获取。在设值的时候会通过与name对应的dynaproperty对象,检查赋值的类别是否正确。
    dynaproperty类描述的是dynabean中所包含的属性的类型。dynaproperty类有三个属性:属性的名称:name,属性的名称;type,属性的类别;contenttype,如果dynaproperty描述的是个容器对象(list或者map),那么这个contenttype就代表这个容器内元素的类别。这个类值得关注的地方是writeobject和readobject方法的实现。它会首先判断自己的type是否是一个primitive的类,如果是,则先写入true标志,再写入对应的primitive类的编号;否则写入false标志,再写入type。因为在调用readobject方法时,如果得出的是primitive类型,则type的值为xxx.type而不是xxx.class。
    dynaclass 是一个接口,用来管理dynabean中所有的dynaproperty属性。

二、basicedyanbean 与 basicdynaclass
    basicedyanbean 实现自dynabean接口。它包含一个实现了dynaclass接口的类的对象,和一个用来存放值的hashmap。这个hashmap的key与dynaclass中hashmap的key是一一对应的。
    basicdynaclass 实现了dynaclass接口,以dynaproperty的name为key保存所有这些dynaproperty对象。它通过newinstance方法动态生成实现了dynabean接口的类的对象;注意这个类是可以动态指定的,如果没有,那么就是默认的basicdynabean类。动态指定类是通过反射实现的,程序如下:
    //dynabeanclass为任意的实现了dynabean接口的类,constructortypes为这个
    //类的构造方法所需要的参数的类型
    constructor = dynabeanclass.getconstructor(constructortypes);
    //constructorvalues为构造方法的参数值,实际上它的值为当前的basicdynaclass
     return ((dynabean) constructor.newinstance(constructorvalues));

commons-beanutils(四)

一、convertutils 和 convertutilsbean
    convertutils 是convertutilsbean类的一个简单封装,即convertutils中的所有方法都是通过直接调用convertutilsbean中的同名方法实现的。如果你需要更复杂的功能,就使用convertutilsbean,否则使用convertutils。
    convertutilsbean 通过一个hashmap管理所有的xxxconverter。这个hashmap的key为xxx的类全名,值为相应的xxxconverter对象。通过deregister()方法,初始化这个hashmap。这个初始化方法会为每一个xxxconverter类提供一个缺省的值。用户可以动过setdefaultxxx(...)方法来自行设置xxxconverter对象的缺省值。这个类还提供了convert(...)方法,对string value进行相应的转化。

二、propertyutils 和 propertyutilsbean
    propertyutils 是propertyutilsbean类的一个简单封装,同样它的所有方法都是通过直接调用propertyutilsbean 中同名方法实现的。
    propertyutilsbean 对dynabean或者一个java标准bean中的属性动态的赋值和取值(非通过getxxx和setxxx方法)。
1、这个类支持多层嵌套,比如:xxx[i].yyy(key).zzz,那么它会为你得到或者设置zzz的属性。
2、所有的set/get方法介绍:
    //对xxx(key)格式的name设值
    setmappedproperty(object bean, string name,string key, object value)
    //对xxx[i]格式的name设值
    setindexedproperty(object bean, string name, int index, object value)
    //对xxx格式的name设值
    setsimpleproperty(object bean, string name, object value)
   //对xxx(key).yyy[i].zzz格式的名称设值。注意,name必须要遵照这种格式。
   //这个方法实际做的就是以“.”为分隔符,逐层的根据情况分别调用上面的几个方法,
   //获取相应的bean。
   setnestedproperty(object bean, string name, object value)
   //它直接调用setnestedproperty方法
   setproperty(object bean, string name, object value)
3、getpropertytype(object bean, string name)方法中用来获取bean的某一个property的类型的代码:
    propertydescriptor descriptor = getpropertydescriptor(bean, name);
    if (descriptor == null) {
        return (null);
    }else if (descriptor instanceof indexedpropertydescriptor) {
         return (((indexedpropertydescriptor) descriptor).getindexedpropertytype());
    } else if (descriptor instanceof mappedpropertydescriptor) {
          return (((mappedpropertydescriptor) descriptor).getmappedpropertytype());
    } else {
          return (descriptor.getpropertytype());
    }
4、getindexedproperty(object bean, string name, int index)
    这个方法用来获取一个数组或者一个list中的属性。它会首先看这个bean是否是dynabean类型的,如果是,再其检查是否有name这个属性,如果有那么就直接调用get(string name, int index)方法返回值;如果不是dynabean类型,那么就会执行如下方法:
    //有没有为数组的某个特定元素取值的方法
    if (descriptor instanceof indexedpropertydescriptor) {
        method readmethod = ((indexedpropertydescriptor) descriptor).
               getindexedreadmethod();    
        if (readmethod != null) {
            object subscript[] = new object[1];
            subscript[0] = new integer(index);
            return (invokemethod(readmethod,bean, subscript));
        }
    }
    // 如果没有,就先取出整个对象
    method readmethod = getreadmethod(descriptor);
    if (readmethod == null) {
       throw new nosuchmethodexception("property '" + name +
               "' has no getter method");
    }
    object value = invokemethod(readmethod, bean, new object[0]);
    //如果这个对象实际上是一个list,那么调用get()方法
    if (!value.getclass().isarray()) {
        if (!(value instanceof java.util.list)) {
            throw new illegalargumentexception("property '" + name
                 + "' is not indexed");
        } else {
            //get the list's value
            return ((java.util.list) value).get(index);
        }
   //否则通过array类提供的相应方法取值
    } else {
        //get the array's value
        return (array.get(value, index));
    }

三、beanutil 和 beanutilbean
    beanutils 是beanutilsbean类的一个简单封装,同样它的所有方法都是通过直接调用beanutilsbean 中同名方法实现的。
    beanutilbean中大多数核心方法都是通过调用propertyutilsbean中的方法实现的。而populate(object bean, map properties)是自己实现的,因为这个赋值过程要首先对value进行格式的转化;这个方法把properties中的key为属性名,value为属性的值,分别对应的设值给bean对象。它通过setproperty(object bean, string name, object value)方法实现逐个设值的。由于此时的value不一定符合bean中name属性的类型,所以首先要把value转换成合适的值,然后再设值。具体的类型转换方法如下:

    
//这种类型转换的原则是:如果value是string或者string[],那么这个值可能为任意的类型, 
    //需要进行转换。如果为其它的类型,则不进行任何转换。
    if (type.isarray() && (index < 0)) {
        // 如果是直接对一个数组赋值,则使用convert(string values&#91;&#93;, class clazz)方法转换
        if (value == null) {
            string values&#91;&#93; = new string&#91;1&#93;;
            values&#91;0&#93; = (string) value;
            newvalue = getconvertutils().convert((string&#91;&#93;) values, type);
        } else if (value instanceof string) {
            string values&#91;&#93; = new string&#91;1&#93;;
            values&#91;0&#93; = (string) value;
            newvalue = getconvertutils().convert((string&#91;&#93;) values, type);
        } else if (value instanceof string&#91;&#93;) {
            newvalue = getconvertutils().convert((string&#91;&#93;) value, type);
        } else {
            newvalue = value;
        }
    } else if (type.isarray()) {
        // 如果是对数组的某一个元素赋值,则使用convert(string value, class clazz)方法转换
        if (value instanceof string) {
            newvalue = getconvertutils().convert((string) value, type.getcomponenttype());
        } else if (value instanceof string&#91;&#93;) {  
            newvalue = getconvertutils().convert(((string&#91;&#93;) value)&#91;0&#93;,type.getcomponenttype());
        } else {
            newvalue = value;    
        }
    } else {                
        // 否则就是一对一的简单赋值,则使用convert(string value, class clazz)方法转换
        if ((value instanceof string) (value == null)) {
            newvalue = getconvertutils().convert((string) value, type);
        } else if (value instanceof string&#91;&#93;) {
            newvalue = getconvertutils().convert(((string&#91;&#93;) value)&#91;0&#93;, type);      
        } else if (getconvertutils().lookup(value.getclass()) != null) {
            newvalue = getconvertutils().convert(value.tostring(), type);
        } else {
            newvalue = value;        }
    }


 


关键字 本文所属关键字

相关 与本文相关文章

分类 所有文章关键字导航

源码编程相关

Java   Asp   PHP   .Net   XML   C/C++   CGI   VB   Jsp   J2ee   J2se   J2me   EJB   Servlet   Tomcat   Resin   Struts   Weblogic   Eclipse   ANT   GUI   JMS   Web servise   IDEA   Webphere   Hibernate   Spring   Jboss   Applet   Swing   Socket   Javamail   Perl   Ajax   P2P   安全   模式   框架   测试   开源   游戏

SQL数据库相关

My-SQL   Ms-SQL   Access   DB2   Oracle   Sybase   SQLserver   索引   存储过程   加密   数据库   分页   视图  

手机无线相关

3G   Wap   CDMA   GRPS   GSM   IVR   彩信   短信   无线   增值业务

网页设计制作相关

HTML   CSS   网页配色   网页特效   Javascript   VBscript   Dreamweaver   Frontpage   JS   Web   网站设计

网站建设推广相关

建站经验   网站优化   网站排名   推广   Alexa

操作系统/服务器相关

Windows XP   Windows 2000   Windows 2003   Windows Me   Windows 9.x   Linux   UNIX   注册表   操作系统   服务器   应用服务器

图形图像多媒体相关

Photoshop   Fireworks   Flash   Coreldraw   Illustrator   Freehand   Photoimpact   多媒体   图形图像

标准 网站致力的规范

Valid CSS!

无不良内容,无不良广告,无恶意代码

Valid XHTML 1.0 Transitional

creativecommons