この章の内容は次のとおりです。
EclipseLink JAXBの高レベルな使用方法には、既存のJavaクラスの使用(「静的MOXyの使用」)とEclipseLinkで生成したメモリー内のJavaクラスの使用(「動的MOXyの使用」)の2つがあります。
EclipseLink JAXBの最も一般的な使用方法は、Java注釈および/またはEclipseLink OXMメタデータによってXMLにマップされた既存のJavaクラスの使用です。これらのクラスは、ユーザーが自分で記述したものか、XJCコンパイラ・ツールでXMLスキーマから生成したものです。
このアプローチを使用して、XMLへの変換およびXMLからの変換において実際のドメイン・オブジェクトを処理します。例9-1に、JAXBで使用できる単純なJavaクラスを示します。
例9-1 Javaクラスのサンプル
import javax.xml.bind.annotation.XmlAttribute; import javax.xml.bind.annotation.XmlRootElement; @XmlRootElement public class Customer { @XmlAttribute private long id; private String name; // ... // get() and set() methods // ... }
注意: JAXBで静的クラスを使用する場合は、JAXBのデフォルトの動作を利用し、デフォルトとは異なる部分にのみ注釈を付けることができます。たとえば、JavaクラスのすべてのフィールドはデフォルトでXML要素にマップされるため、 |
例9-2に、静的JAXBを使用してオブジェクトをアンマーシャリング、変更およびマーシャリングする方法を示します。
例9-2 マーシャリングおよびアンマーシャリングの例
JAXBContext jaxbContext = JAXBContext.newInstance(Customer.class, Address.class); Customer customer = (Customer) jaxbContext.createUnmarshaller().unmarshal(instanceDoc); Address address = new Address(); address.setStreet("1001 Fleet St."); customer.setAddress(address); jaxbContext.createMarshaller().marshal(customer, System.out);
EclipseLinkの動的MOXyでは、JavaクラスパスにJavaクラス・ファイルをコンパイルしなくても、様々なメタデータ・ソースからJAXBContext
をブートストラップでき、既存のJAXB APIを使用してデータのマーシャリングおよびアンマーシャリングを行えます。これにより、必要に応じて以前に生成されたJavaソース・コードを更新および再コンパイルしなくてもメタデータを更新できます。
次の場合は、動的MOXyを検討してください。
EclipseLinkでXMLスキーマ(XSD)からマッピングを生成する場合。
具体的なJavaドメイン・クラスを扱わない場合。
実際のJavaクラス(Customer.class
やAddress.class
など)を使用するかわりに、動的MOXyでは単純なget(propertyName)
/set(propertyName, propertyValue)
APIを使用してデータを操作します。EclipseLinkは、(メモリー内に)各DynamicEntity
に関連付けられたDynamicType
を生成します。
注意:
|
例9-3に、動的JAXBを使用してオブジェクトをアンマーシャリング、変更およびマーシャリングする方法を示します。
例9-3 マーシャリングおよびアンマーシャリングの例
DynamicJAXBContext dynamicJAXBContext = DynamicJAXBContextFactory.createContextFromXSD(xsdInputStream, null, myClassLoader, null); DynamicEntity customer = (DynamicEntity) dynamicJAXBContext.createUnmarshaller().unmarshal(instanceDoc); String lastName = customer.get("lastName"); List orders = customer.get("orders"); ... DynamicEntity address = dynamicJAXBContext.newDynamicEntity("mynamespace.Address"); address.set("street", "1001 Fleet St."); customer.set("lastName", lastName + "Jr."); customer.set("address", address); dynamicJAXBContext.createMarshaller().marshal(customer, System.out);
注意: メタデータのXML名(複合型名、要素名、属性名)は、『Java Architecture for XML Binding (JAXB) 2.2 Specification』( 例9-3では、XML内の |
EclipseLink動的MOXyをJAXB実装として使用するには、jaxb.properties
ファイル内でEclipseLink DynamicJAXBContextFactory
を特定する必要があります。
jaxb.properties
という名前のテキスト・ファイルを作成し、新しいJAXBContexts
の構築に使用されるファクトリとして、DynamicJAXBContextFactory
を次のように指定します。
javax.xml.bind.context.factory=org.eclipse.persistence.jaxb.dynamic.DynamicJAXBContextFactory
JAXBContext
の作成で使用されるコンテキスト・パスにjaxb.properties
ファイルをコピーします。
標準のJAXBContext.newInstance(String contextPath)
APIを使用してDynamicJAXBContext
を作成します。
DynamicJAXBContext jaxbContext = (DynamicJAXBContext) JAXBContext.newInstance("org.example.mypackage");
アプリケーション・コードを変更する必要がないため、異なるJAXB実装間を容易に切り替えることができます。
JAXBContextで次のメソッドを使用して、DynamicJAXBContextsの新しいインスタンスを作成できます。
public static JAXBContext newInstance(String contextPath) throws JAXBException public static JAXBContext newInstance(String contextPath, ClassLoader classLoader) throws JAXBException public static JAXBContext newInstance(String contextPath, ClassLoader classLoader, Map<String,?> properties) throws JAXBException
contextPath: jaxb.properties
ファイルの場所。
classLoader: アプリケーションの現在のクラス・ローダー。新しいDynamicTypes
が生成される前に、クラスの存在を確認するために最初にクラスを検索する際に使用されます。
properties: 新しいDynamicJAXBContext
の作成に使用されるプロパティのマップ。このマップには、次の2つのキーのいずれか1つが含まれている必要があります。
複数の値を取れるorg.eclipse.persistence.jaxb.JAXBContextFactory.XML_SCHEMA_KEY
。
次のいずれかで、XMLスキーマ・ファイルを指すもの。
java.io.InputStream
org.w3c.dom.Node
javax.xml.transform.Source
複数の値を取れるorg.eclipse.persistence.jaxb.JAXBContextProperties.OXM_METADATA_SOURCE
。
次のいずれかで、OXMファイルを指すもの。
java.io.File
java.io.InputStream
java.io.Reader
java.net.URL
javax.xml.stream.XMLEventReader
javax.xml.stream.XMLStreamReader
javax.xml.transform.Source
org.w3c.dom.Node
org.xml.sax.InputSource
注意: これらのオプションの1つを使用する場合、OXMファイルの |
前述のセットからのオブジェクトのリスト。
注意: このオプションを使用する場合、OXMファイルの |
Map<String, Object>
。ここで、String
はパッケージ名で、Object
は前述の可能な値セットからOXMファイルへのポインタです。
EclipseLink MOXyを使用して、既存のXMLスキーマからDynamicJAXBContext
を作成できます。EclipseLinkはスキーマを解析し、各複合型に対してDynamicTypes
を生成します。これは、DynamicJAXBContextFactory
クラスの使用により実現されます。DynamicJAXBContext
は直接インスタンス化できません。ファクトリAPIを介して作成する必要があります。
次のものを使用して、XMLスキーマをDynamicJAXBContextFactory
に渡すことができます。
java.io.InputStream
org.w3c.dom.Node
javax.xml.transform.Source
注意: EclipseLink MOXyは、SunのXJC (XMLからJavaへのコンパイラ)APIを使用してスキーマをメモリー内表現に解析し、動的タイプとマッピングを生成します。XSDからブートストラップするときは、CLASSPATHに(JAXBリファレンス実装から) |
DynamicJAXBContextの作成に使用するAPIは次のとおりです。
例9-4 DynamicJAXBContextの作成
/** * Create a DynamicJAXBContext, using XML Schema as the metadata source. * * @param schemaStream * java.io.InputStream from which to read the XML Schema. * @param resolver * An org.xml.sax.EntityResolver, used to resolve schema imports. Can be null. * @param classLoader * The application's current class loader, which will be used to first lookup * classes to see if they exist before new DynamicTypes are generated. Can be * null, in which case Thread.currentThread().getContextClassLoader() will be used. * @param properties * Map of properties to use when creating a new DynamicJAXBContext. Can be null. * * @return * A new instance of DynamicJAXBContext. * * @throws JAXBException * if an error was encountered while creating the DynamicJAXBContext. */ public static DynamicJAXBContext createContextFromXSD(java.io.InputStream schemaStream, EntityResolver resolver, ClassLoader classLoader, Map<String, ?> properties) throws JAXBException public static DynamicJAXBContext createContextFromXSD(org.w3c.dom.Node schemaDOM, EntityResolver resolver, ClassLoader classLoader, Map<String, ?> properties) throws JAXBException public static DynamicJAXBContext createContextFromXSD(javax.xml.transform.Source schemaSource, EntityResolver resolver, ClassLoader classLoader, Map<String, ?> properties) throws JAXBException
注意: classLoaderパラメータは、アプリケーションの現在のクラス・ローダーです。新しい |
この例では、動的MOXyを使用して新しいオブジェクトを作成およびマーシャリングする方法を示します。
例9-5 XMLスキーマのサンプル
<?xml version="1.0" encoding="UTF-8"?> <xs:schema targetNamespace="example" xmlns:myns="example" xmlns:xs="http://www.w3.org/2001/XMLSchema" attributeFormDefault="qualified" elementFormDefault="qualified"> <xs:element name="customer" type="myns:customer"/> <xs:complexType name="customer"> <xs:sequence> <xs:element name="first-name" type="xs:string"/> <xs:element name="last-name" type="xs:string"/> <xs:element name="address" type="myns:address"/> </xs:sequence> </xs:complexType> <xs:complexType name="address"> <xs:sequence> <xs:element name="street" type="xs:string"/> <xs:element name="city" type="xs:string"/> <xs:element name="province" type="xs:string"/> <xs:element name="postal-code" type="xs:string"/> </xs:sequence> </xs:complexType> </xs:schema>
例9-6のコード・スニペットは次のとおりです。
DynamicJAXBContext
を作成するため、XMLスキーマをDynamicJAXBContextFactory
に渡します。
新しいDynamicEntities
を作成してプロパティを設定します。
JAXBMarshaller
を作成してJavaオブジェクトをXMLにマーシャリングします。
例9-6 アプリケーション・コードのサンプル
InputStream inputStream = myClassLoader.getSystemResourceAsStream("example/resources/xsd/customer.xsd"); DynamicJAXBContext dContext = DynamicJAXBContextFactory.createContextFromXSD(inputStream, null, myClassLoader, null); DynamicEntity newCustomer = dContext.newDynamicEntity("example.Customer"); newCustomer.set("firstName", "George"); newCustomer.set("lastName", "Jones"); DynamicEntity newAddress = dContext.newDynamicEntity("example.Address"); newAddress.set("street", "227 Main St."); newAddress.set("city", "Toronto"); newAddress.set("province", "Ontario"); newAddress.set("postalCode", "M5V1E6"); newCustomer.set("address", newAddress); dContext.createMarshaller().marshal(newCustomer, System.out);
ブートストラップに使用するXMLスキーマが別のスキーマをインポートする場合、org.xml.sax.EntityResolver
を構成してインポートされたスキーマの場所を解決する必要があります。これで、EntityResolver
をDynamicJAXBContextFactory
に渡すことができます。
例9-7では、各タイプは各自のスキーマで定義されます。
例9-7 XMLスキーマのサンプル
<!-- customer.xsd --> <?xml version="1.0" encoding="UTF-8"?> <xs:schema xmlns:myns="example" xmlns:add="addressNamespace" xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="example"> <xs:import namespace="addressNamespace" schemaLocation="address.xsd"/> <xs:element name="customer" type="myns:customer"/> <xs:complexType name="customer"> <xs:sequence> <xs:element name="first-name" type="xs:string"/> <xs:element name="last-name" type="xs:string"/> <xs:element name="address" type="add:address"/> </xs:sequence> </xs:complexType> </xs:schema>
EntityResolver
実装を指定してインポートされたスキーマの場所を解決する必要があります。
例9-8にEntityResolver
を示します。
例9-8 アプリケーション・コードのサンプル
class MyEntityResolver implements EntityResolver { public InputSource resolveEntity(String publicId, String systemId) throws SAXException, IOException { // Imported schemas are located in ext\appdata\xsd\ // Grab only the filename part from the full path String filename = new File(systemId).getName(); // Now prepend the correct path String correctedId = "ext/appdata/xsd/" + filename; InputSource is = new InputSource(ClassLoader.getSystemResourceAsStream(correctedId)); is.setSystemId(correctedId); return is; } }
次に示すように、DynamicJAXBContext
の作成時に、EntityResolver
を渡します。
InputStream inputStream = ClassLoader.getSystemResourceAsStream("com/foo/sales/xsd/customer.xsd"); DynamicJAXBContext dContext = DynamicJAXBContextFactory.createContextFromXSD(inputStream, new MyEntityResolver(), null, null);
別のスキーマをインポートする際に、次の例外が表示される場合があります。
Internal Exception: org.xml.sax.SAXParseException: schema_reference.4: Failed to read schema document '<imported-schema-name>', because 1) could not find the document; 2) the document could not be read; 3) the root element of the document is not <xsd:schema>.
XJCのスキーマの正確性チェック・オプションを次のコードで無効にします。
System.setProperty("com.sun.tools.xjc.api.impl.s2j.SchemaCompilerImpl.noCorrectnessCheck", "true")
または、コマンドラインから次を入力します。
-Dcom.sun.tools.xjc.api.impl.s2j.SchemaCompilerImpl.noCorrect
XSDからブートストラップするときに、オプションでXJCの外部バインディング・カスタマイズ・ファイル形式(.xjb
)を使用して生成されるマッピングをカスタマイズできます。次の例では、動的クラスのパッケージ名がオーバーライドされ、name属性はlast-name-comma-first-name
に名前変更されます。
例9-9 custom1.xjbファイル
<jxb:bindings version="1.0" xmlns:jxb="http://java.sun.com/xml/ns/jaxb" xmlns:xs="http://www.w3.org/2001/XMLSchema"> <jxb:bindings schemaLocation="employee.xsd" node="/xs:schema"> <!-- Customize the package name that is generated for each schema --> <jxb:schemaBindings> <jxb:package name="com.acme.internal"/> </jxb:schemaBindings> <!-- Rename the 'name' element to 'last-name-comma-first-name' --> <jxb:bindings node="//xs:complexType[@name='person']"> <jxb:bindings node=".//xs:element[@name='name']"> <jxb:property name="last-name-comma-first-name"/> </jxb:bindings> </jxb:bindings> </jxb:bindings> </jxb:bindings>
外部バインディング・カスタマイズ・ファイル形式の詳細は、http://download.oracle.com/docs/cd/E17802_01/webservices/webservices/docs/2.0/tutorial/doc/JAXBUsing4.html
を参照してください。
注意: 外部バインディング・カスタマイズ・ファイルを使用する場合、XMLスキーマを指すSourceオブジェクトを使用する必要があります。Sourcesは |
例9-10に、XSDからのブートストラップと、2つの別個の.xjb
ファイルを使用したマッピング生成のカスタマイズを示します。
例9-10 ブートストラップの例
ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); String xsd = "example/resources/xsd/employee.xsd"; String xjb1 = "example/resources/xsd/custom1.xjb"; String xjb2 = "example/resources/xsd/custom2.xjb"; InputStream xsdStream = classLoader.getSystemResourceAsStream(xsd); Source xsdSource = new StreamSource(xsdStream); // Set SYSTEM_ID to the filename part of the XSD xsdSource.setSystemId("employee.xsd"); InputStream xjbStream = classLoader.getResourceAsStream(xjb1); Source xjbSource = new StreamSource(xjbStream); // Set SYSTEM_ID to be the same as the XSD xjbSource.setSystemId(xsdSource.getSystemId()); InputStream xjbStream2 = classLoader.getResourceAsStream(xjb2); Source xjbSource2 = new StreamSource(xjbStream2); // Set SYSTEM_ID to be the same as the XSD xjbSource2.setSystemId(xsdSource.getSystemId()); ArrayList<Source> xjbFiles = new ArrayList<Source>(2); xjbFiles.add(xjbSource); xjbFiles.add(xjbSource2); // Put XSD and XJBs into Properties Map<String, Object> properties = new HashMap<String, Object>(); properties.put(DynamicJAXBContextFactory.XML_SCHEMA_KEY, xsdSource); properties.put(DynamicJAXBContextFactory.EXTERNAL_BINDINGS_KEY, xjbFiles); // Create Context DynamicJAXBContext jaxbContext = (DynamicJAXBContext) JAXBContext.newInstance("example", classLoader, properties);
EXTERNAL_BINDINGS_KEY
の値は、単一のSource
またはList<Source>
のいずれかで、外部バインディング・カスタマイズ・ファイルを指しています。
XMLへのDynamicEntities
のマッピングをさらに制御するには、かわりにEclipseLink OXMメタデータ・ファイルからブートストラップできます。このアプローチを使用すると、EclipseLinkの堅牢なマッピング・フレームワークを活用でき、XMLの複合型をそれぞれ対応するJavaにマップする方法をカスタマイズできます。次のDynamicJAXBContextFactory
のAPIを使用して、OXMファイルからブートストラップできます。
例9-11 DynamicJAXBContextの作成
/** * Create a <tt>DynamicJAXBContext</tt>, using an EclipseLink OXM file as the metadata source. * * @param classLoader * The application's current class loader, which will be used to first lookup classes to * see if they exist before new <tt>DynamicTypes</tt> are generated. Can be <tt>null</tt>, * in which case <tt>Thread.currentThread().getContextClassLoader()</tt> will be used. * @param properties * Map of properties to use when creating a new <tt>DynamicJAXBContext</tt>. This map must * contain a key of JAXBContext.ECLIPSELINK_OXM_XML_KEY, with a value of... (see below) * * @return * A new instance of <tt>DynamicJAXBContext</tt>. * * @throws JAXBException * if an error was encountered while creating the <tt>DynamicJAXBContext</tt>. */ public static DynamicJAXBContext createContextFromOXM(ClassLoader classLoader, Map<String, ?> properties) throws JAXBException {
実際のOXMファイルへのリンクは、特殊キーJAXBContextProperties.OXM_METADATA_SOURCE
を使用し、properties
パラメータを介して渡されます。このキーの値は、次のいずれかの形式によるOXMメタデータ・ファイルへのハンドルとなります。
java.io.File
java.io.InputStream
java.io.Reader
java.net.URL
javax.xml.stream.XMLEventReader
javax.xml.stream.XMLStreamReader
javax.xml.transform.Source
org.w3c.dom.Node
org.xml.sax.InputSource
複数のOXMファイルからブートストラップするために、前述の入力のLists
も受け入れられます。詳細は、DynamicJAXBContextFactory
クラスのドキュメントを参照してください。
次の例では、ClassLoader
からリソースとしてOXMファイルを取得し、結果のInputStream
を使用してDynamicJAXBContext
をブートストラップします。
InputStream iStream = myClassLoader.getResourceAsStream("example/resources/eclipselink/eclipselink-oxm.xml"); Map<String, Object> properties = new HashMap<String, Object>(); properties.put(JAXBContextProperties.OXM_METADATA_SOURCE, iStream); DynamicJAXBContext jaxbContext = DynamicJAXBContextFactory.createContextFromOXM(myClassLoader, properties);
例9-12のOXMのサンプルを使用して、動的MOXyを使用して新しいオブジェクトを作成およびマーシャリングする方法を示します。type
属性をメモしておくことが大切です。基礎となるJavaクラスがないため、各プロパティのタイプを明示的に指定する必要があるからです。
例9-12 XMLスキーマのサンプル
<?xml version="1.0" encoding="US-ASCII"?> <xml-bindings xmlns="http://www.eclipse.org/eclipselink/xsds/persistence/oxm" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xs="http://www.w3.org/2001/XMLSchema" package-name="example"> <java-types> <java-type name="Customer"> <xml-root-element name="customer"/> <java-attributes> <xml-element java-attribute="firstName" type="java.lang.String"/> <xml-element java-attribute="lastName" type="java.lang.String"/> <xml-element java-attribute="address" type="example.Address"/> </java-attributes> </java-type> <java-type name="Address"> <java-attributes> <xml-element java-attribute="street" type="java.lang.String"/> <xml-element java-attribute="city" type="java.lang.String"/> <xml-element java-attribute="province" type="java.lang.String"/> <xml-element java-attribute="postalCode" type="java.lang.String"/> </java-attributes> </java-type> </java-types> </xml-bindings>
例9-13のコードは、次のことを示しています。
DynamicJAXBContext
を作成するため、OXMファイルをDynamicJAXBContextFactory
に渡します。
新しいDynamicEntities
を作成してプロパティを設定します。
JAXBMarshaller
を作成してJavaオブジェクトをXMLにマーシャリングします。
例9-13 アプリケーション・コードのサンプル
InputStream iStream = myClassLoader.getResourceAsStream("example/resources/eclipselink/eclipselink-oxm.xml"); Map<String, Object> properties = new HashMap<String, Object>(); properties.put(JAXBContextProperties.OXM_METADATA_SOURCE, iStream); DynamicJAXBContext jaxbContext = DynamicJAXBContextFactory.createContextFromOXM(myClassLoader, properties); DynamicEntity newCustomer = dContext.newDynamicEntity("example.Customer"); newCustomer.set("firstName", "George"); newCustomer.set("lastName", "Jones"); DynamicEntity newAddress = dContext.newDynamicEntity("example.Address"); newAddress.set("street", "227 Main St."); newAddress.set("city", "Toronto"); newAddress.set("province", "Ontario"); newAddress.set("postalCode", "M5V1E6"); newCustomer.set("address", newAddress); dContext.createMarshaller().marshal(newCustomer, System.out