XML到Java代码的数据绑定之对象

  在这个由四部分组成的系列文章的第一部分,我们将弄清什么是数据绑定,与在 Java 应用程序中处理 XML 数据的其它方法相比它有什么优势,以及如何开始使用它。这一部分将考查为什么使用数据绑定,以及如何为各种约束建立模型,使 XML 文档能转换成 Java 对象。同时还涵盖用于生成数据绑定类的输入和输出。

  您希望在您的 Java 应用程序中使用 XML 吗?那么好,同成千上万的其他人一起上这条船吧。当您深入了解 XML 以后,也许您会发现 DOM 和 SAX API(请参阅参考资料)不过是唬人的东西。您可能认为肯定存在某种简单方法可以取得 XML 文档,并通过 Java 应用程序访问它,对吗?不必通过回调或复杂的树状结构,而是使用像 setOwner(Stringowner) 和 int getNumOrders() 这样的方法,对吗?如果您曾经沿着这一思路考虑问题,那么数据绑定就是您要寻找的解决方案。

  分析各种选择

  当今各种 XML 和 XML 主义正泛滥成灾(XSL、RDF、命名空间、RSS、XML Schema、XSLT...),您可能认为现在会有很多方法去访问 Java 应用程序中的 XML 数据。令人惊讶的是,如果您寻根究底,实际只存在三种访问 XML 数据的方法。没错 -- 只有三种方法,其中的一种还是最近随一种新的 Java API 才出现的。

  应该这样来看待这一问题:选择范围小使您更易于选出适合于您的方法。

  回调

  回调是作为一种事件驱动模型工作的。当分析 XML 文档时,某些事件 -- 如文档的起始和某个元素中的字符数据的起始 -- 将触发回调方法。通过使用执行逻辑所需的数据,您可以实现这些事件的 Java 代码。要弄清这种方法不能全靠直觉;开发人员通常要花费一段时间来理解和掌握回调模型的使用。SAX,用于 XML 的一种简单 API,是这种 XML 使用方法的事实上的标准。

  树

  更常见、更流行的是这种 API,它们取得一个 XML 文档,然后创建数据的树状结构。XML 文档成为树首,充当一种容器。它有若干子级,如根元素。根元素又有其附加的子级,依此类推,直到(在某种意义上)获得 XML 数据的一幅图为止。因为几乎每个大学生在某个阶段肯定都处理过树状结构,所以这就可用作表示 XML 数据的一种非常直观的方法。

  用于 XML 文档树状表示的最流行的 API 就是 W3C 的推荐标准,即文档对象模型 (DOM)。一种更新的 API,JDOM (这不是首字母缩写词)最近也正一直在推广并流行开来。(虽然这个方案是我和 Jason Hunter 建立的,但我还得说实话。)另外,DOM 和 JDOM 都是 Spinnaker 方案设计的基本要求,Spinnaker 是一种新的 XML 分析器,它作为 Apache XML 方案的一部分正在开发之中。

  虽然树状 API 看起来比事件驱动的 SAX 更易于使用,但它们并不总是合适的。非常大的文档可能需要大量的内存(尤其是使用 DOM 时);当对树结构执行转换 (XSLT) 时,系统可能停止运转甚至彻底崩溃。虽然更新的 API(如 JDOM)能处理这些问题,但如果您必须处理极大量的数据,它们仍将是一个问题。并且,有时开发人员宁愿将 XML 文档中的数据建模为一个简单的带有值的读写方法的 Java 对象,而不用树状模型工作。例如,开发人员会宁愿不去访问名为 skuNumber 的子节点并设置该节点的文本值,而只想调用 setSkuNumber("mySKU") 并继续进行。

  用Java代码访问 XML 数据的最新方法要依赖于一套新的 Java 方法和相关的 API,这些 API 仍在开发之中。数据绑定是由 Sun 构建的一种“Java 规范要求”(JSR-031,见参考资料),它设计用于使 Java 对象绑定到 XML 文档更加方便,这样就使一种格式能够容易地转换为另一种格式,反之亦然。绑定引用一个具有读写方法的 Java 对象,读写方法都会影响到底层的 XML 文档,并且也都直接映射为 XML 文档中的元素及特征的名称。当您进入到本系列文章下一部分中的某些细节时,这一说明会更有意义,但在目前,只说一点就够了:这样做使 XML 文档特征 name 能够通过一个称为 setName() 的方法,来更改它的值,就像我上面暗示的那样。

  数据绑定

  这种访问方式正在得到普及,并且当在 XML 文档中存储配置信息时特别有用。许多开发人员发现,它非常便于直接访问所需的参数,而无须使用更复杂的树状结构。虽然这种访问对于文档转换或消息传送没有什么用处,但它对于简单数据处理是极其方便的。它是我们在本文及本系列文章中关注的第三种使用 XML 的方法。

  (当然,任何方法随后都会引出一系列新的术语,所以请查看术语解释以了解这些新的行话。)

  是否任何 XML 文档都可以转换为 Java 对象?还是仅有某些类型的 XML 文档才可以?问得好!您很可能只希望将满足一组约束条件的文档转换为 Java 对象。这与定义 Java 接口的方法类似:您确保只实例化和使用适应该接口的对象,允许就如何操作该对象作出假定。同样,您只允许将满足一组约束条件的 XML 对象转换成 Java 对象;这使您能够按希望的方式来使用所创建的对象。

   约束数据

  在研究代码之前,您需要回答几个有关如何表示 XML 数据的问题。这是数据绑定的最具挑战性的方面之一。是为每个文档创建一个新类,还是创建某个现有类的一个实例?您要使用哪个现有类?并且最重要的是,您正在处理的文档是否适宜转换为 Java 对象?

  那是一大堆问题,但您将在这里找到全部答案。将这些问题看作一系列决策点,一系列选择。首先,您必须确定您能否从该 XML 文档创建 Java 对象(如前面所讨论的那样)。如果能,您就要决定转换应该以新 Java 类的形式出现,还是仅以现有类的一个实例的形式出现。最后,如果选择了现有类,那么使用哪个类呢?结果就是各种各样的决策树。

  如果我们考察清单 1 中所示的一个示例 XML 文档,然后再来处理这些问题,则决策树的意义就更加清楚了。此示例文档表示 Enhydra Application Server 中某个服务(具体说就是一个 web 容器)的配置。

  清单 1. 一个用于配置 Enhydra 中的 web 容器的 XML 文档 <?xml version="1.0"?>

  <webServiceConfiguration version="1.0" name="My Web Container" >
  <port number="80" protocol="http" protected="false" />
  <document root="/usr/local/enhydra/html" index="*.html,*.xml" error="error.html" />
  </webServiceConfiguration>

  此配置文档包含有关服务本身的版本和名称的信息,以及几个嵌套的项目,每个项目都表示有关该 web 容器服务的一些附加信息。它给出了有关端口的详细信息(包括端口号、协议和安全性),也给出了文档服务信息(包括文档根、用于索引页的默认扩展名以及错误页)。所有这些合在一起,就是配置一个新的 web 容器服务所需的全部信息。

  记住这个示例,您就可以开始回答数据表示的各个问题了。

  是否适合转换?

  绝对适合!只要看一看清单 1 中的 XML 文档就会发现,它表示一个对象(总体配置对象),具有若干特征或变量。其中某些变量又是另外的对象(端口和文档),这些对象又具有它们自己的特征。实际上,这是适合转换为 Java 对象的 XML 文档的一个极好例子。为了进一步保证此对象是可用的,稍后我将向您展示一种方法来约束文档中的数据。但是,还是先让我们继续沿着决策树往下走。

  转换成类还是实例?

  解决适宜性问题以后,现在就可以作出决定,是将每个 XML 配置文档都变为一个全新的 Java 类呢,还是简单地将其变为某个现有类的一个新实例。换句话说,就是到底应该生成新代码,还是利用现有的代码。照这样来看,这就变成了一个简单的可重用性问题。更容易且更明智的做法是,为每个 XML 文档生成现有类的新实例。如果您一定要尝试一下从每个文档创建一个新的 Java 类,则得到的各个类之间可能没有兼容性 -- 即两个完全相同的文档可能导致两个不同的 Java 类!

  不用这个可能引起混乱的方法,您可以采用一组 XML 约束条件(由一个 DTD 或 XML 方案表示,将在下面讲述),并根据这些约束条件来生成一个 Java 类(或多个类,根据需要)。这个生成的类将表示符合这些约束条件的任何 XML 文档;这些 XML 文档中的每一个都将被解包到生成的类的一个实例中。在这种情况下,就可以为表示 web 服务配置的文档定义约束条件。这些约束条件将被映射为一个 Java 类,我们将称之为 WebServiceConfiguration。然后您就可以获得任何一种表示特定 web 服务配置的 XML 文档,并假定此文档符合我们的约束条件,由它而创建出前面生成的类的一个实例。这将允许应用程序将不同的 XML 文档用作相同类型的对象,只要这些文档中的数据对于该对象设计时要达到目的来说是有效的即可。

  新类还是现有的类?

  现在您也已经有条件回答下一个问题了:您希望创建一个现有类即 WebServiceConfiguration 类的一个实例。剩下需要弄清的全部事情是,这个类是如何预先生成的。所以,现在请将您的注意力集中在这样一个问题上:如何获得一组约束条件,用 XML 实现它们,并保证文档符合这些约束?再一个问题就是,您如何再从这些约束条件生成一个可重用的 Java 类?

  利用文档约束条件

  既然您知道此文档将转换成一个 Java 实例,这就产生了另一个问题:要考虑到必须以某种方式保证可将此文档正确地解包到一个选定的 Java 类中。缺少变量或数据类型不正确都可能导致在解包过程中出错 -- 或者甚至在客户机访问配置错误的容器时出现运行时异常。

  最好的情况是,在实际的解包过程开始之前,文档的作者能够保证,配置文档对于他们选择用来表示数据的类是“合法的”。阅读到这一方案的 XML 人士说不定就会转动他们的眼睛并嘀咕说,“好吧,当然您将使用 XML 文档约束条件。”确认数据对选定类的合法性可以通过引用 DTD (文档类型定义)或 XML 方案来完成。

  通过使用一组用外部 DTD 或方案文件表示的约束条件,文档作者就可以在这些数据的“接口”上测试配置数据。换句话说,您可以这样来建立应用程序,使之能够对照所需的数据来检查包含在 XML 实例文档中的数据,而所需数据则是在文档约束条件的外部文件中指定的。这样,您就可以为数据创建一个接口。

  在使用 DTD 方案还是使用 XML 方案之间作出决策是一种相当简单的选择:因为 Java 语言是高度类型化的,所以我们希望能在 XML 文档中支持类型化。例如,数据接口应该能够验证,为web容器的端口号提供的是整数,而不是字符串,后者在服务启动时将引起错误。DTD 不支持类型检查,所以我们无疑应该选择XML方案。虽然XML方案在规范的领域在有一点不确定性,但它在很大程度上已趋于稳定,并可望在年内定型。我们可以在一个XML方案中编写数据约束条件,然后用这个方案验证可能的实例文档,以确保解包能在这些实例文档上进行。下面的 XML 方案表示我们的web容器服务的数据接口。

  清单 2. 表示一个 web 容器配置文档的数据接口的 XML 方案 <?xml version="1.0"?>

  <schema targetNamespace="http://www.enhydra.org" xmlns="http://www.w3.org/1999/xmlSchema" xmlns:enhydra="http://www.enhydra.org" >

  <complexType name="ServiceConfiguration">
  <attribute name="name" type="string" />
  <attribute name="version" type="float" />
  </complexType>

  <element name="serviceConfiguration" type="ServiceConfiguration" />

  <complexType name="WebServiceConfiguration" baseType="ServiceConfiguration" derivedBy="extension">
  <element name="port">
  <complexType>
  <attribute name="protocol" type="string" />
  <attribute name="number" type="integer" />
  <attribute name="protected" type="string" />
  </complexType>
  </element>

  <element name="document">
  <complexType>
  <attribute name="root" type="string" />
  <attribute name="index" type="string" />
  <attribute name="error" type="string" />
  </complexType>
  </element>
  </complexType>

  <element name="webServiceConfiguration" type="WebServiceConfiguration" />

  </schema>

  清单 2 中的 XML 方案定义了几个不同的数据对象,它们合起来表示一个 web 服务的配置对象。首先,定义了一个核心服务配置(serviceConfiguration),它包含版本和名称。这可用作所有服务(如负载均衡服务、EJB 容器,当然还有我们的 web 服务)的基本对象。然后,作为此基本服务的扩展,又定义了 web 服务配置(webServiceConfiguration)。请注意,Java 成型之后,方案就已经为数据接口建立了模型。我们将附加的 web 服务属性 port 和 document 添加到 version 和 name 基本属性中。这些属性本身都是对象,具有它们自己的属性(protocol、root、error 等)。

  在此方案的定义方式中,特征代表简单的 Java 类型,通常是原始 (primitive) 类型。这样,name 和 version 就分别成为类型 String 和 float 的 Java 原始类型。port 和 document 这样的元素成为 Java 对象,它们可以有自己的属性,还是用特征来表示。这样就出现了递归现象:元素变成新对象,并对它的每个属性进行检查。如果属性是一个特征,就为此对象创建一个简单的 Java 原始成员变量;如果属性是元素,则创建一个新的对象,并作为一个成员变量将其添加,然后在这个新对象上又开始同样的过程,直到全部类都已创建为止。
   从萝卜 ... 嗯 ... XML 获得 Java

  一旦创建了 XML 方案,您就需要从这个方案中提取出必需的信息,来确定应该创建哪些 Java 类。这个过程的第一步是查看 XML 方案,并严格确定输出应该是什么。对于简单的 serviceConfiguration 对象,定义了两个 Java 原始属性:name 和 version。对于这样一个简单的对象,确定所需的接口并不难。只需将被定义类型的名称的首字母大写,并将这些 Java 属性添加到接口中即可,如清单 3 所示。

  清单 3. 为 ServiceConfiguration 接口而从 XML 方案生成的 Java 代码 public interface

  ServiceConfiguration {
  public void setVersion(float version);
  public float getVersion();
  public void setName(String name);
  public String getName();
  }

   这是相当明白易懂的;清单 3 中的接口为 XML 方案中定义的属性提供读方法和写方法。另外,您将需要生成一个实现类来定义此接口的各个成员变量,并实现此接口中的每个方法。这种使接口从实现中分离出来的方法使我们能够为特定的需要提中供多种实现。 例如,某个特定的服务可能需要执行计算,而不只是接受从写方法中收到的值。现在考虑那种更复杂的情况还有点为时尚早,但我将在后续文章中重新提到它。然而,一般说来,您仍可以确定实现类应该像什么样子,如清单 4 所示。

  清单 4. 为 ServiceConfiguration 实现而从 XML 方案生成的 Java 代码 public class

  ServiceConfigurationImpl implements ServiceConfiguration {
  private String name;
  private float version;

  public void setVersion(float version) {
  this.version = version;
  }

  public float getVersion() {
  return version;
  }

  public void setName(String name) {
  this.name = name;
  }

  public String getName() {
  return name;
  }
  }

  相同的原则也适用于 XML 方案中定义的其它对象。您可以在下面查看到其它 Java 类(因为它们都是应该生成的):

  PortType.java
  PortTypeImpl.java
  DocumentType.java
  DocumentTypeImpl.java
  WebServiceConfiguration.java
  WebServiceConfigurationImpl.java

  总结

  到目前为止,您应该对数据绑定的各个方面都比较熟悉了。我已初步介绍了您应该使用数据绑定的原因,尤其是在配置信息的范围内,并概述了为实现此方法您所需要了解的一些基本概念。

(0)

相关推荐

  • 详解Java多态对象的类型转换与动态绑定

    Java多态对象的类型转换 这里所说的对象类型转换,是指存在继承关系的对象,不是任意类型的对象.当对不存在继承关系的对象进行强制类型转换时,java 运行时将抛出 java.lang.ClassCastException 异常. 在继承链中,我们将子类向父类转换称为"向上转型",将父类向子类转换称为"向下转型". 很多时候,我们会将变量定义为父类的类型,却引用子类的对象,这个过程就是向上转型.程序运行时通过动态绑定来实现对子类方法的调用,也就是多态性. 然而有些时候

  • java的前期绑定和后期绑定使用示例

    后期绑定,是指在运行时根据对象的类型进行绑定,又叫动态绑定或运行时绑定.实现后期绑定,需要某种机制支持,以便在运行时能判断对象的类型,调用开销比前期绑定大.Java中的static方法和final方法属于前期绑定,子类无法重写final方法,成员变量(包括静态及非静态)也属于前期绑定.除了static方法和final方法(private属于final方法)之外的其他方法属于后期绑定,运行时能判断对象的类型进行绑定.验证程序如下: 复制代码 代码如下: class Base{    //成员变量,

  • 解析Java的Jackson库中对象的序列化与数据泛型绑定

    Jackson对象序列化 这里将介绍将Java对象序列化到一个JSON文件,然后再读取JSON文件获取转换为对象.在这个例子中,创建了Student类.创建将有学生对象以JSON表示在一个student.json文件. 创建一个名为JacksonTester在Java类文件在 C:\>Jackson_WORKSPACE. 文件: JacksonTester.java import java.io.File; import java.io.IOException; import org.codeh

  • Java中的静态绑定和动态绑定详细介绍

    一个Java程序的执行要经过编译和执行(解释)这两个步骤,同时Java又是面向对象的编程语言.当子类和父类存在同一个方法,子类重写了父类的方法,程序在运行时调用方法是调用父类的方法还是子类的重写方法呢,这应该是我们在初学Java时遇到的问题.这里首先我们将确定这种调用何种方法实现或者变量的操作叫做绑定. 在Java中存在两种绑定方式,一种为静态绑定,又称作早期绑定.另一种就是动态绑定,亦称为后期绑定. 区别对比 1.静态绑定发生在编译时期,动态绑定发生在运行时 2.使用private或stati

  • javascrpt绑定事件之匿名函数无法解除绑定问题

    经常听到有人说,匿名函数绑定事件不好控制啊,无法解除绑定啊等等等等,一直很奇怪谁说的不能解除绑定. 下面来实现click事件2次后,自动解除绑定. 看代码: 复制代码 代码如下: var dom=document.getElementById("test"),clickt=0; dom.addEventListener("click",function(e){ clickt++; alert('你摸了我'+clickt+'下了.最多摸2下哦'); if(clickt

  • 理解Java中的静态绑定和动态绑定

    一个Java程序的执行要经过编译和执行(解释)这两个步骤,同时Java又是面向对象的编程语言.当子类和父类存在同一个方法,子类重写了父类的方法,程序在运行时调用方法是调用父类的方法还是子类的重写方法呢,这应该是我们在初学Java时遇到的问题.这里首先我们将确定这种调用何种方法实现或者变量的操作叫做绑定. 在Java中存在两种绑定方式,一种为静态绑定,又称作早期绑定.另一种就是动态绑定,亦称为后期绑定. 程序绑定的概念: 绑定指的是一个方法的调用与方法所在的类(方法主体)关联起来.对java来说,

  • 实例解析Java的Jackson库中的数据绑定

    数据绑定API用于JSON转换和使用属性访问或使用注解POJO(普通Java对象).以下是它的两个类型. 简单数据绑定 - 转换JSON,从Java Maps, Lists, Strings, Numbers, Booleans 和 null 对象. 完整数据绑定 - 转换JSON到任何JAVA类型.我们将在下一章分别绑定. ObjectMapper读/写JSON两种类型的数据绑定.数据绑定是最方便的方式是类似XML的JAXB解析器. 简单的数据绑定 简单的数据绑定是指JSON映射到Java核心

  • XML到Java代码的数据绑定之对象

    在这个由四部分组成的系列文章的第一部分,我们将弄清什么是数据绑定,与在 Java 应用程序中处理 XML 数据的其它方法相比它有什么优势,以及如何开始使用它.这一部分将考查为什么使用数据绑定,以及如何为各种约束建立模型,使 XML 文档能转换成 Java 对象.同时还涵盖用于生成数据绑定类的输入和输出. 您希望在您的 Java 应用程序中使用 XML 吗?那么好,同成千上万的其他人一起上这条船吧.当您深入了解 XML 以后,也许您会发现 DOM 和 SAX API(请参阅参考资料)不过是唬人的东

  • 使用java代码代替xml实现SSM教程

    目录 1.在IDEA中创建一个普通的maven项目 2.添加Spring配置 3.添加SpringMVC配置 5.测试 5.1创建HelloController类 5.2创建HelloController2类 5.3路径映射 6.JSON配置 7.总结 SpringBoot推荐开发者使用Java配置来搭建框架,SpringBoot中大量的自动化配置都是通过Java代码配置实现的,而不是XML配置,同理,我们自己也可以使用纯Java来搭建一个SSM环境,即在项目中不存在任何XML配置,包括web.

  • xml与Java对象的转换详解

    xml与Java对象的转换详解 1.xstream解析报文 XStreamComponent x = XStreamComponent.newInstance(); x.processAnnotations(new Class[]{EquityExchangeDetail.class,PearTicketCustomerDTO.class,Date.class,Integer.class}); EquityExchangeDetail ptd = (EquityExchangeDetail) x

  • java读取xml配置参数代码实例

    这篇文章主要介绍了java读取xml配置参数代码实例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 paras.xml文件 <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.

  • 详解Spring Boot 使用Java代码创建Bean并注册到Spring中

    从 Spring3.0 开始,增加了一种新的途经来配置Bean Definition,这就是通过 Java Code 配置 Bean Definition. 与Xml和Annotation两种配置方式不同点在于: 前两种Xml和Annotation的配置方式为预定义方式,即开发人员通过 XML 文件或者 Annotation 预定义配置 bean 的各种属性后,启动 spring 容器,Spring 容器会首先解析这些配置属性,生成对应都?Bean Definition,装入到 DefaultL

  • Spring装配Bean之用Java代码安装配置bean详解

    前言 本文主要给大家介绍了关于Spring之利用Java代码安装配置bean的相关内容,尽管通过组件扫描和自动装配实现Spring的自动化配置很方便也推荐,但是有时候自动配置的方式实现不了,就需要明确显示的配置Spring.比如说,想要将第三方库中的组件装配到自己的应用中,这样的情况下,是没办法在它的类上添加 @Compnent和 @Autowired注解的. 在这种情况下,需要使用显示装配的方式,可以分别通过Java和XML实现,推荐使用Java的方式,因为更加强大,类型安全并且重构友好,因为

  • 养成良好java代码编码规范

    一.基本原则 强制性原则: 1.字符串的拼加操作,必须使用StringBuilder: 2.try-catch的用法 try{ }catch{Exception e e.printStackTrace(); }finally{ }//在最外层的Action中可以使用,其它地方一律禁止使用: try{ //程序代码 }catch(Exception e){ //为空,什么都不写 }//在任何场景中都禁止使用 try{ }catch{Exception e throw new runtimeExce

  • java代码获取数据库表里数据的总数操作

    在访问数据库时,特别是新手,可能会需要查询表中数据总数,以下这段代码可以非常简便的获取到数据数目 //先建立数据库连接,执行查询语句 Connection conn = DriverManager.getConnection(URL, USER, PassWord); Statement st=conn.createStatement(); ResultSet rs =st.executeQuery("select count(*) as result from tablename")

  • Java 代码检查工具之PMD入门使用详细教程

    介绍 PMD是一个静态源代码分析器.它发现了常见的编程缺陷,如未使用的变量.空捕获块.不必要的对象创建等等. 官网:点这里 官方文档:点这里 使用方式 1.使用插件的方式 下载:File -> Settings -> Plugins -> Marketplace 搜索 "PMDPlugin" ,下载插件. 使用方法:在代码编辑框或Project 窗口的文件夹.包.文件右键,选择"Run PMD"->"Pre Defined"

  • java链式创建json对象的实现

    目录 1.假设我们要创建一个json对象格式如下: 2.往常创建JSON语法: 3.解决方案——链式创建JSON: 4.实现多级JSON 5.YtJSONObject类源码 我们主要介绍一下:java中如何通过最简单的方式实现链式创建json对象,解决创建json代码臃肿的问题. 1.假设我们要创建一个json对象格式如下: { "code": 0, "msg": "SUCCESS" } 2.往常创建JSON语法: java中传统的创建json一

随机推荐