|
从XML到Java的数据绑定系列之三:从文本到字节码广告 从XML到Java的数据绑定系列之三:从文本到字节码
Brett McLaughlin 本数据绑定系列的第三部分演示了如何使用“JSR-031:数据绑定,Sun 数据绑定规范申请”中指定的方法,将 XML 元素和属性转换成 Java 对象。这部分主要讲述从数据的 XML 表示移到应用程序代码易于使用的 Java 实例。第三部分论及通过将 XML 文档中的嵌套元素取消编组成 Java 对象、测试和用某些实际示例来使用新的工具。 本系列的目标是演示如何将 XML 元素转换成 Java 对象,然后可以使用 Java 语言 accessor 和 mutator 方法直接处理 XML 数据。第一部分比较了数据绑定和 Java 应用程序中其它处理 XML 数据的方法,分析了设计决策,还定义了示例 Web 服务配置文档的 XML 模式。第二部分说明了如何从 XML 模式生成接口和实现,以便符合 XML 模式的 XML 文档可以转换成这些生成类的实例。 在第三部分(共四部分)中,将完成基础知识的讲解,并且描述了如何精心设计代码以执行取消编组,取消编组将完成将 XML 转换成 Java 对象的过程。执行了取消编组后,可以使用测试类(已包括在内)来检查是否所有部分都已正确组合在一起。本系列的每一部分都建立在其它部分的基础之上,所以如果您还没有看过第一和第二部分,您也许会看不懂本文中的一些描述。如果要回顾专门的词汇表,请参阅术语解释侧栏。 使用第一部分中为 WebServiceConfiguration 定义的 XML 模式(请参阅更新版本)和第二部分中的接口,即将创建为配置数据的特定实例提供数据的 XML 文档。任何符合模式的 XML 文档都可以编组成 Java 对象。这些对象应该是使用 SchemaMapper 类生成的类的实例。当然,最终结果就是数据绑定。 制作 XML 实例文档 清单 1. 符合示例 XML 模式的 XML 实例文档
_ _
清单 1 中的示例完整地显示了 WebServiceConfiguration 的实例。实例文档包括了两个名称空间声明。第一个是缺省名称空间声明,请参考 http://www.enhydra.org。这表示所有没有前缀的元素会分配到此名称空间。虽然,在本示例中不需要声明缺省名称空间,它还给予了文档一些身份。这个缺省名称空间有助于将该文档与其它有相似或等同元素名称的 XML 文档区分出来。 定义的另一个名称空间分配给 xsi 前缀,所以带该前缀的所有元素都分配到此名称空间。它 (http://www.w3.org/1999/XMLSchema/instance) 引用“XML 模式实例规范”的 URI。该规范依次定义了 XML 文档如何引用文档符合的 XML 模式。最后,schemaLocation 属性引用 XML 模式。该属性的第一个变量是受到约束的名称空间(示例缺省名称空间,它包括文档中的每个元素)。第二个变量,用空格与第一个变量分开,引用 XML 模式的实际位置。本例中,模式 configuration.xsd 是一个本地文件,它与文档在同一个目录中。也可以通过使用 URL 来引用网络上任意位置的模式。 在缺省名称空间中,附加属性(因为它们没有前缀)定义了版本 (1.1) 和名称 (Unsecured Web Listener)。 接着,声明了模式中的 Port 对象,并定义了它的数据:端口号为 80,协议是 http。正确取消编组成 Java 代码后,该文档就变成了 WebServiceConfigurationImpl 类的实例。然后,Java 代码可以使用本系列第二部分中设计的接口 WebServiceConfiguration,以使用基本 XML 文档中的数据。(请注意,可能会在应用程序中执行验证,如模式验证侧栏中所概述的。) 模式验证 对于示例 SchemaMapper 类,允许传入 URL 是最有意义的。由于可以使用网络资源作为输入,而不是只允许文件名,这就提供了更多选择。知道了这一点后,下一步就从 URL 创建 JDOM 文档对象 (org.jdom.Document),然后处理文档。请查看清单 2 中执行该操作的代码。 清单 2. 将字符串映射成 Java 指定的类型 /** * * @param instanceURL URL for the instance document. * @return Object - the created Java Object, or * null if problems occur in a way that does not * generate an Exception. * @throws IOException when errors in binding occur. */ public static Object unmarshall(URL instanceURL) throws IOException { // Read in the document SAXBuilder builder = new SAXBuilder(); try { Document doc = builder.build(instanceURL); Element rootElement = doc.getRootElement(); Unmarshaller unmarshaller = new Unmarshaller(); return unmarshaller.getJavaRepresentation(rootElement); } catch (JDOMException e) { throw new IOException (e.getMessage()); } } 清单 2 中的方法是静态的,允许直接调用它而无需实例化类的实例。由于对 unmarshall 方法的多个调用之间没有需要共享的数据,因此该方法可以是静态的。一旦处理了 XML,就将文档的根元素(以 JDOM 表示)就被传到执行从 XML 到 Java 对象转换的内部方法。 转换数据 清单 3. unmarshaller 类的入口点 // For each attribute, get its name and call
mutator
for (Iterator i =
attributes.iterator(); i.hasNext(); )
{
// Only want attributes for this
namespace
// Determine method to
call
// Find the method to call, and its parameter
type 找到了根元素的属性,并确定了每个属性的适用方法。然后,就是处理实际的 java.lang.reflect.Method 对象。XML 属性的值已确定,并作为调用的参数传送到方法。但是,需要解决一个映射问题;XML 文档中的所有数据都作为 String 抽取,但传递时必须是适当的 Java 类型。清单 4 将一个方法添加到 DataMapping 辅助类中,以满足转换的需要。 清单 4 将字符串映射成 Java 特定的类型 /** * * @param value String value to convert. * @param paramType Class with type to convert to. * @return Object - value in correct type. */ public static Object getParameter(String value, Class paramType) { Object ob = null; String type = paramType.getName(); if (type.equals("java.lang.String")) { ob = value; } else if ((type.equals("int")) || (type.equals("java.lang.Integer"))) { ob = Integer.valueOf(value); } else if ((type.equals("long")) || (type.equals("java.lang.Long"))) { ob = Long.valueOf(value); } else if ((type.equals("float")) || (type.equals("java.lang.Float"))) { ob = Float.valueOf(value); } else if ((type.equals("double")) || (type.equals("java.lang.Double"))) { ob = Double.valueOf(value); } else if ((type.equals("boolean")) || (type.equals("java.lang.Boolean"))) { ob = Boolean.valueOf(value); } return ob; } 在清单 4 中,值作为 String 传入,并且还传入了要转换的类和处理类型转换的方法。当然,这里包含的数据类型不多。可以添加更多类型(如 java.util.Date)来支持更复杂的数据映射。 一旦数据转换成适当的类型,可以使用反射调用 accessor 方法,并可传入已转换的数据类型。这就使 XML 文档中的所有属性及其值可以在作为结果的 Java 实例中以方法变量和的值存储。 递归对象树 在如果同一操作必须发生不知多少次的情况下,递归几乎总是完成操作的最佳选择。如果是 unmarshaller 类,则需要在将 XML 绑定到 Java 的完整过程上递归。一旦读取了所有属性并将它们分配给已创建的 Java 实例,就需要取出每个嵌套元素,然后再次执行取消编组。 通过迭代所提供根的子元素,来完成 XML 文档的处理,如清单 5 所示。这些子元素中的每一个都将成为另一个对象,这就表示必须以该元素作为根元素重新开始取消编组过程。 清单 5. 用递归处理嵌套元素 // Now do complex
objects
for (Iterator i =
elements.iterator(); i.hasNext(); )
{
// Only want elements for this
namespace
(!element.getNamespace().equals(Namespace.NO_NAMESPACE)))
{
// Determine method to
call
// Find the method to call, and its parameter
type
// Invoke the
method 注:您也许注意到我在清单 5 中的取消编组中做了一个假设,即成员变量总是由 XML 属性表示,嵌套对象由 XML 元素表示。那么,这些元素可能有自己的属性和嵌套元素。我的假设是唯一设置的限制,并且是合理的。这意味着取消编组过程不必查看引用的 XML 模式并确定特性是由元素表示,还是由属性表示。这也会使编组过程变得更简单,将在本系列的下一篇文章中出现。如果所有这一切对您没有难度,那么只使用属性作为变量,元素作为对象,不必考虑嵌套和递归。 清单 5 中的代码看来很像上一段代码,其主要区别是用红色强调的几行。这段代码通过取消编组嵌套元素来获取参数,而不是使用 DataMapping 辅助类将文本值转换成 Java 数据类型。然后,返回的对象提供给适当的 mutator 方法(例如,setPort),迭代继续进行。一旦递归从底层到顶层解开,则创建的 Java 对象将返回到调用应用程序。很快吗!数据绑定完成了。 通过使用运行的 unmarshaller 类,实际上,它最终使用了数据绑定工具。通过使用 XML 模式、XML 文档和一些简单的 Java 代码,访问 XML 就象访问 JavaBean 一样简单。 生成类 清单 6. 从示例模式生成 Java 类 /projects/dev/binding> export
CLASSPATH=/projects/dev/jdom/lib/xerces.jar /projects/dev/binding> java org.enhydra.xml.binding.SchemaMapper xml/configuration.xsd /projects/dev/binding> javac -d .
*.java 使用 unmarshaller 清单 7. 数据绑定测试类 import java.io.File; public class TestMapper { public static void main(String[] args)
{
System.out.println("Casting to
WebServiceConfiguration...");
System.out.println("Name: " + config.getName());
System.out.println("Port Number: " +
config.getPort().getNumber()); 编译和运行该数据绑定测试类以查看结果,如清单 8 所示。 清单 8. 测试 unmarshaller /projects/dev/binding> javac -d . TestMapper.java /projects/dev/binding> java
TestMapper 启动 Web
服务 清单 9. XML 到 Web 侦听程序 // Assume we have a List of URLs WebService newService =
new
WebService(); // Set up port
information // Set up
document root
newService.start(); 就那么简单,即使是初级开发者也能写出使用这个简单 XML 文档及其数据的 Java 程序,而他甚至还不知道正在使用 XML!有关 XML 数据绑定代码的更多用法,请关注 Enhydra 应用服务器即将推出的新版本,在未来的发行版中将包含这里讨论的数据绑定类(并将在下一篇文章中继续讨论)。完成了 unmarshaller 的代码之后,就可以讨论最终细节了。 跟上不断发展的 API JSR-031,数据绑定 API,在 Java 社区中仍是处在争论和测试过程的建议书。在这个过程中,它还可能做一些更改。尽管它还未成熟,至今为止许多使用 XML 的 Java 开发者还是会使用它,因为它是执行非常有用功能的方法。 术语解释 结束语 本系列的第四篇,也就是最后一篇文章将主要讲述编组,即利用 Marshaller 类得到 Java 类,并将它转换成 XML 文档。该文章将讨论转换原来经过取消编组的 Java 对象,以及未经过取消编组的 Java 对象。到那时,希望您喜欢迄今为止出现的数据绑定代码,下次再见。 下载 zip 文件,其中包含本文中示例的代码,包括
从 David Megginson 的 SAX 页面中下载 XML 的简单 API (SAX) 的版本 2.0,它是用于读取 XML 的基于事件的 Java API。 了解 DOM 的最新状态,在 W3C DOM 工作组的官方页面上,文档对象模型 (DOM) 是一种基于树的 API,用于在 Java 中读写 XML。 下载 JDOM,并了解 JDOM 项目,JDOM 是一种 API,该 API 使从 Java 中使用 XML 变得更简单和直观。 请阅读 JSR-031:数据绑定,它是 Sun 数据绑定规范申请。 下载 Enhydra,它是一种开放源码 Java 应用服务器。 对 XML 文档进行语法分析,然后用 Apache Xerces XML 语法分析器检查其模式有效性。 了解 XML 名称空间的详细信息。 想要了解 Brett 关于 Java 和 XML 的思路吗?请订购 Java 和 XML,由 O'Reilly 出版,是 Brett 关于该主题的著作。 Java 语言开发人员,请加入 developerWorks XML 工具和 API 新闻组。 需要关于 XML 的更多基本介绍吗?尝试 developerWorks 对 XML 的介绍教程和其它教材,其中涉及了最基本的主题。 一些商业工具也从 XML 对象执行数据绑定。它们都基于专有技术;JSR-031 API (aka Adelard) 仍是一个非公开的工作草案,因此没有商业产品可以包含它。请查看 KaanBaan,它在“XML 事务服务器”中执行动态数据绑定,还请查看 Breeze XML Studio。 关于作者 如果您希望与本文章的作者或其所在机构,进一步交流,请联系:畅享网 姜小姐 jill.jiang@amteam.org | 021-51096826-112 | 在线联系 |
节能与优化IT 企业CIO过冬良策当前金融危机的影响还在继续漫延,很多企业都在苦寻过冬的良策,在这种情况下,节能与优化技术与产品无疑成为CIO们关注的首要对象,本次选题就是针对节能与优化IT来为CIO们提供过冬的良…… |
|
|