Skip to main content

Notice: this Wiki will be going read only early in 2024 and edits will no longer be possible. Please see: https://gitlab.eclipse.org/eclipsefdn/helpdesk/-/wikis/Wiki-shutdown-plan for the plan.

Jump to: navigation, search

Difference between revisions of "EclipseLink/UserGuide/MOXy/Runtime/Externalized Metadata (OXM)"

m (Replacing page with ''''Warning This page is obsolete. Please see ''[http://www.eclipse.org/eclipselink/documentation/ Developing JAXB Applications Using EclipseLink M...')
 
(7 intermediate revisions by 2 users not shown)
Line 1: Line 1:
{{EclipseLink_UserGuide
+
'''[[Image:Elug_draft_icon.png|Warning]] This page is obsolete. Please see ''[http://www.eclipse.org/eclipselink/documentation/ Developing JAXB Applications Using EclipseLink MOXy]'' for current information.'''
|eclipselink=y
+
|eclipselinktype=MOXy
+
|info=y
+
|api=n
+
|toc=y
+
}}
+
 
+
= Externalized Metadata (OXM) =
+
 
+
In addition to standard JAXB annotations, EclipseLink offers another way of expressing your metadata - the EclipseLink MOXy Externalized Metadata file (OXM).  Not only can an OXM file separate your mapping information from your actual Java class, it can also be used for more advanced metadata tasks such as:
+
 
+
* Augmenting or overriding existing annotations with additional mapping information
+
* Specifying all mappings information externally, with no annotations in Java at all
+
* Defining your mappings across multiple OXM files
+
* Specifying "virtual" mappings that do not correspond to concrete Java fields
+
* and more..
+
 
+
This page will describe the OXM file format and demonstrate some basic use cases.
+
 
+
 
+
== OXM Format ==
+
 
+
An EclipseLink OXM file is an XML file that specifies Java type information, mapping information, context-wide properties - everything you need to define your JAXB system.  An example OXM file is shown below:
+
 
+
<div style="width:850px">
+
<source lang="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" xml-accessor-type="PUBLIC_MEMBER" xml-accessor-order="ALPHABETICAL"
+
    xml-mapping-metadata-complete="false" xml-name-transformer="example.NameGenerator"
+
    supported-versions="2.3" >
+
 
+
    <xml-schema element-form-default="UNQUALIFIED"
+
        attribute-form-default="UNQUALIFIED" namespace="example">
+
        <xml-ns prefix="ns1" namespace-uri="example" />
+
        <xml-ns prefix="xsd" namespace-uri="http://www.w3.org/2001/XMLSchema" />
+
        <xml-ns prefix="xsi" namespace-uri="http://www.w3.org/2001/XMLSchema-instance" />
+
    </xml-schema>
+
 
+
    <java-types>
+
        <java-type name="Employee">
+
            <java-attributes>
+
                <xml-attribute java-attribute="empId" xml-path="@id" />
+
                <xml-element java-attribute="empName" name="name" />
+
                <xml-element java-attribute="salary" />
+
                <xml-element java-attribute="type" type="EmployeeType" />
+
            </java-attributes>
+
        </java-type>
+
        <java-type name="Company">
+
            <xml-root-element name="company" />
+
            <xml-attribute java-attribute="empId" xml-path="@id" />
+
            <xml-element java-attribute="empName" name="name" />
+
            <java-attributes>
+
                <xml-element java-attribute="employees" name="employee"
+
                    type="example.Employee" container-type="java.util.ArrayList" />
+
            </java-attributes>
+
        </java-type>
+
    </java-types>
+
 
+
    <xml-registries>
+
        <xml-registry name="example.ObjectFactory">
+
            <xml-element-decl java-method="createEmpleado"
+
                name="empleado" type="example.Employee" />
+
            <xml-element-decl java-method="createCorporacion"
+
                name="corporacion" type="example.Company" />
+
        </xml-registry>
+
    </xml-registries>
+
 
+
    <xml-enums>
+
        <xml-enum java-enum="EmployeeType" value="java.lang.String">
+
            <xml-enum-value java-enum-value="CONTRACT">CONTRACT</xml-enum-value>
+
            <xml-enum-value java-enum-value="PART_TIME">PART_TIME</xml-enum-value>
+
            <xml-enum-value java-enum-value="FULL_TIME">FULL_TIME</xml-enum-value>
+
        </xml-enum>
+
    </xml-enums>
+
 
+
</xml-bindings>
+
</source>
+
</div>
+
 
+
'''<xml-bindings>'''
+
* The root of the OXM file. This is also where you can define top-level properties for your JAXB system, such as the '''package-name''' of your classes, specify a default '''xml-accessor-type''', etc.
+
 
+
'''<xml-schema>'''
+
* Defines properties related to the schema-level of your JAXB system.  Corresponds to the JAXB '''@XmlSchema''' annotation.
+
 
+
'''<java-types>'''
+
* Defines mapping information for each of your Java classes.
+
 
+
'''<xml-enums>'''
+
* Defines Java enumerations that can be used with your Java types.
+
 
+
'''<xml-registries>'''
+
* Defines an '''ObjectFactory''' for use in your JAXB system.
+
 
+
 
+
== Bootstrapping with OXM ==
+
 
+
When instantiating a '''JAXBContext''', links to EclipseLink OXM files are passed in via the '''properties''' parameter, using a special key, '''JAXBContextFactory.ECLIPSELINK_OXM_XML_KEY'''. The value of this key will be a handle to the OXM metadata file, in the form of one of the following:
+
 
+
<tt>
+
* 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
+
</tt>
+
 
+
To bootstrap from multiple OXM files:
+
* '''Maps''' of the above inputs are supported, keyed on Java package name.
+
* '''Lists''' of the above inputs are acceptable as well (OXM files must have '''package''' attribute).
+
 
+
 
+
== Using OXM with Annotations ==
+
 
+
Arguably the most typical use of an EclipseLink OXM file is in conjunction with JAXB annotations.  You may have situation where you are not permitted to edit your Java domain classes, but want to add additional mapping functionality.  Or, you may wish to avoid importing any EclipseLink code into your domain model, but still take advantage of MOXy's advanced mapping features.  When EclipseLink OXM metadata is provided during context creation, its mapping information will be combined with any JAXB annotation information.
+
 
+
For example, consider the following simple JAXB domain class and its default JAXB XML representation:
+
 
+
<div style="width:700px">
+
<source lang="java">
+
package example;
+
+
import javax.xml.bind.annotation.*;
+
+
@XmlRootElement
+
@XmlAccessorType(XmlAccessType.FIELD)
+
public class Customer {
+
  @XmlAttribute
+
  private Integer custId;
+
  private String name;
+
  private Double salary;
+
  private byte[] picture;
+
  ...
+
}
+
</source>
+
</div>
+
 
+
<div style="width:700px">
+
<source lang="xml">
+
<?xml version="1.0" encoding="UTF-8"?>
+
<customer custId="15">
+
  <name>Bob Dobbs</name>
+
  <salary>51727.61</salary>
+
  <picture>AgQIECBA</picture>
+
</customer>
+
</source>
+
</div>
+
 
+
Now, let's assume that we would like to make the following mapping changes:
+
 
+
* Change the XML element name of '''custId''' to '''customer-id'''
+
* Change the root element name of the class to '''customer-info'''
+
* Write the '''picture''' to XML as '''picture-hex''' in hex binary format, and use our own custom converter, '''MyHexConverter'''.
+
 
+
 
+
We can specify these three customizations in OXM as follows:
+
 
+
<div style="width:750px">
+
<source lang="xml">
+
<?xml version="1.0" encoding="US-ASCII"?>
+
<xml-bindings xmlns="http://www.eclipse.org/eclipselink/xsds/persistence/oxm"
+
    package-name="example">
+
 
+
    <java-types>
+
        <java-type name="Customer">
+
            <xml-root-element name="customer-info" />
+
            <java-attributes>
+
                <xml-attribute java-attribute="custId" name="customer-id" />
+
                <xml-element java-attribute="picture" name="picture-hex">
+
                    <xml-schema-type name="hexBinary" />
+
                    <xml-java-type-adapter
+
                        value="example.adapters.MyHexConverter" />
+
                </xml-element>
+
            </java-attributes>
+
        </java-type>
+
    </java-types>
+
 
+
</xml-bindings>
+
</source>
+
</div>
+
 
+
 
+
The OXM file must then be provided during JAXB context creation.  OXM information is passed in via the '''properties''' argument:
+
 
+
<div style="width:750px">
+
<source lang="java">
+
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
+
InputStream iStream = classLoader.getResourceAsStream("metadata/eclipselink-oxm.xml");
+
 
+
Map<String, Object> properties = new HashMap<String, Object>();
+
properties.put(JAXBContextFactory.ECLIPSELINK_OXM_XML_KEY, iStream);
+
 
+
JAXBContext ctx = JAXBContext.newInstance(new Class[]{ Customer.class }, properties);
+
</source>
+
</div>
+
 
+
 
+
With an OXM provided, the following will happen during JAXB context creation:
+
 
+
# '''Customer.class''' will be analyzed and JAXB mappings will be generated as usual.
+
# The OXM file is then analyzed, and the original JAXB mappings will be merged with the information in the OXM file.
+
 
+
 
+
After applying the OXM metadata, we have the desired XML representation:
+
 
+
<div style="width:700px">
+
<source lang="xml">
+
<?xml version="1.0" encoding="UTF-8"?>
+
<customer-info customer-id="15">
+
  <name>Bob Dobbs</name>
+
  <salary>51727.61</salary>
+
  <picture-hex>020408102040</picture-hex>
+
</customer-info>
+
</source>
+
</div>
+
 
+
 
+
== Using Multiple OXM Files ==
+
 
+
Starting with version '''2.3''', EclipseLink allows you to use mapping information from multiple OXM files.  Using this approach, you can split your metadata up as you wish.
+
 
+
Using a '''List''' of OXM files:
+
<div style="width:750px">
+
<source lang="java">
+
...
+
+
FileReader file1 = new FileReader("base-bindings.xml");
+
FileReader file2 = new FileReader("override-bindings.xml");
+
+
List<Object> fileList = new ArrayList<Object>();
+
fileList.add(file1);
+
fileList.add(file2);
+
+
Map<String, Object> properties = new HashMap<String, Object>();
+
properties.put(JAXBContextFactory.ECLIPSELINK_OXM_XML_KEY, fileList);
+
+
JAXBContext ctx = JAXBContext.newInstance(new Class[]{ Customer.class }, properties);
+
+
...
+
</source>
+
</div>
+
 
+
<div style="width:750px">
+
{{tip||Note that when using a '''List''' of OXM files, each file ''must'' define the '''package''' attribute of '''<xml-bindings>''', to indicate the package for each OXM file.}}
+
</div>
+
 
+
 
+
Using a '''Map''' for multiple packages:
+
<div style="width:750px">
+
<source lang="java">
+
...
+
 
+
FileReader fooFile1 = new FileReader("foo/base-bindings.xml");
+
FileReader fooFile2 = new FileReader("foo/override-bindings.xml");
+
 
+
List<Object> fooFileList = new ArrayList<Object>();
+
fooFileList.add(fooFile1);
+
fooFileList.add(fooFile2);
+
 
+
FileReader barFile1 = new FileReader("bar/base-bindings.xml");
+
FileReader barFile2 = new FileReader("bar/override-bindings.xml");
+
 
+
List<Object> barFileList = new ArrayList<Object>();
+
barFileList.add(barFile1);
+
barFileList.add(barFile2);
+
 
+
Map<String, List> metadataMap = new HashMap<String, List>();
+
metadataMap.put("foo", fooFileList);
+
metadataMap.put("bar", barFileList);
+
 
+
properties.put(JAXBContextFactory.ECLIPSELINK_OXM_XML_KEY, metadataMap);
+
 
+
JAXBContext ctx = JAXBContext.newInstance(new Class[]{ Customer.class }, properties);
+
 
+
...
+
</source>
+
</div>
+
 
+
 
+
== Override Rules ==
+
 
+
When multiple sources of metadata are encountered for the same package, a unified set of mappings will be created by merging the complete set of metadata.  First, the annotations from the Java class will be processed, and then any OXM information will be applied. The order that OXM files are specified is relevant; values in subsequent OXM documents will override the ones defined in in previous ones.
+
 
+
The following rules will be used for merging:
+
 
+
* '''xml-schema'''
+
** For values such as namespace, elementform, attributeform, the later file will override.
+
** The list of namespace declarations from XmlNs will be merged into a single list containing all entries from all files.
+
*** In the case of conflicting entries (the same prefix bound to multiple namespaces), the last file will override the declarations from previous files.
+
 
+
* '''java-types'''
+
** The merged bindings will contain all unique java-type entries from all bindings files.
+
** If the same java-type occurs in multiple files, any values that are set in the later file will override values from the previous file.
+
** Properties on each java-type will be merged into a unified list. If the same property is referenced in multiple files, this will be an exception case.
+
** Class-level XmlJavaTypeAdpater entries will be overridden if specified in a later bindings file.
+
** Class-level XmlSchemaTypes will create a merged list. If an entry for the same type is listed in multiple bindings files at this level, the last file's entry will override all previous ones.
+
 
+
* '''xml-enums'''
+
** The merged bindings will contain all unique xml-enum entries from all bindings files.
+
** For any duplicated java-enums, a merged list of XmlEnumValues will be created. If an entry for the same enum facet occurs in multiple files, the last file will override the value for that facet.
+
 
+
* '''xml-java-type-adapters'''
+
** Package-level Java type adapters will be merged into a single list. In the case that an adapter is specified for the same class in multiple files, the last file's entry will win.
+
 
+
* '''xml-registries'''
+
** Each unique XmlRegistry entry will be added to the final merged list of XmlRegistries.
+
** For any duplicated XmlRegistry entries, a merged list of XmlElementDecls will be created.
+
*** In the case that an XmlElementDecl for the same XmlRegistry class appears in multiple bindings files, that XmlElementDecl will be replaced with the one from the later bindings.
+
 
+
* '''xml-schema-types'''
+
** XmlSchemaType entries will be merged into a unified list.
+
** In the case that an XmlSchemaType entry for the same java-type appears at the package level in multiple bindings files, the merged bindings will only contain the entry for the last one specified.
+
 
+
 
+
== Metadata Complete ==
+
 
+
If you would like to store all of your metadata in OXM files and ignore any JAXB annotations in your Java class, you can include the '''xml-mapping-metadata-complete''' attribute in the '''&lt;xml-bindings&gt;''' element of your OXM file.  Default JAXB mappings will still be generated (the same as if you were using a completely un-annotated class with JAXB), and then any mapping data defined in the OXM will be applied.
+
 
+
This could be used, for example, to map the same Java class to two completely different XML representations: the annotations on the actual Java class would define the first XML representation, and then a second XML representation could be defined in an OXM file with '''xml-mapping-metadata-complete="true"'''.  This would essentially give you a "blank canvas" to remap your Java class.
+
 
+
If you would like to ignore the default mappings that JAXB generates, you can specify '''xml-accessor-type="NONE"''' in your '''&lt;java-type&gt;''' element.  Using this approach, only mappings that are explicitly defined in OXM will be applied.
+
 
+
Using the '''Customer''' example from above, the following examples demonstrate the XML representations that will be generated when using '''xml-mapping-metadata-complete''':
+
 
+
{|border="0" cellpadding="5"
+
|-
+
|'''Customer.java'''
+
 
+
<div style="width:100%">
+
<source lang="java">
+
package example;
+
+
import javax.xml.bind.annotation.*;
+
+
@XmlRootElement
+
@XmlAccessorType(XmlAccessType.FIELD)
+
public class Customer {
+
  @XmlAttribute
+
  private Integer custId;
+
  private String name;
+
  private Double salary;
+
  private byte[] picture;
+
  ...
+
}
+
</source>
+
</div>
+
|-valign="top"
+
|width="50%"|'''OXM Metadata'''
+
 
+
<source lang="xml">
+
<?xml version="1.0" encoding="US-ASCII"?>
+
<xml-bindings xmlns="http://www.eclipse.org/eclipselink/xsds/persistence/oxm"
+
    package-name="example" xml-mapping-metadata-complete="true">
+
 
+
    <java-types>
+
        <java-type name="Customer">
+
            <xml-root-element />
+
            <java-attributes>
+
                <xml-attribute java-attribute="name" name="customer-name" />
+
            </java-attributes>
+
        </java-type>
+
    </java-types>
+
 
+
</xml-bindings>
+
</source>
+
|width="50%"|'''XML Representation'''
+
 
+
<div style="height:100%">
+
<source lang="xml">
+
<?xml version="1.0" encoding="UTF-8"?>
+
<customer>
+
  <custId>15</custId>
+
  <customer-name>Bob Dobbs</customer-name>
+
  <picture>AgQIECBA</picture>
+
  <salary>51727.61</salary>
+
</customer>
+
</source>
+
</div>
+
|}
+
 
+
* Default JAXB mapping is generated for '''custId''' (note that '''custId''' is now an XML element, as if there were no annotation on the Java field)
+
* The '''name''' element has been renamed to '''customer-name'''
+
* Default JAXB mappings are generated for '''picture''' and '''salary'''
+
 
+
 
+
{|border="0" cellpadding="5"
+
|-valign="top"
+
|width="50%"|'''OXM Metadata''' (with '''xml-accessor-type="NONE"''')
+
 
+
<source lang="xml">
+
<?xml version="1.0" encoding="US-ASCII"?>
+
<xml-bindings xmlns="http://www.eclipse.org/eclipselink/xsds/persistence/oxm"
+
    package-name="example" xml-mapping-metadata-complete="true">
+
 
+
    <java-types>
+
        <java-type name="Customer" xml-accessor-type="NONE">
+
            <xml-root-element />
+
            <java-attributes>
+
                <xml-attribute java-attribute="name" name="customer-name" />
+
            </java-attributes>
+
        </java-type>
+
    </java-types>
+
 
+
</xml-bindings>
+
</source>
+
|width="50%"|'''XML Representation'''
+
 
+
<div style="height:100%">
+
<source lang="xml">
+
<?xml version="1.0" encoding="UTF-8"?>
+
<customer>
+
  <customer-name>Bob Dobbs</customer-name>
+
</customer>
+
</source>
+
</div>
+
|}
+
 
+
* Specifying '''xml-accessor-type="NONE"''' will prevent any default mappings from being generated
+
* The XML representation contains only the mappings defined in the OXM
+
 
+
 
+
== Virtual Mappings ==
+
 
+
An OXM file can also be used to specify virtual mappings, i.e. mappings that do not correspond to a concrete Java field.  For example, you might want to use a '''HashMap''' as the underlying structure to hold data for certain mappings.  For information on using Virtual Mappings, see:
+
 
+
* [[EclipseLink/UserGuide/MOXy/Advanced_Concepts/Virtual_Access_Methods|Virtual Access Methods]]
+

Latest revision as of 13:14, 30 January 2013

Warning This page is obsolete. Please see Developing JAXB Applications Using EclipseLink MOXy for current information.

Back to the top