Java Persistence API (JPA)
Java Persistence API (JPA)
This is a guide for configuring persistence using the Java Persistence API (JPA). We have chosen to use the Apache OpenJPA implementation.
As a workaround for an issue with WebLogic, it was necessary to rename the persistence.xml file to jpa-persistence.xml.
About JPA
Originally part of the JSR-220 Enterprise JavaBeans 3.0 specification, JPA was separated from EJB 2.0 to be a standalone specification for Java persistence. There are many successful implementations of JPA, including
Features of JPA include
- Supports a POJO (Plain Old Java Object) persistence model.
- Rich inheritance support.
- Support for annotations or XML based mapping files.
- Supports pluggable persistence providers.
- Supported by Spring
- Supports native SQL as well as the Java Persistence Query Language (JPQL)
Online documentation
As a starting point, you should take a look at the following documentation.
- Java Persistence API docs
- OpenJPA API docs.
- Spring Object Relational Mapping guide - JPA section.
- Spring JPA integration API docs
Entities and Identities
Entity Characteristics
Any application defined object with the following characteristics can be an Entity:
- It can be made persistent
- It has a persistent identity (i.e. a unique key)
- It is not a primitive, a primitive wrapper of build-in object.
So in most cases a concrete or an abstract class can be an Entity.
Mixed inheritance is supported - the superclass and/or subclass of an Entity does not have to be an Entity.
Entity Identification
All Entities must have a persistent id (i.e. a database primary key). This is known as the entity identity (or persistence identity) JPA supports
- Single field identity (like our long uidPk field)
- Composite primary keys (provided by an Identity class)
The Entity Identity must be defined on the root Entity or mapped superclass of the hierarchy. In our domain model, we have the uidPk identity defined on the Persistable interface. Persistence classes need to implement the getUidPk() method with the @Id annotation and setUidPk() method.
JPA supports several strategies for primary key generation:
- Auto - leave the decision up to the JPA implementation.
- Identity - the database will assign an identity value on insert
- Sequence - use a datastore sequence to generate a value
- Table - use a sequence table to generate a field value
Table is the generator used in our object model, as this will work with all databases, and offers the best overall performance. In our persistence classes we define the generator table JPA_GENERATED_KEYS with columns ID and LAST_VALUE, with a name and primary key value matching the name of the DB table that the class will be persisted to. JPA uses this table to keep track of the last identifier value used to ensure the next one used is unique. You can configure the number of values to allocate in memory for each trip to the database (default is 50). Allocating values in memory allows the JPA runtime to avoid accessing the database for every sequence request.
The annotations on the getUidPk() method are as follows:
@Id @Column(name = "UIDPK") @GeneratedValue(strategy = GenerationType.TABLE, generator = TABLE_NAME) @TableGenerator(name = TABLE_NAME, table = "JPA_GENERATED_KEYS", pkColumnName = "ID", valueColumnName = "LAST_VALUE", pkColumnValue = TABLE_NAME)
Packaging
JPA requires one XML file META-INF/persistence.xml which
- Defines the name of the persistence unit
- Defines the transaction strategy
- Identifies the entities contained within a persistence unit
- Defines persistence provider configuration
- It can also define the location of XML mapping files
Here is a sample META-INF/persistence.xml file
<?xml version="1.0" encoding="UTF-8" ?> <persistence xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd" version="1.0"> <persistence-unit name="myopenjpa"> <provider>org.apache.openjpa.persistence.PersistenceProviderImpl</provider> <class>com.elasticpath.domain.catalog.impl.AbstractPriceImpl</class> <class>com.elasticpath.domain.catalog.impl.BrandImpl</class> <class>com.elasticpath.domain.catalog.impl.CategoryImpl</class> <class>com.elasticpath.domain.catalog.impl.CategoryTypeImpl</class> <class>com.elasticpath.domain.catalog.impl.InventoryImpl</class> <class>com.elasticpath.domain.catalog.impl.ProductAssociationImpl</class> <class>com.elasticpath.domain.catalog.impl.ProductCategoryImpl</class> <class>com.elasticpath.domain.catalog.impl.ProductImpl</class> <class>com.elasticpath.domain.catalog.impl.ProductSkuImpl</class> <class>com.elasticpath.domain.catalog.impl.ProductTypeImpl</class> ... <properties> <property name="openjpa.ConnectionFactoryName" value="java:comp/env/jdbc/epjndi"/commerce-legacy/> </properties> </persistence-unit> </persistence>
This example defines a persistence unit named "myopenjpa", identifies the provider as OpenJPA (org.apache.openjpa.persistence.PersistenceProviderImpl), lists the classes contained in the persistence unit, and sets the connection factory to java:comp/env/jdbc/epjndi.
OpenJPA Properties
In our standard persistence unit (META-INF/jpa-persistence.xml) we set the following OpenJPA properties:
core/ep-persistence-openjpa-itests/src/main/resources/META-INF/jpa-persistence.xml <properties> <property name="openjpa.ConnectionFactoryName" value="java:comp/env/jdbc/epjndi"/commerce-legacy/> <property name="openjpa.Log" value="slf4j"/commerce-legacy/> <property name="openjpa.ConnectionFactoryProperties" value="PrettyPrint=true, PrettyPrintLineLength=120"/commerce-legacy/> <property name="openjpa.jdbc.EagerFetchMode" value="parallel"/commerce-legacy/> <property name="openjpa.jdbc.SubclassFetchMode" value="parallel"/commerce-legacy/> <property name="openjpa.DetachState" value="loaded(DetachedStateField=true)"/commerce-legacy/> <property name="openjpa.Multithreaded" value="true"/commerce-legacy/> <property name="openjpa.AutoDetach" value="close, commit, nontx-read"/commerce-legacy/> <property name="openjpa.jdbc.DBDictionary" value="SupportsSubselect=true, SupportsCorrelatedSubselect=false"/commerce-legacy/> <property name="openjpa.jdbc.FinderCache" value="false"/commerce-legacy/> <!-- OpenJPA 2.x compatibility against spec --> <property name="openjpa.Compatibility" value="convertPositionalParametersToNamed=true"/commerce-legacy/> <!-- Pre-Load Metadata --> <property name="openjpa.MetaDataRepository" value="Preload=true"/commerce-legacy/> <!-- Uncomment the section below to enable data caching using openjpa cache manager, comment them out to disable --> <!-- <property name="openjpa.DataCache" value="true(cacheSize=25000,softReferenceSize=0)"/commerce-legacy/> <property name="openjpa.RemoteCommitProvider" value="sjvm"/commerce-legacy/> <property name="openjpa.DataCacheTimeout" value="1000"/commerce-legacy/> <property name="openjpa.QueryCompilationCache" value="true(cacheSize=2500,softReferenceSize=0)"/commerce-legacy/> <property name="openjpa.QueryCache" value="true(cacheSize=10000,softReferenceSize=0)"/commerce-legacy/> <property name="openjpa.jdbc.QuerySQLCache" value="false"/commerce-legacy/> --> <!-- Or uncomment the section below to enable data caching using Ehcache cache manager, comment them out to disable --> <!-- <property name="openjpa.DataCacheManager" value="ehcache" /> <property name="openjpa.DataCache" value="true"/commerce-legacy/> <property name="openjpa.RemoteCommitProvider" value="sjvm"/commerce-legacy/> <property name="openjpa.DataCacheTimeout" value="1000"/commerce-legacy/> <property name="openjpa.QueryCompilationCache" value="true"/commerce-legacy/> <property name="openjpa.jdbc.FinderCache" value="false"/commerce-legacy/> <property name="openjpa.QueryCache" value="ehcache"/commerce-legacy/> <property name="openjpa.jdbc.QuerySQLCache" value="false"/commerce-legacy/> --> <!-- Don't use this in production!!! --> <property name="openjpa.jdbc.SynchronizeMappings" value="buildSchema"/commerce-legacy/> </properties>
The following table gives a brief summary of the given settings:
Property | Description |
---|---|
ConnectionFactoryName | Tells OpenJPA the JDNI location of the Datasource file. |
Log |
Tells OpenJPA which logging library to use for issuing log messages. |
ConnectionFactoryProperties |
This is used to format the log output of SQL debug messages to a more readable form. |
EagerFetchMode |
Set to "parallel" which was found to be the most efficient eager fetch mode for our domain model. |
SubclassFetchMode | Set to "parallel" which was found to be the most efficient subclass fetch mode for our domain model. |
DetachState | Tell OpenJPA to take advantage of a detached state field to make the attach process more efficient. This field is added by the enhancer and is not visible to your application. The loaded value tells OpenJPA to detach all fields and relations that are already loaded, but don't include unloaded fields in the detached graph. Setting DetachedStateField to true tells OpenJPA to use a non-transient detached state field so that objects crossing serialization barriers can still be attached efficiently. This requires, however, that your client tier have the enhanced versions of your classes and the OpenJPA libraries. |
Multithreaded |
This tells OpenJPA that persistent instances and OpenJPA components other than the EntityManagerFactory will be accessed by multiple threads at once. |
AutoDetatch |
This tells OpenJPA to detach entities on transaction commits, instances are read non-transactionally, or when the OpenJPA interface closes. |
DBDirectory | Tells OpenJPA that the database supports subselects in queries, but not correlated subselects. |
DataCache | Tells OpenJPA to use its own data cache for persistent level caching. |
DataCacheManager | Sets the cache manager. If omitted, the default OpenJPA cache manager will be used. |
RemoteCommitProvider | Sets OpenJPA to use a single JVM. |
DataCacheTimeout | Sets the data cache timeout to 1 second. This will override the Ehcache timeout. |
QueryCompilationCache | Tells OpenJPA to cache parsed query strings. As a result, most queries are only parsed once in OpenJPA, and cached thereafter. |
FinderCache | Tells OpenJPA not to use the FinderCache. The FinderCache currently has a bug which causes data corruption issues and must be disabled. |
QueryCache | Tells OpenJPA to cache the object ids returned by query executions. |
QuerySQLCache | Set to false so that OpenJPA does not cache the SQL queries it generates. |
Compatibility | Tells OpenJPA to convert positional parameters to named parameters to support mixed queries, as well as to use OpenJPA 1 behaviour for Detached state serialization |
MetaDataRepository | Tells OpenJPA to preload the metadata repository as a runtime performance optimization |
Class Enhancement
In order to provide optimal runtime performance, flexible lazy loading, and efficient, immediate dirty tracking, OpenJPA uses an enhancer. The enhancer post-processes the bytecode generated by your Java compiler for your domain classes, adding the necessary fields and methods to implement the required persistence features. This bytecode modification perfectly preserves the line numbers in stack traces and is compatible with Java debuggers.
Annotations
Overview
Most annotations are placed directly into the class files of the objects to be persisted. This makes it easy to maintain consistency between the objects and their persistence definition - there is no need to go find the "mapping file". Annotations are generally quicker to type than XML mapping definitions and IDE's like Eclipse support annotations including syntax checking and auto-completion. The exception to the rule is annotations that define named queries (see below).
Annotations can be at the field level (persistence layer writes directly to the field) or at the property level (persistence layer uses the getter and setter). You cannot mix field level and property level annotations within the same class hierarchy.
As a standard our object model uses property level annotations. So the annotations in the class files are written above the getter method for each property.
The OpenJPA User's Guide contains comprehensive documentation on all of the annotations available along with what parameters they take. You will need to refer to this often when doing your own mappings.
Simple annotations
Here's a list of some of the more common simple annotations:
Annotation | Purpose |
---|---|
@Entity |
denotes an entity class |
@Table(name = "tablename") |
denotes that the entity should persist to the tablename table in the schema |
@Id |
denotes a simple identity field |
@Basic |
denotes a simple value that should be persisted as-is |
@Column(name = "columnname") |
denotes that the value should be persisted to the columnname column in the schema |
@Temporal |
defines how to use Date fields at the JDBC level |
@Enumerated |
control how Enum fields are mapped |
@Transient |
specifies that a field is non-persistent |
Note that properties in a class defined as an Entity that do not have any annotations may still be treated as persistable depending on the type. To avoid any confusion, ensure you annotate all property getters including @Basic and @Transient properties!
Relationship management
Here's a list of some of the annotations commonly used for mapping relationships in JPA
Annotation | Purpose |
---|---|
@OneToOne |
When an entity A references a single entity B, and no other A's can reference the same B, we say there is a one to one relation between A and B |
@OneToMany |
When an entity A references multiple B entities, and no two A's reference the same B, we say there is a one to many relation from A to B |
@ManyToOne |
When an entity A references a single entity B, and other A's might also reference the same B, we say there is a many to one relation from A to B |
@ManyToMany |
When an entity A references multiple B entities, and other A's might reference some of the same B's, we say there is a many to many relation between A and B |
@Embedded |
Embedded fields are mapped as part of the datastore record of the declaring entity. A class can be marked as embeddable by adding the @Embeddable annotation to the class |
Inheritance
JPA provides two annotations for supporting inheritance
Annotation | Purpose |
---|---|
@MappedSuperclass |
a non-entity class that can define persistent state and mapping information for entity subclasses. Mapped superclasses are usually abstract. Unlike true entities, you cannot query a mapped superclass, pass a mapped superclass instance to any EntityManager or Query methods, or declare a persistent relation with a mapped superclass target |
@Inheritance |
Used to indicate the strategy for a hierarchy of entities. There are 3 strategies to chose from
|
OpenJPA specific annotations
OpenJPA provides some useful annotations in addition to those provided by the JPA specs. Many of these were required in our system due to the complexity of the object domain model. An overview of the OpenJPA specific annotations commonly used are as follows:
Annotation | Purpose |
---|---|
@ForeignKey |
Foreign key definition. It is important this annotation is present when there is a DB foreign key so that OpenJPA can calculate the correct order to issue database statements without violating key constraints. |
@Dependent |
Marks a direct relation as dependent. This means the referenced object is deleted whenever the owning object is deleted, or whenever the relation is severed by nulling or resetting the owning field |
@ElementJoinColumn |
Array, collection, or map element join column |
@ElementForeignKey |
Define a foreign key constraint to the columns of a collection element |
@ElementDependent |
Marks the entity elements of a collection, array, or map field as dependent. This means the referenced object is deleted whenever the owning object is deleted, or whenever the relation is severed by nulling or resetting the owning field |
@Factory |
Contains the name of a method that will be invoked to instantiate the field from the external form stored in the database. |
@Externalizer |
Sets the name of a method that will be invoked to convert the field into its external form for database storage |
@DataCache | If @DataCache(enabled = false) is present, then the entity will not be cached; All other combinations will enable caching (assuming that openjpa.DataCache = true in jpa-persistence.xml) of the entity. |
Example
Here is an example of an annotated class file which shows many of the annotation types in use
@Entity @Table(name = "TPRODUCT") public class ProductImpl extends AbstractEntityImpl implements Product { ... @Basic @Column(name = "START_DATE") public Date getStartDate() { return this.startDate; } @Version @Column(name = "LAST_MODIFIED_DATE") @Temporal(TemporalType.TIMESTAMP) public Date getLastModifiedDate() { return lastModifiedDate; } @ManyToOne(targetEntity = ProductTypeImpl.class) @JoinColumn(name = "PRODUCT_TYPE_UID") public ProductType getProductType() { return this.productType; } @Transient public ProductSku getDefaultSku() { if (defaultSku == null && productSkus != null && productSkus.size() > 0) { return (ProductSku) productSkus.values().iterator().next(); } return defaultSku; } @OneToMany(targetEntity = ProductPriceImpl.class, cascade = { CascadeType.PERSIST, CascadeType.REMOVE }) @MapKey(name = "currencyCode") @ElementJoinColumn(name = "PRODUCT_UID") public Map getProductPrices() { return productPrices; } ... }
Java Persistence Query Language (JPQL)
JPQL overview
JPQL executes over the abstract persistence schema (the entities you've created) defined by your persistence unit, rather than over the database like traditional SQL.
JPQL supports a SQL like syntax
SELECT [PD:<result>] [PD:FROM <candidate-class(es)>] [PD:WHERE <filter>] [PD:GROUP BY <grouping>] [PD:HAVING <having>] [PD:ORDER BY <ordering>]
JPQL supports dynamic and static (named) queries
Query basics
A simple query for all CategoryTypeImpl entities
SELECT ct FROM CategoryTypeImpl ct
The optional where clause places criteria on matching results. For example
SELECT j FROM ImportJobImpl j WHERE j.name = '01-SnapItUp'
And of course you can specify parameters, for example
SELECT c FROM CategoryImpl c WHERE c.code = ?1
Fetch joins
JPQL queries may specify one or more join fetch declarations, which allow the query to specify which fields in the returned instances will be pre-fetched
SELECT ct FROM CategoryTypeImpl ct JOIN FETCH ct.categoryAttributeGroupAttributes
Multiple fields may be specified in separate join fetch declarations. You may want to use other join types depending on the data, e.g. left outer join fetch.
Named queries
JPA supports the concept of named queries. While named queries can be defined in the annotations of a class (usually the class in which the named query is most relevant), they can also be defined external to the implementation class source files in XML files. In this case, each Java package has its own named queries XML file in META-INF/, entitled <packagename>-orm.xml. This is useful for keeping all the named queries specific to a package in the same place while allowing easier extensibility, so that queries can be modified without requiring the application to be recompiled.
Here is an example of named queries in an XML file:
<?xml version="1.0" encoding="UTF-8"?> <entity-mappings xmlns="http://java.sun.com/xml/ns/persistence/orm" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence/orm http://java.sun.com/xml/ns/persistence/orm_1_0.xsd" version="1.0"> <package>com.elasticpath.domain.customer.impl</package> <entity class="CustomerDeletedImpl"> <named-query name="CUSTOMER_UIDS_SELECT_BY_DELETED_DATE"> <query>select pd.customerUid from CustomerDeletedImpl as pd where pd.deletedDate >= ?1</query> </named-query> </entity> <entity class="CustomerGroupImpl"> <named-query name="CUSTOMERGROUP_SELECT_ALL"> <query>select cg from CustomerGroupImpl cg</query> </named-query> <named-query name="CUSTOMERGROUP_FIND_BY_NAME"> <query>select cg from CustomerGroupImpl cg where cg.name = ?1</query> </named-query> </entity> </entity-mappings>
Persistence coding
Entity Manager
One of the key interfaces in the Java Persistence API is the EntityManager. This is similar to Hibernate's Session interface, providing services for CRUD operations (persist, remove, find, merge etc), creating Query instances and interfacing to the Transaction API.
Spring integration
Spring provides JPA integration, implementing JPA Container responsibilities. It includes beans like LocalEntityManagerFactoryBean which make it easy to configure the Entity Manager Factory through Spring configuration files, and SharedEntityManagerBean which provides a shared EntityManager reference.
Core Engine Persistence model integration
JPA has been integrated with Elastic Path's core persistence model, which makes considerable use of Spring Inversion of Control and Dependency Injection.
Here is a summary of the core classes that you'll use for persistence. You can find these in the com.elasticpath.persistence.openjpa.impl package of ep-persistence-openjpa
Class | Implements core interface | Purpose | How it works |
---|---|---|---|
JpaPersistenceEngineImpl | PersistenceEngine | The main persistence engine class. This is what you would set as the persistenceEngine property in your Spring configuration files for the service beans | This class uses a shared EntityManager provided by the Spring configuration |
JpaSessionImpl | PersistenceSession | This is used by code such as the Import Manager which uses the PersistenceSession interface to run queries on the session in a transaction under it's control | This class uses the EntityManager methods directly |
JpaQueryImpl | Query | This is used by code such as the Import Manager which uses the Query interface to manipulate queries within it's own transaction | This class uses the javax.persistence.Query methods directly |
JpaTransactionImpl | Transaction | This is used by code such as the Import Manager which uses the Transaction interface control it's own transactions | This class uses the EntityTransaction methods directly |
The majority of the time you'll just use the persistence-api PersistenceEngine interface, and configure Spring to inject the JPA implementation, so your code generally doesn't need to know anything about JPA.
Eager vs. Lazy loading
You can define fields to load lazily or eagerly the annotations. Be aware that using eager loading for everything can seriously affect performance and is unnecessary in cases when you don't need every linked object.
Lazy loading will defer loading of a field's associated entity until it is accessed, but it must be accessed while the connection is still open. Trying to access that field after the connection is closed will throw a NullPointerException.
Best practice is to define all (non-basic) fields as lazy loading (the default for OneToMany and ManyToMany mappings) and then define named queries with fetch join to eagerly load the relation fields. When you need just the basic data you use a query without the fetch join and when you need everything you use the fetch join query.
For example look at the following named queries (shown in class annotation format rather than the preferred XML format):
@NamedQuery(name = "CATEGORY_SELECT_BY_GUID", query = "SELECT c FROM CategoryImpl c WHERE c.code = ?1")
and
@NamedQuery(name = "CATEGORY_SELECT_BY_GUID_EAGER", query = "SELECT c FROM CategoryImpl c " + "LEFT OUTER JOIN FETCH c.localeDependantFieldsMap " + "LEFT OUTER JOIN FETCH c.attributeValueMap " + "WHERE c.code = ?1")
You would use the first one when you just want the basic Category information, and the second when you need all the locale dependent fields and attributes.
Fetch Groups
OpenJPA provides the concept of Fetch Groups - sets of fields that load together. They can be used to to pool together associated fields in order to provide performance improvements over standard data fetching. Specifying fetch groups allows for tuning of lazy loading and eager fetching behavior. Fetch groups are used in our system for objects that are indexed by our Search Server to define exactly what fields need to be loaded by the indexing jobs.
Problems and Workarounds
JPA is designed to be simple and easy to use, so it is less complex than Hibernate. Sometimes this means that mappings that were possible in Hibernate are not possible to do in JPA without some modifications to the object model.
Locale and Currency
JPA does not support the Locale and Currency types so some special OpenJPA annotations are required when using these datatypes.
For example, here are annotated getters for Locale and Currency fields:
@Persistent(optional = false) @Externalizer("toString") @Factory("org.apache.commons.lang.LocaleUtils.toLocale") @Column(name = "LOCALE", length = 20) public Locale getLocale() { return locale; } @Persistent @Column(name = "CURRENCY", length = 3) @Externalizer("getCurrencyCode") @Factory("com.elasticpath.commons.util.impl.UtilityImpl.currencyFromString") public Currency getCurrency() { return currency; }
This tells JPA the externalizer method to use to convert the field into its external form for database storage (eg getCurrencyCode()) for Currency), and to the full class and method to instantiate the field from the external form stored in the database.
Constructors
JPA requires all entities to have a default constructor which it will call when the persistence layer starts up. If there is no default constructor the build-time enhancer will add one for you.
Where you need to be careful is if you have code in your constructor that is expecting other objects to have already been instantiated. For example, this code was originally in the constructor for ShoppingCartImpl
public ShoppingCartImpl() { super(); this.shippingServiceLevelList = new ArrayList(); this.viewHistory = (ViewHistory) getElasticPath().getBean("viewHistory"); }
Before this class was annotated as a JPA Entity the constructor wasn't being called until the ElasticPathImpl bean factory added a bean for ShoppingCartImpl, so the call to getElasticPath() would always work. However, once this class was added to the list of persistence entities, the constructor was being called before ElasticPathImpl was being instantiated, so the call to getElasticPath() would fail!
The work around is to put any code in the constructor that relies on other objects in a more appropriate place. In this particular case the code to get the viewHistory bean was moved into the getViewHistory method of ShoppingCartImpl.
Useful tools
The OpenJPA Maven plugin includes some useful tools that can help with using JPA.
Mapping Tool
The mapping tool can generate a schema from your object model. It is very useful for checking if your annotations map the object(s) to the current schema, or for generating the SQL if you add a new object.
You can run the tool by calling the following Maven command in the ep-core directory:
mvn -Dopenjpa.ConnectionDriverName=com.mysql.jdbc.Driver openjpa:sql
The generated file, database.sql, can be found in ep-core\target.
Logging
Detailed logging for JPA can be enabled by adding the following to your log4j.properties files
log4j.category.openjpa.jdbc.SQL=TRACE log4j.category.openjpa.Runtime=TRACE log4j.category.openjpa.MetaData=TRACE log4j.category.openjpa.Enhance=TRACE log4j.category.openjpa.Query=TRACE
These values should be removed or set to ${ep_log_level} for distribution
Required libraries
The following libraries, which can be found in your local repository (by default, ~/.m2/repository), are required for use by JPA:
GroupId | ArtifactId | Version | Purpose |
---|---|---|---|
org.apache.openjpa |
openjpa |
2.3.0-ep2.0 |
Main Apache OpenJPA API |
org.apache.geronimo.specs |
geronimo-jta_1.1_spec |
1.1 |
JTA specifications API |
org.apache.geronimo.specs |
geronimo-jms_1.1_spec |
1.0.1 |
JMS specifications API |
org.apache.geronimo.specs |
geronimo-jpa_2.0_spec |
1.1 |
JPA specifications API |
net.sourceforge.serp |
serp |
1.14.1 |
Framework for manipulating Java bytecode |
commons-collections |
commons-collections |
3.2 |
Newer release of the commons collections API |
commons-pool |
commons-pool |
1.5.4 |
Object pooling components |
Extensibility
- MergingPersistenceUnitPostProcessor - Allows multiple jpa-persistence.xml files defining the same persistence unit name to exist in your project's classpath. The list of mapping files and managed classes are merged at runtime. For details on adding references to an extension project's jpa-persistence.xml, see Add references to the Persistence Unit
- OverridingPersistenceUnitPostProcessor - Allows an extension project to list mapping files and managed classes that should be excluded from the persistence unit, as well as adding and/or overriding JPA properties. For more details on these overrides, see Exclude references from the Persistence Unit and Override Persistence Unit Properties.