Java Persistence Lab
Java Persistence Lab
Java Persistence Lab
Page 1
Required Software
1. Java SE 1.6.0 SDK (version 1.5 should work as well). 2. MySQL or Derby database. 3. EclipseLink 2.x, an implementation of JPA 2.0. 4. Eclipse or NetBeans. Eclipse Helios and Indigo have good support for JPA, NetBeans 7 has reasonable support. These are not essential: you use JPA with any Java development tools. See end of this document for help installing this software.
Page 2
Persistent Storage
Page 3
EntityManager provides persistence operations such as find(...), persist(Entity), and remove(Entity). The createQuery method uses a String in Java Persistence Query Language (JPQL): SELECT c FROM City c WHERE c.name = 'Bangkok' This looks like SQL but is written in terms of classes and attributes, not tables. "City c" means a City object c, like in Java. The query returns objects (entities), as shown in the query.getResultList( ).
3. JPA Basics
In JPA, a class whose objects are persisted is called an Entity. An entity class is mapped to one or more tables in a database. In some frameworks objects can also be persisted to other forms of storage, including XML files, LDAP directory, or even an Excel spreadsheet. You have to describe the Entities to JPA, such as what attribute is the primary key, what attributes to save/restore, and associations with other objects. There are two ways to describe entities: annotations added to source code XML mapping file containing the same information, but in XML Both ways have advantages and disadvantages. You will use both in this lab.
Java Persistence Lab 5. Test the connection and fix any problems. Eclipse Helios (with Eclipse Data Tools plugin):
Page 4
Eclipse Data Tools let you connect to a database and explore it. You can perform queries, edit schema, and create Java code from schema. The tools are part of the Eclipse JavaEE bundle, and may already be installed on your machine. If your Eclipse has a perspective named "Database Development" then the tools are already installed. If not, you can install them from the Eclipse update site. To create a database connection: 1. In Window -> View, open the "Database Source Explorer" view. Right click on "Database Connections" and choose New. 2. Choose connector type (MySQL, Derby, etc). Eclipse provides only the "profile" for connectors. You must supply a JDBC connector JAR for the database, or create/use a Library for it. Click Next. 3. Enter database name or url, user, and password. Test the connection. 4. Click Next to view summary. Note the database URL. Click Finish
Page 5
4. Add a JDBC driver to your project as a Library or external JAR. For MySQL, the JAR file is mysql-connector-java-5.x.x-bin.jar For Derby embedded server, the JAR is derby.jar
Eclipse Dali JPA Extensions Eclipse has two extensions for JPA: Dali Java Persistence Tools and Dali EclipseLink Support (optional). These extensions are not required to use JPA, but they can reduce typing. The extensions also enable you to generate Java code from database schema and to synchronize files in a JPA project. To install the Dali extensions in Eclipse Helios or Indigo: 1.Click Help Install New Software 2. In the "Work with" box select Helios (or Indigo if you use Eclipse Indigo). 3. Check the boxes for the Dali tools and click "Install".
Java Persistence Lab NetBeans 7.0 1. Create a new Java project named WorldJPA. Any name is OK, but don't use your JDBC project. 2. Create a persistence unit. Right click on the project and choose New Other Persistence and choose Persistence Unit. Click Next and enter a persistence unit name (usually the database name), Persistence Library (the persistence provider), and database connection. Choose "None" for table generation strategy. ("Create" means JPA will create the schema in a new database)
Page 6
Netbeans creates META-INF/persistence.xml (if this file exists, it adds a new persistence unit). 3. Verify that NetBeans added the EclipseLink jars (eclipselink-2.x.jar and javax.persistence-2.0.jar) to your project in the Libraries folder. If not (or if you want to use a newer version of EclipseLink) then add them to the project by right-clicking on the project's Libraries folder. 4. Add a JDBC driver for your database. Right click on the Libraries folder and choose Add JAR or Add Library (if you have a library for the driver). NetBeans includes JDBC libraries for some databases, or you can use your own. Check persistence.xml The persistence.xml that NetBeans creates may contain this line:
<property name="eclipselink.ddl-generation" value="create-tables"/>
For this lab we already have a database schema, so delete this line.
Page 7
Note: In the xml header you can delete the long xsi:schemaLocation if you add eclipselink_orm_2_0.xsd to your IDE's Schema catalog, so the IDE can validate the XML. This avoids connecting to the Internet to get the schema. persistence version="2.0" (or newer). Make sure this is not 1.0. persistence-unit name="world" a persistence unit is a group of related entities. You can use any meaningful name; usually it is the database name. transaction-type="RESOURCE_LOCAL" for a stand-alone application. provider class is the implementation of JPA your are using. We are using EclipseLink. (zero or more times) are names of Entity classes.
properties JPA 2.0 specifies standard property names for URL, JDBC driver, user, and password. JPA providers can add optional properties, which don't begin with "javax.persistence". persistence.xml can specify more than one persistence-unit, each in its own section. It may also specify:
<mapping-file> (zero or more times) the name of a file containing object mapping info as XML.
This file is usually named orm.xml in the META-INF directory, but you can use any name and location. Some developers prefer to put it in the same source package as classes being mapped. <mapping-file>META-INF/orm.xml</mapping-file>
Page 8
5. Entity Classes
An entity class is a class whose objects are persisted. To be an Entity using JPA, a class must satisfy: 1. POJO rules: class has a non-private no-argument constructor (default constructor) get/set methods for persistent attributes, using Java standard naming convention 2. Class must not be final. Persisted variables and their get/set methods are not final, either. 3. Class must define an ID attribute that uniquely identifies each instance. This usually is the primary key of the table in a database. The ID can be a compound attribute. Both abstract and concrete classes can be entities. An entity class can extend another class. If an entity class will be used in a collection, then you should also specify: 4. Meaningful equals() and hashCode() methods. For persisted objects, the id attribute is a good choice. For transient (non-persisted) objects, the choice depends on your application.
Country code: String capital: City continent: String gnp: double lifeExpectancy:float name: String population: int region: String surfaceArea: float
Notice that City contains a reference to a Country object, whereas the city table contains a foreign key reference to a row in the country table. Similarly, a Country object contains a capital City reference, whereas the country table has a foreign key reference to a row in the city table.
Page 9
Next create an orm.xml file in the META-INF directory. orm.xml is where we define how to persist City objects. The xsi:schemaLocation string should be on one line.
<?xml version="1.0" encoding="UTF-8"?> <entity-mappings version="2.0" 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_2_0.xsd"> <entity class="world.domain.City" metadata-complete="true"> <attributes> <id name="id"> <column name="ID" nullable="false"/> <generated-value/> </id> <basic name="name"/>
Page 10
Each <entity> section specifies how to persist one entity class. The meta-data='true" is optional; it means that this file contains all the persistence info for City, so annotations in the City class (if any) are ignored. <attributes> define how to map attributes of City to columns in a database table. <id name="id"> declares the attribute id is a unique identifier for persisted objects. <column name="ID"> says that the id attribute maps to a column named ID in the database. This isn't required: JPA can automatically map attributes to columns when the names are the same ignoring case. <generated-value/> means that the database will generate the value of the id. <basic name="..."/> define an attribute that can be saved as a field in the database, using standard mapping between Java types and SQL types. <table name="CITY"/> we can specify the table name, but the default is a table with the same name as the class (JPA ignores case of letters to determine a matching table name). Since the column names are the same as the attribute names (except for case of letters), we don't have to specify them. We can, however, specify column names if we want.
public static EntityManagerFactory getFactory() { if (factory == null) factory = Persistence.createEntityManagerFactory(PERSISTENCE_UNIT); return factory; }
Page 11
Next, write a findCity( ) method that finds cities by name. There may be more than one match, so this method should return a collection. We will use a List since the JPA Query methods returns a List.
/** Find cities with a given name. Returns all matching cities. */ public static List<City> findCity(String name) { EntityManager em = getFactory().createEntityManager(); Query query = em.createQuery("SELECT c FROM City c WHERE c.name= :name"); query.setParameter("name", name); List<City> cities = query.getResultList(); em.close(); return cities; }
This query string uses Java Persistence Query Language (JPQL). The :name is a named parameter . The query.setParameter(name, value) method inserts an actual value for the named parameter. This is similar to using ? in an SQL PreparedStatement, but safer since values are substituted by name. Write a citySearch() method to prompt user for city name, call findCity, and display the results. Invoke citySearch from the class's main method.
/** User interface for finding cities by name. */ public static void citySearch( ) { Scanner console = new Scanner(System.in); while(true) { System.out.print("Name of city to find: "); String name = console.nextLine().trim(); if (name.length() == 0) break; List<City> cities = findCity(name); for(City city: cities) showCity( city ); } } //TODO write a showCity( City ) method to print city information //TODO invoke citySearch from the class's main method.
JDBC driver for your database not loaded. This could be due to forgetting to add the JAR file to the project, specifying the wrong driver class name in persistence.xml, or a mistake in the URL. For example: "jdbc.mysql://localhost/world" (should be jdbc:mysql). Can't connect to database because user or password is incorrect. If using Derby, a common problem is that a Derby database can have only one active connection. If you connected to Derby using some other tool (including the IDE's database browser), you must close that connection. Attribute name not consistent between Java source, orm.xml, and database field names. get/set method name doesn't match attribute name.
Note: the Exception output is usually very long. Start from the first exception and read down the list. Focus on (a) the Description of the exception, (b) the location. The first location inside your code is usually the cause.
Page 12
6. Entity Relationships
Objects usually contain references to other objects. A persistence framework needs to preserve these relationships. For example, a City refers to the Country it is part of. A Country has a reference to its capital City. There are 4 types of associations: One-to-one One-to-many Many-to-one Many-to-many In addition, relationships can be one-sided (unidirectional) or two-sided (bidirectional). One-sided: a Country has a reference to its capital City. Two-sided: a City refers to its Country, and the Country maintains a collection of its Cities.
Page 13
primary key and how it is generated. For Country, the application supplies the country code. one-to-one association of capital to a City object using the city ID. declare that Country is an entity in persistence.xml
1. Add these lines to orm.xml: <entity class="world.domain.Country"> <attributes> <id name="code"> <column name="Code" length="3"/> </id> <!-- use default mapping of basic attributes --> <one-to-one name="capital" fetch="EAGER"> <join-column name="Capital" referenced-column-name="ID"/> </many-to-one> </attributes> </entity> The <id> element specifies the column name and width for the country code. This is not required. <one-to-one name="capital"> refers to the capital attribute of Country. The <joincolumn...> specifies that the column named "Capital" should be joined to the ID of the city table. This is like the SQL: SELECT * FROM Country JOIN City ON Country.Capital = City.ID It is unfortunate (and confusing) that the capital attribute of Country has the same name as the field. A more standard field name for this would by Capital_ID. If the field name was Capital_ID we could have omitted the <join-column> and use the JPA defaults. 2. In persistence.xml add world.domain.Country as an entity class
<persistence version="2.0" ... <mapping-file>META-INF/orm.xml</mapping-file> <class>world.domain.City</class> <class>world.domain.Country</class>
Java Persistence Lab This code is nearly identical to the code you wrote for citySearch.
Name of country to find: Thailand Thailand is in Southeast Asia region Population 61,399,000 GNP per capita: USD 1,896.06 Capital city: Bangkok Name of country to find:
Page 14
Write a findCountry(name) method that returns a Country object. Since there should be only one country with a given name, we can use query.getSingleResult() to get a single Country object.
/** Find a Country with a given name. Result is null if no match. */ public static Country findCountry(String name) { EntityManager em = getFactory().createEntityManager(); Query query = em.createQuery("SELECT c FROM Country c WHERE c.name= :name"); query.setParameter("name", name); // this throws an Exception if there is more than one match Country co = (Country)query.getSingleResult(); em.close(); return co; }
Run your code. Does it retrieve both a Country object and a City object?
Fetching of Associations
When you use Query to retrieve a Country object, JPA automatically creates the City object for the Country capital. Moreover, if the capital City object refers to another entity, JPA will fetch that, too. JPA keeps track of which entities have been instantiated, so there is only one object for each entity data that is managed by JPA, no matter what queries we perform. For example, if execute a query to find a city named "Tokyo" (returns a City reference) and then perform another query for the country "Japan", Japan will contain a reference to Tokyo (as capital city). But both references to Tokyo refer to the same object.
Page 15
This mapping states that elements of the cities collection are controlled by the country attribute in City. We didn't specify the class of objects that cities maps to (called the target entity). The City class is inferred from the declaration of cities (e.g., Set<City> cities). You can specify the target entity explicitly using target-entity="world.domain.City", but don't do it -redundancy invites errors. 3. Modify showCountry() in JPADemo to display all the cities in a country. For example:
Name of country to find: Denmark Denmark is in Nordic Countries region Population 5,330,000 GNP per capita: USD 32,663.98 Capital city: Kbenhavn Other major cities: Frederiksberg, Frederiksberg pop. 90,327 Aalborg, Nordjylland pop. 161,161 Odense, Fyn pop. 183,912 rhus, rhus pop. 284,846
Don't display the capital city twice. JPA creates a unique object for each distinct row in the database table, so you can compare objects using ==, e.g. if (city != capital) showCity( city ).
Page 16
Bidirectional relationships present a problem: how to keep the two ends of the association consistent? Here is a simple example in Java, using the code for City and Country:
City sangkhla = citySearch.findCity("Sangklaburi"); // in Kanchanaburi // moved to Burma!!! Country burma = countrySearch.findCountry("Myanmar"); sangkhla.setCountry( burma ); // the cities collection for Thailand and Burma must be updated, too!
Persistence frameworks, including JPA, address this problem by designating one end of the association as primary or controlling and the other end is designated as inverse or slave. The framework guarantees to maintain consistency if you make a change on the primary end. But if you make a change on the inverse end the association is not guaranteed to remain consistent.
country For example: Country china = em.find( Country.class, "CHN"); // how many objects are created from database??? Should JPA instantiate all 343 City objects in the china.cities collection?
city
Our application might never reference those objects, resulting in a lot of wasted I/O and memory. It would be more efficient if JPA could wait until the first time our application accessed the City objects. JPA provides two fetching strategies for when associated objects are instantiated: fetch="EAGER" fetch="LAZY" when instantiating an entity, load all referenced entities immediately. when instantiating an entity, don't create referenced entities until they are accessed. The referenced objects will be created the first time they are accessed by the application (which may be never).
You can see the difference in our JPADemo program. In the showCountry() method, add code to display the class name of the cities collection:
Page 17
In orm.xml, the one-to-many mapping for cities has fetch="EAGER". Run JPADemo and search for a country. It should print: cities has type java.util.HashSet No surprise -- an ordinary Set. Now change orm.xml to use LAZY fetching of cities:
<one-to-many name="cities" mapped-by="country" fetch="LAZY"> </one-to-many>
When you run JPADemo again and search for a country it will print: cities has type org.eclipse.persistence.indirection.IndirectSet IndirectSet is a set that lazily Instantiates City objects as needed. Lazy fetching is usually more efficient than eager fetching, but has a potential problem. If you detach the entity before the associated objects are loaded, it will throw an exception when you try to access the unfetched objects.
8. Cascading Operations
When we save (persist) a Country, should the capital City be saved, too? If we tell JPA to delete a Country, should it also delete the referenced Cities and capital City? This behavior is called cascading. You can specify how JPA should cascade each entity association. For example, if we want all persistence operations for a Country to be applied to its capital City, we'd write: <many-to-one name="capital" fetch="EAGER"> <join-column name="Capital" referenced-column-name="ID"/> <cascade> <cascade-all/> <cascade> </many-to-one> Cascading is more complicated than fetching. The books in the references describe cascading in detail.
Page 18
9. Annotations
You can specify mapping information as annotations in Java source code, instead of using XML in mapping files. For existing source code, you can add the annotations yourself. In cases where you want to create classes to match a database schema, you can generate Entity classes with annotations automatically using the IDE. Both Eclipse and NetBeans can generate entity classes from database schema, and OpenJPA has a utility program for this. Java 1.5 supports annotations, but for full annotation processing you should use Java 1.6, aka Java 6.
DELETE
Java Persistence Lab 1. Edit the City class and add annotations.
Page 19
The JPA annotations are in the package javax.persistence; in this example we import all classes to minimize space in the code listing
package world.domain; import javax.persistence.*; // for annotation classes
@Entity public class City { @Id @GeneratedValue private Integer id; @Basic @Column(name="Name",nullable=false) private String name; private String district; private int population; @ManyToOne @JoinColumn(name="CountryCode") private Country country; /** required default constructor */ public City( ) { } //TODO get/set methods for all attributes //TODO equals method. Use the id attribute for comparison. //TODO write a toString() method }
JPA maps attributes to table columns having the same name, using a case insensitive match. It is very lenient about conversion of SQL data types to/from Java data types. An SQL INTEGER type can be mapped to a Java int, long, Integer, or Long (with possible loss of data). Similarly, a Java String can be persisted to SQL CHAR(n) or VARCHAR(n), with possible truncation of the string. We explicitly specified the @Basic and @Column mapping for the name attribute, as an example of how to use attribute mapping annotations. 2. Modify the Country class to use annotations. The "basic" attributes don't require any annotation and aren't shown here.
package world.domain; import javax.persistence.*; // for annotations @Entity public class Country implements Serializable { @Id private String code; private String name; ... //other attributes not shown here @ManyToOne @JoinColumn(name="Capital", referencedColumnName="ID") private City capital; @OneToMany(mappedBy="country") private Set<City> cities; //constructor and methods as before
Page 20
1-to-1 Mapping of Country.capital to City. The @JoinColumn name identifies the joining column in the Country table, and referencedColumnName is the column in the City table. @OneToOne @JoinColumn(name="Capital",referencedColumnName="ID") private City capital;
many-to-1 Mapping of City.country to a Country. @JoinColumn identifies the join column name in the City table. It will be joined to the primary key (code) in the Country table, since we didn't specify a referencedColumnName. @ManyToOne(optional=false) @JoinColumn(name="CountryCode", fetch=FetchType.LAZY) private Country country;
1-to-many Mapping of Country to its City(s), as inverse end of city-to-country mapping: @OneToMany(mappedBy="country") private Collection<City> cities; // inverse of City.country map
many-to-many Mapping A many-to-many mapping requires a join table. Not used in this example. embedded objects and enumerations JPA has special syntax for enumerations and for embedding the data for one object inside the row of data for the referencing object. (Described later.)
Page 21
Entity States
An entity can have several states: new - an object not yet persisted managed - object has been persisted and is currently attached or managed detached - object has been persisted, but is not currently being managed. Detached objects can be reattached (put back in managed state). TODO: Explain the entity life cycle.
The persist method may throw a DatabaseException if the user does not have INSERT permission for the tables or if any database constraint is violated (e.g. a null attribute for a required field).
There is something amazing here. We saved the return value from em.find() as a Country reference without using a cast. This only seems to work on Entity classes using annotations.
Page 22
2. Enter an "update" command using JPQL syntax, like an SQL UPDATE. Use a Query object to execute the update:
Query query = em.createQuery( "UPDATE Country c SET c.population=:pop WHERE c.name='Thailand'"); query.setParameter("pop", 67000000); tx = em.getTransaction( ); tx.begin(); query.executeUpdate( ); tx.commit();
Java Persistence Lab Names of classes and attributes are case-sensitive in JPQL (just like Java). Correct: Wrong: Correct: Correct: Wrong: select c from City c select c from city c SELECT c FROM City c // name of class is "City"
Page 23
select c from City c where c.name='Bangkok' select c from City c where name='Bangkok' // no object
Type-safe Queries
In the previous examples, we assigned q.getResultList( ) to List of City objects using unchecked type conversion. It's up to the programmer to make sure this will work; otherwise the code will throw a ClassCastException at runtime. JPA 2.0 has a typed query which is more type-safe that the Query interface in JPA 1.0. TypedQuery has a type parameter for the class of object(s) the query returns. TypedQuery<City> q = em.createQuery( "SELECT c FROM City c WHERE c.name = :name", City.class); q.setParameter("name", "New York"); List<City> cities = q.getResultList( ); Notice the 2nd parameter in createQuery. This creates a query that can only return City objects.
Page 24
Page 25
We can allow for alternate Dao implementations by writing an Interface for DAO and a DaoFactory to create instances of DAO. The DaoFactory would decide to create JPA-based DAO, JDBC DAO, or any other implementation we write. (See the reference article Core J2EE Patterns - Data Access Object.)
Page 26
Next>
Next>
5. Click Finish. Eclipse may create the association, but in my attempts using Helios SR2 it did not. 6. Complete the dialogs to create the Country class. For "annotation type", select "field". The mapping of capital to a City is a one-sided, many-to-one association. You may need to write this code yourself (delete the "int capital" and edit the get/setCapital methods).
package world.domain; @Entity public class Country implements Serializable { @Id private String code; @ManyToOne @JoinColumn(name="Capital", referencedColumnName="ID") private City capital; //TODO create get/set methods for Capital public City getCapital( ) { return capital; } public void setCaptial(City city) {
Page 27
Annotation for attributes that are associations to other persisted objects. Association to another object using a foreign key reference. Default field is country_code and target table determined by the class of attribute (Country). Default column name is the attribute name + "_" + name of key in target table. So the default for captal would be capital_ID. A Country has a collection of cities. It is an inverse map that is mapped by the country field in the City class.
Page 28
</entity-mapping>
Optional <package>. You can specify a default package name so you don't need to include the package on each class name. The package name applies to all <entity> entries until the next <package>.
<package>world.domain</package>
The mapping of a class is done in an entity tag. The attribute metadata-complete="true" means that this OR mapping specifies all mapping info, and annotations in the class should be ignored.
<entity class="world.domain.city"> </entity> <entity class="world.domain.country" metadata-complete="true"> </entiry>
Page 29
3. Click Next and enter package (world.domain) and select options. If you aren't using Named Queries or JAXB, then uncheck them.
4. The next dialog lets you select how associations should be fetched and whether collections should be declared as Collection, Set, or List.
Page 30
Page 31
2. Derby (Optional) You can use Derby or MySQL. Derby is simple to use, but sometimes annoying since it only allows only one connection to a database. More information on using Derby is in a separate lab sheet. download db-derby-10.1.2.zip (or any recent version) from derby.apache.org. unzip to your library directory, e.g. C:/lib. The zip file will create a subdirectory named "dbderby", such as C:/lib/db-derby. The Derby drivers are JAR files in directory dbderby/lib. So that you can use Derby tools like ij, set the DERBY_HOME environment variable and add DERBY_HOME/bin to your shell path. In Windows, right click MyComputer, choose Properties, Advanced, and add these. On Linux, edit your .profile or .bashrc (Tcsh users, edit .login). This is Windows syntax: set DERBY_HOME = C:/lib/db-derby set PATH = %DERBY_HOME%\bin;%PATH%
Page 32
(Optional) Create a Derby library in your IDE. There are 2 ways of using Derby: embedded server mode and client-server mode. In this lab we use embedded server mode (simpler) that is contained in the file db-derby/lib/derby.jar.
Page 33
Resources
These articles are given in the order that is instructive. 1. Accessing Data through Persistence Frameworks. http://www.developer.com/lang/article.php/3355151/Accessing-Data-Through-PersistenceFrameworks.htm 2. JPA 2.0 with EclipseLink Tutorial. http://www.vogella.de/articles/JavaPersistenceAPI/article.html. 3. Using the Java Persistence API in Desktop Applications, article from Sun (June 2007). http://java.sun.com/developer/technicalArticles/J2SE/Desktop/persistenceapi/. Older and biased toward Sun implementations (NetBeans, Toplink Essentials). 4. MyEclipse JPA Tutorial, http://www.myeclipseide.com/documentation/quickstarts/jpa/. Books and User Guides Bauer & King, Java Persistence with Hibernate, Manning, 2007. Excellent book about Hibernate and data persistence in Java, including JPA. Gavin King is founder of the Hibernate project, Bauer is member of the development team. OpenJPA User's Guide. This manual (in PDF form) has an ongoing example that shows every relationship you'd want to persist, and how to do it using either annotations or XML. Useful even if you don't use OpenJPA. Download from openjpa.apache.org. EclipseLink User's Guide at http://wiki.eclipse.org/EclipseLink. User guide in Wiki form. Examples mostly use annotations. Page /EclipseLink/Examples/JPA/EclipseLink-ORM.XML has XML.
JPA Implementations
JPA is a specification. To use it you need an implementation. JPA implementations are: EclipseLink, http://www.eclipse.org/eclipselink/. This is the JPA 2.0 reference implementation. TopLink Essentials, http://glassfish.dev.java.net/downloads/persistence/JavaPersistence.html a part of the Glassfish project. Hibernate, see JBoss Community Documentation for how to use Hibernate as JPA provider. DataNucleus Access Platform provides both JPA and JDO. Has good documentation and support for IDEs. http://www.datanucleus.org/products/accessplatform.html OpenJPA, an Apache project. http://openjpa.apache.org.
Page 34