手动实现XStream转换器工厂

简介:
XStream提供了与apache betwixt2类似的功能,缺点是在易用性差,优点是提供相当快的速度,即使个头巨大的XML也不在话下。
 
下面是一个通过XML配置装配XStream转换器工厂(方便获取XStream的工具),在大型的XML数据交换中发挥了出色的效果。本例是做复杂封装的一个测试。基本思想如此,放出来大家看看:
 
 
通常要转换的Java类是确定的。因此事先先定义一个比较复杂的Bean,然后以此为蓝本,看看转换器实现过程,以及测试效果。
 
一、目标Bean:
要转换的Java对象
public  class User { 
         private Long id; 
         private String username; 
         private String password; 
         private UserProfile userProfile =  new UserProfile(); 
         private Collection<Address> addresses =  new HashSet<Address>();
 
public  class UserProfile { 
         private  long id; 
         private String sex; 
         private Date birthday; 
         private String telphone; 
         private String email; 
         private Long userId;
 
public  class Address { 
         private Long id; 
         private String addr; 
         private String postCode;
 
 
 
二、转换器配置
主要配置类和成员的别名信息
<? xml  version ="1.0"  encoding ="GBK" ?> 

<!--  
        Document     : InfoUnits.xml.xml 
        Created on : 2008年6月9日, 下午8:10 
        Author         : leizhimin 
        Description: 转换器配置文档所约定的配置规则如下: 
                1:根元素InfoUnits包含了若干要转换目标类的配置信息. 
                2:class属性为节点所对应的类,en为节点类的属性名,元素节点名为别名信息. 
                3:每个目标类都是配置文档根节点下的直接子节点,并且有class属性,而没有en属性. 
                4:目标类下面有还可以包含更多的子元素,如果子元素类型为自定义的Class类型. 
--> 
< InfoUnits > 
         < User  class ="User" > 
                 < ID  en ="id" /> 
                 < MC  en ="username" /> 
                 < MM  en ="password" /> 
                 < UserProfile  class ="UserProfile"  en ="userProfile" > 
                         < ID  en ="id" /> 
                         < XB  en ="sex" /> 
                         < SR  en ="birthday" /> 
                         < DH  en ="telphone" /> 
                         < YJDZ  en ="email" /> 
                         < YHID  en ="userId" /> 
                 </ UserProfile > 
                 < Address-List  en ="addersses" > 
                         < Address  class ="Address" > 
                                 < ID  en ="id" /> 
                                 < DZ  en ="addr" /> 
                                 < YB  en ="postCode" /> 
                         </ Address > 
                 </ Address-List > 
         </ User > 
</ InfoUnits > 
 
 
三、转换器的构建
这是最复杂的部分,需要递归处理。
import com.thoughtworks.xstream.XStream; 
import org.dom4j.Document; 
import org.dom4j.DocumentException; 
import org.dom4j.Element; 
import org.dom4j.io.SAXReader; 

import java.io.InputStream; 
import java.util.HashMap; 
import java.util.Iterator; 
import java.util.List; 
import java.util.Map; 

/** 
* 转换器配置信息工具类,加载配置信息后会生成一个转换器工厂的注册表,为整个系统提供高效的转换器 

* @author leizhimin 
*/
 
public  class InfoUnitConfigUtils { 
         //配置文档路径 
         public  static  final String CONFIG_FILE =  "/InfoUnits.xml"
         //XStream转换器注册表,也成为转换器工厂。 
         public  static  final Map<Class, XStream> converterMap =  new HashMap<Class, XStream>(); 

         static { 
                 try { 
                        reload(); 
                }  catch (ClassNotFoundException ex) { 
                        System.out.println(ex.getMessage()); 
                         throw  new RuntimeException(ex); 
                } 
        } 

         /** 
         * 重新载入配置文件信息并生成XStream转化器注册表 
         * 
         * @throws ClassNotFoundException 
         */
 
         public  static  void reload()  throws ClassNotFoundException { 
                Document document = getCfgDocument(); 
                 //遍历配置文档,构建转换器工厂。 
                 for (Iterator<Element> ite = document.getRootElement().elementIterator(); ite.hasNext();) { 
                        Element element = ite.next(); 
                        XStream xStream =  new XStream(); 
                        getAlias(element, xStream); 
                        Class clazz = Class.forName(element.selectSingleNode( "@class").getText().trim()); 
                        converterMap.put(clazz, xStream); 
                } 
        } 

         /** 
         * 获取配置信息文档对象 
         * 
         * @return 配置信息文档对象 
         */
 
         public  static Document getCfgDocument() { 
                InputStream ins = InfoUnitConfigUtils. class.getResourceAsStream(CONFIG_FILE); 
                SAXReader reader =  new SAXReader(); 
                Document doucument =  null
                 try { 
                        doucument = reader.read(ins); 
                }  catch (DocumentException ex) { 
                        System.out.println(ex.getMessage()); 
                         throw  new RuntimeException(ex); 
                } 
                 return doucument; 
        } 

         public  static Map<Class, XStream> getConverterMap() { 
                 return converterMap; 
        } 

         /** 
         * 递归设置转换器的别名信息 
         * 
         * @param element 配置文档元素节点,该节点带有一个class的属性 
         * @param xStream 转换器对象 
         * @throws ClassNotFoundException 
         */
 
         public  static  void getAlias(Element element, XStream xStream)  throws ClassNotFoundException { 
                 //如果当前元素具有class属性,则为类型节点,设置类别名 
                 if (element.selectSingleNode( "@class") !=  null) { 
                        Class clazz = Class.forName(element.selectSingleNode( "@class").getText().trim()); 
                         //带有class属性的节点名作为类的别名 
                        xStream.alias(element.getName().trim(), clazz); 
                } 
                 //如果当前元素具有en属性,则为属性节点,设置属性的别名。 
                 if (element.selectSingleNode( "@en") !=  null) { 
                         //属性所属的类 
                        Class fatherClazz = Class.forName(element.getParent().selectSingleNode( "@class").getText().trim()); 
                        xStream.aliasField(element.getName().trim(), fatherClazz, element.selectSingleNode( "@en").getText().trim()); 
                } 
                 //递归设置参数元素下所有元素的别名信息 
                List<Element> eList = element.elements(); 
                 if (eList.size() > 0) { 
                         for (Element e : eList) { 
                                getAlias(e, xStream); //递归设置 
                        } 
                } 
        } 
}
 
 
四、测试
有了转换器,就可以将射程范围(所配置的Java类)内的类以及格式匹配的XML做个双向的转换。
 
import com.thoughtworks.xstream.XStream; 

import java.util.Calendar; 
import java.util.Collection; 
import java.util.HashSet; 

/** 
* @author leizhimin 
*/
 
public  class SimpleConverter { 

         public  static  void main(String args[]) { 
                User user =  new User(100L,  "admin""123456"); 
                Calendar c = Calendar.getInstance(); 
                c.set(1982, 3, 3); 
                UserProfile profile =  new UserProfile(1000L,  "M", c.getTime(),  "66668888""[email]admin@yahoo.com.cn[/email]", 100L); 
                Address address1 =  new Address(2000L,  "郑州市花园路""450001"); 
                Address address2 =  new Address(2001L,  "郑州市经三路""450001"); 
                Collection<Address>    co =  new HashSet<Address>(); 
                co.add(address1); 
                co.add(address2); 
                user.setAddresses(co); 
                user.setUserProfile(profile); 

                XStream xStream = InfoUnitConfigUtils.converterMap.get(User. class); 
                String xml = xStream.toXML(user); 
                System.out.println(xml); 

                User u = (User) xStream.fromXML(xml); 
                System.out.println(u); 

                String xml_address =  "        <Address>\n" + 
                                 "            <id>2001</id>\n" + 
                                 "            <addr>郑州市经三路</addr>\n" + 
                                 "            <postCode>450001</postCode>\n" + 
                                 "        </Address>"

                Address add_1 = (Address) xStream.fromXML(xml_address); 
                System.out.println(add_1.getAddr()); 


                XStream xStream1 = InfoUnitConfigUtils.getConverterMap().get(user.getClass()); 
                System.out.println( "------"); 
                System.out.println(xStream1.toXML(user)); 

                NewClass nc =  new NewClass(100L, address1); 
                nc.getUserProfiles().add(profile); 

                String nc_xml = xStream.toXML(nc); 
                System.out.println(nc_xml); 

        } 
}
 
测试结果:
<User> 
    <ID>100</ID> 
    <MC>admin</MC> 
    <MM>123456</MM> 
    <UserProfile> 
        <ID>1000</ID> 
        <XB>M</XB> 
        <SR>1982-04-03 15:55:02.621 CST</SR> 
        <DH>66668888</DH> 
        <YJDZ>[email]admin@yahoo.com.cn[/email]</YJDZ> 
        <YHID>100</YHID> 
    </UserProfile> 
    <addresses  class= "set"
        <Address> 
            <ID>2000</ID> 
            <DZ>郑州市花园路</DZ> 
            <YB>450001</YB> 
        </Address> 
        <Address> 
            <ID>2001</ID> 
            <DZ>郑州市经三路</DZ> 
            <YB>450001</YB> 
        </Address> 
    </addresses> 
</User> 
User@1bca5f1 
郑州市经三路 
------ 
<User> 
    <ID>100</ID> 
    <MC>admin</MC> 
    <MM>123456</MM> 
    <UserProfile> 
        <ID>1000</ID> 
        <XB>M</XB> 
        <SR>1982-04-03 15:55:02.621 CST</SR> 
        <DH>66668888</DH> 
        <YJDZ>[email]admin@yahoo.com.cn[/email]</YJDZ> 
        <YHID>100</YHID> 
    </UserProfile> 
    <addresses  class= "set"
        <Address> 
            <ID>2000</ID> 
            <DZ>郑州市花园路</DZ> 
            <YB>450001</YB> 
        </Address> 
        <Address> 
            <ID>2001</ID> 
            <DZ>郑州市经三路</DZ> 
            <YB>450001</YB> 
        </Address> 
    </addresses> 
</User> 
<NewClass> 
    <id>100</id> 
    <adderss> 
        <ID>2000</ID> 
        <DZ>郑州市花园路</DZ> 
        <YB>450001</YB> 
    </adderss> 
    <userProfiles  class= "set"
        <UserProfile> 
            <ID>1000</ID> 
            <XB>M</XB> 
            <SR>1982-04-03 15:55:02.621 CST</SR> 
            <DH>66668888</DH> 
            <YJDZ>[email]admin@yahoo.com.cn[/email]</YJDZ> 
            <YHID>100</YHID> 
        </UserProfile> 
    </userProfiles> 
</NewClass> 

Process finished with exit code 0 
 
符合期望值,工厂构建成功!
 
 
从上面配置看,配置的代价是非常的小的,比起用Java一个一个设置更方便,更易于维护。甚至比betwixt2还简单很多。这个封装不是最简单的,仅仅是一个可行性的研究。
 

本文转自 leizhimin 51CTO博客,原文链接:http://blog.51cto.com/lavasoft/100208,如需转载请自行联系原作者
相关文章
|
8月前
|
设计模式 Java Spring
更简单的取 Bean 对象(对象装配)(上)
更简单的取 Bean 对象(对象装配)(上)
|
8月前
|
Java 测试技术 Spring
更简单的取 Bean 对象(对象装配)(下)
更简单的取 Bean 对象(对象装配)(下)
|
11月前
|
XML Java 数据格式
Spring OXM-XStream转换器
Spring OXM-XStream转换器
40 0
|
11月前
|
Java Spring 容器
Spring构造通过工厂创建bean
Spring构造通过工厂创建bean
|
分布式计算
OutputFormat接口实现类案例
OutputFormat接口实现类案例
OutputFormat接口实现类案例
SpringMVC - 数据绑定(自定义数据转换器:PropertyEditor、Formatter、Converter)(三)
SpringMVC - 数据绑定(自定义数据转换器:PropertyEditor、Formatter、Converter)(三)
149 0
|
存储 Java
javaBean内省类【javaBean、BeanInfo、Introspector、PropertyDescriptor】
javaBean内省类【javaBean、BeanInfo、Introspector、PropertyDescriptor】
176 0
javaBean内省类【javaBean、BeanInfo、Introspector、PropertyDescriptor】
|
XML Java 数据格式
XStream转换器: 处理xml节点中既有属性又有值
XStream转换器: 处理xml节点中既有属性又有值
553 0
|
Java 数据格式 XML
使用dozer实现对象转换
Dozer的github地址:https://github.com/DozerMapper/dozer Dozer的官方文档:http://dozer.sourceforge.net/ 什么是DozerDozer是一个JavaBean映射工具库。
1331 0
|
XML 前端开发 数据格式
第2章—装配Bean—通过XML装配Bean
通过XML装配Bean ​ 尽管我们在生成Bean的过程中可以用到很多方法,但我们依然需要Spring的XML配置来完善更多的需求,下面就来介绍下XML装配Bean的过程是怎样的.
842 0