在升級的版本中,如果對Java類的改動超出了對象序列化兼容性的範圍,如:改變了類圖結構中的繼承關係和層次結構,改變或增減了類成員變量數量和類型等等,都會造成新老版本的數據不一致性。很有可能新版本的系統不能兼容和使用老版本系統產生的數據。
由於序列化所產生的數據是由JVM內部機制生成的二進制數據,對其進行修改和轉換有一定的困難和風險。而且二進制數據的可讀性比較差。而對這些圖形數據的操作是此係統不可缺少的一部分。例如,不同版本之間的數據轉換,不同格式之間的轉換以及系統數據的導入和導出,都需要對系統數據進行不同程度的操作。
用序列化保存的數據通常包含了大量無用的信息。例如,保存一個簡單的"Button",序列化會保存它所有父類對象的所有實例的成員變量,還會保存這個對象所有缺省的其他屬性。而實際上,我們只要關心這個"Button"上面的文本,加上它在圖面中的座標就行了。要控制序列化保存數據量的大小需要較複雜和繁瑣的設置,例如使用“transit”修飾符等等(詳見參考資料)。
不同的JDK的序列化實現有可能會有差異,保存數據的格式也有所不同,這就使得系統有可能被綁定在某個版本的JDK,而不能使用高版本的JDK所帶來的性能上和功能上的好處!
圖 1 JAXB體系結構
l 使用JAXB 所帶的編譯工具(Binding Compiler),將這個XML Schema文件作爲輸入,產生一系列相關的Java Class和Interfacel 在使用JAXB編譯工具的時候,可以有選擇性的提供一個配置文件(圖1的虛線部分),來控制JAXB編譯工具的一些高級屬性。l 這些Java Class和Interface是你的應用程序操縱XML數據的主要接口和方法。l 通過JAXB對XML文檔進行的操作主要包括:將符合XML Schema規定的XML文檔解析生成一組相應的Java對象;對這些對象進行操作(修改、增加和刪除對象的屬性等等);然後將這些對象的內容保存到這個XML文檔中。
本示例運行的Java環境是JDK1.3.1以上。本示例在Jdk1.4.1運行測試通過。l 展開此壓縮文件,在bin目錄下找到可執行文件rundemo.bat(for windows)或rundemo.sh。 (for unix)l 確保環境變量JAVA_HOME已經正確設置,指向你係統所安裝的JDK的目錄。l 運行rundemo.bat 或rundemo.sh,就會出現如下圖所示的運行畫面。
圖2 demo運行場景
set JAVA_HOME=c:/application/java/jdk1.4.1_01
set JWSDP_HOME=c:/application/wsdp1.1
set JAXB_HOME=%JWSDP_HOME%/jaxb-1.0
set JAXB_LIBS=%JAXB_HOME%/lib
set JAXP_LIBS=%JWSDP_HOME%/jaxp-1.2.2/lib
set JWSDP_LIBS=%JWSDP_HOME%/jwsdp-shared/lib
set PATH=%JAXB_HOME%/bin;%JWSDP_HOME%/jwsdpshared/bin;%PATH%
set CLASSPATH=%JAXB_LIBS%/jaxb-api.jar;%JAXB_LIBS%/jaxb-ri.jar;%JAXB_LIBS%/jaxb-xjc.jar;%JAXB_LIBS%/jaxb-libs.jar;%JAXP_LIBS%/jaxb-api.jar;%JAXP_LIBS%/endorsed/xercesImpl.jar;%JAXP_LIBS%/endorsed/xalan.jar;%JAXP_LIBS%/endorsed/sax.jar;%JAXP_LIBS%/endorsed/dom.jar;%JWSDP_LIBS%/jax-qname.jar;%JWSDP_LIBS%/namespace.jar;.
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<shapeContainer>
<shape>
<xposition>185</xposition>
<yposition>83</yposition>
<shapename>circle</shapename>
<shapecolor>red</shapecolor>
</shape>
<shape>
<xposition>169</xposition>
<yposition>177</yposition>
<shapename>circle</shapename>
<shapecolor>green</shapecolor>
</shape>
<shape>
<xposition>358</xposition>
<yposition>155</yposition>
<shapename>rect</shapename>
<shapecolor>green</shapecolor>
</shape>
</shapeContainer>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:element name="appversion" type="xsd:string"/>
<xsd:element name="shapeContainer" type="ShapeContainerType"/>
<xsd:complexType name="ShapeContainerType">
<xsd:sequence>
<xsd:element name="shape" type="ShapeType" minOccurs="1" maxOccurs="unbounded"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="ShapeType">
<xsd:sequence>
<xsd:element name="xposition" type="xsd:int"/>
<xsd:element name="yposition" type="xsd:int"/>
<xsd:element name="shapename" type="ShapeNameType"/>
<xsd:element name="shapecolor" type="ShapeColorType"/>
</xsd:sequence>
</xsd:complexType>
<xsd:simpleType name="ShapeColorType">
<xsd:restriction base="xsd:string">
<xsd:enumeration value="green"/>
<xsd:enumeration value="red"/>
</xsd:restriction>
</xsd:simpleType>
<xsd:simpleType name="ShapeNameType">
<xsd:restriction base="xsd:string">
<xsd:enumeration value="circle"/>
<xsd:enumeration value="rect"/>
</xsd:restriction>
</xsd:simpleType>
</xsd:schema>
<xsd:complexType name="ShapeContainerType">
<xsd:sequence>
<xsd:element name="shape" type="ShapeType" minOccurs="1" maxOccurs="unbounded"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="ShapeType">
<xsd:sequence>
<xsd:element name="xposition" type="xsd:int"/>
<xsd:element name="yposition" type="xsd:int"/>
<xsd:element name="shapename" type="ShapeNameType"/>
<xsd:element name="shapecolor" type="ShapeColorType"/>
</xsd:sequence>
</xsd:complexType>
%JAXB_HOME%/bin/xjc.bat demo.xsd -d src -p epri.jaxb
JaxbDemoFrame.java中大部分都是處理Frame中組件的代碼。包括畫布、菜單的初始化,以及各種事件的處理代碼。其中和JAXB有關的有JAXB初始化代碼:
127 try {
128 JAXBContext jc = JAXBContext.newInstance( "epri.jaxb" );
129
130 ObjectFactory objFactory = new ObjectFactory();
131 myContainer = objFactory.createShapeContainer();
......
134 m = jc.createMarshaller();
135 u = jc.createUnmarshaller();
136 m.setProperty( Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE );
137
138
139 } catch( JAXBException je ) {
140 je.printStackTrace();
141 }
151 FileDialog open = new FileDialog(this,"open file..",FileDialog.LOAD);
152 open.setVisible(true);
153 filename = open.getDirectory()+open.getFile();
154 try {
155 myContainer =(ShapeContainer)u.unmarshal( new FileInputStream(filename));
156 this.canvas.setShapeContainer(myContainer);
157 this.canvas.repaint();
158 } catch( JAXBException je ) {
159 je.printStackTrace();
160 } catch (FileNotFoundException fe) {
161 System.out.println("file not found!");
162 }
163 }
Unmarshaller.unmarshal() 的方法可以直接將一個XML文件裏的數據轉換成Java對象。此對象應該是整個java對象樹中最靠近根的對象(在本例中爲ShapeContainer)。其他的對象都可以通過這個根對象的其他方法進一步獲得,下面的章節會介紹到。
......
187 m.marshal(myContainer, new FileOutputStream(filename));
......
193 }
53 public void mousePressed(MouseEvent e) {
.......
65 java.util.List shapeList = myContainer.getShape();
66 try {
67 ShapeType newType = this.objectFactory.createShapeType();
68 newType.setShapecolor(this.currentColor);
69 newType.setShapename(this.currentgraph);
70 newType.setXposition(this.currentX);
71 newType.setYposition(this.currentY);
72 shapeList.add(newType);
73 } catch( JAXBException je ) {
74 je.printStackTrace();
75 }
76 repaint();
77 }
90 public void paint(Graphics g) {
91 if (myContainer !=null){
92 java.util.List shapeList = myContainer.getShape();
......
95 for( Iterator iter = shapeList.iterator(); iter.hasNext(); ) {
96 ShapeType myshape = (ShapeType)iter.next();
97 String shapename = myshape.getShapename();
98 String shapeColor = myshape.getShapecolor();
99 int xposition = myshape.getXposition();
100 int yposition = myshape.getYposition();
101 if (shapeColor.equals("red")) g.setColor(Color.red);
102 if (shapeColor.equals("green")) g.setColor(Color.green);
103 if(shapename.equals("circle")) g.drawOval(xposition-25,yposition-25,50,50);
104 if(shapename.equals("rect")) g.drawRect(xposition-25,yposition-25,50,50);
105 this.setForeground(currentcolor);
106 }
107 }
108 }
在鼠標點擊事件的處理中和屏幕繪製的方法中有大量使用JAXB所生成的類的代碼(黑體字所表示的)。這些代碼比較清楚的表現了怎樣使用JAXB所生成的類。鼠標點擊事件的處理中,根據程序的邏輯,每次鼠標的點擊都應該根據鼠標當前的位置,畫筆的當前顏色和當前的形狀,來創建一個圖形,並將此圖形添加到整個對象樹中去;而在屏幕繪製的paint()方法中,應用程序遍歷整個對象樹,找到每個圖形的屬性,並將它們繪製在屏幕上。JAXB所生成的代碼都有一定的規律(遵循JAXB標準),這些規律非常簡單易用。例如,在Schema中我們規定了,在ShapeContainer中允許有一個或多個shap節點,那麼在生成的ShapeContainer這個類中就getShape()方法來返回一個shape的集合。又比如,在Schema中我們規定了每個shape都有一些屬性(shapename, shapecolor, xposition, yposition)。那麼在相應的ShapeType的類中,我們就會看到get和set的一些方法去設置和獲得這些屬性的值。
通過上面的例子,大家可以發現所有對XML文檔的操作都隱藏起來了,你的應用程序不用使用SAX或DOM接口編程去操縱XML文檔,使程序量降低,錯誤率減少,有助於程序質量的提高。
當你的產品需要更新,或是數據模型需要改變時,只需要重新定義Schema,然後讓JAXB重新生成對XML文檔進行操縱的類,使得你的應用程序具有很好的維護性。
當你進行版本更新的時候,往往要考慮兼容性問題。由於你使用了XML作爲數據交換的格式,只需要提供XSLT的模板就能將原有的數據格式自動轉換成新版本的格式。除此以外,你可以將你的XML表示的圖形數據文件任意轉換成其他標準的CAD數據格式,一切都在你的掌握之中。
因爲JAXB在運行時在大部分時間中都是直接操縱內存中的Java對象,只有在讀取和存儲文件的時候纔會與XML文件進行IO操作,實質上是爲XML文件做了一個緩存,因此運行時的性能很好。