`
zerozone
  • 浏览: 203105 次
  • 来自: 北京
社区版块
存档分类
最新评论

用Java实现Object对象树输出到XML文件

    博客分类:
  • Java
阅读更多
本文将结合面向对象设计原则实践来介绍如何将一个Java对象树输出到XML文件模块。

需求

项目功能:查询数据并生成XML文件然后上传至指定服务器
本模块功能:实现Java对象树输出到 XML文件。

要求
1. 支持对象及属性的扩展,而XML输出模块代码基本不变。
2. 考虑到内存压力,要求该模块实现以追加方式操作XML文件。

输入
Java对象树(提供一个类以方法,作为该对象的操作入口)

输出
XML文档

数值传输对象(DTO,Data Transfer Object),仅包含属性和setter/getter方法。如例1所示。属性的型别基本固定(例如String, int,boolean,List等),对于List的属性,可能包含另一个Java Object(如例3所示)。XML输出格式很简单,除去头部信息之外基本是attribute+value。例2是例1对象XML输出片段。

例1
java 代码
 
  1. public class FromTo{    
  2.     private String fromNo;    
  3.     private String toNo;    
  4.     private FromTo() { }    
  5.    
  6.     public void setFromNo(String fromNo){    
  7.           this.fromNo = fromNo;    
  8.     }    
  9.       
  10.      public String getFromNo() {    
  11.            return fromNo;    
  12.      }    
  13.            
  14.      public void setToNo(String toNo){    
  15.            this.toNo = toNo;    
  16.      }    
  17.           
  18.      public String getToNo() {    
  19.            return toNo;    
  20.      }    
  21. }    

例2
xml 代码
 
  1. <fromNo>DLS</fromNo>                
  2. <toNo>BJS</toNo>  

例3
java 代码
 
  1. public class CarrierFlight implements Serializable {    
  2.     /**  
  3.      *  
  4.      */    
  5.     private static final long serialVersionUID = 4295207854877905411L;    
  6.     private List apFlightNoList = new ArrayList(); //apFlightNoList存储FromTo类型的对象    
  7.     private List exFlightNoList = new ArrayList();  //同上    
  8.     private String carrierCode;    
  9.     private String rbd;    
  10.         
  11.     public CarrierFlight(){    }    
  12.         
  13.     /**  
  14.      * @param apFlightNoList  
  15.      */    
  16.     public void setApFlightNoList(List apFlightNoList) {    
  17.         this.apFlightNoList = apFlightNoList;    
  18.     }    
  19.         
  20.     /**  
  21.      * @return  
  22.      */    
  23.     public List getApFlightNoList() {    
  24.         return apFlightNoList;    
  25.     }    
  26.     
  27.     /**  
  28.      * @param apFlightNos  
  29.      */    
  30.     public void setApFlightNoList(ApFlightNo[] apFlightNos){    
  31.         if(!ArraysUtil.foreachable(apFlightNos))    
  32.             return;    
  33.         for(int i=0;i < apFlightNos.length;i++)  
  34.             this.apFlightNoList.add(apFlightNos[i];    
  35.     }    
  36.         
  37.     /**  
  38.       * @param exFlightNoList  
  39.       */    
  40.     public void setExFlightNoList(List exFlightNoList) {    
  41.        this.exFlightNoList = exFlightNoList;    
  42.     }    
  43.         
  44.     /**  
  45.      * @return  
  46.      */    
  47.     public List getExFlightNoList() {    
  48.        return exFlightNoList;    
  49.     }    
  50.         
  51.     /**  
  52.      * @param exFlightNos  
  53.      */    
  54.     public void setExFlightNoList(ExFlightNo[] exFlightNos){    
  55.         if(!ArraysUtil.foreachable(exFlightNos))    
  56.             return;    
  57.         for(int i=0;i < exFlightNos.length;i++)  
  58.            this.exFlightNoList.add(exFlightNos[i];    
  59.     }    
  60.         
  61.    /**  
  62.      * @param carrierCode  
  63.      */    
  64.     public void setCarrierCode(String carrierCode){    
  65.         this.carrierCode = carrierCode;    
  66.     }    
  67.         
  68.    /**  
  69.      * @return  
  70.      */    
  71.     public  String getCarrierCode(){    
  72.          return this.carrierCode;    
  73.     }    
  74.     
  75.    /**  
  76.      * @param rbd  
  77.      */    
  78.     public void setRBD(String rbd){    
  79.         this.rbd = rbd;    
  80.    }    
  81.   
  82.    /**  
  83.      * @return   
  84.      */    
  85.     public  String getRBD(){    
  86.          return this.rbd;    
  87.     }    
  88. }  

分析

先介绍一下XML输出模块的旧版本。它直接处理判断对象的类型,并显示获取其getter方法,得到属性的值后操作XML文档(即dom4j的Document)。如下所示
java 代码
 
  1. Object obj = getFromToObject();      
  2.            
  3. if(fromTo instanceof FromTo){      
  4.     FromTo fromto = (FromTo)obj;      
  5.     String fromNo = fromto.getFromNo();      
  6.     String toNo = fromto.getToNo();      
  7.     if(fromNo!=null && fromNo.length()>0){      
  8.          xml.output("<fromNo>"+fromNo+"</fromNo>");      
  9.     }      
  10.     if(toNo!=null && toNo.length()>0){      
  11.          xml.output("<toNo>"+toNo+"</toNo>");      
  12.     }    
  13. }      
  14. //....     

面向对象设计两个重要原则:单一职责原则(SRP)和开放-闭合原则(OCP)。SRP要求对每个类仅有一个引起它变化的原因。OCP要求对扩展开放,对修改封闭。<o:p></o:p>

上述代码很容易理解,但它充满臭味:不必要的重复和脆弱性(想象如何把例3展示的CarrierFlight输出到XML)。引起上述代码发生变化的原因很多:Java对象树中某个对象的属性或者XML输出格式改变。同时,缺乏抽象导致该类很难扩展(例如增加对新类型的Object的支持而代码不改变),每次修改都必须改动同一个类。<o:p></o:p>

<o:p>遵循SRP和OCP,需要:</o:p>

<o:p>1.把XML输出和对象解析过程分离</o:p>

<o:p>2.把频繁变化的部分抽象
</o:p>


设计

对象解析

如说封装对象及属性的变化。数值对象有属性组成(以及setter/getter方法,此处忽略);Property(及属性)由类型(已封装成Type类,它将常用的类型定义成类并将静态实例暴露给外界),名称和Alias组成。对象树实际上是数据结构中的树。属性就是叶子。List型属性是可解析的,因此有字节点;非List型属性是末级节点。是否可解析可通过调用listable方法判断。

Property类实现了属性初始化(加载所有属性并生成相应对象供解析时使用)。利用反射机制可获得每个属性的的getter方法并在对象上调用该方法以取得其值。遍历所有节点可构造成一棵Element(稍后还会讲到该接口)树。

XML输出


dom4j是一个开源的XML工具,它支持XML解析和输出。但输出XML的过程采用内存构造Document方式。输出时调用Document.write方法写文件。前面已经提到,由于对象树非常庞大,一次构造完整的Document对象将导致OutOfMemoryError错误。如果能够实现以Append操作XML文件方式替换前面提到的方式,将会避免该问题出现。

Element接口定义了XML元素这个概念。它支持设置元素名称,文本和IO输出操作。XMLStream实现了Element接口,可以表示一个XMl元素并能输出到指定设备。XMLWriter实现了对Element输出到XML的过程。



  • 大小: 33.7 KB
分享到:
评论
5 楼 youbin_ 2007-05-28  
有没有试试axiom,听起来不错哦!
4 楼 zyl 2007-05-19  
引用

我提到要输出对象可能非常非常大,一次输出到XML可能会报OutOfMemoryError。

能有多大的对象?xstream应该支持大对象。不过xstream也有其局限的地方。
3 楼 CALM 2007-05-18  
如果不考虑对象很大,java.beans.XMLEncoder,java.beans.XMLDecoder直接就可以做
2 楼 zerozone 2007-05-18  
zhangbo297600 写道
你这个,不能实现,在对像中,还有别的对像的情况吧,你只实现了最基础的一层式xml。

还不如用这个包
com.thoughtworks.xstream.XStream.
可以将对像直接xstream.toXML(obj),也可以将xml 还原成对像 xstream.fromXML(xml);

所有操作,一句话搞定


说的没错。一句话可以搞定。

但你没理解我的应用上下文,我提到要输出对象可能非常非常大,一次输出到XML可能会报OutOfMemoryError。

所以才有我的解决方案:就是降低操作的对象级别,多次写文件。以缓解可能的内存压力。项目从一开始就确定要避免一次性输出文件。

至于对象中的各种情况,代码没有考虑太多,但支持扩展能力。

com.thoughtworks.xstream.XStream的方法toXML(obj),能否支持超大对象的输出?
1 楼 zhangbo297600 2007-05-18  
你这个,不能实现,在对像中,还有别的对像的情况吧,你只实现了最基础的一层式xml。

还不如用这个包
com.thoughtworks.xstream.XStream.
可以将对像直接xstream.toXML(obj),也可以将xml 还原成对像 xstream.fromXML(xml);

所有操作,一句话搞定

相关推荐

    java源码包---java 源码 大量 实例

     Java生成密钥、保存密钥的实例源码,通过本源码可以了解到Java如何产生单钥加密的密钥(myKey)、产生双钥的密钥对(keyPair)、如何保存公钥的字节数组、保存私钥到文件privateKey.dat、如何用Java对象序列化保存私钥...

    JAVA上百实例源码以及开源项目

     Java生成密钥、保存密钥的实例源码,通过本源码可以了解到Java如何产生单钥加密的密钥(myKey)、产生双钥的密钥对(keyPair)、如何保存公钥的字节数组、保存私钥到文件privateKey.dat、如何用Java对象序列化保存私钥...

    java源码包2

     Java生成密钥、保存密钥的实例源码,通过本源码可以了解到Java如何产生单钥加密的密钥(myKey)、产生双钥的密钥对(keyPair)、如何保存公钥的字节数组、保存私钥到文件privateKey.dat、如何用Java对象序列化保存私钥...

    java源码包4

     Java生成密钥、保存密钥的实例源码,通过本源码可以了解到Java如何产生单钥加密的密钥(myKey)、产生双钥的密钥对(keyPair)、如何保存公钥的字节数组、保存私钥到文件privateKey.dat、如何用Java对象序列化保存私钥...

    java源码包3

     Java生成密钥、保存密钥的实例源码,通过本源码可以了解到Java如何产生单钥加密的密钥(myKey)、产生双钥的密钥对(keyPair)、如何保存公钥的字节数组、保存私钥到文件privateKey.dat、如何用Java对象序列化保存私钥...

    JAVA上百实例源码以及开源项目源代码

     Java生成密钥、保存密钥的实例源码,通过本源码可以了解到Java如何产生单钥加密的密钥(myKey)、产生双钥的密钥对(keyPair)、如何保存公钥的字节数组、保存私钥到文件privateKey.dat、如何用Java对象序列化保存私钥...

    JAVA_API1.6文档(中文)

    java.io 通过数据流、序列化和文件系统提供系统输入和输出。 java.lang 提供利用 Java 编程语言进行程序设计的基础类。 java.lang.annotation 为 Java 编程语言注释设施提供库支持。 java.lang.instrument 提供...

    成百上千个Java 源码DEMO 4(1-4是独立压缩包)

    凯撒加密解密程序 1个目标文件 1、程序结构化,用函数分别实现 2、对文件的加密,解密输出到文件 利用随机函数抽取幸运数字 简单 EJB的真实世界模型(源代码) 15个目标文件 摘要:Java源码,初学实例,基于EJB的真实...

    java开源包4

    WebSocket4J 是一个用 Java 实现的 WebSocket 协议的类库,可使用 Java 来构建交互式 Web 应用。WebSocket4J 并未实现客户端通讯协议,所以不能用它来连接 WebSocket 服务器。 Struts验证码插件 JCaptcha4Struts2 ...

    成百上千个Java 源码DEMO 3(1-4是独立压缩包)

    凯撒加密解密程序 1个目标文件 1、程序结构化,用函数分别实现 2、对文件的加密,解密输出到文件 利用随机函数抽取幸运数字 简单 EJB的真实世界模型(源代码) 15个目标文件 摘要:Java源码,初学实例,基于EJB的真实...

    java开源包3

    WebSocket4J 是一个用 Java 实现的 WebSocket 协议的类库,可使用 Java 来构建交互式 Web 应用。WebSocket4J 并未实现客户端通讯协议,所以不能用它来连接 WebSocket 服务器。 Struts验证码插件 JCaptcha4Struts2 ...

    Java 1.6 API 中文 New

    org.omg.CORBA 提供 OMG CORBA API 到 JavaTM 编程语言的映射,包括 ORB 类,如果已实现该类,则程序员可以使用此类作为全功能对象请求代理(Object Request Broker,ORB)。 org.omg.CORBA_2_3 CORBA_2_3 包定义对 ...

    java开源包8

    WebSocket4J 是一个用 Java 实现的 WebSocket 协议的类库,可使用 Java 来构建交互式 Web 应用。WebSocket4J 并未实现客户端通讯协议,所以不能用它来连接 WebSocket 服务器。 Struts验证码插件 JCaptcha4Struts2 ...

    java开源包11

    WebSocket4J 是一个用 Java 实现的 WebSocket 协议的类库,可使用 Java 来构建交互式 Web 应用。WebSocket4J 并未实现客户端通讯协议,所以不能用它来连接 WebSocket 服务器。 Struts验证码插件 JCaptcha4Struts2 ...

    java开源包6

    WebSocket4J 是一个用 Java 实现的 WebSocket 协议的类库,可使用 Java 来构建交互式 Web 应用。WebSocket4J 并未实现客户端通讯协议,所以不能用它来连接 WebSocket 服务器。 Struts验证码插件 JCaptcha4Struts2 ...

    java开源包9

    WebSocket4J 是一个用 Java 实现的 WebSocket 协议的类库,可使用 Java 来构建交互式 Web 应用。WebSocket4J 并未实现客户端通讯协议,所以不能用它来连接 WebSocket 服务器。 Struts验证码插件 JCaptcha4Struts2 ...

    java开源包101

    WebSocket4J 是一个用 Java 实现的 WebSocket 协议的类库,可使用 Java 来构建交互式 Web 应用。WebSocket4J 并未实现客户端通讯协议,所以不能用它来连接 WebSocket 服务器。 Struts验证码插件 JCaptcha4Struts2 ...

    java api最新7.0

    org.omg.CORBA 提供 OMG CORBA API 到 JavaTM 编程语言的映射,包括 ORB 类,如果已实现该类,则程序员可以使用此类作为全功能对象请求代理(Object Request Broker,ORB)。 org.omg.CORBA_2_3 CORBA_2_3 包定义对 ...

Global site tag (gtag.js) - Google Analytics