Jump to: navigation, search

Difference between revisions of "EclipseLink/UserGuide/MOXy/Runtime/Bootstrapping/From Schema"

m (Replacing page with 'See http://www.eclipse.org/eclipselink/documentation/2.4/moxy/dynamic_jaxb003.htm')
 
(4 intermediate revisions by one other user not shown)
Line 1: Line 1:
{{EclipseLink_UserGuide
+
See http://www.eclipse.org/eclipselink/documentation/2.4/moxy/dynamic_jaxb003.htm
|info=y
+
|eclipselink=y
+
|eclipselinktype=MOXy
+
|api=y
+
|apis= * [http://www.eclipse.org/eclipselink/api/latest/org/eclipse/persistence/jaxb/dynamic/DynamicJAXBContextFactory.html DynamicJAXBContextFactory]
+
|toc=y
+
}}
+
 
+
= Bootstrapping from XML Schema (XSD) =
+
 
+
With EclipseLink MOXy, you can provide an existing XML schema from which to create a '''DynamicJAXBContext'''. EclipseLink will parse the schema and generate '''DynamicTypes''' for each complex type. This is achieved by use of the '''DynamicJAXBContextFactory''' class. A '''DynamicJAXBContext''' cannot be instantiated directly; it must be created through the factory API.
+
 
+
You can pass the XML Schema to '''DynamicJAXBContextFactory''' by using:
+
 
+
*'''java.io.InputStream'''
+
*'''org.w3c.dom.Node'''
+
*'''javax.xml.transform.Source'''
+
 
+
 
+
{{tip||EclipseLink MOXy uses Sun's XJC (XML-to-Java Compiler) APIs to parse the schema into an in-memory representation and  generate dynamic types and mappings. When bootstrapping from XSD, you will need to include '''jaxb-xjc.jar''' (from the JAXB reference implementation) on your '''CLASSPATH'''.}}
+
 
+
 
+
The APIs used to create a '''DynamicJAXBContext''' are as follows:
+
 
+
<source lang="java">
+
/**
+
* 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
+
</source>
+
 
+
{{tip||The '''classLoader''' parameter is your application's current class loader, and will be used to first lookup classes to see if they exist before new '''DynamicTypes''' are generated. The user may pass in null for this parameter, and '''Thread.currentThread().getContextClassLoader()''' will be used instead.}}
+
 
+
 
+
=== Example ===
+
 
+
This example shows how to create and marshall a new object using Dynamic MOXy.
+
 
+
Sample XML Schema:
+
<source lang="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>
+
</source>
+
 
+
The following code snippet:
+
 
+
* Passes the XML Schema to '''DynamicJAXBContextFactory''' to create a '''DynamicJAXBContext'''
+
* Creates new '''DynamicEntities''' and sets their properties
+
* Creates a '''JAXBMarshaller''' and marshals the Java objects to XML
+
 
+
<source lang="java">
+
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);
+
</source>
+
 
+
 
+
== Importing other Schemas / EntityResolvers  ==
+
 
+
If the XML schema that you use to bootstrap imports other schemas, you must configure an '''org.xml.sax.EntityResolver '''to resolve the locations of the imported schemas. You can then pass the '''EntityResolver''' to the '''DynamicJAXBContextFactory'''.<br>
+
 
+
In this example, each type is defined in its own schema:
+
 
+
<source lang="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>
+
</source>
+
 
+
You must supply an '''EntityResolver''' implementation to resolve the location of the imported schema.
+
 
+
This sample illustrates the '''EntityResolver''':
+
 
+
<source lang="java">
+
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;
+
  }
+
+
}
+
</source>
+
 
+
When you create the '''DynamicJAXBContext''', pass the '''EntityResolver''' to it, as shown in this example:
+
 
+
<source lang="java">
+
InputStream inputStream = ClassLoader.getSystemResourceAsStream("com/foo/sales/xsd/customer.xsd");
+
DynamicJAXBContext dContext = DynamicJAXBContextFactory.createContextFromXSD(inputStream, new MyEntityResolver(), null, null);
+
</source>
+
 
+
'''NOTE''': If you encounter the following exception when importing another shema:
+
 
+
<tt>
+
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>.
+
</tt>
+
 
+
You should disable XJC's schema correctness check option, either in code:
+
 
+
<source lang="java">
+
System.setProperty("com.sun.tools.xjc.api.impl.s2j.SchemaCompilerImpl.noCorrectnessCheck", "true")
+
</source>
+
 
+
or from the command line:
+
 
+
<source lang="text">
+
-Dcom.sun.tools.xjc.api.impl.s2j.SchemaCompilerImpl.noCorrect
+
</source>
+
 
+
 
+
== Customizing Generated Mappings with XJC External Binding Customization Files ==
+
 
+
When bootstrapping from an XSD, you have the option to customize the mappings that will be generated through the use of XJC's External Binding Customization file format ('''.xjb''').  In the example below, the package name of the dynamic classes has been overridden, and the '''name''' attribute has been renamed to '''last-name-comma-first-name'''.
+
 
+
custom1.xjb:
+
<source lang="java">
+
<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>
+
</source></div>
+
 
+
For complete information on the External Binding Customization file format, please see [http://download.oracle.com/docs/cd/E17802_01/webservices/webservices/docs/2.0/tutorial/doc/JAXBUsing4.html http://download.oracle.com/docs/cd/E17802_01/webservices/webservices/docs/2.0/tutorial/doc/JAXBUsing4.html].
+
 
+
If you wish to use External Binding Customization files, you will need to use '''Source''' objects to point to your XML Schema.  '''Sources''' are used to load the '''.xjb''' files as well, and they must all have the same System ID set.  Below is an example of bootstrapping from an XSD, and customizing the mapping generation using two separate '''.xjb''' files. 
+
 
+
<source lang="java">
+
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
+
String xsd = "mynamespace/resources/xsd/employee.xsd";
+
String xjb1 = "mynamespace/resources/xsd/custom1.xjb";
+
String xjb2 = "mynamespace/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("mynamespace", classLoader, properties);
+
</source>
+
 
+
The value of '''EXTERNAL_BINDINGS_KEY''' can be either a single '''Source''' or a '''List&lt;Source&gt;''', pointing to your External Binding Customization file(s).
+

Latest revision as of 10:36, 8 November 2012

See http://www.eclipse.org/eclipselink/documentation/2.4/moxy/dynamic_jaxb003.htm