You can use the Java Architecture for XML Binding (JAXB) and its Mapping Objects to XML (MOXy) extensions to map JPA entities to XML. Mapping JPA entities to XML is useful when you want to create a data access service with Java API for RESTful Web Services (JAX-RS), Java API for XML Web Services (JAX-WS), or Spring.
This chapter demonstrates some typical techniques for mapping JPA entities to XML. It contains the following sections:
Section 7.3, "Main Tasks for Mapping Simple Java Values to XML Text Nodes"
Section 7.4, "Main Tasks for Using XML Metadata Representation to Override JAXB Annotations"
Working with the examples that follow requires some understanding of such high-level JPA-to-XML mapping concepts, such as JAXB, MOXy, XML binding, and how to override JAXB annotations. The following sections will give you a basic understanding of these concepts:
XML binding is how you represent information in an XML document as an object in computer memory. This allows applications to access the data in the XML from the object rather than using the Domain Object Model (DOM), the Simple API for XML (SAX) or the Streaming API for XML (StAX) to retrieve the data from a direct representation of the XML itself. When binding, JAXB applies a tree structure to the graph of JPA entities. Multiple tree representations of a graph are possible and will depend on the root object chosen and the direction the representations are traversed.
You can find examples of XML binding with JAXB in Section 7.2, "Binding JPA Entities to XML".
JAXB is a Java API that allows a Java program to access an XML document by presenting that document to the program in a Java format. This process, called binding, represents information in an XML document as an object in computer memory. In this way, applications can access the data in the XML from the object rather than using the Domain Object Model (DOM) or the Streaming API for XML (SAX) to retrieve the data from a direct representation of the XML itself. Usually, an XML binding is used with JPA entities to create a data access service by optimizing a JAX-WS or JAX-RS implementation. Both of these web service standards use JAXB as the default binding layer. This service provides a means to access data exposed by JPA across computers, where the client computer might or might not be using Java.
JAXB uses an extended set of annotations to define the binding rules for Java-to-XML mapping. These annotations are subclasses of the javax.xml.bind.
*
packages in the Oracle TopLink API. For more information on these annotations, see Oracle Fusion Middleware Java API Reference for Oracle TopLink.
For more information about JAXB, see "Java Architecture for XML Binding (JAXB)" at:
MOXy implements JAXB for TopLink. It allows you to map a Plain Old Java Objects (POJO) model to an XML schema, greatly enhancing your ability to create JPA-to-XML mappings. MOXy supports all the standard JAXB annotations in the javax.xml.bind.annotation
package plus has its own extensions in the org.eclipse.persistence.oxm.annotations
package. You can use these latter annotations in conjunction with the standard annotations to extend the utility of JAXB. Because MOXy represents the optimal JAXB implementation, you still implement it whether or not you explicitly use any of its extensions. MOXy offers these benefits:
It allows you to map your own classes to your own XML schema, a process called "Meet in the Middle Mapping". This avoids static coupling of your mapped classes with a single XML schema.
It offers specific features, such as compound key mapping and mapping relationships with back-pointers to address critical JPA-to-XML mapping issues.
It allows you to map your existing JPA models to industry standard schemas.
It allows you to combine MOXy mappings and the TopLink persistence framework to interact with your data through the J2EE connector architecture (JCA).
It offers superior performance in several mapping scenarios.
For more information on MOXy, see the MOXy FAQ at:
JAXB/MOXy is not always the most effective way to map JPA to XML. For example, you would not use JAXB if:
You want to specify metadata for a third-party class but do not have access to the source.
You want to map an object model to multiple XML schemas, because JAXB rules preclude applying more than one mapping by using annotations.
Your object model already contains too many annotations—for example, from such services as JPA, Spring, JSR-303, and so on—and you want to specify the metadata elsewhere.
Under these and similar circumstances, you can use an XML data representation by exposing the eclipselink_oxm.xml
file.
XML metadata works in two modes:
It adds to the metadata supplied by annotations. This is useful when:
Annotations define version one of the XML representation, and you use XML metadata to change the metadata for future versions.
You use the standard JAXB annotations, and use the XML metadata for the MOXy extensions. In this way you do not introduce new compile time dependencies in the object model.
It completely replaces the annotation metadata, which is useful when you want to map to different XML representations.
For more information about how to use XML data representation, see Section 7.4, "Main Tasks for Using XML Metadata Representation to Override JAXB Annotations".
The following tasks demonstrate how to bind JPA entities to XML by using JAXB annotations. For more information about binding, see Section 7.1.1, "XML Binding"; for more information about JAXB, see Section 7.1.2, "JAXB"
Section 7.2.1, "Main Tasks for Binding JPA Relationships to XML"
Section 7.2.2, "Main Tasks for Binding Compound Primary Keys to XML"
Section 7.2.3, "Main Tasks for Binding Embedded ID Classes to XML"
The following tasks demonstrate how to use JAXB to derive an XML representation from a set of JPA entities, a process called binding (read about XML binding in Section 7.2, "Binding JPA Entities to XML"). These tasks will show how to bind two common JPA relationships to map an Employee
entity to that employee's telephone number, address, and department:
Privately-owned relationships
Shared reference relationships
The tasks for binding JPA relationships to XML are the following:
Because all of the following examples use the same accessor type, FIELD
, define it at the package level by using the JAXB annotation @XmlAccessorType
. At this point, you would also import the necessary packages:
@XmlAccessorType(XmlAccessType.FIELD) package com.example.model; import javax.xml.bind.annotation.XmlAccessType; import javax.xml.bind.annotation.XmlAccessorType;
A privately owned relationship occurs when the target object is referenced only by a single source object. This type of relationship can be either one-to-one and embedded, or one-to-many.
This task shows how to create bidirectional mappings for both of these types of relationships between the Employee
entity and the Address
and PhoneNumber
entities.
The JPA @OneToOne
and @Embedded
annotations indicate that only one instance of the source entity is able to refer to the same target entity instance. This example shows how to map the Employee
entity to the Address
entity and then back to the Employee
entity. This is considered a one-to-one mapping because the employee can be associated with only one address. Because this relationship is bidirectional, that is, Employee
points to Address
, which must point back to Employee
, it uses the TopLink extension @XmlInverseReference
to represent the back-pointer.
To create the one-to-one and embedded mapping:
Ensure that the accessor type FIELD
has been defined at the package level, as described in Section 7.2.1.1, "Task 1: Define the Accessor Type and Import Packages".
Map one direction of the relationship, in this case the employee
property on the Address
entity, by inserting the @OneToOne
annotation in the Employee
entity:
@OneToOne(mappedBy="resident") private Address residence;
The mappedBy
argument indicates that the relationship is owned by the resident
field.
Map the return direction, that is, the address
property on the Employee
entity by inserting the @OneToOne
and @XmlInverseMapping
annotations into the Address
entity:
@OneToOne @JoinColumn(name="E_ID") @XmlInverseReference(mappedBy="residence") private Employee resident;
The mappedBy
field indicates that this relationship is owned by the residence
field. @JoinColumn
identifies the column that will contain the foreign key.
The entities should look like those shown in Example 7-1 and Example 7-2.
The JPA @OneToMany
annotation indicates that a single instance of the source entity can refer to multiple instances of the same target entity. For example, one employee can have multiple telephone numbers, such as a land line, a mobile number, a desired contact number, and an alternative workplace number. Each different number would be an instance of the PhoneNumber
entity and a single Employee
entity could point to each instance.
This task maps the employee to one of that employee's telephone numbers and back. Because the relationship between Employee
and PhoneNumber
is bidirectional, the example again uses the TopLink extension @XmlInverseReference
to map the back-pointer.
To create a one-to-many mapping:
Ensure that the accessor type FIELD
has been defined at the package level, as described in Section 7.2.1.1, "Task 1: Define the Accessor Type and Import Packages".
Map one direction of the relationship, in this case the employee
property on the PhoneNumber
entity, by inserting the @OneToMany
annotation in the Employee
entity:
@OneToMany(mappedBy="contact") private List<PhoneNumber> contactNumber;
The mappedBy
field indicates that this relationship is owned by the contact
field.
Map the return direction, that is the telephone number property on the Employee
entity, by inserting the @ManyToOne
and @XmlInverseMapping
annotations into the PhoneNumber
entity:
@ManyToOne @JoinColumn(name="E_ID", referencedColumnName = "E_ID") @XmlInverseReference(mappedBy="contactNumber") private Employee contact;
The mappedBy
field indicates that this relationship is owned by the contactNumber
field. The @JoinColumn
annotation identifies the column that will contain the foreign key (name="E_ID"
) and the column referenced by the foreign key (referencedColumnName = "E_ID"
).
The entities should look like those shown in Example 7-1 and Example 7-3.
A shared reference relationship occurs when target objects are referenced by multiple source objects. For example, a business might be segregated into multiple departments, such as IT, human resources, finance, and so on. Each of these departments has multiple employees of differing job descriptions, pay grades, locations, and so on. Managing departments and employees requires shared reference relationships.
Because a shared reference relationship cannot be safely represented as nesting in XML, use key relationships. To specify the ID fields on JPA entities, use the TopLink JAXB @XmlID
annotation on non-string fields and properties and @XmlIDREF
on string fields and properties.
The following examples how to map a many-to-one shared reference relationship and a many-to-many shared reference relationship.
In a many-to-one mapping, one or more instances of the source entity are able to refer to the same target entity instance. This example demonstrates how to map an employee to one of that employee's multiple telephone numbers.
To map a many-to-one shared reference relationship:
Ensure that the accessor type FIELD
has been defined at the package level, as described in Section 7.2.1.1, "Task 1: Define the Accessor Type and Import Packages".
Map one direction of the relationship, in this case the phone number property on the Employee
entity, by inserting the @ManyToOne
annotation in the PhoneNumber
entity:
@ManyToOne @JoinColumn(name="E_ID", referencedColumnName = "E_ID") @XmlIDREF private Employee contact;
The @JoinColumn
annotation identifies the column that will contain the foreign key (name="E_ID"
) and the column referenced by the foreign key (referencedColumnName = "E_ID"
). The @XmlIDREF
annotation indicates that this will be the primary key for the corresponding table.
Map the return direction, that is the employee property on the PhoneNumber
entity, by inserting the @OneToMany
and @XmlInverseMapping
annotations into the Address
entity:
@OneToMany(mappedBy="contact") @XmlInverseReference(mappedBy="contact") private List<PhoneNumber> contactNumber;
The mappedBy
field for both annotations indicates that this relationship is owned by the contact
field.
The entities should look like those shown in Example 7-1 and Example 7-3.
The @ManyToMany
annotation indicates that one or more instances of the source entity are able to refer to one or more target entity instances. Because the relationship between Department
and Employee
is bidirectional, this example again uses the TopLink @XmlInverseReference
annotation to represent the back-pointer.
To map a many-to-many shared reference relationship, do the following:
Ensure that the accessor type FIELD
has been defined at the package level, as described in Section 7.2.1.1, "Task 1: Define the Accessor Type and Import Packages".
Create a Department
entity by inserting the following code:
@Entity public class Department {
Under this entity, define the many-to-many relationship and the entity's join table by inserting the following code:
@ManyToMany @JoinTable(name="DEPT_EMP", joinColumns = @JoinColumn(name="D_ID", referencedColumnName = "D_ID"), inverseJoinColumns = @JoinColumn(name="E_ID", referencedColumnName = "E_ID"))
This code creates a join table called DEPT_EMP
and identifies the column that will contain the foreign key (name="E_ID"
) and the column referenced by the foreign key (referencedColumnName = "E_ID"
). Additionally, it identifies the primary table on the inverse side of the relationship.
Complete the initial mapping, in this case the Department
entity's employee
property, and make it a foreign key for this entity by inserting the following code:
@XmlIDREF private List<Employee> member;
In the Employee
entity created in Section 7.2.1.2.1, "Mapping a One-to-One and Embedded Relationship", specify that eId
is the primary key for JPA (the @Id
annotation), and for JAXB (the @XmlID
annotation) by inserting the following code:
@Id @Column(name="E_ID") @XmlID private BigDecimal eId;
Still within the Employee
entity, complete the return mapping by inserting the following code:
@ManyToMany(mappedBy="member") @XmlInverseReference(mappedBy="member") private List<Department> team;
The entities should look like those shown in Example 7-1 and Example 7-4.
After the mappings are created, the entities should look like those in the following examples:
Note:
To save space, package names, import statements, and the get
and set
methods have been omitted from the code examples. All examples use standard JPA annotations.
@Entity
public class Employee {
@Id
@Column(name="E_ID")
private BigDecimal eId;
private String name;
@OneToOne(mappedBy="resident")
private Address residence;
@OneToMany(mappedBy="contact")
private List<PhoneNumber> contactNumber;
@ManyToMany(mappedBy="member")
private List<Department> team;
}
@Entity
public class Address {
@Id
@Column(name="E_ID", insertable=false, updatable=false)
private BigDecimal eId;
private String city;
private String street;
@OneToOne
@JoinColumn(name="E_ID")
private Employee resident;
}
Example 7-3 PhoneNumber Entity
@Entity
@Table(name="PHONE_NUMBER")
public class PhoneNumber {
@Id
@Column(name="P_ID")
private BigDecimal pId;
@ManyToOne
@JoinColumn(name="E_ID", referencedColumnName = "E_ID")
private Employee contact;
private String num;
}
@Entity
public class Department {
@Id
@Column(name="D_ID")
private BigDecimal dId;
private String name;
@ManyToMany
@JoinTable(name="DEPT_EMP", joinColumns =
@JoinColumn(name="D_ID", referencedColumnName = "D_ID"),
inverseJoinColumns = @JoinColumn(name="E_ID",
referencedColumnName = "E_ID"))
private List<Employee> member;
}
When a JPA entity has compound primary keys, you can bind the entity by using JAXB annotations and certain Oracle TopLink extensions, as shown in the following tasks:
Define the accessor type as FIELD
, as described in Section 7.2.1.1, "Task 1: Define the Accessor Type and Import Packages".
To create the target object, do the following:
Create an Employee
entity with a composite primary key class called EmployeeId
to map to multiple fields or properties of the entity:
@Entity
@IdClass(EmployeeId.class)
public class Employee {
Specify the first primary key, eId
, of the entity and map it to a column:
@Id @Column(name="E_ID") @XmlID private BigDecimal eId;
Specify the second primary key, country
. In this instance, you need to use @XmlKey
to identify the primary key because only one property—here, eId
—can be annotated with the @XmlID
annotation.
@Id @XmlKey private String country;
The @XmlKey
annotation marks a property as a key that will be referenced by using a key-based mapping via the @XmlJoinNode
annotation in the source object. This is similar to the @XmlKey
annotation except it does not require the property be bound to the schema type ID. This is a typical application of the @XmlKey
annotation.
Create a many-to-one mapping of the Employee
property on PhoneNumber
by inserting the following code:
@OneToMany(mappedBy="contact") @XmlInverseReference(mappedBy="contact") private List<PhoneNumber> contactNumber;
The Employee
entity should look like that shown in Example 7-5.
Example 7-5 Employee Entity with Compound Primary Keys
@Entity @IdClass(EmployeeId.class) public class Employee { @Id @Column(name="E_ID") @XmlID private BigDecimal eId; @Id @XmlKey private String country; @OneToMany(mappedBy="contact") @XmlInverseReference(mappedBy="contact") private List<PhoneNumber> contactNumber; }
This task creates the source object, the PhoneNumber
entity. Because the target object has a compound key, you must use the TopLink @XmlJoinNodes
annotation to set up the mapping.
To create the source object:
Create the PhoneNumber
entity:
@Entity public class PhoneNumber {
Create a many-to-one relationship and define the join columns:
@ManyToOne @JoinColumns({ @JoinColumn(name="E_ID", referencedColumnName = "E_ID"), @JoinColumn(name="E_COUNTRY", referencedColumnName = "COUNTRY") })
Set up the mapping by using the TopLink @XmlJoinNodes
annotation:
@XmlJoinNodes( { @XmlJoinNode(xmlPath="contact/id/text()", referencedXmlPath="id/text()"), @XmlJoinNode(xmlPath="contact/country/text()", referencedXmlPath="country/text()") })
Define the contact
property:
private Employee contact; }
The target object should look like that shown in Example 7-6.
Example 7-6 PhoneNumber Entity
@Entity public class PhoneNumber { @ManyToOne @JoinColumns({ @JoinColumn(name="E_ID", referencedColumnName = "E_ID"), @JoinColumn(name="E_COUNTRY", referencedColumnName = "COUNTRY") }) @XmlJoinNodes( { @XmlJoinNode(xmlPath="contact/id/text()", referencedXmlPath="id/text()"), @XmlJoinNode(xmlPath="contact/country/text()", referencedXmlPath="country/text()") }) private Employee contact; }
An embedded ID defines a separate Embeddable
Java class to contain the entity's primary key. It is defined through the @EmbeddedId
annotation. The embedded ID's Embeddable
class must define each Id
attribute for the entity using basic mappings. In the embedded Id, all attributes in its Embeddable
class are assumed to be part of the primary key. The following tasks show how to derive an XML representation from a set of JPA entities using JAXB when a JPA entity has an embedded ID class:
Task 3: Implement DescriptorOrganizer as EmployeeCustomizer Class
Task 5: Implement the DescriptorCustomizer as PhoneNumberCustomizer Class
Define the XML accessor type as FIELD
, as described in Section 7.2.1.1, "Task 1: Define the Accessor Type and Import Packages".
The target object is an entity called Employee
and contains the mapping for an employee's contact telephone number. Creating this target object requires implementing a DescriptorCustomizer
interface, so you must include the TopLink @XmlCustomizer
annotation. Also, because the relationship is bidirectional, you must implement the @XmlInverseReference
annotation.
To create the target object:
Create the Employee
entity. Use the @IdClass
annotation to specify that the EmployeeID
class will be mapped to multiple properties of the entity and use the @XmlCustomizer
annotation to indicate that the class EmployeeCustomizer
will implement the DescriptorCustomizer
interface (see Section 7.2.3.3, "Task 3: Implement DescriptorOrganizer as EmployeeCustomizer Class").
@Entity
@IdClass(EmployeeId.class)
public class Employee {
Define the id
property and make it embeddable.
@EmbeddedId @XmlPath("."); private EmployeeId id;
Define a one-to-many mapping, in this case, the employee
property on the PhoneNumber
entity. Because the relationship is bidirectional, use @XmlInverseReference
annotation to define the return mapping. Both of these relationships will be owned by the contact
field, as indicated by the mappedBy
argument.
@OneToMany(mappedBy="contact") @XmlInverseReference(mappedBy="contact") private List<PhoneNumber> contactNumber;
The completed target object should look like that shown in Example 7-7.
In Task 2: Create the Target Object, DescriptorCustomizer
was implemented as the class EmployeeCustomizer
. This allows changing the XML Path (XPath) on the mapping for the id
property to either self or "." and then specifying the XPath to the XML nodes that represent the ID. To do this:
Implement the DescriptorOrganizer
class as EmployeeOrganizer
.
import org.eclipse.persistence.oxm.mappings.XMLCompositeObjectMapping;
public class EmployeeCustomizer implements DescriptorCustomizer {
Specify the XPath to the XML nodes that represent the ID:
descriptor.addPrimaryKeyFieldName("eId/text()"); descriptor.addPrimaryKeyFieldName("country/text()");
The EmployeeCustomizer
class should look like Example 7-8.
Example 7-8 EmployeeCustomizer Class with Updated XPath Information
import org.eclipse.persistence.config.DescriptorCustomizer; import org.eclipse.persistence.descriptors.ClassDescriptor; import org.eclipse.persistence.oxm.mappings.XMLCompositeObjectMapping; public class EmployeeCustomizer implements DescriptorCustomizer { descriptor.addPrimaryKeyFieldName("eId/text()"); descriptor.addPrimaryKeyFieldName("country/text()"); } }
The source object in this task has a compound key, so you must annotate the field with the @XmlTransient
annotation to prevent a key from being mapped by itself. Use the TopLink @XmlCustomizer
annotation to set up the mapping.
To create the source object, do the following:
Create the PhoneNumber
entity and specify another class, PhoneNumberCustomizer
, to implement the DescriptorCustomizer
interface.
@Entity
@XmlCustomizer(PhoneNumberCustomizer.class)
public class PhoneNumber {
Create a many-to-one mapping and define the join columns.
@ManyToOne @JoinColumns({ @JoinColumn(name="E_ID", referencedColumnName = "E_ID"), @JoinColumn(name="E_COUNTRY", referencedColumnName = "COUNTRY") })
Define the contact
property. Use the @XmlTransient
annotation to prevent this key from being mapped by itself.
@XmlTransient private Employee contact;
The completed PhoneNumber
class should look like Example 7-9.
Example 7-9 PhoneNumber Class as Source Object
@Entity @XmlCustomizer(PhoneNumberCustomizer.class) public class PhoneNumber { @ManyToOne @JoinColumns({ @JoinColumn(name="E_ID", referencedColumnName = "E_ID"), @JoinColumn(name="E_COUNTRY", referencedColumnName = "COUNTRY") }) @XmlTransient private Employee contact; }
Code added in Task 4 indicated the need to map the XMLObjectReferenceMapping
class to the new values. This requires implementing the DescriptorCustomizer
class as the PhoneNumberCustomizer
class and adding the multiple key mappings. To do this:
Implement DescriptorCustomizer
as PhoneNumberCustomizer
. Import org.eclipse.persistence.oxm.mappings.XMLObjectReferenceMapping
:
import org.eclipse.persistence.oxm.mappings.XMLObjectReferenceMapping;
public class PhoneNumberCustomizer implements DescriptorCustomizer {
In the customize
method, update the following mappings:
contactMapping.setAttributeName
to "contact"
.
contactMapping.addSourceToTargetKeyFieldAssociation
to "contact/@eID", "eId/text()"
.
contactMapping.addSourceToTargetKeyFieldAssociation
to "contact/@country", "country/text()"
.
The PhoneNumberCustomizer
should look like that shown in Example 7-10.
Example 7-10 PhoneNumber Customizer with Updated Key Mappings
import org.eclipse.persistence.config.DescriptorCustomizer; import org.eclipse.persistence.descriptors.ClassDescriptor; import org.eclipse.persistence.oxm.mappings.XMLObjectReferenceMapping; public class PhoneNumberCustomizer implements DescriptorCustomizer { public void customize(ClassDescriptor descriptor) throws Exception { XMLObjectReferenceMapping contactMapping = new XMLObjectReferenceMapping(); contactMapping.setAttributeName("contact"); contactMapping.setReferenceClass(Employee.class); contactMapping.addSourceToTargetKeyFieldAssociation("contact/@eID", "eId/text()"); contactMapping.addSourceToTargetKeyFieldAssociation("contact/@country", "country/text()"); descriptor.addMapping(contactMapping); } }
As demonstrated in the preceding tasks, TopLink implements the standard JAXB annotations to map JPA entities to an XML representation. You can also express metadata by using the EclipseLink XML Bindings document. Not only can you use XML bindings to separate your mapping information from your actual Java class, but you can also use it for more advanced metadata tasks, such as:
Augmenting or overriding existing annotations with additional mapping information
Specifying all mapping information externally, without using any Java annotations
Defining your mappings across multiple EclipseLink XML Bindings documents
Specifying virtual mappings that do not correspond to concrete Java fields
For more information on using the XML Bindings document, see XML Bindings in the JAXB/MOXy documentation at http://wiki.eclipse.org/EclipseLink/UserGuide/MOXy/Runtime/XML_Bindings
.
There are several ways to map simple Java values directly to XML text nodes. It includes the following tasks:
This task maps the id
property in the Java object Customer
to its XML representation as an attribute of the <customer>
element. The XML will be based on the schema in Example 7-11.
Example 7-11 Example XML Schema
<?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:attribute name="id" type="xsd:integer"/> </xsd:complexType> </xsd:schema>
The following procedures demonstrate how to map the id
property from the Java object and, alternatively, how to represent the value in the Oracle TopLink Object-to-XML Mapping (OXM) metadata format.
The key to creating this mapping from a Java object is the @XmlAttribute
JAXB annotation, which maps the field to the XML attribute. To create this mapping:
Create the object and import javax.xml.bind.annotation.*
:
package example; import javax.xml.bind.annotation.*;
Declare the Customer
class and use the @XmlRootElement
annotation to make it the root element. Set the XML accessor type to FIELD
:
@XmlRootElement @XmlAccessorType(XmlAccessType.FIELD) public class Customer {
Map the id
property in the Customer
class as an attribute:
@XmlAttribute
private Integer id;
The object should look like that shown in Example 7-12.
If you want to represent the mapping in the TopLink OXM metadata format, use the XML tags defined in the eclipselink-oxm.xml
file and populate them with the appropriate values, as shown in Example 7-13.
Example 7-13 Mapping id as an Attribute in OXM Metadata Format
... <java-type name="Customer"> <xml-root-element name="customer"/> <java-attributes> <xml-attribute java-attribute="id"/> </java-attributes> </java-type> ...
For more information about the OXM metadata format, see Section 7.4, "Main Tasks for Using XML Metadata Representation to Override JAXB Annotations".
Oracle TopLink makes it easy for you to map values from a Java object to various kinds of XML text nodes; for example, to simple text nodes, text nodes in a simple sequence, in a subset, or by position. These mappings are demonstrated in the following examples:
You can map a value from a Java object either by using JAXB annotations in the Java object or, alternatively, by representing the mapping in the TopLink OXM metadata format.
Assume the associated schema defines an element called <phone-number>
that accepts a string value. You can use the @XmlValue
annotation to map a string to the <phone-number>
node. Do the following:
Create the object and import javax.xml.bind.annotation.*
:
package example; import javax.xml.bind.annotation.*;
Declare the PhoneNumber
class and use the @XmlRootElement
annotation to make it the root element with the name phone-number
. Set the XML accessor type to FIELD
:
@XmlRootElement(name="phone-number") @XmlAccessorType(XmlAccessType.FIELD) public class PhoneNumber {
Insert the @XmlValue
annotation on the line before the number
property in the Customer
class to map this value as an attribute:
@XmlValue
private String number;
The object should look like that shown in Example 7-14.
If you want to represent the mapping in the TopLink OXM metadata format, then use the XML tags defined in the eclipselink-oxm.xml
file and populate them with the appropriate values, as shown in Example 7-15.
You can map a sequence of values, for example a customer's first and last name, as separate elements either by using JAXB annotations or by representing the mapping in the TopLink OXM metadata format. The following procedures illustrate how to map values for customers' first names and last names
Assuming the associated schema defines the following elements:
<"customer">
of the type customer-type
, which itself is defined as complexType
Sequential elements called <"first-name">
and <"last-name">
, both of the type string
You can use the @XmlElement
annotation to map values for a customer's first and last names to the appropriate XML nodes. To do so:
Create the object and import javax.xml.bind.annotation.*
:
package example; import javax.xml.bind.annotation.*;
Declare the Customer
class and use the @XmlRootElement
annotation to make it the root element. Set the XML accessor type to FIELD
:
@XmlRootElement @XmlAccessorType(XmlAccessType.FIELD) public class Customer {
Define the firstname
and lastname
properties and annotate them with the @XmlElement
annotation. Use the name=
argument to customize the XML element name (if you do not explicitly set the name with name=
, then the XML element will match the Java attribute name; for example, here the <first-name>
element combination would be specified <firstName> </firstName>
in XML).
@XmlElement(name="first-name") private String firstName; @XmlElement(name="last-name") private String lastName;
The object should look like Example 7-16.
Example 7-16 Customer Object Mapping Values to a Simple Sequence
package example; import javax.xml.bind.annotation.*; @XmlRootElement @XmlAccessorType(XmlAccessType.FIELD) public class Customer { @XmlElement(name="first-name") private String firstName; @XmlElement(name="last-name") private String lastName; ... }
If you want to represent the mapping in the TopLink OXM metadata format, then use the XML tags defined in the eclipselink-oxm.xml
file and populate them with the appropriate values, as shown in Example 7-17.
Example 7-17 Mapping Sequential Attributes in OXM Metadata Format
... <java-type name="Customer"> <xml-root-element name="customer"/> <java-attributes> <xml-element java-attribute="firstName" name="first-name"/> <xml-element java-attribute="lastName" name="last-name"/> </java-attributes> </java-type> ...
You can map values from a Java object to text nodes that are nested as a subelement in the XML document by using JAXB annotations or by representing the mapping in the TopLink OXM metadata format. For example, if you want to populate <first-name>
and <last-name>
elements, which are subelements of a <personal-info>
element under a <customer>
root element, you could use the following procedures to achieve these mappings.
Assume the associated schema defines the following elements:
<"customer">
of the type customer-type, which itself is defined as complexType
<personal-info>
Subelements of <personal-info>
called <"first-name">
and <"last-name">
, both of the type String
You can use JAXB annotations to map values for a customer's first and last name to the appropriate XML subelement nodes. Because this example goes beyond a simple element name customization and actually introduces a new XML structure, it uses the TopLink @XmlPath
annotation. To achieve this mapping:
Create the object and import javax.xml.bind.annotation.*
and org.eclipse.persistence.oxm.annotations.*
.
package example; import javax.xml.bind.annotation.*; import org.eclipse.persistence.oxm.annotations.*;
Declare the Customer
class and use the @XmlRootElement
annotation to make it the root element. Set the XML accessor type to FIELD
:
@XmlRootElement @XmlAccessorType(XmlAccessType.FIELD) public class Customer {
Define the firstName
and lastName
properties.
Map the firstName
and lastName
properties to the subelements defined by the XML schema by inserting the @XmlPath
annotation on the line immediately preceding the property declaration. For each annotation, define the mapping by specifying the appropriate XPath predicate:
@XmlPath("personal-info/first-name/text()") private String firstName; @XmlPath("personal-info/last-name/text()") private String lastName;
The object should look like that shown in Example 7-18.
Example 7-18 Customer Object Mapping Properties to Subelements
package example; import javax.xml.bind.annotation.*; import org.eclipse.persistence.oxm.annotations.*; @XmlRootElement @XmlAccessorType(XmlAccessType.FIELD) public class Customer { @XmlPath("personal-info/first-name/text()") private String firstName; @XmlPath("personal-info/last-name/text()") private String lastName; ... }
If you want to represent the mapping in the TopLink OXM metadata format, you need to use the XML tags defined in the eclipselink-oxm.xml
file and populate them with the appropriate values, as shown in Example 7-19.
Example 7-19 Mapping Attributes as Subelements in OXM Metadata Format
... <java-type name="Customer"> <xml-root-element name="customer"/> <java-attributes> <xml-element java-attribute="firstName" xml-path="personal-info/first-name/text()"/> <xml-element java-attribute="lastName" xml-path="personal-info/last-name/text()"/> </java-attributes> </java-type> ...
When multiple nodes have the same name, map their values from the Java object by specifying their position in the XML document. Do this by using mapping the values to the position of the attribute rather than the attribute's name. You can do this either by using JAXB annotations or by representing the mapping in the TopLink OXM metadata format. In the following example, XML contains two <name>
elements; the first occurrence of name
should represent the customer's first name and the second occurrence should represent the customer's last name.
Assume an XML schema defines the following attributes:
<customer>
of the type customer-type, which itself is specified as a complexType
<name>
of the type String
This example uses the JAXB @XmlPath
annotation to map a customer's first and last names to the appropriate <name>
element. It also uses the @XmlType(propOrder)
annotation to ensure that the elements are always in the proper positions. To achieve this mapping:
Create the object and import javax.xml.bind.annotation.*
and org.eclipse.persistence.oxm.annotations.XmlPath
.
package example; import javax.xml.bind.annotation.*; import org.eclipse.persistence.oxm.annotations.XmlPath;
Declare the Customer
class and insert the @XmlType(propOrder)
annotation with the arguments "firstName"
followed by "lastName"
. Insert the @XmlRootElement
annotation to make Customer
the root element and set the XML accessor type to FIELD
:
@XmlRootElement @XmlType(propOrder={"firstName", "lastName"}) @XmlAccessorType(XmlAccessType.FIELD) public class Customer {
Define the properties firstName
and lastName
with the type String
.
Map the properties firstName
and lastName
to the appropriate position in the XML document by inserting the @XmlPath
annotation with the appropriate XPath predicates.
@XmlPath("name[1]/text()") private String firstName; @XmlPath("name[2]/text()") private String lastName;
The predicates, "name[1]/text()"
and "name[2]/text()"
indicate the <name>
element to which that specific property will be mapped; for example, "name[1]/text"
will map the firstName
property to the first <name>
element.
The object should look like that shown in Example 7-20.
Example 7-20 Customer Object Mapping Values by Position
package example; import javax.xml.bind.annotation.*; import org.eclipse.persistence.oxm.annotations.XmlPath; @XmlRootElement @XmlType(propOrder={"firstName", "lastName"}) @XmlAccessorType(XmlAccessType.FIELD) public class Customer { @XmlPath("name[1]/text()") private String firstName; @XmlPath("name[2]/text()") private String lastName; ... }
For more information on using XPath predicates, see Section 7.5, "Using XPath Predicates for Mapping".
In addition to using Java annotations, TopLink provides an XML mapping configuration file called eclipselink-oxm.xml
that you can use in place of or to override JAXB annotations in the source with an XML representation of the metadata. In addition to allowing all of the standard JAXB mapping capabilities, it also includes advanced mapping types and options.
An XML metadata representation is useful when:
You cannot modify the domain model because, for example, it comes from a third party.
You do not want to introduce compilation dependencies on JAXB APIs (if you are using a version of Java that predates Java SE 6).
You want to apply multiple JAXB mappings to a domain model (you are limited to one representation with annotations).
Your object model already contains so many annotations from other technologies that adding more would make the class unreadable.
Use the eclipselink-oxm.xml
configuration file to override JAXB annotations by performing the following tasks:
Caution:
While using this mapping file enables many advanced features, it might prevent you from porting it to other JAXB implementations.
First, update the XML mapping file to expose the eclipselink_oxm_2_3.xsd
schema. Example 7-21 shows how to modify the <xml-bindings>
element in the mapping file to point to the correct namespace and optimize the schema. Each Java package can have one mapping file.
Example 7-21 Updating XML Binding Information in the Mapping File
<?xml version="1.0"?> <xml-bindings xmlns="http://www.eclipse.org/eclipselink/xsds/persistence/oxm" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eclipse.org/eclipselink/xsds/persistence/oxm http://www.eclipse.org/eclipselink/xsds/eclipselink_oxm_2_3.xsd" version="2.3"> </xml-bindings>
Next, pass the mapping file to the JAXBContext
class in your object:
Specify the externalized metadata by inserting this code:
Map<String, Source> metadata = new HashMap<String,Source>(); metadata.put("example.order", new StreamSource("order-metadata.xml")); metadata.put("example.customer", new StreamSource("customer-metadata.xml"));
Create the properties object to pass to JAXBContext
. For this example:
Map<String,Object> properties = new HashMap<String,Object>(); properties.put(JAXBContextFactory.ECLIPSELINK_OXM_XML_KEY, metadata);
Create JAXBContext
. For example:
JAXBContext.newInstance("example.order:example.customer", aClassLoader, properties);
You must use MOXy as your JAXB implementation. To do so, do the following:
Open a jaxb.properties
file and add the following line:
javax.xml.bind.context.factory=org.eclipse.persistence.jaxb.JAXBContextFactory
Copy the jaxb.properties
file to the package that contains your domain classes.
The TopLink MOXy API uses XPath predicates to define an expression that specifies the XML element's name. An XPath predicate is an expression that defines a specific object-to-XML mapping. As shown in previous examples, by default, JAXB will use the Java field name as the XML element name.
This section contains the following subsections:
As described previously, an XPath predicate is an expression that defines a specific object-to-XML mapping when standard annotations are not sufficient. For example, the following XML code shows a <data>
element with two <node>
subelements. If you want to create this mapping in a Java object, then specify an XPath predicate for each <node>
subelement, for example Node[2]
in the following Java:
<java-attributes>
<xml-element java-attribute="node" xml-path="node[1]/ABC"/>
<xml-element java-attribute="node" xml-path="node[2]/DEF"/>
</java-attributes>
This would match the second occurrence of the node element ("DEF"
) in the following XML:
<?xml version="1.0" encoding="UTF-8"?>
<data>
<node>ABC</node>
<node>DEF</node>
</data>
Thus, by using the XPath predicate, you can use the same attribute name for a different attribute value.
In another example, if you wanted to map attributes based on position, you would follow the instructions described in Section 7.3.2.4, "Mapping Values to a Text Node by Position".
Beginning with TopLink MOXy 2.3, you can also map to an XML element based on an attribute value. In these tasks, you will annotate the JPA entity to render the XML document shown in Example 7-22. Note that all of the XML elements are named node
but are differentiated by the value of their name
attribute.
<?xml version="1.0" encoding="UTF-8"?> <node> <node name="first-name">Bob</node> <node name="last-name">Smith</node> <node name="address"> <node name="street">123 A Street</node> </node> <node name="phone-number" type="work">555-1111</node> <node name="phone-number" type="cell">555-2222</node> </node>
To attain this mapping, declare three classes, Name
, Address
, and PhoneNumber
and then use an XPath in the form of element-name
[@
attribute-name
='
value
']
to map each Java field. To create entities from the Customer, Address, and PhoneNumber classes, perform the following tasks:
To create an entity from the Customer
class:
Import the necessary JPA packages by adding the following code:
import javax.xml.bind.annotation.*; import org.eclipse.persistence.oxm.annotations.XmlPath;
Declare the Customer
class and use the @XmlRootElement
annotation to make it the root element. Set the XML accessor type to FIELD
:
@XmlRootElement @XmlAccessorType(XmlAccessType.FIELD) public class Customer {
Declare these properties as local to the Customer
class:
firstName
(String
type)
lastName
(String
)
Address
(Address
)
For each property, set the Xpath predicate by preceding the property declaration with the annotation @XmlPath(
element-name
[@
attribute-name
='
value
'])
. For example, for firstName
, you would set the XPath predicate with this statement:
@XmlPath("node[@name='first-name']/text()")
Also declare local to the Customer
class the phoneNumber
property as a List<PhoneNumber>
type and assign it the value new ArrayList<PhoneNumber>()
.
The Customer
class should look like that shown in Example 7-23.
Example 7-23 Customer Object Mapping to an Attribute Value
package example; import javax.xml.bind.annotation.*; import org.eclipse.persistence.oxm.annotations.XmlPath; @XmlRootElement(name="node") @XmlAccessorType(XmlAccessType.FIELD) public class Customer { @XmlPath("node[@name='first-name']/text()") private String firstName; @XmlPath("node[@name='last-name']/text()") private String lastName; @XmlPath("node[@name='address']") private Address address; @XmlPath("node[@name='phone-number']") private List<PhoneNumber> phoneNumbers = new ArrayList<PhoneNumber>(); ... }
To create an entity from the Address
class, do the following:
Import the necessary JPA packages by adding the following code:
import javax.xml.bind.annotation.*; import org.eclipse.persistence.oxm.annotations.XmlPath;
Declare the Address
class and set the XML accessor type to FIELD
:
@XmlAccessorType(XmlAccessType.FIELD)
public class Address {
This instance does not require the @XmlRootElement
annotation as in Task 1: Create the Customer Class Entity because the Address
class is not a root element in the XML document.
Declare the String
property street
local to the Address
class. Set the XPath predicate by preceding the property declaration with the annotation @XmlPath("node[@name='street']/text()")
.
The Address
class should look like that shown in Example 7-24.
To create an entity from the PhoneNumber
class:
Import the necessary JPA packages by adding the following code:
import javax.xml.bind.annotation.*; import org.eclipse.persistence.oxm.annotations.XmlPath;
Declare the PhoneNumber
class and use the @XmlRootElement
annotation to make it the root element. Set the XML accessor type to FIELD
:
@XmlRootElement @XmlAccessorType(XmlAccessType.FIELD) public class Customer {
Create the type
and string
properties and define their mapping as attributes under the PhoneNumber
root element by using the @XmlAttribute
. annotation.
@XmlAttribute private String type; @XmlValue private String number;
The PhoneNumber
object should look like that shown in Example 7-25.
A self-mapping occurs on one-to-one mappings when you set the target object's XPath to "." (dot) so the data from the target object appears inside the source object's XML element. This exercise uses the example in Section 7.5.2, "Main Tasks for Mapping Based on an Attribute Value" to map the address information to appear directly under the customer element and not wrapped in its own element.
To create the self mapping:
Repeat Tasks 1 and 2 in Section 7.5.2.1, "Task 1: Create the Customer Class Entity".
Declare these properties local to the Customer
class:
firstName
(String
)
lastName
(String
)
Address
(Address
)
For the firstName
and lastName
properties, set the @XmlPath
annotation by preceding the property declaration with the annotation @XmlPath(
element-name
[@
attribute-name
='
value
'])
. For example, for firstName
, you would set the XPath predicate with this statement:
@XmlPath("node[@name='first-name']/text()")
For the address
property, set @XmlPath
to "." (dot):
@XmlPath(".") private Address address;
Also declare the phoneNumber
property local to the Customer
class. Declare it as a List<PhoneNumber>
type and assign it the value new ArrayList<PhoneNumber>()
.
The rendered XML for the Customer
entity should look like that shown in Example 7-26.
Example 7-26 XML Node with Self-Mapped Address Element
<?xml version="1.0" encoding="UTF-8"?> <node> <node name="first-name">Bob</node> <node name="last-name">Smith</node> <node name="street">123 A Street</node> <node name="phone-number" type="work">555-1111</node> <node name="phone-number" type="cell">555-2222</node> </node>
Dynamic JAXB/MOXy allows you to bootstrap a JAXBContext
class from a variety of metadata sources and use familiar JAXB APIs to marshal and unmarshal data, without requiring compiled domain classes. This is an enhancement over static JAXB, because now you can update the metadata without having to update and recompile the previously generated Java source code.
The benefits of using dynamic JAXB/MOXy entities are:
Instead of using actual Java classes (for example, Customer.class
, Address.class
, and so on), the domain objects are subclasses of the DynamicEntity
class.
Dynamic entities offer a simple get(propertyName)
/set(propertyName propertyValue)
API to manipulate their data.
Dynamic entities have an associated DynamicType
class, which is generated in-memory, when the metadata is parsed.
The following Tasks demonstrate how to use dynamic JAXB/MOXy:
Use the DynamicJAXBContextFactory
class to create a dynamic JAXBContext
object. Example 7-27 specifies the input stream and then bootstraps a DynamicJAXBContext
class from the customer.xsd
schema (Example 7-28) by using the createContextFromXSD()
method.
Example 7-27 Specifying the Input Stream and Creating DynamicJAXBContext
import java.io.FileInputStream; import org.eclipse.persistence.jaxb.dynamic.DynamicJAXBContext; import org.eclipse.persistence.jaxb.dynamic.DynamicJAXBContextFactory; public class Demo { public static void main(String[] args) throws Exception { FileInputStream xsdInputStream = new FileInputStream("src/example/customer.xsd"); DynamicJAXBContext jaxbContext = DynamicJAXBContextFactory.createContextFromXSD(xsdInputStream, null, null, null);
The first parameter represents the XML schema itself and must be in one of the following forms: java.io.InputStream
, org.w3c.dom.Node
, or javax.xml.transform.Source
.
Example 7-28 shows the customer.xsd
schema that represents the metadata for the dynamic JAXBContext
you are bootstrapping.
Example 7-28 Sample XML Schema Document
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://www.example.org" targetNamespace="http://www.example.org" elementFormDefault="qualified"> <xsd:complexType name="address"> <xsd:sequence> <xsd:element name="street" type="xsd:string" minOccurs="0"/> <xsd:element name="city" type="xsd:string" minOccurs="0"/> </xsd:sequence> </xsd:complexType> <xsd:element name="customer"> <xsd:complexType> <xsd:sequence> <xsd:element name="name" type="xsd:string" minOccurs="0"/> <xsd:element name="address" type="address" minOccurs="0"/> </xsd:sequence> </xsd:complexType> </xsd:element> </xsd:schema>
To bootstrap DynamicJAXBContext
from an XML schema that contains imports of other schemas, you need to configure an org.xml.sax.EntityResolver
to resolve the locations of the imported schemas and pass the EntityResolver
to DynamicJAXBContextFactory
.
Example 7-29 shows the schema document customer.xsd
and Example 7-30 shows the schema document address.xsd
. You can see that customer.xsd
imports address.xsd
by using the statement:
<xsd:import namespace="http://www.example.org/address" schemaLocation="address.xsd"/>
<?xml version="1.0" encoding="UTF-8"?>
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:add="http://www.example.org/address"
xmlns="http://www.example.org/customer"
targetNamespace="http://www.example.org/customer"
elementFormDefault="qualified">
<xsd:import namespace="http://www.example.org/address" schemaLocation="address.xsd"/>
<xsd:element name="customer">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="name" type="xsd:string" minOccurs="0"/>
<xsd:element name="address" type="add:address" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<?xml version="1.0" encoding="UTF-8"?> xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://www.example.org/address" targetNamespace="http://www.example.org/address" elementFormDefault="qualified"> <xsd:complexType name="address"> <xs:sequence> <xs:element name="street" type="xs:string"/> <xs:element name="city" type="xs:string"/> </xs:sequence> </xsd:complexType> </xsd:schema>
If you want to bootstrap DynamicJAXBContext
from the customer.xsd
schema then pass an entity resolver. Do the following:
To resolve the locations of the imported schemas, implement entityResolver
by supplying the code shown in Example 7-31.
Example 7-31 Implementing an 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)); is.setSystemId(correctedId); return is; } }
After you implement DynamicJAXBContext
, pass the EntityResolver
, as shown in Example 7-32.
You might see the following exception when importing another schema:
Internal Exception: org.xml.sax.SAXParseException: schema_reference.4: Failed to read schemadocument '<imported-schema-name>', because 1) could not find the document; 2) the document couldnot be read; 3) the root element of the document is not <xsd:schema>.
To work around this exception, disable the XJC schema correctness check by setting the noCorrectnessCheck
Java property. You can set this property in one of two ways:
From within the code, by adding this line:
System.setProperty("com.sun.tools.xjc.api.impl.s2j.SchemaCompilerImpl.noCorrectnessCheck", "true")
From the command line, by using this command:
-Dcom.sun.tools.xjc.api.impl.s2j.SchemaCompilerImpl.noCorrectnessCheck=true
Use your application's current class loader as the classLoader
parameter. This parameter verifies that specified classes exist before a new DynamicType
is generated. In most cases you can pass null
for this parameter and use Thread.currentThread().getContextClassLoader()
method instead.
Use the DynamicJAXBContext
class to create instances of a DynamicEntity
object. The entity and property names correspond to the class and property names, in this case the customer and address, that would have been generated if you had used static JAXB.
Example 7-33 Creating the Dynamic Entity
DynamicEntity customer = jaxbContext.newDynamicEntity("org.example.Customer"); customer.set("name", "Jane Doe"); DynamicEntity address = jaxbContext.newDynamicEntity("org.example.Address"); address.set("street", "1 Any Street").set("city", "Any Town"); customer.set("address", address);
The marshaller obtained from the DynamicJAXBContext
is a standard marshaller and can be used normally to marshal instances of DynamicEntity
, as shown in Example 7-34.
Example 7-34 Standard Dynamic JAXB Marshaller
Marshaller marshaller = jaxbContext.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);marshaller.marshal(customer, System.out);
Example 7-35 show resultant XML document:
This task shows how to unmarshal from XML the dynamic entities you created in Task 2: Create Dynamic Entities and Marshal Them to XML. The XML in reference is shown in Example 7-35.
The Unmarshaller obtained from the DynamicJAXBContext
object is a standard unmarshaller, and can be used to unmarshal instances of DynamicEntity
, as shown in Example 7-36.
Example 7-36 Standard Dynamic JAXB Unmarshaller
FileInputStream xmlInputStream = new FileInputStream("src/example/dynamic/customer.xml");
Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
DynamicEntity customer = (DynamicEntity) unmarshaller.unmarshal(xmlInputStream);
Specify which data in the dynamic entity to obtain. Specify this value by using the System.out.println()
method and passing in the entity name. DynamicEntity
offers property-based data access; for example, get("name")
instead of getName()
:
System.out.println(customer.<String>get("name"));
Instances of DynamicEntity
have a corresponding DynamicType
, which you can use to introspect the DynamicEntity
object, as shown in Example 7-37.
The following additional resourcs are available:
Numerous code samples and tutorials can be found at the EclipseLink MOXy wiki site:
The following Javadoc is available:
JAXB uses an extended set of annotations to define the binding rules for Java-to-XML mapping. These annotations are subclasses of the javax.xml.bind.*
packages in the Oracle TopLink API. Javadoc is for these annotations is at:
http://docs.oracle.com/javase/6/docs/api/javax/xml/bind/package-summary.html
MOXy supports all the standard JAXB annotations in the javax.xml.bind.annotation
package:
MOXy has its own extensions in the org.eclipse.persistence.oxm.annotations
package: