この章の内容は次のとおりです。
@XmlSchemaType
注釈を使用して、日付および時刻の情報のXML表示をカスタマイズできます。また、EclipseLink MOXyでは、JAXB仕様(JSR-222)で扱われていない次の型がサポートされています。
java.sql.Date
java.sql.Time
java.sql.Timestamp
次のXMLスキーマには、xsd:date
型のdate-of-birth要素が含まれています。
例5-1 XMLスキーマのサンプル
<?xml version="1.0" encoding="UTF-8"?> <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <xsd:element name="customer"> <xsd:complexType> <xsd:sequence> <xsd:element name="date-of-birth" type="xsd:date" minOccurs="0"/> </xsd:sequence> </xsd:complexType> </xsd:element> </xsd:schema>
JAXB XML Schema to Javaコンパイラ(XJC)を使用して、サンプル・スキーマからクラス・モデルを生成できます。次に例を示します。
> xjc -d output-dir -p example date.xsd
これにより、次のCustomerクラスが生成されます。
例5-2 Customerクラスのサンプル
package example; import javax.xml.bind.annotation.XmlAccessType; import javax.xml.bind.annotation.XmlAccessorType; import javax.xml.bind.annotation.XmlElement; import javax.xml.bind.annotation.XmlRootElement; import javax.xml.bind.annotation.XmlSchemaType; import javax.xml.bind.annotation.XmlType; import javax.xml.datatype.XMLGregorianCalendar; @XmlAccessorType(XmlAccessType.FIELD) @XmlType(name = "", propOrder = {"dateOfBirth"}) @XmlRootElement(name = "customer") public class Customer { @XmlElement(name = "date-of-birth") @XmlSchemaType(name = "date") protected XMLGregorianCalendar dateOfBirth; public XMLGregorianCalendar getDateOfBirth() { return dateOfBirth; } public void setDateOfBirth(XMLGregorianCalendar value) { this.dateOfBirth = value; } }
次の点に注意してください。
dateOfBirth
プロパティの型はjavax.xml.datatype.XMLGregorianCalendar
dateOfBirth
プロパティは@XmlSchemaType
注釈を使用
Javaの一部のデータ型(XMLGregorianCalendarなど)には、複数のXML表現(xsd:date
、xsd:time
、xsd:dateTimeなど)があります。@XmlSchemaType
を使用して適切な表現を選択します。
デフォルトでは、JAXB XML schema to Javaコンパイラ(XJC)によって、XMLGregorianCalendar
型のプロパティが生成されます。ただし、例5-3に示すように、これは、java.util.Date
またはjava.util.Calendar
に簡単に変更できます。
例5-3 java.util.Dateの使用
package blog.date; import java.util.Date; import javax.xml.bind.annotation.XmlAccessType; import javax.xml.bind.annotation.XmlAccessorType; import javax.xml.bind.annotation.XmlElement; import javax.xml.bind.annotation.XmlRootElement; import javax.xml.bind.annotation.XmlSchemaType; @XmlAccessorType(XmlAccessType.FIELD) @XmlRootElement(name = "customer") public class Customer { @XmlElement(name = "date-of-birth") @XmlSchemaType(name = "date") protected Date dateOfBirth; public Date getDateOfBirth() { return dateOfBirth; } public void setDateOfBirth(Date value) { this.dateOfBirth = value; } }
次のXMLスキーマとクラス図は、XMLスキーマの結合の代表的な用途を示しています。
例5-4 XMLスキーマの結合
<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:element name="customer" type="customer-type" />
<xsd:complexType name="customer-type">
<xsd:sequence>
<xsd:element name="shoe-size" type="size-type" />
</xsd:sequence>
</xsd:complexType>
<xsd:simpleType name="size-type">
<xsd:union memberTypes="xsd:decimal xsd:string" />
</xsd:simpleType>
</xsd:schema>
図5-2に、XML文書内のunionフィールドへのマッピングを示します。このXML文書はこの例のスキーマに準拠しています。EclipseLinkでXML文書をアンマーシャリングする場合、正常な変換が行われるまで、union型のそれぞれが試行されます。unionにおける最初のスキーマ・タイプはxsd:decimal
です。10.5は有効な10進数であるため、EclipseLinkはその値を適切な型に変換します。
図5-3では、値Mは、有効なxsd:decimal
型ではないため、次のunion型であるxsd:string
が試行されます。
現時点では、EclipseLinkは、注釈またはOXMメタデータを使用したunionのマッピングをサポートしていません。ただし、EclipseLinkのXMLカスタマイザを使用してマッピングを作成することはできます。
最初に、shoeSize
属性に@XmlTransient
という注釈を付けて、そのマッピングが自動的に生成されないようにします。また、@XmlCustomizer
注釈も付けます。こうすると、CustomerCustomizer
クラスによって、コード内にunionマッピングが作成されます。
例5-5 EclipseLinkのカスタマイザの使用
package example;
import javax.xml.bind.annotation.*;
import org.eclipse.persistence.oxm.annotations.*;
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
@XmlCustomizer(CustomerCustomizer.class)
public class Customer {
@XmlTransient
private Object shoeSize;
...
}
CustomerCustomizer
クラスを使用すると、shoeSize
属性にマッピングを手動で追加できます。例5-6では、マッピング上にXMLUnionField
が構成されており、addSchemaType()
を呼び出すことによって、可能なunionメンバー・タイプが追加されます。
例5-6 unionフィールドのマッピング
package example;
import org.eclipse.persistence.config.DescriptorCustomizer;
import org.eclipse.persistence.descriptors.ClassDescriptor;
import org.eclipse.persistence.oxm.*;
public class CustomerCustomizer implements DescriptorCustomizer {
@Override
public void customize(ClassDescriptor descriptor) throws Exception {
XMLDirectMapping shoeSizeMapping = new XMLDirectMapping();
shoeSizeMapping.setAttributeName("shoeSize");
XMLUnionField shoeSizeField = new XMLUnionField();
shoeSizeField.setXPath("shoe-size/text()");
shoeSizeField.addSchemaType(XMLConstants.DECIMAL_QNAME);
shoeSizeField.addSchemaType(XMLConstants.STRING_QNAME);
shoeSizeMapping.setField(shoeSizeField);
descriptor.addMapping(shoeSizeMapping);
}
}
addSchemaType()
の呼出し順は重要です。XMLの値をJavaに変換する際、EclipseLinkは、フィールドに追加された順に変換を試行し、正常な変換が行われるとすぐに戻ります。たとえば、10.5のshoeSize
をアンマーシャリングするとします。
... shoeSizeField.addSchemaType(XMLConstants.DECIMAL_QNAME); shoeSizeField.addSchemaType(XMLConstants.STRING_QNAME); ...
BigDecimal
が作成され、値が格納されます。ただし、XMLUnionFieldが次のように設定された場合は異なります。
... shoeSizeField.addSchemaType(XMLConstants.STRING_QNAME); shoeSizeField.addSchemaType(XMLConstants.DECIMAL_QNAME); ...
この場合は、shoeSizeの値はString
("10.5")となります。
byte[]
やByte[]
などのバイナリ型フィールドにマッピングする際には、これ以外にも検討すべき項目があります。
EclipseLinkでは、base64Binary
(デフォルト)とhexBinary
という、2つの表現形式でのバイナリ・データのマーシャリングおよびアンマーシャリングをサポートしています。EclipseLink OXMで@XmlSchemaType
注釈または<xml-schema-type>
要素を使用して、目的のバイナリ形式を指定できます。次の例は、これらの形式のそれぞれに対して同じbyte[]
をマーシャリングした結果を示しています。
例5-7 注釈
package example; import javax.xml.bind.annotation.*; @XmlRootElement public class BinaryData { @XmlSchemaType(name="hexBinary") public byte[] hexBytes; @XmlSchemaType(name="base64Binary") public byte[] base64Bytes; }
例5-8 EclipseLink OXM
... <java-type name="example.BinaryData"> <xml-root-element/> <java-attributes> <xml-element java-attribute="hexBytes"> <xml-schema-type name="hexBinary"/> </xml-element> <xml-element java-attribute="base64Bytes"> <xml-schema-type name="base64Binary"/> </xml-element> </java-attributes> </java-type> ...
BinaryData b = new BinaryData(); b.hexBytes = new byte[] {2,4,8,16,32,64}; b.base64Bytes = b.hexBytes; jaxbContext.createMarshaller().marshal(b, System.out);
他のJavaプリミティブ/ラッパー型と異なり、EclipseLinkでは、byte[]
(プリミティブ)データ型とByte[]
(ラッパー)データ型が区別されます。次の例で示されているように、デフォルトでは、byte[]
は単一の要素または属性にマーシャリングする一方、Byte[]
はそれぞれのbyte
をその要素としてマーシャリングします。
例5-10 byte[]とByte[]の使用
package example; import javax.xml.bind.annotation.*; @XmlRootElement public class BinaryData { public byte[] primitiveBytes; public Byte[] byteObjects; }
BinaryData b = new BinaryData(); b.primitiveBytes = new byte[] {34,45,56,67,78,89,89,34,23,12,12,11,2}; b.byteObjects = new Byte[] {23,1,112,12,1,64,1,14,3,2}; jaxbContext.createMarshaller().marshal(b, System.out);
例5-11 出力
<?xml version="1.0" encoding="UTF-8"?> <binaryData> <primitiveBytes>Ii04Q05ZWSIXDAwLAg==</primitiveBytes> <byteObjects>23</byteObjects> <byteObjects>1</byteObjects> <byteObjects>112</byteObjects> <byteObjects>12</byteObjects> <byteObjects>1</byteObjects> <byteObjects>64</byteObjects> <byteObjects>1</byteObjects> <byteObjects>14</byteObjects> <byteObjects>3</byteObjects> <byteObjects>2</byteObjects> </binaryData>
Webサービス環境でEclipseLink MOXyを使用している場合は、一部のタイプのバイナリ・データは、XMLの要素または属性に直接書き込まれるのではなく、MTOM/XOP添付ファイルとして作成されることがあります。これは、大量のバイナリ・データの最適化として行われます。
次の表は、添付ファイルとして自動的に扱われるJavaタイプを、それに対応するMIMEタイプとともに示しています。
表5-1 添付ファイルとして扱われるJava属性
Javaタイプ | MIMEタイプ |
---|---|
java.awt.Image |
image/gif |
java.awt.Image |
image/jpeg |
javax.xml.transform.Source |
text/xml |
application/xml |
* |
javax.activation.DataHandler |
*/* |
注意: SOAP添付ファイルの基本の詳細は、『Java Architecture for XML Binding (JAXB) Specification』(http://jcp.org/en/jsr/detail?id=222)の「Appendix H: Enhanced Binary Data Handling」を参照してください。 |
次のJavaクラスには、単純なbyte[]
とjava.awt.Image
という2つのバイナリ・フィールドがあります。Webサービス環境では、Imageデータは添付ファイルとして自動的に作成されます。
例5-12 Javaクラスのサンプル
package example; import java.awt.Image; import javax.xml.bind.annotation.*; @XmlRootElement public class BinaryData { public byte[] bytes; public Image photo; }
Webサービス環境では、例5-12に示すオブジェクトのマーシャリングは例5-13のようになります(実際の外観は、アプリケーション・サーバーのAttachmentMarshaller
の実装に応じて異なります)。
例5-13 結果となるXML
<?xml version="1.0" encoding="UTF-8"?> <binaryData> <bytes>Ii04Q05ZWSIXDAwLAg==</bytes> <photo> <xop:Include href="cid:1" xmlns:xop="http://www.w3.org/2004/08/xop/include"/> </photo> </binaryData>
バイナリ・データがインラインのstring
としてXMLに強制的に書き込まれるようにする場合は、フィールドに@XmlInlineBinaryData
という注釈を付けることができます。
例5-14 @XmlInlineBinaryData注釈の使用
package example;
import java.awt.Image;
import javax.xml.bind.annotation.*;
@XmlRootElement
public class BinaryData {
public byte[] bytes;
@XmlInlineBinaryData
public Image photo;
}
これで、XML文書は次のようになります。
<?xml version="1.0" encoding="UTF-8"?> <binaryData> <bytes>Ii04Q05ZWSIXDAwLAg==</bytes> <photo>/9j/4AAQSkZJRgABAgAAAQABAAD/2wBDAAgGBgcGBQgHB ... Af/2Q==</photo> </binaryData>