Packaging a Persistence Unit




Packaging a Persistence Unit

An EntityManager maps a fixed set of classes to a particular database. This set of classes is called a persistence unit . Before you can even think about creating or querying entities with an entity manager, you must learn how to package a persistence unit for use within a Java SE (regular Java application) or Java EE (application server) environment. A persistence unit is defined in a persistence.xml file. This file is a required deployment descriptor for the Java Persistence specification. A persistence.xml file can define one or more persistence units. This file is located in the META-INF directory of:

  • A plain JAR file within the classpath of a regular Java SE program.

  • An EJB-JAR file. A persistence unit can be included with an EJB deployment.

  • A JAR file in the WEB-INF/lib directory in a web archive file (.war). See chapter-20 for details on what a WAR file is.

  • A JAR file in the root of an enterprise archive (.ear). See chapter-20 for details on what an EAR file is.

  • A JAR file in the EAR lib directory.

Figure shows what the structure of one of these JAR files might look like.

titan-persistence.jar


The persistence.xml deployment descriptor defines the identities and configuration properties of each persistence unit described within it. Each persistence unit must have an identity, although the empty string is a valid name.

The set of classes that belong to the persistence unit can be specified, or you can opt for the persistence provider to scan the JAR file automatically for the set of classes to deploy as entities. When scanning is used, the persistence provider will look at every class file within the JAR to determine if it is annotated with the @javax.persistence.Entity annotation and, if it is, it will add it to the set of entities that must be mapped.

Each persistence unit is tied to one and only one data source. In Java SE environments, vendor-specific configuration must be used to define and configure these data sources. In Java EE environments, specific XML elements define this association.

The root of the persistence.xml XML schema is the <persistence> element, which contains one or more <persistence-unit> elements. Each <persistence-unit> has two attributes: name (required) and transaction-type (optional). The subelements of <persistence-unit> are <description> (optional), <provider> (optional), <jta-data-source> (optional), <non-jta-data-source> (optional), <mapping-file> (optional), <jar-file> (optional), <class> (optional), <properties> (optional), and <exclude-unlisted-classes> (optional).

Here's an example of a persistence.xml file:

<persistence>
   <persistence-unit name="titan">
      <jta-data-source>java:/OracleDS</jta-data-source>
      <properties>
         <property name="org.hibernate.hbm2ddl">update</property>
      </properties>
   </persistence-unit>
</persistence>

The name attribute defines the name by which the unit will be referenced. This name is used by injection annotations and XML deployment descriptor elements to reference this unit. This attribute is required.

The transaction-type attribute defines whether you want your persistence unit to be managed by and integrated with Java EE transactions (JTA) or you want to use the resource local (RESOURCE_LOCAL ) javax.persistence.EntityTransaction API to manage the integrity of your EntityManager instances. This attribute defaults to JTA in Java EE environments and to RESOURCE_LOCAL in SE environments.

The <description> element is really just a comment describing the given persistence unit and is not required.

The <provider> element is the fully qualified name of a class that implements the javax.persistence.PersistenceProvider interface. In Java EE and SE environments, the persistence implementation is pluggable: your vendor provides an appropriate implementation. Usually, you do not have to define this element and can rely on the default value.

If you are using JTA or RESOURCE_LOCAL persistence units, you will probably define a <jta-data-source> or <non-jta-data-source> element, respectively. These elements specify a vendor-specific identity of a particular data source. Usually, this string is the global JNDI name for referencing the data source. If neither is defined, then a vendor-provided default will be used.

The <properties> element defines the set of vendor-specific attributes passed to the persistence provider. They specify configuration that is specific to a vendor implementation. Since there is no registry or JNDI service within Java SE, this is usually how vendors configure data sources, instead of using the <jta-data-source> and <non-jta-data-source> elements.

The JAR file of the persistence unit may also optionally contain a mapping XML deployment descriptor called orm.xml in the META-INF directory of the deployment. This file is used to define the mapping between the classes contained in the persistence unit and the database to which they map. Additional mapping files can be referenced using the <mapping-file> element. The value of this element is a classpath location and not a hardcoded URL. You can specify as many <mapping-file> elements as you wish. Examples of orm.xml mapping files are shown throughout chapter-6chapter-8.

The Persistence Unit Class Set

A persistence unit maps a fixed set of classes to a relational database. By default, if you specify no other metadata within your persistence.xml file, the JAR file that contains persistence.xml will be scanned from its root for any classes annotated with the @javax.persistence.Entity annotation. These classes are added to the set of classes the persistence unit will manage. You can specify additional JARs that you want to be scanned using the <jar-file> element. The value of this element is a path relative to the JAR file that contains persistence.xml:

<persistence>
   <persistence-unit name="titan">
      <jta-data-source>java:/OracleDS</jta-data-source>
      <jar-file>../lib/customer.jar</jar-file>
      <properties>
         <property name="org.hibernate.hbm2ddl">update</property>
      </properties>
   </persistence-unit>
</persistence>

Scanning JAR files is guaranteed to work in Java EE environments but is not portable in Java SE applications. In theory, it may not be possible to determine the set of JAR files that must be scanned. In practice, however, this is not the case. All major vendors in the EJB 3.0 Expert Group were polled unofficially and said they would have no problems supporting this feature in SE. Whether you do or do not rely on a JAR scan, classes can be listed explicitly with the <class> element:

<persistence>
   <persistence-unit name="titan">
      <jta-data-source>java:/OracleDS</jta-data-source>
      <class>com.titan.domain.Cabin</class>
      <class>com.titan.domain.Customer</class>
      <properties>
         <property name="org.hibernate.hbm2ddl">update</property>
      </properties>
   </persistence-unit>
</persistence>

The Cabin and Customer classes listed within the <class> elements are added to the persistence unit set along with any other classes scanned in the persistence unit's archive. If you do not want the persistence.xml's JAR file to be scanned, then you can use the <exclude-unlisted-classes> element.

<persistence>
   <persistence-unit name="titan">
      <jta-data-source>java:/OracleDS</jta-data-source>
      <class>com.titan.domain.Cabin</class>
      <class>com.titan.domain.Customer</class>
      <exclude-unlisted-classes/>
      <properties>
         <property name="org.hibernate.hbm2ddl">update</property>
      </properties>
   </persistence-unit>
</persistence>

The final set of classes is determined by a union of all of the following metadata:

  • Classes annotated with @Entity in the persistence.xml file's JAR file (unless <exclude-unlisted-classes> is specified)

  • Classes annotated with @Entity that are contained within any JARs listed with any <jar-file> elements

  • Classes mapped in the META-INF/orm.xml file if it exists

  • Classes mapped in any XML files referenced with the <mapping-file> element

  • Classes listed with any <class> elements

Usually, you will find that you do not need to use the <class>, <jar-file>, or <mapping-file> element. One case where you may have the need is when the same class is being used and mapped within two or more persistence units.