Jump to: navigation, search

EclipseLink/UserGuide/MOXy/Runtime/Bootstrapping/From Schema

< EclipseLink‎ | UserGuide‎ | MOXy‎ | Runtime‎ | Bootstrapping
Revision as of 10:50, 5 April 2011 by Rick.sapir.oracle.com (Talk | contribs) (Customizing Generated Mappings with EclipseLink Metadata)

EclipseLink MOXy

Mailing ListForumsIRCmattermost
OpenHelp WantedBug Day
Browse Source

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.

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.

You can pass the XML Schema to DynamicJAXBContextFactory by using:

  • java.io.InputStream
  • org.w3c.dom.Node
  • javax.xml.transform.Source

The following example demonstrates these methods:

 * 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

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.


This example shows how to create and marshall a new object using Dynamic MOXy.

Sample XML Schema:

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema targetNamespace="mynamespace" xmlns:myns="mynamespace" xmlns:xs="http://www.w3.org/2001/XMLSchema"
    attributeFormDefault="qualified" elementFormDefault="qualified">
    <xs:element name="customer" type="myns:customer"/>
    <xs:complexType name="customer">
            <xs:element name="first-name" type="xs:string"/>
            <xs:element name="last-name" type="xs:string"/>
            <xs:element name="address" type="myns:address"/>
    <xs:complexType name="address">
            <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"/>

The following code:

  • Passes the XML Schema to DynamicJAXBContextFactory to create a DynamicJAXBContext
  • Creates new DynamicEntities and setting their properties
  • Creates a JAXBMarshaller and marshalling the Java objects to XML
InputStream inputStream = myClassLoader.getSystemResourceAsStream("mynamespace/resources/xsd/customer.xsd");
DynamicJAXBContext dContext = DynamicJAXBContextFactory.createContextFromXSD(inputStream, null, myClassLoader, null);
DynamicEntity newCustomer = dContext.newDynamicEntity("mynamespace.Customer");
newCustomer.set("firstName", "George");
newCustomer.set("lastName", "Jones");
DynamicEntity newAddress = dContext.newDynamicEntity("mynamespace.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);

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.

In this example, each type is defined in its own schema:

<!-- customer.xsd -->
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:myns="myNamespace" xmlns:add="addressNamespace"
   xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="myNamespace">
    <xs:import namespace="addressNamespace" schemaLocation="address.xsd"/>
    <xs:element name="customer" type="myns:customer"/>
    <xs:complexType name="customer">
            <xs:element name="first-name" type="xs:string"/>
            <xs:element name="last-name" type="xs:string"/>
            <xs:element name="address" type="add:address"/>

You must supply an EntityResolver implementation to resolve the location of the imported schema.

This sample illustrates the EntityResolver:

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));
      return is;

When you create the DynamicJAXBContext, pass the EntityResolver to it, as shown in this example:

InputStream inputStream = ClassLoader.getSystemResourceAsStream("com/foo/sales/xsd/customer.xsd");
DynamicJAXBContext dContext = DynamicJAXBContextFactory.createContextFromXSD(inputStream, new MyEntityResolver(), null, null);

NOTE: If you encounter the following exception when importing another shema:

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>.

You should disable XJC's schema correctness check option, either in code:

<soucre lang="java"> System.setProperty("com.sun.tools.xjc.api.impl.s2j.SchemaCompilerImpl.noCorrectnessCheck", "true") </source>

or from the command line:


Customizing Generated Mappings with EclipseLink Metadata

When bootstrapping from an XML Schema (or an EclipseLink project), you can customize the mappings that EclipseLink generates by using your own EclipseLink OXM Bindings file. This file contains your additional mappings and allows you to combine OXM 'and' XSD bootstrapping. This means that you can use EclipseLink mappings to customize an existing XML schema.


This example shows how to override mappings defined in the schema.


Taking our Customer / Address example, lets say that we wanted our XML to contain Addresses in US format, as opposed to the Canadian format that is defined in our schema.

First, you must create an eclipselink-oxm.xml file that contains the mapping overrides. In this example, we modify the XPaths for province and postalCode:

<?xml version="1.0" encoding="US-ASCII"?>
<xml-bindings xmlns="http://www.eclipse.org/eclipselink/xsds/persistence/oxm" package-name="mynamespace">
        <java-type name="Address">
                <xml-element java-attribute="province" xml-path="state/text()"/>
                <xml-element java-attribute="postalCode" xml-path="zip-code/text()"/>

When you create a DynamicJAXBContext', use the properties argument to pass this binding file to the DynamicJAXBContextFactory (in addition to the Schema):

// Load Schema
InputStream xsdStream = myClassLoader.getSystemResourceAsStream("mynamespace/resources/xsd/customer.xsd");
// Load OXM with customizations, put into Properties
InputStream oxmStream = myClassLoader.getSystemResourceAsStream("mynamespace/resources/eclipselink/eclipselink-oxm.xml");
Map<String, Object> props = new HashMap<String, Object>();
props.put(JAXBContextFactory.ECLIPSELINK_OXM_XML_KEY, oxmStream);
// Create Context
DynamicJAXBContext dContext = DynamicJAXBContextFactory.createContextFromXSD(inputStream, null, myClassLoader, props);

Version: 2.2.0 - DRAFT
Other versions...