`
chenming47
  • 浏览: 94287 次
  • 性别: Icon_minigender_1
  • 来自: 厦门
社区版块
存档分类
最新评论

实用数据绑定: 考察 JAXB,第 1 部分

    博客分类:
  • jaxb
阅读更多
往返和 XML 到 Java 的转换

Brett McLaughlin (brett@oreilly.com), 编辑, O'Reilly and Associates
Brett McLaughlin 从 Logo 时代(还记得那个小三角吗?)就开始从事计算机。他目前专门使用 Java 相关技术构建应用程序基础设施。他最近几年为 Nextel Communications 和 Allegiance Telecom, Inc. 实现了这些基础设施。Brett 是 Java Apache 项目 Turbine 的缔造者之一,该项目使用 Java servlet 为 Web 应用程序开发建立了可重用的组件体系结构。他还参与了 EJBoss 项目(一种开放源代码的 EJB 应用程序服务器)和 Cocoon(一种开放源代码的 XML Web 发布引擎)。

简介: 上一期文章中,Brett 分析了数据绑定中的几个重要概念,包括往返和语义等价。他在本文中按照这些术语考察了 Sun JAXB 的体系结构和实现。您将了解到 JAXB 如何处理类的生成,以及对 API 接受的 XML 输入和输出有什么样的影响。


标记本文!
发布日期: 2004 年 5 月 01 日
级别: 初级
访问情况 418 次浏览
建议: 0 (添加评论)

  平均分 (共 1 个评分 )
在深入数据绑定的细节,尤其是探讨如何将数据绑定工具包用于一般的编程问题之前,您需要选择使用的数据绑定工具包。我的一般原则是您应该自行挑选软件,因为每个人的编程需求无疑都是唯一的。也就是说,程序员做出这些决策所用的信息是普遍适用的。本文中,我将根据这些普遍的原则分析 JAXB,并帮助确定 JAXB 是否适合您的数据绑定需求。

简述


不过在展开 JAXB 的讨论之前,我要简要地回顾一下本系列 上一篇文章中所提到的概念。其中的重要定义有:

解组:把 XML 数据转化成 Java 类(或者多个类)的过程。
编组:把 Java 数据转化成 XML 文档的过程(恰恰与解组相反)。
语义等价:基于 XML 规则的相等。即使两个文档 看起来不同,但在语义上可能是等价的,参见上一篇文章中的例子。
往返:从 XML 文档到 Java 代码然后再回到 XML 的整个过程。有效的往返保证输入和输出文档是相同的(语义等价)。
本文中将不那么严格地使用这些术语,一定要真正掌握每个概念的含义。

还应该明白,本文以及后面的几篇文章中,重点不一定是讨论基本的功能,而使这种功能的实现。煤中数据绑定工具包都能编组和解组数据。但是许多工具包不那么严格地执行这项任务,结果危害了往返的语义等价性。实现中的瑕疵(或者实现的功能不完整)是本系列中开始几篇文章的重点,因此我要用几篇文章来说明工具包的基本用法就不奇怪了,如果不知道它是否 真正有效, 使用一个工具包又有什么意义呢?

最后,我假设您已经安装并运行了 JAXB。您可以在 developerWorks上找到详细描述安装过程的大量文章,而且有了新的 Sun Java Web Services Developer Toolkit,安装非常简单。安装好工具包并设置正确的类路径,就万事俱备了。


生成类


使用 JAXB 进行之前,首先要生成表示 XML 数据的 Java 类。这些例子中将使用一个非常简单的 XML 文档,如清单 1 所示。这是一份吉他的简单列表,吉他是我的爱好之一。

清单 1. 简单的 XML 文档:吉他列表


<guitars>
  <guitar id="10021">
    <builder luthier="true">Ryan</builder>
    <model>Mission Grand Concert</model>
    <back-sides>Brazilian Rosewood</back-sides>
    <top>Adirondack Spruce</top>
    <notes>
      <![CDATA[
        Just unbelievable...   this guitar has all the tone &
        resonance you could ever want. I mean, <<WOW!!!>> This
        is a lifetime guitar.
      ]]>
    </notes>
  </guitar>
  <guitar id="0923">
    <builder smallShop="true">Bourgeois</builder>
    <model>OMC</model>
    <back-sides>Bubinga</back-sides>
    <top>Adirondack Spruce</top>
  </guitar>
  <guitar id="11091">
    <builder>Martin & Company</builder>
    <model>OM-28VR</model>
    <back-sides>Indian Rosewood</back-sides>
    <top bearclaw="true">Sitka Spruce</top>
    <notes>It's certainly true that Martin isn't the only game in town anymore.
           Still, the OM-28VR is one of their best models...     and this one
           has some fabulous bearclaw to boot.              Nice specimen of a
           still-important guitar manufacturer.
    </notes>
  </guitar>
</guitars>
                


使用 JAXB 时还需要一个 XML Schema 以生成类和数据结构。 清单 1的 XML Schema 如清单 2 所示。

清单 2. 清单 1 的 XML Schema


<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
           elementFormDefault="qualified">
  <xs:element name="back-sides" type="xs:string"/>
  <xs:element name="builder">
    <xs:complexType>
      <xs:simpleContent>
        <xs:extension base="xs:string">
          <xs:attribute name="luthier" default="false">
            <xs:simpleType>
              <xs:restriction base="xs:NMTOKEN">
                <xs:enumeration value="true"/>
                <xs:enumeration value="false"/>
              </xs:restriction>
            </xs:simpleType>
          </xs:attribute>
          <xs:attribute name="smallShop" default="false">
            <xs:simpleType>
              <xs:restriction base="xs:NMTOKEN">
                <xs:enumeration value="true"/>
                <xs:enumeration value="false"/>
              </xs:restriction>
            </xs:simpleType>
          </xs:attribute>
        </xs:extension>
      </xs:simpleContent>
    </xs:complexType>
  </xs:element>
  <xs:element name="guitar">
    <xs:complexType>
      <xs:sequence>
        <xs:element ref="builder"/>
        <xs:element ref="model"/>
        <xs:element ref="back-sides"/>
        <xs:element ref="top"/>
        <xs:element ref="notes" minOccurs="0"/>
      </xs:sequence>
      <xs:attribute name="id" type="xs:string" use="required"/>
    </xs:complexType>
  </xs:element>
  <xs:element name="guitars">
    <xs:complexType>
      <xs:sequence>
        <xs:element ref="guitar" maxOccurs="unbounded"/>
      </xs:sequence>
    </xs:complexType>
  </xs:element>
  <xs:element name="model" type="xs:string"/>
  <xs:element name="notes" type="xs:string"/>
  <xs:element name="top">
    <xs:complexType>
      <xs:simpleContent>
        <xs:extension base="xs:string">
          <xs:attribute name="bearclaw" default="false">
            <xs:simpleType>
              <xs:restriction base="xs:NMTOKEN">
                <xs:enumeration value="true"/>
                <xs:enumeration value="false"/>
              </xs:restriction>
            </xs:simpleType>
          </xs:attribute>
        </xs:extension>
      </xs:simpleContent>
    </xs:complexType>
  </xs:element>
</xs:schema>
                


基本步骤


准备好了 XML 和 XML Schema,生成 JAXB 类就很简单了。确认已设置好命令行和环境,然后输入以下命令:

xjc -p com.ibm.dw guitars.xsd -d src
                


一定要在和 guitars.xsd文件相同的目录中执行上述命令,并且在工作目录中建立一个 src目录。如果没有按这些步骤操作,就会出现某种 java.io.IOException 错误。否则应该能看到一长串的输出结果,如清单 3 所示。

清单 3. JAXB 类生成的输出结果


C:\developerworks>xjc -p com.ibm.dw guitars.xsd -d src
parsing a schema...
compiling a schema...
com\ibm\dw\impl\runtime\MSVValidator.java
com\ibm\dw\impl\runtime\SAXUnmarshallerHandlerImpl.java
com\ibm\dw\impl\runtime\ErrorHandlerAdaptor.java
com\ibm\dw\impl\runtime\AbstractUnmarshallingEventHandlerImpl.java
com\ibm\dw\impl\runtime\UnmarshallableObject.java
com\ibm\dw\impl\runtime\SAXMarshaller.java
com\ibm\dw\impl\runtime\XMLSerializer.java
com\ibm\dw\impl\runtime\ContentHandlerAdaptor.java
com\ibm\dw\impl\runtime\UnmarshallingEventHandlerAdaptor.java
com\ibm\dw\impl\runtime\SAXUnmarshallerHandler.java
com\ibm\dw\impl\runtime\ValidatorImpl.java
com\ibm\dw\impl\runtime\ValidatableObject.java
com\ibm\dw\impl\runtime\UnmarshallerImpl.java
com\ibm\dw\impl\runtime\NamespaceContext2.java
com\ibm\dw\impl\runtime\Discarder.java
com\ibm\dw\impl\runtime\NamespaceContextImpl.java
com\ibm\dw\impl\runtime\ValidatingUnmarshaller.java
com\ibm\dw\impl\runtime\UnmarshallingContext.java
com\ibm\dw\impl\runtime\GrammarInfoImpl.java
com\ibm\dw\impl\runtime\ValidationContext.java
                


实在是有点太多了--注意,即使对于一个相当简单的 XML Schema,JAXB 也创建了 大量的类。


对往返的影响


现在我已经介绍了基本的步骤,下面将实际分析一下其中到底发生了什么。不必浪费时间回顾 JAXB 的基础(其他文章已经做了很好的介绍),对于每个元素都有两个源文件,一个文件和元素同名(比如,Guitar.java),另一个则在元素名后面加上“Type”(如 GuitarType.java)。这两个文件都是接口,类的实现在子目录 impl 下。这样就生成了很多类--我认为有点太过分了。

但真正有意思的是这些类本身。要知道数据绑定实现的主要问题之一是往返--即从 XML 到 Java 代码再返回到 XML 的过程中数据不会发生不可预料的变化的能力。换句话说,进去的是什么出来的就是什么。在目前,您还没有准备好通过解组-编组循环测试输出的结果(尽管以后要这样做),首先来分析源代码中可能存在的潜在问题。

第一个问题出现在任何数据绑定软件包通常都会出问题的地方:类型化。即使有 XML Schema 的帮助,XML 也不一定能和 Java 类型很好的匹配。这通常意味着要损失一些数据类型信息,有可能掺入非法的数据。有时候问题出在 XML Schema 中,有时候则是因为 XML 到 Java 映射的局限性,必须仔细观察。源代码中发现的一个此类问题是 top 元素的表示。注意清单 4 中粗体显示的那一行,这是 TopType 类的源代码。

清单 4. TopType.java 的源代码


package com.ibm.dw;
public interface TopType {
    java.lang.String getValue();
    void setValue(java.lang.String value);
            java.lang.String getBearclaw();
    void setBearclaw(java.lang.String value);
}
               
      


回头再看一看源文档及其 XML Schema,很明显 bearclaw 属性的值应该是“true”或“false”。不幸的是,JAXB 没有发现这一点并使用布尔数据类型, TopType 类的这个属性可以接受任何字符串值。结果可能造成错误的数据。最终可能出现“True”、“true”、“tRUe”或者任何其他变化形式,而令使用 XML 的应用程序举止失措。换句话说,您碰到了必须解决的一个问题域。

这类问题可能有以下不同的解决办法:

手工编辑 TopType 类的源代码,只接受布尔值。
向 TopType 方法中手工添加异常处理代码,保证只能提供可以转化成布尔值的字符串。
在 XML Schema 中创建表达布尔数据类型的新类型。
前两种选择非常明显。第三种选择也很简单,尽管 W3C 那帮人实际上应该把这一条放在规范中说明。清单 5 给出了一个简单的布尔类型定义:

清单 5. 模式中的布尔类型


<xsd:simpleType name="xsd:boolean">
  <xsd:restriction base="xsd:string">
    <xsd:enumeration value="true"/>
    <xsd:enumeration value="True"/>
    <xsd:enumeration value="TRUE"/>
    <xsd:enumeration value="false"/>
    <xsd:enumeration value="False"/>
    <xsd:enumeration value="FALSE"/>
  </xsd:restriction>
</xsd:simpleType>
                


看起来不错,是吧?但问题是它还不能解决这个问题。JAXB 根据 XML Schema 中 xsd:string 构造的用法,仍然会生成接受字符串参数的类。

在您准备告诉我这不成为一个问题之前,先让我说明 JAXB 通过 什么来保护您的数据。当从 Java 类编组回到 XML 时,将调用根据 XML Schema(和限制性的类型,如 清单 2和 清单 5所示)生成的验证方法。换句话说,如果您为 bearclaw 属性提供了一个值“foobar”,它就会被找出来。不过像“TRUe”、“fAlSe”和“tRue”这样的值--当然也不想要这种结果--在验证过程中也会被找出来。现在就需要使用 清单 5中详细定义的类型, 还要注意“true”和“false”这两个词因为大小写带来的变化。这种繁杂的工作看起来意义不大。正是这类问题使得往返非常复杂,真正实现要比说起来困难得多。这也 恰恰是在选择和使用数据绑定软件包时应该考虑到的那类问题。

更加需要关注的是,至少对我而言,这样可能造成超出单次往返过程的问题。要知道错误检查只有在编组时进行,这意味着只要还在内存中,错误数据就可以自由地存在于这些成员变量之中等待编组。另外, 任何具有有限值集的性质都存在这种问题,而不仅仅是布尔值。但其中最值得注意的问题是,有时候 XML 文档被读入、处理然后供其他应用程序使用,而不是被编组回到 XML。因此所有的应用程序都有可能在这些字段中插入错误的数据,而其他任何使用数据的应用程序都会得到那个错误数据。除非希望每次访问信息时都编组类,否则这个问题就确实存在。顺便说一句,这些问题表明数据绑定相对而言还不够成熟,而不仅仅是 JAXB。


我该怎么做?


那么您能做什么呢?首先要坚持阅读这些文章。我将详细分析 JAXB,后面还将探讨 Castor,尝试标志出那些需要注意的地方。不知道问题的关键在哪里,就不能编写防弹代码和错误检查代码;这正是本文以及后面几篇文章的核心。更重要的是,要认识到即使最好的数据绑定软件包,也需要一两个很棒的程序员增加另外的保护措施,才能使其正确地运行。

最后还要记住,数据绑定并不总是魔法子弹。我并不想打消你们对数据绑定的兴趣,恰恰相反,我认为它是一种了不起的应用程序。但是有时候一个简单的 SAX 程序或者 DOM 树就能提供需要的全部功能,就不需要再引入数据绑定项目的复杂性了。在以后的专栏中,我将分析使用数据绑定的最佳时机,什么时候使用 SAX 和 DOM 更有效,并通过大量的例子帮助您作出决策。


结束语


显然这里关于 JAXB 的分析还不够完全,但是您已经看到了研究数据绑定软件包时有价值的分析方法。选择一个数据绑定软件包要比选择喜欢的网站和单击链接复杂得多,要保证选择的应用程序能够正确处理像往返这样的问题。

JAXB 仍然不够成熟,仍然是一种非常新的技术的较早主要版本。还要记住 JAXB 以前的几个版本基本上已经废弃了(还记得当时 JAXB 只能使用 DTD 吗?它现在只能使用 XSD),因此 1.x 版是对这类问题真正的 第一次尝试。并不说不应使用 JAXB,只是说必须小心谨慎。

下一篇文章,我将从类生成转移到解组和编组,并说明它是如何工作的。我还将钻研像空格、CDATA 节以及许多其他问题的处理。请继续坚持,您将看到更多的代码、更多的细节和更多的乐趣。下一次网上见!


分享到:
评论

相关推荐

    数据绑定之JAXB

    JAXB(Java Architecture for XML Binding)是Java平台标准的一部分,用于实现这种数据绑定。JAXB允许开发者在Java类和XML文档之间进行自动的序列化和反序列化,极大地简化了XML处理。 在Java世界中,JAXB是处理XML...

    JAXB的安装包及插件

    **JAXB(Java Architecture for XML Binding)** 是Java平台中用于XML到Java对象绑定的API,它是Java EE和Java SE标准的一部分,允许开发者在Java应用程序中方便地将XML数据转换为Java对象,反之亦然。这个过程极大...

    jaxb-svg11-1.0.2-API文档-中文版.zip

    赠送jar包:jaxb-svg11-1.0.2.jar; 赠送原API文档:jaxb-svg11-1.0.2-javadoc.jar; 赠送源代码:jaxb-svg11-1.0.2-sources.jar; 赠送Maven依赖信息文件:jaxb-svg11-1.0.2.pom; 包含翻译后的API文档:jaxb-svg11...

    JAXB-2.2.6-release-documentation

    - **运行时绑定框架**:这部分详细介绍了如何在运行时使用 JAXB 进行数据绑定操作。 ### 知识点三:JAXB 2.2.6 发行说明 - **平台要求**:JAXB 2.2.6 需要在 Java 2 平台标准版 (J2SE) 上运行,具体版本依赖于...

    Java与XML数据绑定

    1. JAXB简介:JAXB是Java平台标准的一部分,提供了一种无代码生成的、基于注解的方式来实现XML和Java对象之间的绑定。通过在Java类上添加注解,JAXB可以自动地将XML文档解析为Java对象,同时也能将Java对象转换为XML...

    Java XML绑定技术 (Castor JAXB XMLBeans)

    虽然Castor最初并非专为XML绑定设计,但其提供的XML绑定功能仍然非常实用。 **特点:** - **支持旧版本JDK**:可以在JDK 1.3及更高版本上运行。 - **自动生成XML定义**:允许开发者通过定义Java Bean来生成XML定义...

    jaxb-api-2.3.0-API文档-中英对照版.zip

    赠送jar包:jaxb-api-2.3.0.jar; 赠送原API文档:jaxb-api-2.3.0-javadoc.jar; 赠送源代码:jaxb-api-2.3.0-sources.jar; 赠送Maven依赖信息文件:jaxb-api-2.3.0.pom; 包含翻译后的API文档:jaxb-api-2.3.0-...

    jaxb-api-2.3.1-API文档-中文版.zip

    赠送jar包:jaxb-api-2.3.1.jar; 赠送原API文档:jaxb-api-2.3.1-javadoc.jar; 赠送源代码:jaxb-api-2.3.1-sources.jar; 赠送Maven依赖信息文件:jaxb-api-2.3.1.pom; 包含翻译后的API文档:jaxb-api-2.3.1-...

    jaxb-impl.jar包

    impl.jar`是Java Architecture for XML Binding (JAXB)的一个实现包,它是Java平台标准版(Java SE)和企业版(Java EE)的一部分,主要用于XML到Java对象的绑定以及反之,使得开发者能够方便地在Java程序中处理XML...

    jaxb-api-2.0.5.jar.zip

    2. **XJC (XML Java Compiler)**:是JAXB的一部分,用于从XML Schema生成Java类,实现XML到Java的绑定。 **与其他技术的配合**: JAXB通常与Java的其他XML处理技术一起使用,如StAX(Streaming API for XML)用于...

    JAXB2 jaxb-api.jar jaxb-xjc.jar jaxb-impl.jar activation.jar

    1. **jaxb-api.jar**:这是JAXB2的主要API接口定义,包含了所有的注解和接口,如`@XmlRootElement`、`@XmlElement`等,以及用于转换的核心类,如`Unmarshaller`和`Marshaller`。这个jar文件提供了与XML绑定的基本...

    jaxb-runtime-2.3.5-API文档-中文版.zip

    赠送jar包:jaxb-runtime-2.3.5.jar; 赠送原API文档:jaxb-runtime-2.3.5-javadoc.jar; 赠送源代码:jaxb-runtime-2.3.5-sources.jar; 赠送Maven依赖信息文件:jaxb-runtime-2.3.5.pom; 包含翻译后的API文档:...

    jaxb-runtime-2.3.5-API文档-中英对照版.zip

    赠送jar包:jaxb-runtime-2.3.5.jar; 赠送原API文档:jaxb-runtime-2.3.5-javadoc.jar; 赠送源代码:jaxb-runtime-2.3.5-sources.jar; 赠送Maven依赖信息文件:jaxb-runtime-2.3.5.pom; 包含翻译后的API文档:...

    jaxb-svg11-1.0.2-API文档-中英对照版.zip

    赠送jar包:jaxb-svg11-1.0.2.jar; 赠送原API文档:jaxb-svg11-1.0.2-javadoc.jar; 赠送源代码:jaxb-svg11-1.0.2-sources.jar; 赠送Maven依赖信息文件:jaxb-svg11-1.0.2.pom; 包含翻译后的API文档:jaxb-svg11...

    jaxb-ri-2.2.7

    **Java Architecture for XML Binding (JAXB)** 是Java平台上的一个标准技术,用于在XML和Java对象之间进行数据绑定。它提供了方便的接口和工具,使得开发者可以轻松地将XML文档转换为Java对象,同时也可以将Java...

    jaxb2.1jar包

    JAXB2.1是JAXB的第二个主要版本,它为开发者提供了更强大、更灵活的功能,以处理XML文档的序列化和反序列化。 **一、JAXB2.1的主要功能** 1. **自动代码生成**:JAXB2.1引入了更强的代码生成能力,可以自动生成...

    jaxb-api jaxb-impl jar

    `jaxb-api`和`jaxb-impl`是JAXB框架的核心组成部分。这两个JAR文件在处理XML到Java对象的绑定过程中扮演着关键角色。 1. **jaxb-api.jar**: 这个库包含了JAXB API,即Java接口和抽象类,定义了JAXB的工作方式。它...

    jaxb-api-2.3.0-API文档-中文版.zip

    赠送jar包:jaxb-api-2.3.0.jar; 赠送原API文档:jaxb-api-2.3.0-javadoc.jar; 赠送源代码:jaxb-api-2.3.0-sources.jar; 赠送Maven依赖信息文件:jaxb-api-2.3.0.pom; 包含翻译后的API文档:jaxb-api-2.3.0-...

    idea 中用jaxb 读xml中数据

    通过JAXB,我们可以在Java对象和XML之间进行无缝的数据绑定,大大简化了XML的处理工作。在Idea中使用JAXB,我们需要遵循以下步骤: 1. **创建Java类**:首先,我们需要定义与XML元素相对应的Java类。这些类会包含...

Global site tag (gtag.js) - Google Analytics