© Mike Keith, Merrick Schincariol, Massimo Nardone 2018
Mike Keith, Merrick Schincariol and Massimo NardonePro JPA 2 in Java EE 8https://doi.org/10.1007/978-1-4842-3420-4_13

13. XML Mapping Files

Mike Keith1 , Merrick Schincariol2 and Massimo Nardone3
(1)
Ottawa, Ontario, Canada
(2)
RR 3, RR 3, Almonte, Ontario, Canada
(3)
Helsinki, Finland
 

Back in the early days, after the release of Java SE 5, there was a quiet, and sometimes not-so-quiet, debate about whether annotations were better or worse than XML. The defenders of annotations vigorously proclaimed how annotations are so much simpler and provide in-lined metadata that is co-located with the code that it is describing. The claim was that this avoids the need to replicate the information that is inherent in the source code context of where the metadata applies. The XML proponents then retorted that annotations unnecessarily couple the metadata to the code, and that changes to metadata should not require changes to the source code.

The truth is that both sides were right, and there are appropriate times for using annotation metadata and other times for using XML. When the metadata really is coupled to the code, it does make sense to use annotations because the metadata is just another aspect of the program. For example, specification of the identifier field of an entity is not only a relevant piece of information to the provider but also a necessary detail known and assumed by the referencing application code. Other kinds of metadata, such as which column a field is mapped to, can be safely changed without needing to change the code. This metadata is akin to configuration metadata and might be better expressed in XML, where it can be configured according to the usage pattern or execution environment.

The arguments also tended to unfairly compartmentalize the issue because in reality it goes deeper than simply deciding when it might make sense to use one type of metadata or another. In many talks and forums before the release of the JPA 1.0 specification, we asked people whether they planned on using annotations or XML, and we consistently saw that there was a split. The reason was that there were other factors that have nothing to do with which is better, such as existing development processes, source control systems, developer experience, and so forth.

Now that developers have a few years of using annotations under their belts there is not nearly the same hesitation to embed annotations in their code as there once was. In fact, most people are perfectly happy with annotations, making their acceptance pretty much a fait accompli. Nevertheless, there are still use cases for employing XML, so we continue to describe and illustrate how mapping metadata is allowed to be specified in either format. In fact, XML mapping usage is defined to allow annotations to be used and then overridden by XML. This provides the ability to use annotations for some things and XML for others, or to use annotations for an expected configuration but then supply an overriding XML file to suit a particular execution environment. The XML file might be sparse and supply only the information that is being overridden. You will see later on in this chapter that the granularity with which this metadata can be specified offers a good deal of object-relational mapping flexibility.

The persistence.xml and orm.xml mapping files and schemas were updated in JPA version 2.2.
  • The persistence.xml file defines a persistence unit and is located in the META-INF directory of the root of the persistence unit.

  • The orm.xml file, contained in the META-INF directory of the root of the persistence unit, includes the managed persistence classes used to take the form of annotations of the object-relational mapping information. The orm.xml mapping file or other mapping file will be loaded as a resource by the persistence provider.

Note

The JPA versions 2.1 and 2.2 request that the XML file mappings, such as persistence.xml and orm.xml, be located in the Java classpath.

JPA 2.2 version says:
  • “An object/relational mapping XML file named orm.xml may be specified in the META-INF directory in the root of the persistence unit or in the META-INF directory of any JAR file referenced by the persistence.xml.”

Notice that we can add more mapping files which may be present anywhere on the classpath and the ClassLoader can load them as resources.

Over the course of this chapter, we describe the structure and content of the mapping file and how it relates to the metadata annotations. We also discuss how XML mapping metadata can combine with and override annotation metadata. We have tried to structure the chapter in a format that will allow it to be used as both a source of information and a reference for the mapping file format.

The Metadata Puzzle

The rules of XML and annotation usage and overriding can be a little confusing to say the least, especially given the permutation space of mixing annotations with XML. The trick to understanding the semantics, and being able to properly specify metadata the way that you would like it to be specified, is to understand the metadata collection process. Once you have a solid understanding of what the metadata processor does, you will be well on your way to understanding what you need to do to achieve a specific result.

The provider can choose to perform the metadata gathering process in any way it chooses, but the result is that it must honor the requirements of the specification. Developers understand algorithms, so we decided that it would be easier to understand if we presented the logical functionality as an algorithm, even though the implementation might not actually implement it this way. The following algorithm can be considered as the simplified logic for obtaining the metadata for the persistence unit:
  1. 1.

    Process the annotations. The set of entities, mapped superclasses, and embedded objects (we call this set E) is discovered by looking for the @Entity, @MappedSuperclass, and @Embeddable annotations. The class and method annotations in all the classes in set E are processed, and the resulting metadata is stored in set C. Any missing metadata that was not explicitly specified in the annotations is left empty.

     
  2. 2.

    Add the classes defined in XML. Look for all the entities, mapped superclasses, and embedded objects that are defined in the mapping files and add them to E. If we find that one of the classes already exists in E, we apply the overriding rules for class-level metadata that we found in the mapping file. Add or adjust the class-level metadata in C according to the overriding rules.

     
  3. 3.

    Add the attribute mappings defined in XML. For each class in E, look at the fields or properties in the mapping file and try to add the method metadata to C. If the field or property already exists there, apply the overriding rules for attribute-level mapping metadata.

     
  4. 4.

    Apply defaults. Determine all default values according to the scoping rules and where defaults might have been defined (see the following for description of default rules). The classes, attribute mappings, and other settings that have not yet been filled in are assigned values and put in C.

     

Some of the following cases might cause this algorithm to be modified slightly, but in general this is what will logically happen when the provider needs to obtain the mapping metadata.

You already learned in the mapping chapters that annotations might be sparse and that not annotating a persistent attribute will usually cause it to default to being mapped as a basic mapping. Other mapping defaults were also explained, and you saw how much easier they made configuring and mapping entities. You will notice in our algorithm that the defaults are applied at the end, so the same defaults that you saw for annotations will be applied when using mapping files as well. It should be of some comfort to XML users that mapping files might be sparsely specified in the same way as annotations. They also have the same requirements for what needs to be specified; for example, an identifier must be specified, a relationship mapping must have at least its cardinality specified, and so forth.

The Mapping File

By this point, you are well aware that if you don’t want to use XML for mapping, you don’t need to use XML. In fact, as you will see in Chapter 14, any number of mapping files, or none, might be included in a persistence unit. If you do use one, however, each mapping file that is supplied must conform and be valid against the XSD (XML Schema Definition) schema file.

Note

When using a JPA 1.0, JPA 2.0, or JPA 2.1 implementation, the schema will be orm_1_0.xsd, orm_2_0.xsd or orm_2_1.xsd respectively, located at http://xmlns.jcp.org/xml/ns/persistence/ . When using JPA 2.2, the schema will instead be named persistence_2_2.xsd. It will be located as before at http://xmlns.jcp.org/xml/ns/persistence/ .

This schema defines a namespace called http://xmlns.jcp.org/xml/ns/persistence/orm that includes all the ORM elements that can be used in a mapping file. A typical XML header for a mapping file is shown in Listing 13-1. You will notice that it refers that the the XML schema file may be named META-INF/orm.xml in the persistence archive or it may be named some other name, which would be used to locate the file as resource on the classpath.

<?xml version="1.0" encoding="UTF-8" ?>
<persistence xmlns="http://xmlns.jcp.org/xml/ns/persistence"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence
    http://xmlns.jcp.org/xml/ns/persistence/persistence_2_2.xsd"
    version="2.2">
<xsd:annotation>
   <xsd:documentation>
      @(#)orm_2_2.xsd 2.2 July 7 2017
        </xsd:documentation>
</xsd:annotation>
<xsd:annotation>
   <xsd:documentation><![CDATA[
   This is the XML Schema for the persistence object/relational mapping file.
   The file may be named "META-INF/orm.xml" in the persistence
   archive or it may be named some other name which would be
   used to locate the file as resource on the classpath.
   Object/relational mapping files must indicate the object/relational
   mapping file schema by using the persistence namespace:
   http://xmlns.jcp.org/xml/ns/persistence/orm
   and indicate the version of the schema by
   using the version element as shown below:
   <entity-mappings xmlns="http://xmlns.jcp.org/xml/ns/persistence/orm"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence/orm
      http://xmlns.jcp.org/xml/ns/persistence/orm_2_2.xsd"
      version="2.2">
      ...
   </entity-mappings>
    ]]></xsd:documentation>
</xsd:annotation>
Listing 13-1

XML Header for Mapping File

The root element of the mapping file is called entity-mappings . All object-relational XML metadata is contained within this element, and as seen in the example, the header information is also specified as attributes in this element. The subelements of entity-mappings can be categorized into four main scoping and functional groups: persistence unit defaults, mapping files defaults, queries and generators, and managed classes and mappings. There is also a special setting that determines whether annotations should be considered in the metadata for the persistence unit. These groups are discussed in the following sections. For the sake of brevity, we won’t include the header information in the XML examples in these sections.

Disabling Annotations

For those who are perfectly happy with XML and don’t feel the need for annotations, there are ways to skip the annotation processing phase (Step 1 in the previous algorithm). The xml-mapping-metadata-complete element and metadata-complete attribute provide a convenient way to reduce the overhead that is required to discover and process all the annotations on the classes in the persistence unit. It is also a way to effectively disable any annotations that do exist. These options will cause the processor to completely ignore them as if they did not exist at all.

xml-mapping-metadata-complete

When the xml-mapping-metadata-complete element is specified, all annotations in the entire persistence unit will be ignored, and only the mapping files in the persistence unit will be considered as the total set of provided metadata. Only entities, mapped superclasses, and embedded objects that have entries in a mapping file will be added to the persistence unit.

The xml-mapping-metadata-complete element needs to be in only one of the mapping files if there are multiple mapping files in the persistence unit. It is specified as an empty subelement of the persistence-unit-metadata element, which is the first1 subelement of entity-mappings. An example of using this setting is shown in Listing 13-2.

<entity-mappings>
    <persistence-unit-metadata>
        <xml-mapping-metadata-complete/>
    </persistence-unit-metadata>
    ...
</entity-mappings>
Listing 13-2

Disabling Annotation Metadata for the Persistence Unit

If enabled, there is no way to portably override this setting. It will apply globally to the persistence unit, regardless of whether any metadata-complete attribute is set to false in an entity.

metadata-complete

The metadata-complete attribute is an attribute on the entity, mapped-superclass, and embeddable elements. If specified, all annotations on the specified class and on any fields or properties in the class will be ignored, and only the metadata in the mapping file will be considered as the set of metadata for the class.

Caution

Annotations defining queries, generators, or result set mappings are ignored if they are defined on a class that is marked as metadata-complete in an XML mapping file.

When metadata-complete is enabled, the same rules that we applied to annotated entities will still apply when using XML-mapped entities. For example, the identifier must be mapped, and all relationships must be specified with their corresponding cardinality mappings inside the entity element.

An example of using the metadata-complete attribute is shown in Listing 13-3. The entity mappings in the annotated class are disabled by the metadata-complete attribute, and because the fields are not mapped in the mapping file, the default mapping values will be used. The name and salary fields will be mapped to the NAME and SALARY columns, respectively.

@Entity
public class Employee {
    @Id private int id;
    @Column(name="EMP_NAME")
    private String name;
    @Column(name="SAL")
    private long salary;
    // ...
}
Listing 13-3

Disabling Annotations for a Managed Class

Here is an orm.xml snippet:

<entity-mappings>
    ...
    <entity class="examples.model.Employee"
            metadata-complete="true">
        <attributes>
            <id name="id"/>
        </attributes>
    </entity>
    ...
</entity-mappings

Persistence Unit Defaults

One of the conditions for using annotation metadata is that we need to have something to annotate. If we want to define metadata for a persistence unit, we are in the unfortunate position of not having anything to annotate because a persistence unit is just a logical grouping of Java classes, basically a configuration. This brings us back to the discussion we had earlier when we decided that if metadata is not coupled to code, maybe it shouldn’t really be in the code. These are the reasons why persistence unit metadata can be specified only in an XML mapping file.

In general, a persistence unit default means that whenever a value for that setting is not specified at a more local scope, the persistence unit default value will apply. It is a convenient way to set default values that will apply to all entities, mapped superclasses, and embedded objects in the entire persistence unit, be they in any of the mapping files or annotated classes. The default values will not be applied if a value is present at any level below the persistence unit. This value can be in the form of a mapping file default value, some value in an entity element, or an annotation on one of the managed classes or persistent fields or properties.

The element that encloses all the persistence unit level defaults is the aptly named persistence-unit-defaults element. It is the other subelement of the persistence-unit-metadata element (after xml-mapping-metadata-complete). If more than one mapping file exists in a persistence unit, only one of the files should contain these elements.

There are six settings that can be configured to have default values for the persistence unit. They are specified using the schema, catalog, delimited-identifiers, access, cascade-persist, and entity-listeners elements.

schema

The schema element is useful if you don’t want to have to specify a schema in every @Table, @SecondaryTable, @JoinTable, @CollectionTable, or @TableGenerator annotation; or table, secondary-table, join-table, collection-table, or table-generator XML element in the persistence unit. When set here, it will apply to all tables in the persistence unit, whether they were actually defined or defaulted by the provider. The value of this element can be overridden by any of the following:
  • schema element defined in the mapping file defaults (see the “Mapping File Defaults” section)

  • schema attribute on any table, secondary-table, join-table, collection-table, sequence-generator, or table-generator element in a mapping file

  • schema defined within a @Table, @SecondaryTable, @JoinTable, @CollectionTable, @SequenceGenerator, or @TableGenerator annotation; or in a @TableGenerator annotation (unless xml-mapping-metadata-complete is set)

Listing 13-4 shows an example of how to set the schema for all the tables in the persistence unit that do not already have their schema set.

<entity-mappings>
    <persistence-unit-metadata>
        <persistence-unit-defaults>
            <schema>HR</schema>
        </persistence-unit-defaults>
    </persistence-unit-metadata>
    ...
</entity-mappings>
Listing 13-4

Setting the Default Persistence Unit Schema

catalog

The catalog element is exactly analogous to the schema element, but it is for databases that support catalogs. It can be used independently whether schema is specified or not, has the same behavior as schema, and is overridden in exactly the same ways. The exact same rules can be applied to the catalog mapping file default as described in the preceding schema section.

delimited-identifiers

The delimited-identifiers element causes database table, schema, and column identifiers used in the persistence unit, defined in annotation form, XML, or defaulted, to be delimited when sent to the database (refer to Chapter 10 for more on delimited identifiers). It cannot be disabled locally, so it is important to have a full understanding of the consequences before enabling this option. If an annotation or XML element is locally delimited with quotes, they will be treated as part of the identifier name.

No value or text is included in the delimited-identifiers element. Only the empty element should be specified within the persistence-unit-defaults element to enable persistence unit identifier delimiting.

access

The access element that is defined in the persistence-unit-defaults section is used to set the access type for all the managed classes in the persistence unit that have XML entries but are not annotated. Its value can be either FIELD or PROPERTY, indicating how the provider should access the persistent state.

The access setting is a subtly different default that does not affect any of the managed classes that have annotated fields or properties. It is a convenience for when XML is used and obviates having to specify the access for all the entities listed in all the XML mapping files.

This element affects only the managed classes defined in the mapping files because a class with annotated fields or properties is considered to have overridden the access mode by virtue of its having annotations placed on its fields or properties. If the xml-mapping-metadata-complete element is enabled, the persistence unit access default will be applied to these annotated classes that have entries in XML. Put another way, the annotations that would have otherwise overridden the access mode would no longer be considered, and the XML defaults, including the default access mode, would be applied.

The value of this element can be overridden by one or more of the following:
  • access element defined in the mapping file defaults (see the “Mapping File Defaults” section)

  • access attribute on any entity, mapped-superclass, or embeddable element in a mapping file

  • access attribute on any basic, id, embedded-id, embedded, many-to-one, one-to-one, one-to-many, many-to-many, element-collection, or version element in a mapping file

  • @Access annotation on any entity, mapped superclass, or embeddable class

  • @Access annotation on any field or property in an entity, mapped superclass, or embedded object

  • An annotated field or property in an entity, mapped superclass, or embedded object

Listing 13-5 shows an example of setting the access mode to PROPERTY for all the managed classes in the persistence unit that do not have annotated fields.

<entity-mappings>
    <persistence-unit-metadata>
        <persistence-unit-defaults>
            <access>PROPERTY</access>
        </persistence-unit-defaults>
    </persistence-unit-metadata>
    ...
</entity-mappings>
Listing 13-5

Setting the Default Access Mode for the Persistence Unit

cascade-persist

The cascade-persist element is unique in a different way. When the empty cascade-persist element is specified, it is analogous to adding the PERSIST cascade option to all the relationships in the persistence unit. Refer to Chapter 6 for a discussion about the cascade options on relationships.

The term “persistence-by-reachability" is often used to signify that when an object is persisted, all the objects that are reachable from that object are also automatically persisted. The cascade-persist element provides the persistence-by-reachability semantics that some people are used to having. This setting cannot currently be overridden, the assumption being that when somebody is accustomed to persistence-by-reachability semantics they don’t normally want to be turning it off. If more fine-grained control over cascading of the persist operation is needed, this element should not be specified, and the relationships should have the PERSIST cascade option specified locally.

An example of using the cascade-persist element is shown in Listing 13-6.

<entity-mappings>
    <persistence-unit-metadata>
        <persistence-unit-defaults>
            <cascade-persist/>
        </persistence-unit-defaults>
    </persistence-unit-metadata>
    ...
</entity-mappings>
Listing 13-6

Configuring for Persistence-by-Reachability Semantics

entity-listeners

This is the only place where a list of default entity listeners can be specified. A default entity listener is a listener that will be applied to every entity in the persistence unit. They will be invoked in the order that they are listed in this element, before any other listener or callback method is invoked on the entity. It is the logical equivalent of adding the listeners in this list to the front of the @EntityListeners list in the root superclass. We discussed entity listeners in the last chapter, so refer to Chapter 12 to review the order of invocation if you need to. A description of how to specify an entity listener is given in the “Entity Listeners" section of that chapter.

The entity-listeners element is composed of zero or more entity-listener elements that each defines an entity listener. They can be overridden or disabled in either of the following two ways:
  • exclude-default-listeners element in an entity or mapped-superclass mapping file element

  • @ExcludeDefaultListeners annotation on an entity or mapped superclass (unless xml-mapping-metadata-complete is set)

Mapping File Defaults

The next level of defaults, after the ones defined for the entire persistence unit, are those that pertain only to the entities, mapped superclasses, and embedded objects that are contained in a particular mapping file. In general, if there is a persistence unit default defined for the same setting, this value will override the persistence unit default for the managed classes in the mapping file. Unlike the persistence unit defaults, the mapping file defaults do not affect managed classes that are annotated and not defined in the mapping file. In terms of our algorithm, the defaults in this section apply to all the classes of C that have entries in the mapping file.

The mapping file defaults consist of four optional subelements of the entity-mappings element. They are package, schema, catalog, and access; and they follow the persistence-unit-metadata element.

package

The package element is intended to be used by developers who don’t want to have to repeat the fully qualified class name in all the mapping file metadata. It can be overridden in the mapping file by fully qualifying a class name in any element or attribute in which a class name is expected. They are the following:
  • class attribute of id-class, entity-listener, entity, mapped-superclass, or embeddable elements

  • target-entity attribute of many-to-one, one-to-one, one-to-many, and many-to-many elements

  • target-class attribute of element-collection element

  • result-class attribute of named-native-query element

  • entity-class attribute of entity-result element

An example of using this element is shown in Listing 13-7. We set the default mapping file package name to examples.model for the entire mapping file and can just use the unqualified Employee and EmployeePK class names throughout the file. The package name will not be applied to OtherClass, though, because it is already fully specified.

<entity-mappings>
    <package>examples.model</package>
    ...
    <entity class="Employee">
        <id-class class="EmployeePK"/>
        ...
    </entity>
    <entity class="examples.tools.OtherClass">
        ...
    </entity>
    ...
</entity-mappings>
Listing 13-7

Using the package Element

schema

The schema element will set a default schema to be assumed for every table, secondary table, join table, or table generator defined or defaulted within the mapping file. This element can be overridden by the specification of the schema attribute on any table, secondary-table, join-table, collection-table, sequence-generator, or table-generator element in the mapping file.

Listing 13-8 shows the mapping file schema default set to HR, so the EMP table that Employee is mapped to is assumed to be in the HR schema.

<entity-mappings>
    <package>examples.model</package>
    <schema>HR</schema>
    ...
    <entity class="Employee">
        <table name="EMP"/>
        ...
    </entity>
    ...
</entity-mappings>
Listing 13-8

Using the schema Element

The mapping file schema default will also affect the @Table, @SecondaryTable, @JoinTable, @CollectionTable, @SequenceGenerator, and @TableGenerator annotations on classes that have entries in the mapping file. For example, because Employee is listed in the mapping file, it becomes part of the set of classes to which the default applies. If there was a @TableGenerator(name="EmpGen", table="IDGEN") annotation on Employee, the mapping file default will be applied to it, and the IDGEN table will be assumed to be in the HR schema.

catalog

The catalog element is again exactly analogous to the schema element, but it is for databases that support catalogs. It can be used independently of whether schema is specified or not, has the same behavior as schema at the mapping file default level, and is overridden in exactly the same ways. As we mentioned in the persistence unit section, the exact same rules can be applied to the catalog mapping file default, as described in the schema mapping file default section.

access

Setting a particular access mode as the mapping file default value affects only the managed classes that are defined in the mapping file. The default mapping file access mode can be overridden by one or more of the following:
  • access attribute on any entity, mapped-superclass, or embeddable element in a mapping file

  • access attribute on any basic, id, embedded-id, embedded, many-to-one, one-to-one, one-to-many, many-to-many, element-collection, or version element in a mapping file

  • @Access annotation on any entity, mapped superclass, or embeddable class

  • @Access annotation on any field or property in an entity, mapped superclass, or embedded object

  • An annotated field or property in an entity, mapped superclass, or embedded object

Queries and Generators

Some persistence artifacts, such as ID generators and queries, are defined as annotations on a class even though they are actually global to the persistence unit in scope because they are annotations and there is no other place to put them other than on a class. Earlier, we pointed out the inappropriateness of expressing persistence unit metadata as annotations on a random class, but generators and queries create something concrete, as opposed to being just settings. Nevertheless, it is still not ideal, and in XML this global query-related metadata does not need to be placed arbitrarily within a class but can be defined at the level of subelements of the entity-mappings element.

The global query metadata elements are made up of generator and query elements that include sequence-generator, table-generator, named-query, named-native-query, and sql-result-set-mapping. For historical reasons, these elements might appear in different contexts, but they are nevertheless still scoped to the persistence unit. There are three different persistence unit namespaces, one for queries, one for generators, and one for result set mappings that are used for native queries. When any of the elements that we just listed are defined in the mapping file, the artifacts they define will be added into the persistence unit namespace to which they apply.

The namespaces will already contain all the existing persistence unit artifacts that might have been defined in annotations or in another mapping file. Because these artifacts share the same global persistence unit namespace type, when one of the artifacts defined in XML shares the same name as one that already exists in the namespace of the same type, it is viewed as an override. The artifact that is defined in XML overrides the one that was defined by the annotation. There is no concept of overriding queries, generators, or result set mappings within the same or different mapping files. If one or more mapping files contains one of these objects defined with the same name, it is undefined, which overrides the other because the order that they are processed in is not specified.2

sequence-generator

The sequence-generator element is used to define a generator that uses a database sequence to generate identifiers. It corresponds to the @SequenceGenerator annotation (refer to Chapter 4) and can be used to define a new generator or override a generator of the same name that is defined by a @SequenceGenerator annotation in any class in the persistence unit. It can be specified either at the global level as a subelement of entity-mappings, at the entity level as a subelement of entity, or at the field or property level as a subelement of the id mapping element.

The attributes of sequence-generator line up exactly with the elements in the @SequenceGenerator annotation. Listing 13-9 shows an example of defining a sequence generator.

<entity-mappings>
    ...
    <sequence-generator name="empGen" sequence-name="empSeq"/>
    ...
</entity-mappings>
Listing 13-9

Defining a Sequence Generator

table-generator

The table-generator element defines a generator that uses a table to generate identifiers. Its annotation equivalent is the @TableGenerator annotation (refer to Chapter 4). This element might define a new generator or it might be overriding a generator defined by a @TableGenerator annotation . Like the sequence-generator element, it can be defined within any of entity-mappings, entity, or id elements.

The attributes of table-generator also match the @TableGenerator annotation elements. Listing 13-10 shows an example of defining a sequence generator in annotation form but overriding it to be a table generator in XML.

@Entity
public class Employee {
    @SequenceGenerator(name="empGen")
    @Id @GeneratedValue(generator="empGen")
    private int id;
    // ...
}
Listing 13-10

Overriding a Sequence Generator with a Table Generator

Here is an orm.xml snippet:

<entity-mappings>
    ...
    <table-generator name="empGen" table="ID_GEN" pk-column-value="EmpId"/>
    ...
</entity-mappings>

named-query

Static or named queries can be defined both in annotation form using @NamedQuery (refer to Chapter 7) or in a mapping file using the named-query element. A named-query element in the mapping file can also override an existing query of the same name that was defined as an annotation. It makes sense, of course, when overriding a query to override it only with a query that has the same result type, be it an entity, data, or projection of data. Otherwise, all the code that executes the query and processes the results stands a pretty good chance of breaking.

A named-query element can appear as a subelement of entity-mappings or as a subelement of entity. Regardless of where it is defined, it will be keyed by its name in the persistence unit query namespace.

The name of the query is specified as an attribute of the named-query element, while the query string goes in a query subelement within it. Any one of the enumerated LockModeType constants can be included. Any number of query hints can also be provided as hint subelements.

Listing 13-11 shows an example of two named queries, one of which uses a hint that bypasses the cache.

<entity-mappings>
    ...
    <named-query name="findEmpsWithName">
        <query>SELECT e FROM Employee e WHERE e.name LIKE :empName</query>
        <hint name="javax.persistence.cacheRetrieveMode"
                 value="CacheRetrieveMode.BYPASS"/>
    </named-query>
    <named-query name="findEmpsWithHigherSalary">
        <query><![CDATA[SELECT e FROM Employee e WHERE e.salary > :salary]]></query>
    </named-query>
    ...
</entity-mappings>
Listing 13-11

Named Query in a Mapping File

Query strings can also be expressed as CDATA within the query element. You can see in Listing 13-11, that this is helpful in cases when the query includes XML characters such as > that would otherwise need to be escaped.

named-native-query

Native SQL can also be used for named queries by defining a @NamedNativeQuery annotation (refer to Chapter 11) or by specifying a named-native-query element in a mapping file. Both named queries and native queries share the same query namespace in the persistence unit, so using either the named-query or named-native-query element will cause that query to override any query of the same name defined in annotation form.

Native queries are the same as named queries in that the native-named-query element can appear as a subelement of entity-mappings or as a subelement of entity. The name is specified using the name attribute, and the query string uses a query subelement. The hints are also specified in the same way. The only difference is that two additional attributes have been added to named-native-query to supply the result class or the result set mapping.

One use case for overriding queries is when the DBA comes to you and demands that your query run a certain way on a certain database. You can leave the query as generic JP QL for the other databases, but it turns out that, for example, the Oracle database can do this one particular thing very well using native syntax. By putting this query in a DB-specific XML file, it will be much easier to manage in the future. Listing 13-12 has an example of a vanilla named query in JP QL that is being overridden by a native SQL query.

@NamedQuery(name="findAllManagers"
            query="SELECT e FROM Employee e WHERE e.directs IS NOT EMPTY")
@Entity
public class Employee { ... }
Listing 13-12

Overriding a JP QL Query with SQL

Here is an orm.xml snippet:

<entity-mappings>
    ...
    <named-native-query name="findAllManagers"
                        result-class="examples.model.Employee">
        <query>
            SELECT /*+ FULL(m) */ e.id, e.name, e.salary,
                   e.manager_id, e.dept_id, e.address_id
            FROM   emp e,
                   (SELECT DISTINCT manager_id AS id FROM emp) m
            WHERE  e.id = m.id
        </query>
    </named-native-query>
    ...
</entity-mappings>

named-stored-procedure-query

A stored procedure can be represented by a named query by defining a @NamedStoredProcedureQuery annotation (refer to Chapter 11) or by specifying a named-stored-procedure-query element in a mapping file. Like other named queries, named stored procedure queries can be specified as subelements of entity-mappings or entity. While they may share the same persistence unit query namespace with all of the other named queries, the API creation method of a named stored procedure query returns an instance of StoredProcedureQuery. This means that in practice they are different types of named queries and you will not, for example, be able to override a JP QL named query with a stored procedure query. You could, however, override a stored procedure query defined in annotation form with a stored procedure query defined using the named-stored-procedure-query element.

Similar to other named queries, the name of the query is specified using the name attribute, and any number of hint subelements can be used to supply query hints. However, since multiple result sets can be returned from stored procedure queries, instead of the result-class and result-set-mapping attributes that existed on named-native-query, multiple result-class and result-set-mapping subelements can be specified under the named-stored-procedure-query element. Although the schema does not disallow it, using both result-class and result-set-mapping subelements for different result sets in the same query is not permitted.

The unique parts of a stored procedure query are the additional procedure-name attribute to specify the name of the stored procedure in the database and the parameter subelements to define the parameter names and types. Each parameter subelement has a name, class, and mode attribute to indicate the parameter name, the JDBC class, and whether the parameter is an IN, OUT, INOUT, or REF_CURSOR parameter. The parameters must be defined in the order they appear in the actual stored procedure definition.

Listing 13-13 shows an example of using a named-stored-procedure-query element to add the stored procedure query from Chapter 11.

@NamedStoredProcedureQuery(
    name="fetch_emp",
    procedureName="fetch_emp",
    parameters={
        @StoredProcedureParameter(name="empList", type=void.class,
                                mode=ParameterMode.REF_CURSOR)
    },
    resultClasses=Employee.class
)
Listing 13-13

Defining a Named Stored Procedure Query

Here is an orm.xml snippet:

<entity-mappings>
    ...
    <named-stored-procedure-query name="fetch_emp" procedure-name="fetch_emp">
        <parameter name="empList" class="void " mode="REF_CURSOR"/>
        <result-class>Employee</result-class>
    </named- stored-procedure-query>
    ...
</entity-mappings>

sql-result-set-mapping

A result set mapping is used by native queries or stored procedure queries to instruct the persistence provider how to map the results. The sql-result-set-mapping element corresponds to the @SqlResultSetMapping annotation. The name of the result set mapping is specified in the name attribute of the sql-result-set-mapping element. The result can be mapped as one or more entity types, non-entity Java types, projection data, or a combination of the these. Just as @SqlResultSetMapping encloses arrays of @EntityResult, @ConstructorResult, and @ColumnResult, so also can the sql-result-set-mapping element contain multiple entity-result, constructor-result, and column-result elements. Similarly, because each @EntityResult contains an array of @FieldResult, the entity-result element can contain multiple field-result elements. The other entityClass and discriminatorColumn elements of the @EntityResult annotation map directly to the entity-class and discriminator-column attributes of the entity-result element. Likewise, a @ConstructorResult contains an array of @ColumnResult, so the constructor-result subelement contains an arbitrary number of column subelements, along with a target-class attribute to specify the name of the non-entity class to construct.

Each sql-result-set-mapping can define a new mapping or override an existing one of the same name that was defined by an annotation. It is not possible to override only a part of the result set mapping. If you’re overriding an annotation, the entire annotation will be overridden, and the components of the result set mapping defined by the sql-result-set-mapping element will apply.

Having said all this about overriding, there is really not that much use in overriding a @SqlResultSetMapping because they are used to structure the result format from a static native or stored procedure query. As we mentioned earlier, queries tend to be executed with a certain expectation of the result that is being returned. Result set mappings are typically defined in a mapping file because that is also generally where the query that is defining the result is defined.

Listing 13-14 shows the DepartmentSummary result set mapping that we defined in Chapter 11 and its equivalent XML mapping file form.

@SqlResultSetMapping(
    name="DepartmentSummary",
    entities={
        @EntityResult(entityClass=Department.class,
                      fields=@FieldResult(name="name", column="DEPT_NAME")),
        @EntityResult(entityClass=Employee.class)
    },
    columns={@ColumnResult(name="TOT_EMP"),
             @ColumnResult(name="AVG_SAL")}
)
Listing 13-14

Specifying a Result Set Mapping

Here is an orm.xml snippet:

<entity-mappings>
    ...
    <sql-result-set-mapping name="DepartmentSummary">
        <entity-result entity-class="examples.model.Department">
            <field-result name="name" column="DEPT_NAME"/>
        </entity-result>
        <entity-result entity-class="examples.model.Employee"/>
        <column-result name="TOT_EMP"/>
        <column-result name="AVG_SAL"/>
    </sql-result-set-mapping>
    ...
</entity-mappings>

Managed Classes and Mappings

The main portion of every mapping file will typically be the managed classes in the persistence unit that are the entity, mapped-superclass, and embeddable elements and their state and relationship mappings. Each of them has its class specified as a class attribute of the element and its access type specified in an access attribute. The access attribute is required only when there are no annotations on the managed class or when metadata-complete (or xml-mapping-metadata-complete) has been specified for the class. If neither of these conditions apply and annotations do exist on the class, the access attribute setting should match the access used by the annotations.

For entities, an optional cacheable attribute can also be set to a boolean value. This attribute corresponds to the @Cacheable annotation and when specified will override the value of the annotation. Like the annotation, it dictates whether the shared cache is used for instances of the entity class, and is applicable only when the shared-cache-mode (see Chapter 14) is set to one of the selective modes. The cacheable attribute is inherited by subclasses and is overridden by either the @Cacheable annotation on the subclass, or the cacheable attribute in the subclass element.

Queries and generators can be specified within an entity element. Generators can also be defined inside an id element in an entity or mapped superclass. They have already been described in the preceding “Queries and Generators” section.

Attributes

Unfortunately, the word “attribute” is grossly overloaded. It can be a general term for a field or property in a class, it can be a specific part of an XML element that can be inlined in the element tag, or it can be a generic term referring to a characteristic. Throughout these sections, we have usually referred to it in the context of the second meaning because we have been talking a lot about XML elements. In this section, however, it refers to the first definition of a state attribute in the form of a field or property.

The attributes element is a subelement of the entity, mapped-superclass, and embeddable elements. It is an enclosing element that groups all the mapping subelements for the fields or properties of the managed class. Because it is only a grouping element, it does not have an analogous annotation. It dictates which mappings are allowed for each type of managed class.

In the entity and mapped-superclass elements, there are a number of mapping subelements that can be specified. For identifiers, either multiple id subelements or a single embedded-id subelement can be included. The simple basic, version, and transient mapping subelements can also be specified, as well as the many-to-one, one-to-one, one-to-many, and many-to-many association subelements. The mapping mix is rounded out with the embedded and element-collection subelements. An embeddable element is not permitted to contain id, embedded-id, or version mapping subelements. These elements will all be discussed separately in their own sections later, but they all have one thing in common. Each one has a name attribute (in the XML attribute sense) that is required to indicate the name of the attribute (in this case, we mean field or property) that it is mapping.

A general comment about overriding attribute mappings is that overriding annotations with XML is done at the level of the attribute (field or property) name. Our algorithm will apply to these mappings as they are keyed by attribute name, and XML overrides will be applied by attribute name alone. All the annotated mapping information for the attribute will be overridden as soon as a mapping element for that attribute name is defined in XML.

There is nothing to stop the type of attribute mapping defined in annotation form from being overridden in XML to be a different mapping type. The provider is responsible only for implementing the overriding rules and likely won’t prevent this kind of behavior. This leads us to our second comment about overriding, which is that when overriding annotations, you should use the correct and compatible XML mapping. There are some cases where it might be valid to actually map an attribute differently in XML, but these cases are few and far between and primarily for exceptional types of testing or debugging.

For example, one could imagine overriding a field mapped in annotation form as a basic mapping with a transient mapping in XML. This would be completely legal, but not necessarily a good idea. At some point, a client of the entity might actually be trying to access that state, and if it is not being persisted, the client might get quite confused and fail in curious ways that are difficult to debug. An address association property mapped as a many-to-one mapping could conceivably be overridden to be stored serially as a blob, but this could not only break client access but also spill over to break other areas like JP QL queries that traverse the address.

The rule of thumb is that mappings should be overridden primarily to change the data-level mapping information. This would normally need to be done when, for example, an application is developed on one database but deployed to another or must deploy to multiple different databases in production. In these cases, the XML mappings would likely be xml-mapping-metadata-complete anyway, and the XML metadata would be used in its entirety rather than cobbling together bits of annotations and bits of XML and trying to keep it all straight across multiple database XML mapping configurations.

Tables

Specifying tables in XML works pretty much the same way as it does in annotation form. The same defaults are applied in both cases. There are two elements for specifying table information for a managed class: table and secondary-table.

table

A table element can occur as a subelement of entity and describes the table that the entity is mapped to. It corresponds to the @Table annotation (refer to Chapter 4) and has name, catalog, and schema attributes. One or more unique-constraint subelements might be included if unique column constraints are to be created in the table during schema generation.

If a @Table annotation exists on the entity, the table element will override the table defined by the annotation. Overriding a table is usually accompanied also by the overridden mappings of the persistent state to the overridden table. Listing 13-15 shows how an entity can be mapped to a different table than what it is mapped to by an annotation.

@Entity
@Table(name="EMP", schema="HR")
public class Employee { ... }
Listing 13-15

Overriding a Table

Here is an orm.xml snippet:

<entity class="examples.model.Employee">
    <table name="EMP_REC" schema="HR"/>
    ...
</entity>
secondary-table

Any number of secondary tables can be added to the entity by adding one or more secondary-table subelements to the entity element. This element corresponds to the @SecondaryTable annotation (refer to Chapter 10), and if it is present in an entity element, it will override any and all secondary tables that are defined in annotations on the entity class. The name attribute is required, just as the name is required in the annotation. The schema and catalog attributes and the unique-constraint subelements can be included, just as with the table element.

Every secondary table needs to be joined to the primary table through a primary key join column (refer to Chapter 10). The primary-key-join-column element is a subelement of the secondary-table element and corresponds to the @PrimaryKeyJoinColumn annotation. As with the annotation, this is required only if the primary key column of the secondary table is different from that of the primary table. If the primary key happens to be a compound primary key, multiple primary-key-join-column elements can be specified.

Listing 13-16 compares the specification of secondary tables in annotation and XML form.

@Entity
@Table(name="EMP")
@SecondaryTables({
    @SecondaryTable(name="EMP_INFO"),
    @SecondaryTable(name="EMP_HIST",
                    pkJoinColumns=@PrimaryKeyJoinColumn(name="EMP_ID"))
 })
public class Employee {
    @Id private int id;
    // ...
}
Listing 13-16

Specifying Secondary Tables

Here is an orm.xml snippet:

<entity class="examples.model.Employee">
    <table name="EMP"/>
    <secondary-table name="EMP_INFO"/>
    <secondary-table name="EMP_HIST">
        <primary-key-join-column name="EMP_ID"/>
    </secondary-table>
    ...
</entity>

Identifier Mappings

The three different types of identifier mappings can also be specified in XML. Overriding applies to the configuration information within a given identifier type, but the identifier type of a managed class should almost never be changed.

id

The id element is the most common method used to indicate the identifier for an entity. It corresponds to the @Id annotation but also encapsulates metadata that is relevant to identifiers. This includes a number of subelements, the first of which is the column subelement. It corresponds to the @Column annotation that might accompany an @Id annotation on the field or property. When not specified, the default column name will be assumed even if a @Column annotation exists on the field or property. As we discussed in the “Attributes” section, this is because the XML mapping of the attribute overrides the entire group of mapping metadata on the field or property.

A generated-value element corresponding to the @GeneratedValue annotation can also be included in the id element. It is used to indicate that the identifier will have its value automatically generated by the provider (refer to Chapter 4). This generated-value element has strategy and generator attributes that match those on the annotation. The named generator can be defined anywhere in the persistence unit. Sequence and table generators can also be defined within the id element. These were discussed in the “Queries and Generators” section.

An example of overriding an id mapping is to change the generator for a given database (see Listing 13-17).

@Entity
public class Employee {
    @Id @GeneratedValue(strategy=GenerationType.TABLE, generator="empTab")
    @TableGenerator(name="empTab", table="ID_GEN")
    private long id;
    // ...
}
Listing 13-17

Overriding an ID Generator

Here is an orm.xml snippet:

<entity class="examples.model.Employee">
    ...
    <attributes>
        <id name="id">
            <generated-value strategy="SEQUENCE" generator="empSeq"/>
            <sequence-generator name="empSeq" sequence-name="mySeq"/>
        </id>
        ...
    </attributes>
</entity>
embedded-id

An embedded-id element is used when a compound primary key class is used as the identifier (refer to Chapter 10). It corresponds to the @EmbeddedId annotation and is really just mapping an embedded class as the identifier. All the state is actually mapped within the embedded object, so there are only attribute overrides available within the embedded-id element. As we discuss in the “Embedded Object Mappings” section, attribute overrides allow mapping of the same embedded object in multiple entities. The zero or more attribute-override elements in the property or field mapping of the entity provide the local overrides that apply to the entity table. Listing 13-18 shows how to specify an embedded identifier in annotation and XML form.

@Entity
public class Employee {
    @EmbeddedId private EmployeePK id;
    // ...
}
Listing 13-18

Specifying an Embedded ID

Here is an orm.xml snippet:

<entity class="examples.model.Employee">
    ...
    <attributes>
        <embedded-id name="id"/>
        ...
    </attributes>
</entity>
id-class

An ID class is one strategy that can be used for a compound primary key (refer to Chapter 10). The id-class subelement of an entity or mapped-superclass element corresponds to the @IdClass annotation, and when it is specified in XML, it will override any @IdClass annotation on the class. Overriding the ID class should not normally be done in practice because code that uses the entities will typically assume a particular identifier class.

The name of the class is indicated as the value of the class attribute of the id-class element, as shown in Listing 13-19.

@Entity
@IdClass(EmployeePK.class)
public class Employee { ... }
Listing 13-19

Specifying an ID Class

Here is an orm.xml snippet:

<entity class="examples.model.Employee">
    ...
    <id-class="examples.model.EmployeePK"/>
    ...
</entity>

Simple Mappings

A simple mapping takes an attribute and maps it to a single column in a table. The majority of persistent state mapped by an entity will be composed of simple mappings. In this section, we discuss basic mappings and also cover the metadata for versioning and transient attributes.

basic

Basic mappings were discussed in detail in the early part of the book; they map a simple state field or property to a column in the table. The basic element provides this same ability in XML and corresponds to the @Basic annotation. Unlike the @Basic annotation (described in Chapter 4) that is rarely used, the basic element is required when mapping persistent state to a specific column. Just as with annotations, when a field or property is not mapped, it will be assumed to be a basic mapping and will be defaulted as such. This will occur if the field or property is not annotated or has no named subelement entry in the attributes element.

In addition to a name, the basic element has fetch and optional attributes that can be used for lazy loading and optionality. They are not required and not very useful at the level of a field or property. The only other attribute of the basic element is the access attribute. When specified, it will cause the state to be accessed using the prescribed mode.

The most important and useful subelement of basic is the column element. One of four other subelements can optionally be included inside the basic element. They are primarily for indicating the type to use when communicating with the JDBC driver. The first is an empty lob element that corresponds to the @Lob annotation. This is used when the target column is a large object type. Whether it is a character or binary object depends on the type of the field or property.

The second one is the temporal element that contains one of DATE, TIME, or TIMESTAMP as its content. It corresponds to the @Temporal annotation and is used for fields of type java.util.Date or java.util.Calendar.

The third is used if the field or property is an enumerated type, and the enumerated values are to be mapped using strings instead of ordinals. In this case, the enumerated element should be used. It corresponds to the @Enumerated annotation and contains either ORDINAL or STRING as its content.

Finally, if the attribute is to be converted using a converter, then the convert annotation can be added. The convert element is discussed later in the “Converters” section.

Listing 13-20 shows some examples of basic mappings. By not specifying the column in the basic element mapping for the name field, the column is overridden from using the annotated EMP_NAME column to being defaulted to NAME. The comments field, however, is overridden from using the default to being mapped to the COMM column. It is also stored in a character large object (CLOB) column due to the lob element being present and the fact that the field is a String. The type field is overridden to be mapped to the STR_TYPE column, and the enumerated type of STRING is specified to indicate that the values should be stored as strings. The salary field does not have any metadata either in annotation or XML form and continues to be mapped to the default column name of SALARY.

@Entity
public class Employee {
    // ...
    @Column(name="EMP_NAME")
    private String name;
    private String comments;
    private EmployeeType type;
    private long salary;
    // ...
}
Listing 13-20

Overriding Basic Mappings

Here is an orm.xml snippet:

<entity class="examples.model.Employee">
    ...
    <attributes>
        ...
        <basic name="name"/>
        <basic name="comments">
            <column name="COMM"/>
            <lob/>
        </basic>
        <basic name="type">
            <column name="STR_TYPE"/>
            <enumerated>STRING</enumerated>
        </basic>
        ...
    </attributes>
</entity>
transient

A transient element marks a field or property as being non-persistent. It is equivalent to the @Transient annotation or having a transient qualifier on the field or property. Listing 13-21 shows an example of how to set a field to be transient.

<entity-mappings>
    <entity class="examples.model.Employee">
        <attributes>
            <transient name="cacheAge"/>
            ...
        </attributes>
    </entity>
</entity-mappings>
Listing 13-21

Setting a Transient Field in a Mapping File

version

The version element is used to map the version number field in the entity. It corresponds to the @Version annotation and is normally mapped to an integral field for the provider to increment when it makes persistent changes to the entity (refer to Chapter 12). The column subelement specifies the column that stores the version data. Only one version field should exist for each entity. Listing 13-22 shows how a version field is specified in annotations and XML.

@Entity
public class Employee {
    // ...
    @Version
    private int version;
    // ...
}
Listing 13-22

Specifying the Version

Here is an orm.xml snippet:

<entity-mappings>
    <entity class="examples.model.Employee">
        <attributes>
            ...
            <version name="version"/>
            ...
        </attributes>
    </entity>
    ...
</entity-mappings>

Relationship and Collection Mappings

Like their annotation counterparts, the XML relationship and collection elements are used to map the associations and element collections.

We are now confronted yet again with the problem of an overloaded term. Throughout this chapter, we have been using the term “element” to signify an XML token (the thing with angled brackets around it). But in Chapter 5 we introduced the notion of an element collection, a mapping that designates a collection of either simple objects or embeddable objects. The following sections discuss each of the relationship and element collection mapping types that exist in XML.

many-to-one

To create a many-to-one mapping for a field or property, the many-to-one element can be specified. This element corresponds to the @ManyToOne annotation and, like the basic mapping, has fetch, optional, and access attributes.

Normally the target entity is known by the provider because the field or property is almost always of the target entity type, but if not, then the target-entity attribute should also be specified. When the many-to-one foreign key contributes to the identifier of the entity and the @MapsId annotation described in Chapter 10 applies, then the maps-id attribute would be used. The value, when required, is the name of the embeddable attribute of the embedded ID class that maps the foreign key relationship. If, on the other hand, the relationship is part of the identifier but a simple @Id would be applied to the relationship field or property, the boolean id attribute of the many-to-one element should be specified and set to true.

A join-column element can be specified as a subelement of the many-to-one element when the column name is different from the default. If the association is to an entity with a compound primary key, multiple join-column elements will be required. Mapping an attribute using a many-to-one element causes the mapping annotations that might have been present on that attribute to be ignored. All the mapping information for the relationship, including the join column information, must be specified or defaulted within the many-to-one XML element.

Instead of a join column, it is possible to have a many-to-one or one-to-many relationship that uses a join table. It is for this case that a join-table element can be specified as a subelement of the many-to-one element. The join-table element corresponds to the @JoinTable annotation and contains a collection of join-column elements that join to the owning entity, which is normally the many-to-one side. A second set of join columns joins the join table to the inverse side of the relationship. They are called inverse-join-column elements. In the absence of one or both of these, the default values will be applied.

Unique to relationships is the ability to cascade operations across them. The cascade settings for a relationship dictate which operations are cascaded to the target entity of the many-to-one mapping. To specify how cascading should occur, a cascade element should be included as a subelement of the many-to-one element. Within the cascade element, we can include our choice of empty cascade-all, cascade-persist, cascade-merge, cascade-remove, cascade-refresh, or cascade-detach subelements that dictate that the given operations be cascaded. Of course, specifying cascade elements in addition to the cascade-all element is simply redundant.

Now we come to an exception to the rule that we gave earlier when we said that overriding of mappings will typically be for physical data overrides. When it comes to relationships, there are times where you will want to test the performance of a given operation and would like to be able to set certain relationships to load eagerly or lazily. You will not want to go through the code and have to keep changing these settings back and forth, however. It would be more practical to have the mappings that you are tuning in XML and just change them when required.3 Listing 13-23 shows overriding two many-to-one relationships to be lazily loaded.

@Entity
public class Employee {
    // ...
    @ManyToOne
    private Address address;
    @ManyToOne
    @JoinColumn(name="MGR")
    private Employee manager;
    // ...
}
Listing 13-23

Overriding Fetch Mode

Here is an orm.xml snippet:

<entity class="examples.model.Employee">
    ...
    <attributes>
        ...
        <many-to-one name="address" fetch="LAZY"/>
        <many-to-one name="manager" fetch="LAZY">
            <join-column name="MGR"/>
        </many-to-one>
        ...
    </attributes>
</entity>
one-to-many

A one-to-many mapping is created by using a one-to-many element. This element corresponds to the @OneToMany annotation and has the same optional target-entity, fetch, and access attributes that were described in the many-to-one mapping. It has an additional attribute called mapped-by, which indicates the field or property of the owning entity (refer to Chapter 4) and an orphan-removal attribute to specify that orphaned entities should be automatically removed (refer to Chapter 10).

A one-to-many mapping is a collection-valued association, and the collection can be a List, Map, Set, or Collection. If it is a List, the elements can be populated in a specific order by specifying an order-by subelement. This element corresponds to the @OrderBy annotation and will cause the contents of the list to be ordered by the specific field or property name that is specified in the element content. Alternatively, a List can have its order persisted using an order-column subelement, which provides all the functionality of its @OrderColumn annotation counterpart.

If the collection is a Map, there are a number of different options, depending on the key type. If the key type is a field or property of the target entity, an optional map-key subelement can be specified to indicate the name of the field or property to use as the key. This element corresponds to the @MapKey annotation and will default to the primary key field or property when none is specified. If the key type is an entity, a map-key-join-column can be used, whereas if the key is a basic type, a map-key-column subelement indicates the column that stores the key. Furthermore, for basic keys, map-key-enumerated or map-key-temporal can be used if the basic type is an enumerated or temporal type, respectively. If the key type is an embeddable type, map-key-attribute-override can be specified to override where an embedded field or property of the embeddable type is mapped. The map-key-class subelement is included to indicate the type of the key when the Map is not generically typed, and the key is not a field or property of the target entity. The map-key-convert element can be used if the key is a basic type and is to be converted using a converter. The map-key-convert element contains the same attributes as the convert element described in the “Converters” section.

A join table is used by default to map a unidirectional one-to-many association that does not store a join column in the target entity. To use this kind of mapping, the mapped-by attribute is omitted, and the join-table element is included. If the mapping is a unidirectional one-to-many with the foreign key in the target table, one or more join-column subelements are used instead of the join-table. The join-column elements apply to the target entity table, though, not the source entity table (refer to Chapter 10).

Finally, cascading across the relationship is specified through an optional cascade element. Listing 13-24 shows a bidirectional one-to-many mapping, both in annotations and XML.

@Entity
public class Employee {
    // ...
    @OneToMany(mappedBy="manager")
    @OrderBy
    private List<Employee> directs;
    @ManyToOne
    private Employee manager;
    // ...
}
Listing 13-24

Specifying a One-to-Many Mapping

Here is an orm.xml snippet:

<entity class="examples.model.Employee">
    ...
    <attributes>
        ...
        <one-to-many name="directs" mapped-by="manager">
            <order-by/>
        </one-to-many>
        <many-to-one name="manager"/>
        ...
    </attributes>
</entity>
one-to-one

To map a one-to-one association, the one-to-one element must be used. This element corresponds to the @OneToOne annotation described in Chapter 4 and has the same target-entity, fetch, optional, access, maps-id, and id attributes that the many-to-one element has. It also has the mapped-by and orphan-removal attributes that are in the one-to-many mapping to refer to the owning entity and to cause orphaned target entities to be automatically removed.

A one-to-one element might contain a join-column element if it is the owner of the relationship or it might have multiple join-column elements if the association is to an entity with a compound primary key. In some legacy systems, it is mapped using a join table, so a join-table element should be used in this case.

When the one-to-one association is joined using the primary keys of the two entity tables, instead of using either the maps-id or id attributes, the one-to-one element might contain a primary-key-join-column element. When it has a compound primary key, multiple primary-key-join-column elements will be present. Either of primary-key-join-column or join-column elements might be present, but not both.

Note

The use of primary key join columns for one-to-one primary key associations was instituted in JPA 1.0. In JPA 2.0, the option to use id and maps-id was introduced, and it is the preferred method going forward.

The annotated classes and XML mapping file equivalents for a one-to-one mapping using a primary key association are shown in Listing 13-25.

@Entity
public class Employee {
    // ...
    @OneToOne(mappedBy="employee")
    private ParkingSpace parkingSpace;
    // ...
}
@Entity
public class ParkingSpace {
    @Id
    private int id;
    // ...
    @OneToOne @MapsId
    private Employee employee;
    // ...
}
Listing 13-25

One-to-One Primary Key Association

Here is an orm.xml snippet:

<entity-mappings>
    <entity class="examples.model.Employee">
        <attributes>
            ...
            <one-to-one name="parkingSpace" mapped-by="employee"/>
            ...
        </attributes>
    </entity>
    <entity class="examples.model.ParkingSpace">
        <attributes>
            ...
            <one-to-one name="employee" maps-id="true"/>
            ...
        </attributes>
    </entity>
</entity-mappings>
many-to-many

Creating a many-to-many association is done through the use of a many-to-many element. This element corresponds to the @ManyToMany annotation (refer to Chapter 4) and has the same optional target-entity, fetch, access, and mapped-by attributes that were described in the one-to-many mapping.

Also, being a collection-valued association like the one-to-many mapping, it supports the same order-by, order-column, map-key, map-key-class, map-key-column, map-key-join-column, map-key-enumerated, map-key-temporal, map-key-attribute-override, map-key-convert, join-table, and cascade subelements as the one-to-many mapping. Listing 13-26 shows an entity class example and equivalent XML, with a sample many-to-many relationship.

@Entity
public class Employee {
    // ...
    @ManyToMany
    @MapKey(name="name")
    @JoinTable(name="EMP_PROJ",
          joinColumns=@JoinColumn(name="EMP_ID"),
          inverseJoinColumns=@JoinColumn(name="PROJ_ID"))
    private Map<String, Project> projects;
    // ...
}
@Entity
public class Project {
    // ...
    private String name;
    @ManyToMany(mappedBy="projects")    private Collection<Employee> employees;
    // ...
}
Listing 13-26

Many-to-Many Mapping Annotations and XML

Here is an orm.xml snippet:

<entity-mappings>
    <entity class="examples.model.Employee">
        <attributes>
            ...
            <many-to-many name="projects">
                <map-key name="name"/>
                <join-table name="EMP_PRJ">
                    <join-column name="EMP_ID"/>
                    <inverse-join-column name="PROJ_ID"/>
                </join-table>
            </many-to-many>
            ...
        </attributes>
    </entity>
    <entity class="examples.model.Project">
        <attributes>
            ...
            <many-to-many name="employee" mapped-by="projects"/>
            ...
        </attributes>
    </entity>
</entity-mappings>
element-collection

A collection of basic or embeddable objects is mapped using an element-collection element, which corresponds to the @ElementCollection annotation (refer to Chapter 5) and has the same optional target-entity, fetch, and access attributes that were described in the one-to-many and many-to-many mapping sections.

If the collection is a List, one of order-by or order-column can be specified as a subelement. If the collection is a Map and contains embeddables as values, a map-key element can be used to indicate that a field or property in the embeddable value is to be used as the map key. Alternatively, the various map-key-column, map-key-join-column, map-key-enumerated, map-key-temporal, map-key-attribute-override, map-key-convert, and map-key-class can be used as described in the one-to-many section.

Embeddables can contain basic mappings as well as relationships, so in order to override the columns and join columns that embeddable objects are mapped to, the attribute-override and association-override subelements are used.

If the value is a basic type, the column subelement—with the possibility of one of temporal, lob, enumerated or convert subelements—can be included. These all refer to the basic values in the collection, and the column element refers to the column in the collection table that stores the values.

Finally, element collections are stored in a collection table, so the collection-table subelement will obviously be a common one. It corresponds to the @CollectionTable annotation and refers to the table that stores the basic or embeddable objects in the collection as well as the keys that index them if the collection is a Map. An example of a Map element collection is one that stores the number of hours worked against a particular project name, as shown in Listing 13-27.

@Entity
public class Employee {
    // ...
    @ElementCollection(targetClass=java.lang.Integer)
    @MapKeyClass(name="java.lang.String")
    @MapKeyColumn(name="PROJ_NAME")
    @Column(name="HOURS_WORKED")
    @CollectionTable(name="PROJ_TIME")
    private Map projectHours;
    // ...
}
Listing 13-27

Element Collection of Integers with String Keys

Here is an orm.xml snippet:

<entity class="examples.model.Employee">
    <attributes>
        ...
        <element-collection name="projectHours" target-class="java.lang.Integer">
            <map-key-class name="java.lang.String"/>
            <map-key-column name="PROJ_NAME"/>
            <column name="HOURS_WORKED"/>
            <collection-table name="PROJ_TIME"/>
        </element-collection>
    </attributes>
</entity>

Embedded Object Mappings

An embedded object is a class that depends on its parent entity for its identity. Embedded objects are specified in XML using the embedded element and are customized using the attribute-override element.

embedded

An embedded element is used for mapping an embedded object contained within a field or property (refer to Chapter 4). It corresponds to the @Embedded annotation and permits an access attribute to be specified to dictate whether the state is to be accessed using a field or property. Because the persistent state is mapped within the embedded object, only the attribute-override, association-override, and convert subelements are allowed within the embedded element.

There must be an embeddable class entry in a mapping file for the embedded object, or it must be annotated as @Embeddable. An example of overriding an embedded Address is shown in Listing 13-28.

@Entity
public class Employee {
    // ...
    @Embedded
    private Address address;
    // ...
}
@Embeddable
public class Address {
    private String street;
    private String city;
    private String state;
    private String zip;
    // ...
}
Listing 13-28

Embedded Mappings in Annotations and XML

Here is an orm.xml snippet:

<entity-mappings>
    <entity class="examples.model.Employee">
        <attributes>
            ...
            <embedded name="address"/>
            ...
        </attributes>
    </entity>
    <embeddable class="examples.model.Address"/>
</entity-mappings>

The convert subelement is used to apply or override conversion for a particular field or property in the embedded object. See the “Converters” section for details on how the convert element can be used to override conversion.

attribute-override

When an embedded object is used by multiple entity types, it is likely that some of the basic mappings in the embedded object will need to be remapped by one or more of the entities (refer to Chapter 4). The attribute-override element can be specified as a subelement of the embedded, embedded-id, and element-collection elements to accommodate this case.

The annotation that corresponds to the attribute-override element is the @AttributeOverride annotation . This annotation can be on the entity class or on a field or property that stores an embedded object, collection of embedded objects, or embedded id. When an @AttributeOverride annotation is present in the entity, it will be overridden only by an attribute-override element in the entity mapping file entry that specifies the same named field or property. Our earlier algorithm still holds if we think of the attribute overrides as keyed by the name of the field or property that they are overriding. All the annotation overrides for an entity are gathered, and all the XML overrides for the class are applied on top of the annotation overrides. If there is an override in XML for the same named field or property, it will overwrite the annotated one. The remaining non-overlapping overrides from annotations and XML will also be applied.

The attribute-override element stores the name of the field or property in its name attribute and the column that the field or property maps to as a column subelement. Listing 13-29 revisits Listing 13-28 and overrides the state and zip fields of the embedded address.

@Entity
public class Employee {
    // ...
    @Embedded
    @AttributeOverrides({
        @AttributeOverride(name="state", column=@Column(name="PROV")),
        @AttributeOverride(name="zip", column=@Column(name="PCODE"))})
    private Address address;
    // ...
}
Listing 13-29

Using Attribute Overrides

Here is an orm.xml snippet:

<entity class="examples.model.Employee">
    <attributes>
        ...
        <embedded name="address">
            <attribute-override name="state">
                <column name="PROV"/>
            </attribute-override>
            <attribute-override name="zip">
                <column name="PCODE"/>
            </attribute-override>
        </embedded>
        ...
    </attributes>
</entity>
association-override

Embeddable objects also support relationship mappings, although it is a less common requirement. When a many-to-one or one-to-one relationship is present in an embeddable, a join column is mapped either explicitly or by default by the association in the embedded object. Reusing the embeddable type within another entity class means there is a possibility that the join column will need to be remapped. The association-override element, which corresponds to the @AssociationOverride annotation (refer to Chapter 10), can be included as a subelement of the embedded, embedded-id, and element-collection elements to accommodate this case.

The association-override element maps the name of the field or property in its name attribute and the join columns that the field or property maps to as one or more join-column subelements. If the mapping being overridden uses a join table, the join-table subelement is used instead of join-column.

The same XML overriding annotation rules apply as were described for attribute overrides.

Listing 13-30 revisits our embedded example again, but this time overrides the city association in the embedded address.

@Entity
public class Employee {
    // ...
    @Embedded
    @AssociationOverride(name="city", joinColumns=@JoinColumn(name="CITY_ID"))
    private Address address;
    // ...
}
@Embeddable
public class Address {
    private String street;
    @ManyToOne
    @JoinColumn(name="CITY")
    private City city;
    // ...
}
Listing 13-30

Using Association Overrides

Here is an orm.xml snippet:

<entity class="examples.model.Employee">
    <attributes>
        ...
        <embedded name="address">
            <association-override name="city">
                <join-column name="CITY_ID"/>
            </association-override>
        </embedded>
        ...
    </attributes>
</entity>

Inheritance Mappings

An entity inheritance hierarchy is mapped using the inheritance, discriminator-column, and discriminator-value elements. If the inheritance strategy is changed, it must be overridden for the entire entity hierarchy.

inheritance

The inheritance element is specified to indicate the root of an inheritance hierarchy. It corresponds to the @Inheritance annotation and indicates the inheritance-mapping strategy that is to be used. When it is included in the entity element, it will override any inheritance strategy that is defined or defaulted in the @Inheritance annotation on the entity class.

Changing the inheritance strategy can cause repercussions that spill out into other areas. For example, changing a strategy from single table to joined will likely require adding a table to each of the entities below it. The example in Listing 13-31 overrides an entity hierarchy from using a single table to using a joined strategy.

@Entity
@Table(name="EMP")
@Inheritance
@DiscriminatorColumn(name="TYPE")
public abstract class Employee { ... }
@Entity
@DiscriminatorValue("FT")
public class FullTimeEmployee { ... }
@Entity
@DiscriminatorValue("PT")
public class PartTimeEmployee { ... }
Listing 13-31

Overriding an Inheritance Strategy

Here is an orm.xml snippet:

<entity-mappings>
    <entity class="examples.model.Employee">
        <table name="EMP"/>
        <inheritance strategy="JOINED"/>
        ...
    </entity>
    <entity class="examples.model.FullTimeEmployee">
        <table name="FT_EMP"/>
        ...
    </entity>
    <entity class="examples.model.PartTimeEmployee">
        <table name="PT_EMP"/>
        ...
    </entity>
</entity-mappings>
discriminator-column

Discriminator columns store values that differentiate between concrete entity subclasses in an inheritance hierarchy (refer to Chapter 10). The discriminator-column element is a subelement of the entity or entity-result elements and is used to define or override the discriminator column. It corresponds to and overrides the @DiscriminatorColumn annotation and has attributes that include the name, discriminator-type, columnDefinition, and length. It is an empty element that has no subelements.

The discriminator-column element is not typically used to override a column on its own but in conjunction with other inheritance and table overrides. Listing 13-32 demonstrates specifying a discriminator column.

@Entity
@Inheritance
@DiscriminatorColumn(name="TYPE")
public abstract class Employee { ... }
Listing 13-32

Specifying a Discriminator Column

Here is an orm.xml snippet:

<entity class="examples.model.Employee">
    <inheritance/>
    <discriminator-column name="TYPE"/>
    ...
</entity >
discriminator-value

A discriminator-value element is used to declare the value that identifies the concrete entity subclass that is stored in a database row (refer to Chapter 10). It exists only as a subelement of the entity element. The discriminator value is indicated by the content of the element. It has no attributes or subelements.

The discriminator-value element corresponds to the @DiscriminatorValue annotation and overrides it when it exists on the entity class. As with the other inheritance overrides, it is seldom used as an override. Even when a hierarchy is remapped to a different database or set of tables, it will not normally be necessary to override the value. Listing 13-33 shows how to specify a discriminator value in annotation and XML form.

@Entity
@DiscriminatorValue("FT")
public class FullTimeEmployee extends Employee { ... }
Listing 13-33

Specifying a Discriminator Column

Here is an orm.xml snippet:

<entity class="examples.model.FullTimeEmployee">
    <discriminator-value>FT</discriminator-value>
    ...
</entity >
attribute-override and association-override

Simple mappings and associations can be overridden through the use of attribute overrides and association overrides, but only in the case of an entity that is the subclass of a mapped superclass. Simple persistent state or association state that is inherited from an entity superclass cannot portably be overridden.

An example of overriding two simple name and salary persistent field mappings, and a manager association with a compound primary key, is shown in Listing 13-34.

@MappedSuperclass
@IdClass(EmployeePK.class)
public abstract class Employee {
    @Id private String name;
    @Id private java.sql.Date dob;
    private long salary;
    @ManyToOne
    private Employee manager;
    // ...
}
@Entity
@Table(name="PT_EMP")
@AttributeOverrides({
    @AttributeOverride(name="name", column=@Column(name="EMP_NAME")),
    @AttributeOverride(name="salary", column=@Column(name="SAL"))})
@AssociationOverride(name="manager",
    joinColumns={
        @JoinColumn(name="MGR_NAME", referencedName="EMP_NAME"),
        @JoinColumn(name="MGR_DOB", referencedName="DOB")})
public class PartTimeEmployee extends Employee { ... }
Listing 13-34

Using Attribute and Association Overrides with Inheritance

Here is an orm.xml snippet:

<entity class="examples.model.PartTimeEmployee">
    ...
    <attribute-override name="name">
        <column name="EMP_NAME"/>
    </attribute-override>
    <attribute-override name="salary">
        <column name="SAL"/>
    </attribute-override>
    <association-override name="manager">
        <join-column name="MGR_NAME"  referenced-column-name="EMP_NAME"/>
        <join-column name="MGR_DOB" referenced-column-name="DOB"/>
    </association-override>
    ...
</entity>

Lifecycle Events

All the lifecycle events that can be associated with a method in an entity listener can also be associated directly with a method in an entity or mapped superclass (refer to Chapter 12). The pre-persist, post-persist, pre-update, post-update, pre-remove, post-remove, and post-load methods are all valid subelements of the entity or mapped-superclass elements. Each of them can occur only once in each class. Each lifecycle event element will override any entity callback method of the same event type that might be annotated in the entity class.

Before anyone goes out and overrides all their annotated callback methods with XML overrides, we should mention that the use case for doing such a thing borders on, if not completely falls off into, the non-existent. An example of specifying an entity callback method in annotations and in XML is shown in Listing 13-35.

@Entity
public class Employee {
    // ...
    @PrePersist
    @PostLoad
    public void initTransientState() { ... }
    // ...
}
Listing 13-35

Specifying Lifecycle Callback Methods

Here is an orm.xml snippet:

<entity class="examples.model.Employee">
    ...
    <pre-persist method-name="initTransientState"/>
    <post-load method-name="initTransientState"/>
    ...
</entity>

Entity Listeners

Lifecycle callback methods defined on a class other than the entity class are called entity listeners. The following sections describe how to configure entity listeners in XML using the entity-listeners element and how to exclude inherited and default listeners.

entity-listeners

One or more ordered entity listener classes can be defined in an @EntityListeners annotation on an entity or mapped superclass (refer to Chapter 12). When a lifecycle event fires, the listeners that have methods for the event will get invoked in the order in which they are listed. The entity-listeners element can be specified as a subelement of an entity or mapped-superclass element to accomplish exactly the same thing. It will also have the effect of overriding the entity listeners defined in an @EntityListeners annotation with the ones defined in the entity-listeners element.

An entity-listeners element includes a list of ordered entity-listener subelements, each of which defines an entity-listener class in its class attribute. For each listener, the methods corresponding to lifecycle events must be indicated as subelement events. The events can be one or more of pre-persist, post-persist, pre-update, post-update, pre-remove, post-remove, and post-load, which correspond to the @PrePersist, @PostPersist, @PreUpdate, @PostUpdate, @PreRemove, @PostRemove, and @PostLoad annotations, respectively. Each of the event subelements has a method-name attribute that names the method to be invoked when its lifecycle event is triggered. The same method can be supplied for multiple events, but no more than one event of the same type can be specified on a single listener class.

The entity-listeners element can be used to disable all the entity listeners defined on a class or just add an additional listener. Disabling listeners is not recommended, of course, because listeners defined on a class tend to be fairly coupled to the class itself, and disabling them might introduce bugs into either the class or the system as a whole.

Listing 13-36 shows that the XML mapping file is overriding the entity listeners on the Employee class. It is keeping the existing ones, but also adding one more at the end of the order to notify the IT department to remove an employee’s user accounts when he or she leaves the company.

@Entity
@EntityListeners({ EmployeeAuditListener.class, NameValidator.class })
public class Employee { ... }
public class EmployeeAuditListener {
    @PostPersist
    public void employeeCreated(Employee emp) { ... }
    @PostUpdate
    public void employeeUpdated(Employee emp) { ... }
    @PostRemove
    public void employeeRemoved(Employee emp) { ... }
}
public class NameValidator {
    @PrePersist
    public void validateName(Employee emp) { ... }
}
public class EmployeeExitListener {
    public void notifyIT(Employee emp) { ... }
}
Listing 13-36

Overriding Entity Listeners

Here is an orm.xml snippet:

<entity class="examples.model.Employee">
    ...
    <entity-listeners>
        <entity-listener class="examples.listeners.EmployeeAuditListener">
            <post-persist method-name="employeeCreated"/>
            <post-update method-name="employeeUpdated"/>
            <post-remove method-name="employeeRemoved"/>
        </entity-listener>
        <entity-listener class="examples.listeners.NameValidator">
            <pre-persist method-name="validateName"/>
        </entity-listener>
        <entity-listener class="examples.listeners.EmployeeExitListener">
            <post-remove method-name="notifyIT"/>
        </entity-listener>
    </entity-listeners>
    ...
</entity>

Note that we have fully specified each of the entity callback listeners in XML. Some vendors will find the lifecycle event annotations on the EmployeeAuditListener and NameValidator entity listener classes, but this is not required behavior. To be portable, the lifecycle event methods should be specified in each of the entity-listener elements.

exclude-default-listeners

The set of default entity listeners that applies to all entities is defined in the entity-listeners subelement of the persistence-unit-defaults element (see the entity-listeners section). These listeners can be turned off or disabled for a particular entity or hierarchy of entities by specifying an empty exclude-default-listeners element within the entity or mapped-superclass element. This is equivalent to the @ExcludeDefaultListeners annotation, and if either one is specified for a class, default listeners are disabled for that class. Note that exclude-default-listeners is an empty element, not a Boolean. If default entity listeners are disabled for a class by an @ExcludeDefaultListeners annotation, there is currently no way to re-enable them through XML.

exclude-superclass-listeners

Entity listeners defined on the superclass of an entity will normally be fired before the entity listeners defined on the entity class itself are fired (refer to Chapter 12). To disable the listeners defined on an entity superclass or mapped superclass, an empty exclude-superclass-listeners element can be supplied inside an entity or mapped-superclass element. This will disable the superclass listeners for the managed class and all its subclasses.

The exclude-superclass-listeners element corresponds to the @ExcludeSuperclassListeners annotation and, like the exclude-default-listeners/@ExcludeDefaultListeners pair, either one of the two can be specified in order to disable the superclass listeners for the entity or mapped superclass and its subclasses.

Named Entity Graphs

Named entity graphs act as fetch plans for object queries and can override the fetch mode of field or property mappings for entity and embeddable types (see Chapter 11). The named-entity-graph element is equivalent to the @NamedEntityGraph annotation (see Chapter 11) and can only occur as a subelement of the entity element. Any named entity graphs defined in XML will be added to the named entity graphs defined in annotation form. If an XML named entity graph is named the same as one defined by an annotation, then the XML version will supercede the annotation definition.

A named-entity-graph has two optional attributes: a name attribute to explicitly declare its name and an includeAllAttributes boolean attribute that serves as a short form for including each and every field or property of the entity. Three subelements may multiply occur within named-entity-graph:
  • A named-attribute-node subelement is added for each named field or property to be fetched and is similar in structure to the @NamedAttributeNode annotation. It has a mandatory name attribute and optional subgraph and key-subgraph String attributes to refer to a subgraph element.

  • The subgraph subelement of named-entity-graph is the analogue to the @NamedSubgraph annotation and is used to specify a type template for an entity or embeddable type. It has a mandatory name attribute and a class attribute that is only used when the subgraph is for a class in an inheritance hierarchy. A named-attribute-node subelement must be specified for each field or property that is to be included in the subgraph.

  • The subclass-subgraph subelement of named-entity-graph can be specified the same as a subgraph element, with name and class attributes, and a named-attribute-node subelement for each field or property to be fetched. The subclass-subgraph element is only used to specify subgraphs for the subclasses of the entity that is the root of the named entity graph.

An example will make it much easier to see how the XML compares with the annotation. Listing 13-37 starts by showing an annotation from Chapter 11 that defines a named entity graph with multiple subgraph type definitions. The XML equivalent that uses multiple named-attribute-node and subgraph subelements follows.

@NamedEntityGraph(
    attributeNodes={
        @NamedAttributeNode("name"),
        @NamedAttributeNode("salary"),
        @NamedAttributeNode(value="address"),
        @NamedAttributeNode(value="phones", subgraph="phone"),
        @NamedAttributeNode(value="manager", subgraph="namedEmp"),
        @NamedAttributeNode(value="department", subgraph="dept")},
    subgraphs={
        @NamedSubgraph(name="phone",
            attributeNodes={
                @NamedAttributeNode("number"),
                @NamedAttributeNode("type"),
                @NamedAttributeNode(value="employee", subgraph="namedEmp")}),
        @NamedSubgraph(name="namedEmp",
            attributeNodes={
                @NamedAttributeNode("name")}),
        @NamedSubgraph(name="dept",
            attributeNodes={
                @NamedAttributeNode("name")})
    })
Listing 13-37

Named Entity Graph with Multiple Subgraphs

Here is an orm.xml snippet:

<named-entity-graph>
    <named-attribute-node name="name"/>
    <named-attribute-node name="salary"/>
    <named-attribute-node name="address"/>
    <named-attribute-node name="phones", subgraph="phone"/>
    <named-attribute-node name="manager", subgraph="namedEmp"/>
    <named-attribute-node name="department", subgraph="dept"/>
    <subgraph name="phone">
        <named-attribute-node name="number"/>
        <named-attribute-node name="type"/>
        <named-attribute-node name="employee" subgraph="namedEmp"/>
    </subgraph>
    <subgraph name="namedEmp">
        <named-attribute-node name="name"/>
    </subgraph>
    <subgraph name="dept">
        <named-attribute-node name="name"/>
    </subgraph>
</named-entity-graph>

Converters

Converters are a way to programmatically transform the data in a basic mapped field or property into an alternate form before it gets saved to the database, and then reverse the transformation again when the data gets read from the database back into the entity.

There are two parts to conversion: first, defining a converter, and second, applying it to entity fields or properties. This section discusses doing each of these in XML.

converter

A converter is a managed class that can be declared either using the @Converter annotation or in the mapping file using the converter subelement of entity-mappings. The converter element can be specified at the same level as the entity, embeddable, or mapped-superclass elements. It has only two attributes: class and auto-apply. The class attribute refers to the class that implements the javax.persistence.AttributeConverter<X,Y> interface while the auto-apply boolean option dictates whether the converter is to be automatically applied to entity fields or properties of type X throughout the persistence unit. See Chapter 10 for more details on how to use the auto-apply feature.

Note

JPA version 2.2 added support for CDI injection into the AttributeConverter classes, which mainly allow us to inject our reusable conversion implementation into the AttributeConverter.

It is undefined4 to have more than one converter class declared using the @Converter annotation to be auto-applied to the same target field or property type. However, an annotated converter can be overridden by using the converter element to declare a different (unannotated) converter class auto-applied to the same target type. For example, if we had a SecureURLConverter class that implemented AttributeConverter<URL,String>, then we could override the annotated URLConverter defined in Listing 13-5 with the secure version by declaring it in a converter element, as shown in Listing 13-38.

<entity-mappings>
    ...
    <converter class="examples.SecureURLConverter" auto-apply="true"/>
    ...
</entity-mappings>
Listing 13-38

Declaring an Auto-Applied Converter

convert

If a converter is not auto-applied, then it must be explicitly applied to a field or property in order for it to take effect. A converter can be applied to a field or property either by annotating it with the @Convert annotation or adding a convert subelement to the basic or element-collection element that maps the field or property.

The convert element contains three attributes. The first attribute, converter, is used to indicate the name of the converter class to apply. It is used whenever conversion is being explicitly applied to a field or property. Listing 13-39 shows how to apply a converter to an entity attribute using the convert element.

<entity-mappings>
    ...
    <entity class="examples.model.Employee">
        <attributes>
            ...
            <basic name="homePage">
                <convert converter="URLConverter"/>
            </basic>
        </attributes>
    </entity>
    ...
</entity-mappings>
Listing 13-39

Applying Conversion to an Entity Attribute

Two other attributes are used for overriding or adding conversion to an embedded or inherited field or property. One is the attribute-name attribute, which contains the name of the entity field or property to override or apply a converter to. The next attribute is a boolean-valued attribute called disable-conversion and it is used to override conversion in order to cause it not to occur.

A field or property can be marked for conversion, or overridden to not be converted, when the convert element is used within an entity or embedded element. Listing 13-40 shows how FTEmployee, an Employee subclass, can override the converter that was applied to homePage in Listing 13-39.

<entity-mappings>
    ...
    <entity class="examples.model.FTEmployee">
        ...
        <convert converter="SecureURLConverter" attribute-name="homePage"/>
    </entity>
    ...
</entity-mappings>
Listing 13-40

Overriding a Converter in an Inherited Entity Attribute

Summary

With all the XML mapping information under your belt, you should now be able to map entities using annotations, XML, or a combination of the two. In this chapter, we went over all the elements in the mapping file and compared them with their corresponding annotations. We discussed how each of the elements is used, what they override, and how they are overridden. We also used them in some short examples.

Defaults can be specified in the mapping files at different levels, from the global persistence unit level to the mapping file level. We covered what each of the defaulting scopes was and how they were applied.

The next chapter shows how to package and deploy applications that use JPA. We also look at how XML mapping files are referenced as part of a persistence unit configuration.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.141.244.153