38.2. 指定 XML Schema 原语的 Java 类

概述

默认情况下,XML Schema 类型映射到 Java 原语类型。虽然这是 XML Schema 和 Java 之间的最逻辑映射,但它并不始终满足应用程序开发人员的要求。您可能希望将 XML Schema 原语类型映射到可以存放额外信息的 Java 类,或者您可能希望将 XML 原语类型映射到允许简单替换的类。

JAXB javaType 自定义元素允许您自定义 XML Schema 原语类型和 Java 原语类型之间的映射。它可用于自定义全局级别和单个实例级别的映射。您可以使用 javaType 元素作为简单类型定义的一部分,或者作为复杂类型定义的一部分。

使用 javaType 自定义元素时,您必须指定用于将原语类型的 XML 表示转换为目标 Java 类或从目标 Java 类转换的方法。某些映射具有默认转换方法。对于没有默认映射的实例,Apache CXF 提供 JAXB 方法来简化所需方法的开发。

语法

javaType 自定义元素使用四个属性,如 表 38.1 “用于自定义 XML Schema 类型的 Java 类的属性” 所述。

表 38.1. 用于自定义 XML Schema 类型的 Java 类的属性

属性必需描述

name

指定 XML Schemitive 类型映射的 Java 类的名称。它必须是有效的 Java 类名称或 Java 原语类型的名称。您必须确保此类存在且可以被您的应用程序访问。代码生成器不检查此课程。

xmlType

指定被自定义的 XML 原语类型。只有在 javaType 元素被用作 globalBindings 元素的子项时才使用此属性。

parseMethod

指定负责将数据的基于字符串的 XML 表示解析为 Java 类实例的方法。更多信息请参阅 “指定转换器”一节

printMethod

指定负责将 Java 对象转换为基于字符串的 XML 表示数据的方法。更多信息请参阅 “指定转换器”一节

javaType 自定义元素可通过三种方式使用:

  • 要修改 XML Schema 原语类型的所有实例 - javaType 元素将修改 schema 文档中的所有 XML Schema 类型实例,当它用作 全局Bindings 自定义元素的子状态时。以这种方式使用时,您必须为 xmlType 属性指定一个值,用于标识要修改的 XML Schema 原语类型。

    例 38.7 “全球原语类型自定义” 显示一个在线全局自定义,用于指示代码生成器对 schema 中的所有 xsd:short 实例使用 java.lang.Integer

    例 38.7. 全球原语类型自定义

    <schema targetNamespace="http://widget.com/types/widgetTypes"
            xmlns="http://www.w3.org/2001/XMLSchema"
            xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
            xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
            jaxb:version="2.0">
      <annotation>
        <appinfo>
          <jaxb:globalBindings ...>
            <jaxb:javaType name="java.lang.Integer"
                           xmlType="xsd:short" />
          </globalBindings
        </appinfo>
      </annotation>
      ...
    </schema>
  • 要修改简单的类型定义 - javaType 元素会在将 XML 简单类型的所有实例应用到简单类型定义时,修改生成的类。当使用 javaType 元素修改简单类型定义时,请勿使用 xmlType 属性。

    例 38.8 “用于自定义简单类型的绑定文件” 显示外部绑定文件,用于修改名为 zipCode 的简单类型的生成。

    例 38.8. 用于自定义简单类型的绑定文件

    <jaxb:bindings xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
                   xmlns:xsd="http://www.w3.org/2001/XMLSchema"
                   jaxb:version="2.0">
      <jaxb:bindings wsdlLocation="widgets.wsdl">
        <jaxb:bindings node="xsd:simpleType[@name='zipCode']">
            <jaxb:javaType name="com.widgetVendor.widgetTypes.zipCodeType"
                           parseMethod="com.widgetVendor.widgetTypes.support.parseZipCode"
                           printMethod="com.widgetVendor.widgetTypes.support.printZipCode" />
        </jaxb:bindings>
      </jaxb:bindings>
    <jaxb:bindings>
  • 要修改复杂类型定义的元素或属性 - javaType 可以被应用于复杂类型定义的独立部分,方法是将它作为 JAXB 属性自定义的一部分包含在内。javaType 元素被置于属性的 baseType 元素的子项。当使用 javaType 元素修改复杂类型定义的特定部分时,请不要使用 xmlType 属性。

    例 38.9 “在复杂类型中自定义元素的绑定文件” 显示修改复杂类型的元素的绑定文件。

    例 38.9. 在复杂类型中自定义元素的绑定文件

    <jaxb:bindings xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
                   xmlns:xsd="http://www.w3.org/2001/XMLSchema"
                   jaxb:version="2.0">
      <jaxb:bindings schemaLocation="enumMap.xsd">
        <jaxb:bindings node="xsd:ComplexType[@name='widgetOrderInfo']">
          <jaxb:bindings node="xsd:element[@name='cost']">
            <jaxb:property>
              <jaxb:baseType>
                <jaxb:javaType name="com.widgetVendor.widgetTypes.costType"
                                parseMethod="parseCost"
                                printMethod="printCost" >
              </jaxb:baseType>
            </jaxb:property>
          </jaxb:bindings>
        </jaxb:bindings>
      </jaxb:bindings>
    <jaxb:bindings>

    有关使用 baseType 元素的更多信息,请参阅 第 38.6 节 “指定元素或属性的 Base Type”

指定转换器

Apache CXF 无法将 XML Schema 原语类型转换为随机 Java 类。当您使用 javaType 元素自定义 XML Schema 原语类型的映射时,代码生成器会创建一个适配器类,用于汇总自定义 XML Schema 原语类型。例 38.10 “JAXB Adapter Class” 中显示了一个适配器类示例。

例 38.10. JAXB Adapter Class

public class Adapter1 extends XmlAdapter<String, javaType>
{
  public javaType unmarshal(String value)
  {
    return(parseMethod(value));
  }

  public String marshal(javaType value)
  {
    return(printMethod(value));
  }
}

parseMethodprintMethod 被对应的 parseMethod 属性和 printMethod 属性的值替代。值必须识别有效的 Java 方法。您可以通过以下两种方式之一指定方法的名称:

  • 完全限定的 Java 方法名称,格式为 packagename.ClassName.methodName
  • methodName的形式的简单方法名称

    当您只提供简单方法名称时,代码生成器假定方法存在于 javaType 元素的 name 属性指定的类中。

重要

代码生成器 不会生成 解析或打印方法。您负责提供它们。有关开发解析和打印方法的详情请参考 “实现转换器”一节

如果没有提供 parseMethod 属性的值,代码生成器假定 name 属性指定的 Java 类具有 buildor,其第一个参数是 Java String 对象。生成的适配器的 unmarshal () 方法使用假定的构造器使用 XML 数据填充 Java 对象。

如果没有提供 printMethod 属性的值,代码生成器会假定 name 属性指定的 Java 类具有 toString () 方法。生成的适配器的 marshal () 方法使用 assumed toString () 方法将 Java 对象转换为 XML 数据。

如果 javaType 元素的 name 属性指定 Java 原语类型,或者 Java 原语打包程序类型之一,则代码生成器使用默认转换器。有关默认转换器的更多信息,请参阅 “默认原语类型转换器”一节

生成的内容

“指定转换器”一节 所述,使用 javaType 自定义元素可为每个自定义 XML Schema 原语类型触发一个适配器类生成。适配器使用模式 适配器N 来按顺序命名。如果您指定了两种原语自定义,则代码生成器创建两个适配器类: Adapter1Adapter2

为 XML 模式构建生成的代码取决于其效果的 XML Schema 结构是全局定义的元素,或者被定义为复杂类型的一部分。

当 XML Schema 结构是一个全局定义元素时,从默认方法中为类型生成的对象工厂方法如下:

  • 该方法通过 @XmlJavaTypeAdapter 注释进行解码。

    该注解指示当处理这个元素的实例时要使用的运行时。适配器类指定为类对象。

  • 默认类型由 javaType 元素的 name 属性指定的类替换。

例 38.11 “全球元素的自定义对象工厂方法” 显示 例 38.7 “全球原语类型自定义” 中受自定义影响的元素的对象工厂方法。

例 38.11. 全球元素的自定义对象工厂方法

 @XmlElementDecl(namespace = "http://widgetVendor.com/types/widgetTypes", name = "shorty")
 @XmlJavaTypeAdapter(org.w3._2001.xmlschema.Adapter1.class)
 public JAXBElement<Integer> createShorty(Integer value) {
     return new JAXBElement<Integer>(_Shorty_QNAME, Integer.class, null, value);
 }

当 XML Schema 结构定义为复杂类型的一部分时,生成的 Java 属性将按如下所示修改:

  • 属性使用 @XmlJavaTypeAdapter 注释进行解码。

    该注解指示当处理这个元素的实例时要使用的运行时。适配器类指定为类对象。

  • 该属性的 @XmlElement 包含 type 属性。

    type 属性的值是代表所生成的对象默认基础类型的类对象。如果是 XML Schema 原语类型,则类为 String

  • 属性使用 @XmlSchemaType 注释进行解码。

    该注释标识了构造的 XML Schema 原语类型。

  • 默认类型由 javaType 元素的 name 属性指定的类替换。

例 38.12 “自定义复杂度类型” 显示 例 38.7 “全球原语类型自定义” 中受自定义影响的元素的对象工厂方法。

例 38.12. 自定义复杂度类型

public class NumInventory {

    @XmlElement(required = true, type = String.class) @XmlJavaTypeAdapter(Adapter1.class) @XmlSchemaType(name = "short") protected Integer numLeft;
    @XmlElement(required = true)
    protected String size;

    public Integer getNumLeft() {
        return numLeft;
    }

    public void setNumLeft(Integer value) {
        this.numLeft = value;
    }

    public String getSize() {
        return size;
    }

    public void setSize(String value) {
        this.size = value;
    }

}

实现转换器

Apache CXF 运行时不知道如何将 XML 原语类型转换为 javaType 元素指定的 Java 类,除了它应该调用 parseMethod 属性和 printMethod 属性指定的方法。您需要提供运行时调用方法的实现。实施的方法必须能够处理 XML 原语类型的传统结构。

为简化数据转换方法的实施,Apache CXF 提供 javax.xml.bind.DatatypeConverter 类。此类提供了解析和打印所有 XML 原语类型的方法。解析方法使用 XML 数据的字符串表示,它们返回 表 34.1 “XML Schema Primitive Type to Java Native Type Mapping” 中定义的默认类型实例。print 方法获取默认类型的实例,它们返回 XML 数据表示的字符串。

DatatypeConverter 类的 Java 文档可在 https://docs.oracle.com/javase/8/docs/api/javax/xml/bind/DatatypeConverter.html 中找到。

默认原语类型转换器

javaType 元素的 name 属性中指定 Java 原语类型 Wrapper 类中的 Java 原语类型或 Java 原语类型时,不需要为 parseMethod 属性或 printMethod 属性指定值。如果没有提供值,Apache CXF 运行时会替换默认转换器。

默认数据转换器使用 JAXB DatatypeConverter 类来解析 XML 数据。默认转换器也会提供必要的任何类型,以便进行转换。