ヘッダーをスキップ
Oracle® Fusion Middleware Oracle TopLinkによるJAXBアプリケーションの開発
12c (12.1.2)
E48003-01
  目次へ移動
目次

前
 
次
 

3 タイプ・レベルのマッピング

この章の内容は次のとおりです。

3.1 デフォルトのルート要素の定義

マップされたクラスのうち、少なくとも1つには、デフォルトのルート要素が定義されている必要があります。これにより、XML文書の最上位レベルのルートが何になるかがEclipseLinkに通知されます。図3-1に示すCustomerクラスとAddressクラスについて考えてみます。

図3-1 マップされたクラスのサンプル

マップされたクラスのサンプル
「図3-1 マップされたクラスのサンプル」の説明

これらのクラスは、例3-1に示すXMLスキーマに対応しています。このスキーマには、タイプcustomer-typeの最上位の要素が含まれているため、Customerクラスには、デフォルトのルート要素を指定する必要があります。

例3-1 XMLスキーマのサンプル

<xsd:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
   <xsd:complexType name="address-type">
      <xsd:sequence>
         <element name="street" type="xsd:string"/>
         <element name="city" type="xsd:string"/>
      </xsd:sequence>
   </xsd:complexType>
 
   <xsd:element name="customer" type="customer-type"/>
 
   <xsd:complexType name="customer-type">
      <xsd:sequence>
         <xsd:element name="name" type="xsd:string"/>
         <xsd:element name="billing-address" type="address-type"/>
         <xsd:element name="shipping-address" type="address-type"/>
      </xsd:sequence>
   </xsd:complexType>
</xsd:schema>
 

例3-2は、デフォルトのルート要素を指定するためにJavaクラスに注釈を付ける方法を示しています。必要なのは、JAXBの標準的な@XmlRootElement注釈のみです。

例3-2 @XmlRootElement注釈の使用

package example;
 
import javax.xml.bind.annotation.*;
 
@XmlRootElement
public class Customer {
   private String name;
 
   @XmlElement(name="billing-address")
   private Address billingAddress;
 
   @XmlElement(name="shipping-address")
   private Address shippingAddress;
 
   ...
}
 

例3-3は、EclipseLinkのOXMメタデータ形式でデフォルトのルート要素を指定する方法を示しています。

例3-3 デフォルトのルート要素の指定

...
<java-type name="Customer">
   <xml-root-element/>
   <java-attributes>
      <xml-element java-attribute="name"/>
      <xml-element java-attribute="billingAddress" name="billing-address"/>
      <xml-element java-attribute="shippingAddress" name="shipping-address"/>
   </java-attributes>
</java-type>
...
 

3.1.1 デフォルトのルート要素のカスタマイズ

例3-2では、クラスはCustomerと呼ばれ、XMLでのルート要素名はcustomerです。デフォルトでは、@XmlRootElementが指定されると、そのクラスの名前は先頭が小文字となり、ルート要素名として設定されます。ただし、XMLの要素名がJavaクラス名と異なる場合は、(例3-4に示すように)注釈に、または(例3-5に示すように)OXMメタデータに、name属性を含めることができます。

例3-4 注釈の使用

package example;
 
import javax.xml.bind.annotation.*;
 
@XmlRootElement(name="my-customer")
public class Customer {
   private String name;
 
   @XmlElement(name="billing-address")
   private Address billingAddress;
 
   @XmlElement(name="shipping-address")
   private Address shippingAddress;
 
   ...
}
 

例3-5 OXMメタデータの使用

...
<java-type name="Customer">
   <xml-root-element name="my-customer"/>
   <java-attributes>
      <xml-element java-attribute="name"/>
      <xml-element java-attribute="billingAddress" name="billing-address"/>
      <xml-element java-attribute="shippingAddress" name="shipping-address"/>
   </java-attributes>
</java-type>
...
 

JAXBの名前バインディング・アルゴリズムの詳細は、『Java Architecture for XML Binding (JAXB) Specification』(http://jcp.org/en/jsr/detail?id=222)の「Appendix D: Binding XML Names to Java Identifiers」を参照してください。

3.1.2 EclipseLinkがデフォルトのルート要素をどのように使用するかの理解

CustomerクラスのインスタンスをXMLに永続化する際には、EclipseLinkランタイムで次の処理が行われます。

  • デフォルトのルート要素が取得されます。Customerクラス・インスタンスは、XML文書のルートに対応しています。EclipseLinkランタイムは、注釈とOXMのいずれかに指定されているデフォルトのルート要素(customer)を使用して、XML文書を開きます。次に、EclipseLinkはクラスに対するマッピングを使用して、そのオブジェクトの属性をマーシャリングします。

    <customer>
       <name>...</name>
    </customer>
     
    
  • EclipseLinkランタイムは、billingAddressなどのオブジェクト属性に遭遇すると、この属性に関連付けられているマッピングをチェックし、処理をどの要素(billing-address)に移すかを判別します。

    <customer>
       <name>...</name>
       <billing-address/>
    </customer>
     
    
  • EclipseLinkランタイムはマッピングの参照ディスクリプタ(Address)をチェックして、永続化する属性を判別します。

    <customer>
       <name>...</name>
       <billing-address>
          <street>...</street>
          <city>...</city>
       </billing-address>
    </customer>
    

3.2 ネームスペース情報の設定

ほとんどのXML文書は、ネームスペースで修飾されています。Javaクラスの要素は、次の各レベルでネームスペースによって修飾できます。

ほとんどの場合は、パッケージ・レベルの注釈で十分です。他のレベルを使用してドキュメントをカスタマイズできます。ネームスペースを指定するには、@XmlSchema注釈を使用します。

3.2.1 パッケージ・レベルでの修飾

パッケージに対して@XmlSchema注釈を使用して、デフォルトのネームスペースを設定し、パッケージ内の要素がすべてネームスペースで修飾されることを指定します。この情報は、特殊なJavaソース・ファイルpackage-info.javaで指定されています。

例3-6 注釈の使用

@XmlSchema(
   namespace="http://www.example.org/package",
   elementFormDefault=XmlNsForm.QUALIFIED)
package example;
 
import javax.xml.bind.annotation.XmlNsForm;
import javax.xml.bind.annotation.XmlSchema;
 

これは、EclipseLink XMLバインディングで次のように指定できます。

例3-7 OXMメタデータの使用

<?xml version="1.0" encoding="UTF-8"?>
<xml-bindings xmlns="http://www.eclipse.org/eclipselink/xsds/persistence/oxm">
    <xml-schema
        element-form-default="QUALIFIED"
        namespace="http://www.example.org/package">
    </xml-schema>
 
    <java-types>
        <java-type name="Customer">
        ...
 
</xml-bindings>
 

単純なCustomerクラスを使用すると、例3-6例3-7では、次のXMLが生成されます。

<customer xmlns="http://www.example.org/package">
   <name>Jane Doe</name>
   <account>36328721</account>
</customer>
 

すべての要素は、http://www.example.org/packageネームスペースで修飾されています。

3.2.2 タイプ・レベルでの修飾

タイプ・レベルの注釈によって、パッケージ・レベルのネームスペースがオーバーライドされます。

例3-8 注釈の使用

package example;
 
@XmlRootElement
@XmlType(namespace="http://www.example.org/type")
public class Customer {
   private String name;
 
   private String account;
 
   ...
}
 

これは、EclipseLink XMLバインディングで次のように指定できます。

例3-9 XMLバインディング・ファイルの使用

<?xml version="1.0" encoding="UTF-8"?>
<xml-bindings xmlns="http://www.eclipse.org/eclipselink/xsds/persistence/oxm">
    <xml-schema
        element-form-default="QUALIFIED"
        namespace="http://www.example.org/package">
    </xml-schema>
 
    <java-types>
        <java-type name="Customer">
            <xml-type namespace="http://www.example.org/type" />
            <java-attributes>
                <xml-element java-attribute="name" />
                <xml-element java-attribute="account" />
            </java-attributes>
        </java-type>
    </java-types>
</xml-bindings>
 

これにより、次のXMLが生成されます。

<custom xmlns="http://www.example.org/package" xmlns:ns0="http://www.example.org/type">
   <ns0:name>Bob</ns0:name>
   <ns0:account>1928712</ns0:account>
</custom>
 

Customerタイプ内の要素は、http://www.example.org/typeネームスペースで修飾されています。

3.2.3 フィールド/プロパティ・レベルでの修飾

パッケージまたはタイプのネームスペースは、プロパティ/フィールド・レベルでオーバーライドできます。属性および要素の注釈はすべて、namespaceパラメータを受け入れます。

例3-10 ネームスペースのオーバーライド

package example;
 
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(namespace="http://www.example.org/type")
public class Customer {
   private String name;
 
   @XmlElement(namespace="http://www.example.org/property")
   private String account;
 
   ...
}
 

これは、EclipseLink XMLバインディングで次のように指定できます。

例3-11 バインディング・ファイルのサンプル

<?xml version="1.0" encoding="UTF-8"?>
<xml-bindings xmlns="http://www.eclipse.org/eclipselink/xsds/persistence/oxm">
    <xml-schema
        element-form-default="QUALIFIED"
        namespace="http://www.example.org/package">
    </xml-schema>
 
    <java-types>
        <java-type name="Customer">
            <xml-type namespace="http://www.example.org/type" />
            <java-attributes>
                <xml-element java-attribute="name" />
                <xml-element java-attribute="account" namespace="http://www.example.org/property" />
            </java-attributes>
        </java-type>
    </java-types>
</xml-bindings>
 

これにより、次のXMLが生成されます。

<custom xmlns="http://www.example.org/package" xmlns:ns1="http://www.example.org/property"
   xmlns:ns0="http://www.example.org/type">
   <ns0:name>Bob</ns0:name>
   <ns1:account>1928712</ns1:account>
</custom>
 

account要素のみが、http://www.example.org/propertyネームスペースで修飾されています。

3.3 継承の指定

EclipseLink MOXyには、次のように、XMLでの継承階層を表す手段がいくつか用意されています。

3.3.1 xsi:typeの使用

デフォルトでは、EclipseLinkは、継承をXMLで表すためにxsi:type属性を使用します。

この例では、抽象スーパー・クラス(ContactInfo)には、すべてのタイプの連絡先情報が含まれています。AddressPhoneNumberは、ContactInfoの具体的な実装です。

例3-12 Javaクラスのサンプル

public abstract class ContactInfo {
}
 
public class Address extends ContactInfo {
 
   private String street;
   ... 
 
}
 
public class PhoneNumber extends ContactInfo {
 
   private String number;
   ...
 
}
 

Customerオブジェクトには様々なタイプの連絡先情報を指定できるため、そのプロパティはスーパークラスを参照します。

@XmlRootElement
public class Customer {
 
   private ContactInfo contactInfo;
   ... 
 
}

例にあるCustomerをマーシャリングすると、次のXMLが生成されます。

<customer>
   <contactInfo 
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
      xsi:type="address">
      <street>323 Main Street</street>
   </contactInfo>
</customer>
 

contactInfo要素上のxsi:type属性に注目してください。

3.3.2 置換グループの使用

XMLで継承をモデル化する別の方法は、XMLスキーマの置換グループ機能を使用することです。この手法を使用すると、要素名自体によって、どのサブクラスを使用するかが決定します。

同じ例3-12で、サブクラスのそれぞれに@XmlRootElement注釈を追加します。これは継承インジケータの役割を果たします。

例3-13 @XmlRootElement注釈の使用

public abstract class ContactInfo {
}
 
@XmlRootElement
public class Address extends ContactInfo {
 
   private String street;
   ... 
 
}
 
@XmlRootElement
public class PhoneNumber extends ContactInfo {
 
   private String number;
   ...
 
}
 

また、CustomerオブジェクトのcontactInfoプロパティに@XmlElementRefという注釈を付けます。これによって、値タイプが要素名(およびネームスペースURI)から導出されることが示されます。

public class Customer {
    private ContactInfo contactInfo;
 
    @XmlElementRef
    public ContactInfo getContactInfo() {
        return contactInfo;
    }

   ...
}
 

この手法を使用し、例にあるCustomerをマーシャリングすると、次のXMLが生成されます。

<customer>
   <address>
      <street>323 Main Street</street>
   </address>
</customer>
 

Addressオブジェクトがaddress要素にマーシャリングされていることに注意してください。

3.3.3 @XmlDiscriminatorNode/@XmlDiscriminatorValueの使用

また、(EclipseLink 2.2で導入された)MOXY固有の注釈である@XmlDiscriminatorNodeおよび@XmlDiscriminatorValueを使用して、継承を表すこともできます。この手法では、属性を選択してサブタイプを表すことができます。

例3-13を使用すると、ContactInfoクラスは@XmlDiscriminatorNode注釈を使用して、サブクラス・インジケータを保持するXML属性(classifier)を指定します。AddressPhoneNumber@XmlDiscriminatorValueという注釈が付けられ、そのクラスのインジケータ名(address-classifierphone-number-classifier)が示されます。

例3-14 @XmlDiscriminatorNode注釈および@XmlDiscriminatorValue注釈の使用

@XmlDiscriminatorNode("@classifier")
public abstract class ContactInfo {
}
 
@XmlDiscriminatorValue("address-classifier")
public class Address extends ContactInfo {
 
   private String street;
   ... 
 
}
 
@XmlDiscriminatorValue("phone-number-classifier")
public class PhoneNumber extends ContactInfo {
 
   private String number;
   ...
 
}
 

例3-14のXMLは、次のようになります。

<customer>
   <contactInfo classifier="address-classifier">
      <street>323 Main Street</street>
   </contactInfo>
</customer>

AddresscontactInfo要素にマーシャリングされていることに注目してください。そのclassifier属性には、識別子ノードの値address-classifierが含まれています。