IBM®
跳转到主要内容
    中国 [选择]    使用条款
 
 
Select a scope: Search for:    
    首页    产品    服务与解决方案     支持与下载    个性化服务    
跳转到主要内容

developerWorks 中国  >  SOA and Web services  >

Web 服务提示与技巧: JAX-RPC 与 JAX-WS,第 2 部分

了解数据映射中的差异

developerWorks
文档选项

未显示需要 JavaScript 的文档选项


级别: 中级

Russell Butek (butek@us.ibm.com), IT 专家, IBM
Nicholas Gallardo (nlgallar@us.ibm.com), 软件工程师, IBM

2007 年 5 月 28 日

JAX-WS 2.0 是 JAX-RPC 1.1 的后续版本,通过使用 JAXB (Java Architecture for XML Binding),一种 JCP 定义的技术,它对数据映射方法进行了改进。本系列文章中的第 2 部分对这两种 Web 服务规范的数据映射进行了比较。有关 JAX-RPC 与 JAX-WS 更广泛的差异比较,请阅读本系列的第 1 部分。

引言

尽管 JAX-WS 2.0 中的一些方面是在 JAX-RPC 1.1 的基础上进行的改进,但其他的部分却是革命性的。例如,JAX-WS 没有提供 XML 模式和 Java 之间的映射,而这是 JAX-RPC 1.1 中的一个重要特性。相反,JAX-WS 使用了另一种 JCP 定义的技术 JAXB (Java Architecture for XML Binding) 2.0,为其完成数据映射。JAX-WS 仅仅提供了 Web 服务调用模型。它不再关心表示应用程序数据的 Java Bean,而仅仅关注于将其提供给目标 Web 服务。在本文中,我们将比较 JAX-RPC 1.1 和 JAXB 2.0 的映射。






回页首


从 XML 模式到 Java 的映射

JAX-RPC 和 JAXB
JAX-RPC 为什么没有直接使用 JAXB 呢?其原因是时间问题。在 JAXB 之前已经完成了 JAX-RPC 的第 1 个版本,所以 JAX-RPC 的作者开发了自己的映射特性,而不是等待使用 JAXB。

在 JAX-RPC 和 JAX-WS/JAXB 中,将 XML 名称映射到 Java 名称的方式基本上是相同的,尽管在简单类型的映射上有些细微的差异。表 1 介绍了这些差异,这些差异看起来非常显著,然而除了日期/时间类型之外,其他的 XML 简单类型都很少使用。


表 1. JAX-RPC 1.1 和 JAXB 2.0 中 XML 简单类型映射的差异
类型JAX-RPC 1.1JAXB 2.0
xsd:anySimpleTypejava.lang.Stringjava.lang.Object
xsd:durationjava.lang.Stringjavax.xml.datatype.Duration(新的类型)
xsd:dateTimejava.util.Calendarjavax.xml.datatype.XMLGregorianCalendar(新的类型)
xsd:timejava.util.Calendarjavax.xml.datatype.XMLGregorianCalendar
xsd:datejava.util.Calendarjavax.xml.datatype.XMLGregorianCalendar
xsd:gYearMonthjava.lang.Stringjavax.xml.datatype.XMLGregorianCalendar
xsd:gYearjava.lang.Stringjavax.xml.datatype.XMLGregorianCalendar
xsd:gMonthDayjava.lang.Stringjavax.xml.datatype.XMLGregorianCalendar
xsd:gMonthjava.lang.Stringjavax.xml.datatype.XMLGregorianCalendar
xsd:gDayjava.lang.Stringjavax.xml.datatype.XMLGregorianCalendar
xsd:anyURIjava.net.URIjava.lang.String
xsd:NMTOKENSjava.lang.String[]java.util.List<java.lang.String>
xsd:IDREFjava.lang.Stringjava.lang.Object
xsd:IDREFSjava.lang.String[]java.util.List<java.lang.Object>
xsd:ENTITYnot supportedjava.lang.String
xsd:ENTITIESnot supportedjava.util.List<java.lang.String>

在 JAX-RPC 和 JAXB 之间,简单类型映射的纯 Java 方面几乎相同,但是 JAXB 映射还使用了新的 Java 注释特性。清单 1 至 3 提供了一些简单类型映射的示例。


清单 1. XML complexType 元素和属性
                  
  <xsd:sequence>
    <xsd:element name="intField" type="xsd:int"/>
    <xsd:element name="intMinField" type="xsd:int" minOccurs="0"/>
    <xsd:element name="intNilField" type="xsd:int" nillable="true"/>
    <xsd:element name="stringField" type="xsd:string"/>
    <xsd:element name="stringMinField" type="xsd:string" minOccurs="0"/>
    <xsd:element name="stringNilField" type="xsd:string" nillable="true"/>
  </xsd:sequence>
  <xsd:attribute name="intAttr" type="xsd:int"/>
  <xsd:attribute name="intAttrReq" type="xsd:int" use="required"/>


清单 2. 通过 JAX-RPC 1.1 映射为 Java Bean 属性
                    
	private int intField;
    private Integer intMinField;
    private Integer intNilField;
    private String stringField;
    private String stringMinField;
    private String stringNilField;
    private Integer intAtt;
    private int intAttReq;


清单 3. 通过 JAXB 2.0 映射为 Java Bean 属性
                    
  protected int intField;
  protected Integer intMinField;

    @XmlElement(required = true, type = Integer.class, nillable = true)
    protected Integer intNilField;

    @XmlElement(required = true)
    protected String stringField;

    protected String stringMinField;

    @XmlElement(required = true, nillable = true)
    protected String stringNilField;

    @XmlAttribute
    protected Integer intAtt;

    @XmlAttribute(required = true)
    protected int intAttReq;

在 JAX-RPC 1.1 所生成的 Java Bean 中,您无法区分下面的差别:

  • 元素字段和属性字段
  • minOccurs="0" type="xsd:int" 映射的字段和从 nillable="true" type="xsd:int" 映射的字段
  • type="xsd:string" 映射的字段和从 type="xsd:string" minOccurs="0" 映射的字段

但由于 JAXB 使用了新的 Java 注释,现在您可以区分出它们之间的差别。@XmlElement@XmlAttribute 注释具有一些选项。其中与本文相关的选项包括:

  • Required:该元素是否必须存在?例如,minOccurs 是否不等于 1?
  • Nillable:该字段是否包含 nillable="true" 属性?

数组映射

在 JAX-RPC 和 JAXB 之间,从 XML 到 Java 的数组映射存在着差异,这是因为 JAXB 使用了新的泛型 Java 特性,如清单 4 至 6 所示。


清单 4. XML 数组
                    
  <xsd:element name="intArrayField" type="xsd:int" minOccurs="0" maxOccurs="unbounded"/>


清单 5. 通过 JAX-RPC 1.1 映射为 Java Bean 属性
                    
  private int[] intArrayField;
    public int[] getIntArrayField() {...}
    public void setIntArrayField(int[] intArrayField) {...}
    public int getIntArrayField(int i) {...}
    public void setIntArrayField(int i, int value) {...}


清单 6. 通过 JAXB 2.0 映射为 Java Bean 属性
                    
  @XmlElement(type = Integer.class)
    protected List<Integer> intArrayField;
    public List<Integer> getIntArrayField() {...}

注意访问器方法中的差别。JAX-RPC 映射遵循 Java Bean 数组访问器的严格定义。JAXB 映射并没有映射为数组,所以有些不同。getIntArrayField 返回一个引用,不仅仅是快照,而是实际的列表。因此,您对返回的列表所做的任何修改都将出现在属性中。这就是为什么对于数组属性没有 set 方法的原因。

复杂类型的映射

在 JAX-RPC 和 JAXB 中,对 complexType 的映射几乎相同,除了这些字段在 JAX-RPC 中是私有的,而在 JAXB 中是保护的,并且 JAXB 映射添加了相应的注释对字段顺序进行描述。清单 7 至 9 提供了这两种映射的示例和比较。


清单 7. XML 模式 complexType
                  
  <xsd:element name="Phone" type="tns:Phone"/>
  <xsd:complexType name="Phone">
    <xsd:sequence>
      <xsd:element name="areaCode" type="xsd:string"/>
      <xsd:element name="exchange" type="xsd:string"/>
      <xsd:element name="number" type="xsd:string"/>
    </xsd:sequence>
  </xsd:complexType>


清单 8. complexType 的 JAX-RPC 1.1 映射
                
  public class Phone {
    private String areaCode;
    private String exchange;
    private String number;

    ...
}


清单 9. complexType 的 JAXB 2.0 映射
                
  @XmlType(name = "Phone", propOrder = {
    "areaCode",
    "exchange",
    "number"
})
public class Phone {

    @XmlElement(required = true)
    protected String areaCode;
    @XmlElement(required = true)
    protected String exchange;
    @XmlElement(required = true)
    protected String number;

    ...
}

请注意,清单 7 中的模式使用了 xsd:sequence。如果它使用的是 xsd:all,那么 propOrder 注释应该为空:@XmlType(name = "Phone", propOrder = {})

新的 ObjectFactory 类

JAXB 生成了一个文件 ObjectFactory,而 JAX-RPC 则没有。每个包含 Java Bean 的目录都会有一个 ObjectFactory。对于在模式相应的命名空间中定义的每种类型,ObjectFactory 类都为该类型提供了一种创建方法。对于每个元素,ObjectFactory 类提供了一种创建元素的方法,该方法返回一个 javax.xml.bind.JAXBElement<Type>。例如,对于清单 7 中的 Phone 模式,清单 10 显示了所生成的 ObjectFactory 类,这个类具有一个返回 Phone 的实例和一个返回 JAXBElement<Phone> 的实例的方法。您仍然可以直接实例化该目录中的 Java Bean,但最好是使用这个工厂。


清单 10. Phone 的 JAXB 2.0 ObjectFactory
                
import javax.xml.bind.JAXBElement;
import javax.xml.bind.annotation.XmlElementDecl;
import javax.xml.namespace.QName;

public class ObjectFactory {

    private final static QName _Phone_QNAME = new QName
    ("urn:types.MyServiceSample.ibm.com", "Phone");

    public ObjectFactory() {...}

    public Phone createPhone() {...}

    @XmlElementDecl(namespace = "urn:types.MyServiceSample.ibm.com", name = "Phone")
    public JAXBElement<Phone> createPhone(Phone value) {...}
}





回页首


从 Java 到 XML 模式的映射

灵活且少量地使用这些新的 JAXB 定义的注释,Java 可以以一种良好控制的方式映射到 XML,尤其是在对已提供的从 XML 到 Java 的映射进行逆映射的情况下。但是,如果使用没有注释的 Java 又会如何呢?

在 JAX-RPC 和 JAXB 中,将 Java 名称映射到 XML 名称基本上是相同的。也就是说,无论映射遵循 JAX-RPC 或 JAXB,Java 基本数据类型可以映射到相同的 XML 模式。JAX-RPC 定义了一组映射到 XML 的标准 Java 类。对于所有这些类(除了其中一个之外),JAXB 可以进行完全相同的映射,但是 JAXB 向映射类列表中添加了更多的类,如表 2 所示。


表 2. JAX-RPC 1.1 和 JAXB 2.0 之间在标准 Java 类映射上的差别
类型JAX-RPC 1.1JAXB 2.0
java.lang.Stringxsd:stringxsd:string
java.math.BigIntegerxsd:integerxsd:integer
java.math.BigDecimalxsd:decimalxsd:decimal
java.util.Calendarxsd:dateTimexsd:dateTime
java.util.Datexsd:dateTimexsd:dateTime
javax.xml.namespace.QNamexsd:QNamexsd:QName
java.net.URIxsd:anyURIxsd:string
javax.xml.datatype.XMLGregorianCalendarn/axsd:anySimpleType
javax.xml.datatype.Durationn/axsd:duration
java.lang.Objectn/a1 xsd:anyType
java.awt.Imagen/a2 xsd:base64Binary
javax.activation.DataHandlern/a2 xsd:base64Binary
javax.xml.transform.Sourcen/a2 xsd:base64Binary
java.util.UUIDn/axsd:string

表 2 中需要注意的地方:
1. 一些供应商将 java.lang.Object 映射为 xsd:anyType。
2. 在 JAX-RPC 中,这被映射为 MIME 绑定类型,即未定义的 XML 类型。





回页首


结束语

我们比较了 JAX-RPC 1.1 和 JAXB 2.0 的映射。除了一些值得注意的地方外,它们基本上是类似的:

  • 从 XML 到 Java:
    • 对一些简单类型的映射存在差别
    • JAXB 添加了 ObjectFactory 类
    • JAXB 使用了新的 Java 语言注释特性和泛型特性
  • 从 Java 到 XML:
    • 基本数据类型的映射是相同的
    • 标准 Java 映射基本上相同

有关 JAXB 2.0 规范,还有很多的内容,特别是 Java 注释的使用,但是这个主题已经超出了本文的范围。有关 JAXB 2.0 的更多信息,请参见参考资料部分。



参考资料



作者简介

Russell Butek 是 IBM 的一名 SOA 和 Web 服务顾问。他曾是 IBM WebSphere Web 服务引擎的开发人员之一。他也是 JAX-RPC Java Specification Request (JSR) 专家组的成员。他参与了 Apache 的 AXIS SOAP 引擎的实现,并推动 AXIS 1.0 遵守 JAX-RPC。


Nick Gallardo 担任 IBM WebSphere 平台软件工程师,主要负责 Web 服务支持的各个方面。在此之前,他从事 IBM WebSphere 和 Tivoli 平台中其他方面的工作。Nick 于 2001 加入 IBM,此前他曾在德克萨斯州奥斯汀市两家不同的初创技术型公司从事开发工作。




对本文的评价










回页首


IBM 公司保留在 developerWorks 网站上发表的内容的著作权。未经IBM公司或原始作者的书面明确许可,请勿转载。如果您希望转载,请通过 提交转载请求表单 联系我们的编辑团队。
    关于 IBM 隐私条约 联系 IBM 使用条款