6 Understanding Mappings

This chapter introduces and describes mappings. EclipseLink can transform data between an object representation and a representation specific to a data source. This transformation is called mapping and it is the core of EclipseLink projects.

A mapping corresponds to a single data member of a domain object. It associates the object data member with its data source representation and defines the means of performing the two-way conversion between object and data source.

This chapter includes the following sections:

6.1 Common Mapping Concepts

This section describes concepts for relational and nonrelational mappings that are unique to EclipseLink:

6.1.1 Mapping Architecture

To define a mapping, you draw upon the following components:

  • The data representation specific to the data source (such as a relational database table or schema-defined XML element) in which you store the object's data.

  • A descriptor for a particular object class.

  • An object class to map.

Note:

A mapping is the same regardless of whether your project is persistent or nonpersistent.

For an example of a typical EclipseLink mapping, see Section 6.1.2, "Mapping Examples".

The type of data source you define in your project determines the type of mappings you can use and how you configure them. In a persistent project, you use mappings to persist to a data source. In a nonpersistent project, you use mappings simply to transform between the object format and some other data representation (such as XML).

A descriptor represents a particular domain object: it describes the object's class. A descriptor also owns the mappings: one mapping for each of the class data members that you intend to persist or transform in memory. For more information about descriptors, see Chapter 5, "Understanding Descriptors".

6.1.2 Mapping Examples

Although EclipseLink supports more complex mappings, most EclipseLink classes map to a single database table or XML element that defines the type of information available in the class. Each object instance of a given class maps to a single row comprising the object's attributes, plus an identifier (the primary key) that uniquely identifies the object.

Figure 6-1 illustrates the simplest database mapping case in which:

  • Table_X in the database represents Class_X.

  • Object_X1 and Object_X2 are instances of Class_X.

  • Individual rows in Table_X represent Object_X1 and Object_X2, as well as any other instances of Class_X.

Figure 6-1 How Classes and Objects Map to a Database Table

Description of Figure 6-1 follows
Description of "Figure 6-1 How Classes and Objects Map to a Database Table"

EclipseLink provides you with the tools to build these mappings, from the simple mappings illustrated in Figure 6-1, to complex mappings.

For an additional example of a relational mapping, see Figure 6-2, "Serialized Object Converter (relational)".

6.1.3 Mapping Converters

If existing EclipseLink mappings do not meet your needs, you can create custom mappings using mapping extensions. These extensions include the following:

Note:

Except for simple type translation, you can use the mapping converters and transformers regardless of whether your data source is relational or nonrelational. Simple type translation is applicable only to XML projects.

6.1.3.1 Serialized Object Converter

The serialized object converter can be used with direct and direct collection mappings, allowing you to map complex objects into binary fields through Java object serialization. Serialized objects are normally stored in RAW or Binary Large Object (BLOB) fields in the database, or HEX or BASE64 elements in an XML document.

Figure 6-2 shows an example of a direct-to-field mappings that uses a serialized object converter. The attribute jobDescription contains a formatted text document that is stored in the JOB_DESC field of the database.

Figure 6-2 Serialized Object Converter (relational)

Description of Figure 6-2 follows
Description of "Figure 6-2 Serialized Object Converter (relational)"

Figure 6-3 demonstrates an example of a nonrelational mapping that uses a serialized object converter. The attribute jobDescription contains a formatted text document that EclipseLink stores in the JOB DESCRIPTION element of an XML schema.

Figure 6-3 Serialized Object Converter (nonrelational)

Description of Figure 6-3 follows
Description of "Figure 6-3 Serialized Object Converter (nonrelational)"

The serialized object converter relies on the Java serializer. Before you map a domain object with the serialized object converter, ensure that the domain object implements the java.io.Serializable interface (or inherits that implementation) and marks all nonserializable fields transient.

6.1.3.2 Type Conversion Converter

The type conversion converter can be used with direct and direct collection mappings, allowing you to map complex objects into binary fields. For example, a Number in the data source can be mapped to a String in Java, or a java.util.Date in Java can be mapped to a java.sql.Date in the data source.

Figure 6-4 illustrates a type conversion mapping (relational). Because the java.util.Date class is stored by default as a Timestamp in the database, it must first be converted to an explicit database type such as java.sql.Date (required only for DB2–most other databases have a single date data type that can store any date or time).

Figure 6-4 Type Conversion Mapping (relational)

Description of Figure 6-4 follows
Description of "Figure 6-4 Type Conversion Mapping (relational) "

Figure 6-5 illustrates a type conversion mapping (nonrelational). java.util.Date object is mapped to a String in a XML schema.

Figure 6-5 Type Conversion Mapping (nonrelational)

Description of Figure 6-5 follows
Description of "Figure 6-5 Type Conversion Mapping (nonrelational)"

You can use a type conversion converter to specify the specific database type when that type must be handled specially for the database. This includes support for the special Oracle JDBC binding options required for NCHAR, NVARCHAR2, and NCLOB fields as well as the special Oracle Thin JDBC insert and update requirements for handling BLOB and CLOB fields greater than 5K.

EclipseLink uses the NCharacter, NClob and NString types in the org.eclipse.persistence.platform.database.oracle package as the converter data type to support the NCHAR, NCLOB and NVARCHAR2 types. EclipseLink uses the java.sql.Blob and Clob types as the converter data type to support BLOB and CLOB values greater than 5K.

You can configure a type conversion converter to map a data source time type (such as TIMESTAMP) to a java.lang.String provided that the String value conforms to the following formats:

  • YYYY/MM/DD HH:MM:SS

  • YY/MM/DD HH:MM:SS

  • YYYY-MM-DD HH:MM:SS

  • YY-MM-DD HH:MM:SS

For more complex String to TIMESTAMP type conversion, consider a transformation mapping (see Section 6.1.4, "Transformation Mapping").

You can also use the @TypeConverter annotation to modify data values during the reading and writing of a mapped attribute. Each TypeConverter must be uniquely named and can be defined at the class, field, and property level, and can be specified within an Entity, MappedSuperclass and Embeddable class. A TypeConverter is always specified by using an @Convert annotation.

You can place a @TypeConverter on a Basic, BasicMap, or BasicCollection mapping. For more information on these annotations, see Java Persistence API (JPA) Extensions Reference for Oracle TopLink.

6.1.3.3 Object Type Converter

The object type converter can be used with direct and direct collection mappings allowing you to match a fixed number of values to Java objects. Use this converter when the values in the schema differ from those in Java.

Figure 6-6 illustrates an object type conversion between the Employee attribute gender and the XML element gender. If the value of the Java object attribute is Female, EclipseLink stores it in the XML element as F.

Figure 6-6 Object Type XML Converter

Description of Figure 6-6 follows
Description of "Figure 6-6 Object Type XML Converter"

You can also perform object type transformations by using the @ObjectTypeConverter annotation. This annotation specifies an org.eclipse.persistence.mappings.converters.ObjectTypeConverter that converts a fixed number of database data value(s) to Java object value(s) during the reading and writing of a mapped attribute. For this annotation you must provide values for the array of conversion values by using the @ConversionValue annotation. For more information, see the descriptions of @ObjectTypeConverter and @ConversionValue in Java Persistence API (JPA) Extensions Reference for Oracle TopLink.

6.1.4 Transformation Mapping

In some special circumstances, existing mapping types and their default Java to data source type handling may be insufficient. In these special cases, you can consider using a transformation mapping to perform specialized translations between how a value is represented in Java and in the data source.

Tip:

Because of the complexity of transformation mappings, it is often easier to perform the transformation with a converter or getter and setter methods of a direct-to-field mapping.

Figure 6-7 illustrates a transformation mapping. The values from the B_DATE and B_TIME fields are used to create a java.util.Date to be stored in the birthDate attribute.

Figure 6-7 Transformation Mappings

Description of Figure 6-7 follows
Description of "Figure 6-7 Transformation Mappings"

A transformation mapping is made up of the following two components:

  • attribute transformer: performs the object attribute transformation at read time

  • field transformer: performs the object attribute-to-field transformation at write time

You can implement a transformer as either a separate class or as a method on your domain object.

Often, a transformation mapping is appropriate when values from multiple fields are used to create an object. This type of mapping requires that you provide an attribute transformation that is invoked when reading the object from the database. This must have at least one parameter that is an instance of Record. In your attribute transformation, you can use Record method get to retrieve the value in a specific column. Your attribute transformation can optionally specify a second parameter, an instance of Session. The Session performs queries on the database to get additional values needed in the transformation. The transformation should return the value to be stored in the attribute.

Transformation mappings also require a field transformation for each field, to be written to the database when the object is saved. The transformation returns the value to be stored in that field.

Within your implementation of the attribute and field transformation, you can take whatever actions are necessary to transform your application data to suit your data source, and vise versa.

You can perform transformation mappings between database columns and attribute values by using the @Transformation annotation. Use this annotation with the @WriteTransformer and @ReadTransformer annotations. The @WriteTransformer annotation is used to transform a single attribute value to a single database column value. For this annotation you have the option of providing an implementation of the FieldTransformer interface. For the @ReadTransformer annotation, you must provide an implementation of the org.eclipse.persistence.mappings.transformers.AttributeTransformer interface. For more information on these annotations, see the descriptions of the @Transformation, @ReadTransformer, and @WriteTransformer in Java Persistence API (JPA) Extensions Reference for Oracle TopLink.

6.2 Object-Relational Mapping Concepts

This section describes concepts for relational mappings that are unique to EclipseLink:

6.2.1 Indirection (Lazy Loading)

By default, when EclipseLink retrieves a persistent object, it retrieves all of the dependent objects to which it refers. When you configure indirection (also known as lazy reading, lazy loading, and just-in-time reading) for an attribute mapped with a relationship mapping, EclipseLink uses an indirection object as a place holder for the referenced object: EclipseLink defers reading the dependent object until you access that specific attribute. This can result in a significant performance improvement, especially if the application is interested only in the contents of the retrieved object, rather than the objects to which it is related.

Oracle strongly recommends using indirection for all relationship mappings. Not only does this lets you optimize data source access, but it also allows EclipseLink to optimize the persistence unit processing, cache access, and concurrency.

Notes:

  • The use of indirection is especially important for providing a proper maintenance of bidirectional relationships. In this case, you must use indirection. If you are operating with collections, you must use transparent indirection (see Section 6.2.4, "Transparent Indirection").

  • The implementation of indirection (lazy loading) is vendor-specific. Serializing entities and merging those entities back into a persistence context may not be interoperable across vendors when lazy properties or fields and/or relationships are used.

Figure 6-8 shows an indirection example. Without indirection, reading the Order object also reads the dependent collection of LineItem objects. With indirection, reading the Order object does not read the dependent collection of LineItem objects: the lineItems attribute refers to an indirection object. You can access other attributes (such as customerId), but EclipseLink reads the dependent LineItem objects only if and when you access the lineItems attribute.

Figure 6-8 EclipseLink Indirection

Description of Figure 6-8 follows
Description of "Figure 6-8 EclipseLink Indirection"

EclipseLink supports the following types of indirection:

When using indirection with an object that your application serializes, you must consider the effect of any untriggered indirection objects at deserialization time. See Section 6.2.2, "Indirection, Serialization, and Detachment".

6.2.2 Indirection, Serialization, and Detachment

When using indirection (lazy loading), it is likely that a graph of persistent objects will contain untriggered indirection objects. Because indirection objects are transient and do not survive serialization between one JVM and another, untriggered indirection objects will trigger an error if the relationship is accessed after deserialization.

The application must ensure that any indirect relationships that will be required after deserialization have been instantiated before serialization. This can be done through accessing the get method for any relationship using ValueHolder or weaved indirection, and by calling the size method to any relationship using transparent indirection. If the application desired the relationships to be always instantiated on serialization, you could overwrite the serialization writeObject method in the persistent class to first instantiate the desired relationships. Use caution for objects with many or deep relationships to avoid serializing large object graphs: ideally, only the relationships required by the client should be instantiated.

When serializing JPA entities, any lazy relationships that have not been instantiated prior to serialization will trigger errors if they are accessed. If weaving is used on the server, and the entities are serialized to a client, the same weaved classes must exist on the client, either through static weaving of the jar, or through launching the client JVM using the EclipseLink agent.

For more information, see Section 3.2.1.4, "Using Java Byte-code Weaving".

6.2.3 Value Holder Indirection

Persistent classes that use indirection must replace relationship attributes with value holder attributes. A value holder is an instance of a class that implements the ValueHolderInterface interface, such as ValueHolder. This object stores the information necessary to retrieve the object it is replacing from the database. If the application does not access the value holder, the replaced object is never read from the database.

To obtain the object that the value holder replaces, use the getValue and setValue methods of the ValueHolderInterface. A convenient way of using these methods is to hide the getValue and setValue methods of the ValueHolderInterface inside get and set methods, as shown in the following illustrations.

Figure 6-9 shows the Employee object being read from the database. The Address object is not read and will not be created unless it is accessed.

Figure 6-9 Address Object Not Read

Description of Figure 6-9 follows
Description of "Figure 6-9 Address Object Not Read"

The first time the address is accessed, as in Figure 6-10, the ValueHolder reads and returns the Address object.

Figure 6-10 Initial Request

Description of Figure 6-10 follows
Description of "Figure 6-10 Initial Request"

Subsequent requests for the address do not access the database, as shown in Figure 6-11.

Figure 6-11 Subsequent Requests

Description of Figure 6-11 follows
Description of "Figure 6-11 Subsequent Requests"

If you are using method access, the get and set methods specified in the mapping must access the instance of ValueHolderInterface, rather than the object referenced by the value holder. The application should not use these getter and setter, but use the getter and setter that hide the usage of value holders.

6.2.4 Transparent Indirection

Transparent indirection lets you declare any relationship attribute of a persistent class that holds a collection of related objects as any of the following Java objects:

  • java.util.Collection

  • java.util.Hastable

  • java.util.List

  • java.util.Map

  • java.util.Set

  • java.util.Vector

EclipseLink will use an indirection object that implements the appropriate interface and also performs just-in-time reading of the related objects. When using transparent indirection, you do not have to declare the attributes as ValueHolderInterface.

Newly created collection mappings use transparent indirection by default if their attribute is not a ValueHolderInterface.

You can configure EclipseLink to automatically weave transparent indirect container indirection for JPA entities and Plain Old Java Object (POJO) classes. For more information, see Section 3.2.1.4, "Using Java Byte-code Weaving" and Section 3.5, "About Weaving."

6.2.5 Proxy Indirection

The Java class Proxy lets you use dynamic proxy objects as place-holders for a defined interface. Certain EclipseLink mappings can be configured to use proxy indirection, which gives you the benefits of indirection without the need to include EclipseLink classes in your domain model. Proxy indirection is to one-to-one relationship mappings as indirect containers are to collection mappings.

To use proxy indirection, your domain model must satisfy all of the following criteria:

  • The target class of the one-to-one relationship must implement a public interface.

  • The one-to-one attribute on the source class must be of the interface type.

  • If you employ method accessing, then the getter and setter methods must use the interface.

Before using proxy indirection, be aware of the restrictions it places on how you use the persistence unit (see Section 6.2.5.1, "Proxy Indirection Restrictions").

To configure proxy indirection, you can use JDeveloper or Java in an amendment method.

6.2.5.1 Proxy Indirection Restrictions

Proxy objects in Java are only able to intercept messages sent. If a primitive operation such as ==, instanceof, or getClass is used on a proxy, it will not be intercepted. This limitation can require the application to be somewhat aware of the usage of proxy objects.

You cannot register the target of a proxy indirection implementation with a persistence unit. Instead, first register the source object with the persistence unit. This lets you retrieve a target object clone with a call to a getter on the source object clone.

6.2.6 Weaved Indirection

For JPA entities or POJO classes that you configure for weaving, EclipseLink weaves value holder indirection for one-to-one mappings. If you want EclipseLink to weave change tracking and your application includes collection mappings (one-to-many or many-to-many), then you must configure all collection mappings to use transparent indirect container indirection only (you may not configure your collection mappings to use eager loading nor value holder indirection).

For more information, see Section 3.2.1.4, "Using Java Byte-code Weaving".

6.2.7 About JPA Mapping Types

To map entity classes to relational tables you must configure a mapping per persistent field. The following sections describe EclipeLink's JPA mapping types:

6.2.7.1 Basic Mappings

Simple Java types are mapped as part of the immediate state of an entity in its fields or properties. Mappings of simple Java types are called basic mappings.

By default, the EclipseLink persistence provider automatically configures a basic mapping for simple types.

Use the following annotations to fine-tune how your application implements these mappings:

For all mapping types there are a common set of options:

  • Read-Only: Specifies that the mapping should populate the value on read and copy. Required when multiple mappings share the same database column.

  • Converters: Allows custom data types and data conversions to be used with most mapping types

    • Annotations: @Converter, @TypeConverter, @ObjectTypeConverter, @StructConverter, @Convert

    • External Metadata: <converter>, <type-converter>, <object-type-converter>, <struct-converter>, <convert>

For more information on these annotations, see Java Persistence API (JPA) Extensions Reference for Oracle TopLink.

6.2.7.2 Default Conversions and Converters

The section "Converter Annotations" in Java Persistence API (JPA) Extensions Reference for Oracle TopLink provides a list of the converter annotation extensions defined by EclipseLink and links to their descriptions.

See the individual converter annotations in Java Persistence API (JPA) Extensions Reference for Oracle TopLink for descriptions of the following:

  • the order in which the EclipseLink persistence provider searches the converter annotations

  • the types of classes for which you can specify converters (you can define converters at the class, field and property level)

  • the mappings with which you can use converters

6.2.7.3 Collection Mappings

You can access additional advanced mappings and mapping options through the EclipseLink descriptor and mapping API using a DescriptorCustomizer class.

6.2.7.3.1 One-to-Many Mapping

One-to-many mappings are used to represent the relationship between a single source object and a collection of target objects. They are a good example of something that is simple to implement in Java using a Collection (or other collection types) of target objects, but difficult to implement using relational databases.

In a Java Collection, the owner references its parts. In a relational database, the parts reference their owner. Relational databases use this implementation to make querying more efficient.

Figure 6-12 One-to-Many Relationships

This figure illustrates the one-to-many relationship.
Description of "Figure 6-12 One-to-Many Relationships"

Note:

The phone attribute shown in the One-to-Many Relationships is of type Vector. You can use a Collection interface (or any class that implements the Collection interface) for declaring the collection attribute.

6.2.7.3.2 JPA Mapping

By default, JPA automatically defines a OneToMany mapping for a many-valued association with one-to-many multiplicity.

Use the @OneToMany annotation to do the following:

  • configure the fetch type to EAGER

  • configure the associated target entity, because the Collection used is not defined using generics

  • configure the operations that must be cascaded to the target of the association: for example, if the owning entity is removed, ensure that the target of the association is also removed

  • configure the details of the join table used by the persistence provider for unidirectional one-to-many relationships. For a one-to-many using a mappedBy or JoinColumn, the deletion of the related objects is cascaded on the database. For a one-to-many using a JoinTable, the deletion of the join table is cascaded on the database (target objects cannot be cascaded even if private because of constraint direction).

For more information, see Section 11.1.23 "JoinTable Annotation" in the JPA Specification.

http://jcp.org/en/jsr/detail?id=338

6.2.7.3.3 Many-to-Many Mapping

Many-to-many mappings represent the relationships between a collection of source objects and a collection of target objects. They require the creation of an intermediate table for managing the associations between the source and target records.

Figure 6-13 illustrates a many-to-many mapping in Java and in relational database tables.

Figure 6-13 Many-to-Many Relationships

Many-to-many Relationships
Description of "Figure 6-13 Many-to-Many Relationships"

Note:

For the projects attribute shown in the Many-to-many Relationships you can use a Collection interface (or any class that implements the Collection interface) for declaring the collection attribute.

6.2.7.3.4 JPA Mapping

By default, JPA automatically defines a many-to-many mapping for a many-valued association with many-to-many multiplicity.

Use the @ManyToMany annotation to do the following:

  • configure the FetchType to EAGER

  • configure the mapping to forbid null values (for nonprimitive types) in case null values are inappropriate for your application

  • configure the associated target entity because the Collection used is not defined using generics

  • configure the operations that must be cascaded to the target of the association (for example, if the owning entity is removed, ensure that the target of the association is also removed)

For a list of supported attributes for the @ManyToMany annotation, see the Java Persistence specification:

http://jcp.org/en/jsr/detail?id=338

6.2.7.3.5 Using Indirection with Collections

JPA specifies that lazy loading is a hint to the persistence provider that data should be fetched lazily when it is first accessed, if possible. If you are developing your application in a Java EE environment, set fetch to javax.persistence.FetchType.LAZY, and the persistence provider supplies all the necessary functionality.

When using a one-to-one or many-to-one mapping in a Java SE environment, use either dynamic or static weaving to perform lazy loading when the fetch attribute is set to FetchType.LAZY. Also in the Java SE environment, one-to-many and many-to-many relationships are lazy by default and use transparent indirection, while one-to-one and many-to-one relationships are not lazy.

When using a one-to-one or many-to-one mapping in a Java SE environment and the environment does not permit the use of -javaagent on the JVM command line, use static weaving to perform lazy loading when the fetch attribute is set to FetchType.LAZY.

If you set one-to-one or many-to-one relationships to lazy, and you enable weaving, the EclipseLink JPA persistence provider will use weaving to enable value holder indirection for these relationships.

The collection annotations @OneToOne, @OneToMany, @ManyToMany, and @ManyToOne provide a fetch mapping attribute which can be set to lazy or eager. When you set the attribute to lazy, the EclipseLink JPA persistence provider uses indirection.

Table 6-1 lists support for lazy loading by mapping type.

Table 6-1 Support for Lazy Loading by Mapping Type

Mapping Java EE Java SE

Many-to-many

Lazy loading is performed when the fetch attribute is set to javax.persistence.FetchType.LAZY (default).

Lazy loading is performed when the fetch attribute is set to javax.persistence.FetchType.LAZY (default).

One-to-many

Lazy loading is performed when the fetch attribute is set to javax.persistence.FetchType.LAZY (default).

Lazy loading is performed when the fetch attribute is set to javax.persistence.FetchType.LAZY (default).

One-to-one

Lazy loading is performed when the fetch attribute is set to javax.persistence.FetchType.LAZY.

The fetch attribute is ignored and default javax.persistence.FetchType.EAGER applies.

Many-to-one

Lazy loading is performed when the fetch attribute is set to javax.persistence.FetchType.LAZY.

The fetch attribute is ignored and default javax.persistence.FetchType.EAGER applies

Basic

Lazy loading is performed when the fetch attribute is set to javax.persistence.FetchType.LAZY.

The fetch attribute is ignored and default javax.persistence.FetchType.EAGER applies


6.2.7.4 Using Optimistic Locking

Oracle recommends using optimistic locking. With optimistic locking, all users have read access to the data. When a user attempts to write a change, the application checks to ensure the data has not changed since the user read the data.

6.2.7.4.1 Optimistic Locking in a Stateless Environment

In a stateless environment, take care to avoid processing out-of-date (stale) data. A common strategy for avoiding stale data is to implement optimistic locking, and store the optimistic lock values in the object. This solution requires careful implementation if the stateless application serializes the objects, or sends the contents of the object to the client in an alternative format. In this case, transport the optimistic lock values to the client in the HTTP contents of an edit page. You must then use the returned values in any write transaction to ensure that the data did not change while the client was performing its work.

You can use optimistic version locking or optimistic field locking policies. Oracle recommends using version locking policies.

6.2.7.4.2 Optimistic Version Locking

Use the @Version annotation to enable the JPA-managed optimistic locking by specifying the version field or property of an entity class that serves as its optimistic lock value (recommended).

When choosing a version field or property, ensure that the following is true:

  • there is only one version field or property per entity

  • you choose a property or field persisted to the primary table

  • your application does not modify the version property or field

For more information, see Section 11.1.45 "Table Annotation" in the JPA Specification.

http://jcp.org/en/jsr/detail?id=338

Note:

The field or property type must either be a numeric type (such as Number, long, int, BigDecimal, and so on), or a java.sql.Timestamp. EclipseLink recommends using a numeric type.

The @Version annotation does not have attributes. The @Version annotation allows you to use EclipseLink converters. See Section 6.2.7.2, "Default Conversions and Converters."

For more information, see Section 11.1.9 "Column Annotation" in the JPA Specification.

http://jcp.org/en/jsr/detail?id=338

6.3 MOXy Mapping Concepts

XML mappings transform object data members to the XML elements of an XML document whose structure is defined by an XML Schema Document (XSD). You can map the attributes of a Java object to a combination of XML simple and complex types using a wide variety of XML mapping types.

Classes are mapped to complex types, object relationships map to XML elements, and simple attributes map to text nodes and XML attributes. The real power in using MOXy is that when mapping an object attribute to an XML document, XPath statements are used to specify the location of the XML data.

EclipseLink stores XML mappings for each class in the class descriptor. EclipseLink uses the descriptor to instantiate objects mapped from an XML document and to store new or modified objects as XML documents.

EclipseLink provides XML mappings that are not defined in the JAXB specification. Some of the MOXy extensions are available through EclipseLink annotations; others require programmatic changes to the underlying metadata.

Mapping concepts for MOXy are described in Developing JAXB Applications Using Oracle TopLink. See the following chapters:

"EclipseLink MOXy Runtime" describes:

  • the EclipseLink XML Bindings document, which is an alternative to the JAXB annotations. Not only can XML Bindings separate your mapping information from your actual Java class, it can also be used for more advanced metadata

  • the several different bootstrapping options that you can use when creating your JAXBContext.

  • the MetadataSource interface, which is responsible for serving up EclipseLink metadata. Providing an implementation of this interface allows you to store mapping information outside of your application and have it retrieved when the application's JAXBContext is being created or refreshed.

  • schema generation and validation.

  • the several mechanisms by which you can get event callbacks during the marshalling and unmarshalling processes. You can specify callback methods directly on your mapped objects, or define separate Listener classes and register them with the JAXB runtime

  • querying objects by XPath. This is an alternative to using conventional Java access methods to get and set your object's values. EclipseLink MOXy allows you to access values using an XPath statement. There are special APIs on EclipseLink's JAXBContext to allow you to get and set values by XPath.

  • the use of the JAXB Binder interface, which allows you to preserve an entire XML document, even if only some of the items are mapped.

"Mapping Type Levels" describes the initial tasks of setting up a mapping in MOXy:

  • the default root element, which tells EclipseLink what the top-level root of your XML document will be.

  • namespace information for the Java class, and that all of the elements must be qualified for the namespace. You can namespace-qualify the elements on the package, type, or field/property level.

  • the ways in which you can specify inheritance hierarchy in XML by using xsi:type attribute, substitution groups, or the MOXY-specific @XmlDiscriminatorNode and @XmlDiscriminatorValue annotations

"Mapping Simple Values" and "Mapping Special Schema Types" describes how Java values can be mapped to XML in several different ways:

  • Java values can be mapped to XML attributes, text nodes, schema types, or simple type translators

  • collections of simple Java values can be mapped to text nodes, text nodes within a grouping element, list elements, or a collection of XmlAttributes or XmlValues

  • multiple Java mappings can be created for a single property using OXM metadata, with the caveat that at most one mapping will be readable (the rest will be "write-only")

  • Java enums can be mapped to XML using the @XmlEnum and @XmlEnumValue annotations

  • dates and time: EclipseLink MOXy supports the following types which are not covered in the JAXB specification: java.sql.Date java.sql.Time , and java.sql.Timestamp.

  • union files: When EclipseLink unmarshalls the XML document, such as an XML Schema Union, it tries each of the union types until it can make a successful conversion. Currently, EclipseLink does not support the mapping of Unions using Annotations or OXM Metadata. However, an EclipseLink XML Customizer can be used to create the mapping.

  • binary types: EclipseLink supports marshalling and unmarshalling binary data in two different representation formats: base64Binary (default) and hexBinary. You can specify the desired binary format using the @XmlSchemaType annotation, or <xml-schema-type> element in EclipseLink OXM.

6.3.1 Understanding an XML Data Representation

Annotations are 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 tweak the metadata for future versions.

    • You use the standard JAXB annotations, and use the XML metadata for the MOXy extensions. In this way you don't 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.

6.3.2 Mapping Values

There are several ways to map simple Java values and collections of simple values directly to XML text nodes. You can map to attributes, text nodes, or schema types. You can also use simple type translators to map types of nodes that are not defined in your XML schema. These techniques are described in "Mapping Simple Values" in Developing JAXB Applications Using Oracle TopLink.

6.3.3 Marshalling and Unmarshalling a Subset of Attributes in MOXy

In object-relational mapping, EclipseLink defines FetchGroups and AttributeGroups to control which attributes of a given object are to be written out and read in.

In the current MOXy/JAXB release, you can now configure a subset of object attributes to be marshaled and unmarshaled. To do this, you use a set of annotations to set up attribute groups on the descriptor. The annotations are: XmlNamedObjectGraphs, XmlNamedObjectGraph, XmlNamedAttributeNode, and XmlNamedSubGraph. Note that they use Xml prefix to differentiate them from the equivalent JPA annotations.

The @XmlNamedObjectGraph extension is used to specify subsets of the model you want to marshal or unmarshal. This is done by specifying one or more @XmlNamedAttributeNode annotations. If you want an object graph applied to a property you can specify a subgraph for it. The subgraph can either be defined with the @XmlNamedSubgraph or with the @XmlNamedObjectGraph annotation on the target class.

A set of interfaces have also been defined to allow for the creation of ObjectGraphs dynamically at runtime. These ObjectGraphs can be set on the Marshaller or Unmarshaller instead of the name of a pre-defined ObjectGraph. The interfaces are: ObjectGraph, Subgraph, and AttributeNode. Methods have been included in the JAXBContext class to create a new instance of ObjectGraph.

6.3.4 @XmlInverseReference is Writable in Both Directions

The MOXy @XmlInverseReference annotation enables you to map a back pointer during the unmarshal operation (useful when mapping JPA entities). However, it acts like @XmlTransient during the marshal operation. This means that in previous releases, the mapping could only be used in one direction. In the current release, you can now make properties writable during the marshalling operation by pairing the @XmlInverseReference annotation with the @XmlElement annotation. This enables the mapping to be used in both directions.

6.4 Object-JSON Mapping Concepts

EclipseLink MOXy supports the ability to convert objects to and from JSON (JavaScript Object Notation). This feature is useful when creating RESTful services; JAX-RS services can accept both XML and JSON messages.

EclipseLink supports all MOXy object-to-XML options when reading and writing JSON, including:

  • EclipseLink's advanced and extended mapping features (in addition to the JAXB specification)

  • Storing mappings in external bindings files

  • Creating dynamic models with Dynamic JAXB

  • Building extensible models that support multitenant applications

EclipseLink provides the following support for mapping JSON documents:

  • JSON bindings that do not require compile time dependencies, in addition to those required for normal JAXB use. You can also write MOXy External Bindings files as JSON documents.

  • Although XML has a single datatype, JSON differentiates between strings, numbers, and booleans. EclipseLink supports these datatypes automatically.

  • JSON does not use attributes; anything mapped with a @XmlAttribute annotation will be marshalled as an element. By default, EclipseLink triggers both the attribute and element events, thereby allowing either the mapped attribute or element to handle the value.

  • EclipseLink supports JSON documents without a root element. By default, if no @XmlRootElement annotation exists, the marshalled JSON document will not have a root element. With EclipseLink, you can override this behavior (that is, omit the root element from the JSON output).

  • Because JSON does not use namespaces, all namespaces and prefixes are ignored by default when marshaling and unmarshaling. With EclipseLink, you can supply a Map of namespace-to-prefix (or an instance of NamespacePrefixMapper) to the marshaller and unmarshaller. The namespace prefix will appear in the marshalled document prepended to the element name.

  • By default, when marshalling to JSON, EclipseLink marshals empty collections as [ ], EclipseLink allows you to override this behavior, so that empty collections are not marshalled at all.

  • You can marshal and unmarshal root-level collections.

For more information on EclipseLink support for JSON documents, see "Using JSON Documents" in Developing JAXB Applications Using Oracle TopLink

6.4.1 Collection Mapping to both XML and JSON

By default, a JAXB implementation will not output a grouping element around collection data. However, you can accomplish this by using the @XmlElementWrapper annotation as the JSON key. This grouping element often has a plural name and is a better fit for the key of a JSON array than the repeating element defined by the @XmlElement annotation.

6.5 About JSON with Padding

JSONP or "JSON with padding" is a communication technique used in JavaScript programs which run in Web browsers. It provides a way to request data from a server in a different domain, something prohibited by typical web browsers because of the same origin policy.

The usage pattern, known as JSONP, uses the open policy of the <script> element to retrieve JavaScript code that operates on dynamically-generated JSON-formatted data from other origins. Requests for JSONP do not retrieve JSON, but arbitrary JavaScript code. They are evaluated by the JavaScript interpreter, not parsed by a JSON parser.

6.6 Extending JAX-RS Implementations

MOXy includes an implementation of the MessageBodyReader and MessageBodyWriter classes called MOXyJsonProvider. The MOXyJsonProvider class can be used to enable EclipseLink JAXB (MOXy) as the JSON provider. This class can be used directly or extended to make JAX-RS integration even easier. The following enhancements have been made to the MOXyJsonProvider class:

  • The genericType parameter in the readFrom and writeTo methods can now accept a value of null.

  • The final key word has been removed from readFrom and writeTo methods.

  • The value APPLICATION_JSON has been added as a supported media type in addition to WILD_CARD.