Hibernate Migration - webdev home pagewebdev.jhuep.com/.../content/pdf/hibernate-migration.pdf ·...
Transcript of Hibernate Migration - webdev home pagewebdev.jhuep.com/.../content/pdf/hibernate-migration.pdf ·...
![Page 1: Hibernate Migration - webdev home pagewebdev.jhuep.com/.../content/pdf/hibernate-migration.pdf · 2014-03-07 · Chapter 1. Hibernate Legacy P... 2 4. Customer extends Person and](https://reader030.fdocuments.in/reader030/viewer/2022041017/5ec9985628e0741c1957f138/html5/thumbnails/1.jpg)
Hibernate Migration
Migrating from Legacy Hibernate
Session/HBM descriptors to JPA
Revision: v2013-08-19Built on: 2014-03-07 00:16 EST
Copyright © 2014 jim stafford ([email protected])
This presentation provides information for developers to migrate a legacy application from
Hibernate/HBM descriptor files to the Java Persistence API. It contains coverage of how to
construct Maven poms for the build environment, how to layout the project, and how to leverage
schema generation plugins within the build.
![Page 2: Hibernate Migration - webdev home pagewebdev.jhuep.com/.../content/pdf/hibernate-migration.pdf · 2014-03-07 · Chapter 1. Hibernate Legacy P... 2 4. Customer extends Person and](https://reader030.fdocuments.in/reader030/viewer/2022041017/5ec9985628e0741c1957f138/html5/thumbnails/2.jpg)
![Page 3: Hibernate Migration - webdev home pagewebdev.jhuep.com/.../content/pdf/hibernate-migration.pdf · 2014-03-07 · Chapter 1. Hibernate Legacy P... 2 4. Customer extends Person and](https://reader030.fdocuments.in/reader030/viewer/2022041017/5ec9985628e0741c1957f138/html5/thumbnails/3.jpg)
iii
Purpose ............................................................................................................................ v
1. Hibernate Legacy Project ............................................................................................ 1
1.1. Class Model ....................................................................................................... 1
1.2. Hibernate Configuration ....................................................................................... 2
1.3. Hibernate Session API ........................................................................................ 7
1.4. Test Case .......................................................................................................... 9
1.5. Maven Build ..................................................................................................... 11
1.6. Generating Schema from HBM files ................................................................... 14
1.7. Summary .......................................................................................................... 16
2. JPA Persistence Unit Using ORM.xml Mapping Files ................................................ 17
2.1. Going from HBM to ORM mapping files ............................................................. 17
2.2. JPA EntityManager API ..................................................................................... 21
2.3. Obtaining HIbernate Session from JPA .............................................................. 23
2.4. Mixing HBM and JPA definitions ........................................................................ 23
2.5. Generating Schema for JPA files ....................................................................... 24
2.6. Summary .......................................................................................................... 26
3. Adding Metadata thru Class Annotations .................................................................. 27
3.1. Entity Class Annotations .................................................................................... 27
3.2. Using Annotated Classes with Hibernate Configuration ........................................ 29
3.3. Accessing Annotated Classes with Hibernate Session ......................................... 30
3.4. Adding Overrides thru Custom Configuration ...................................................... 30
3.5. Adding Overrides thru Custom NamingStrategy .................................................. 33
3.6. Generating Schema from Class Annotations and NamingStrategy ........................ 36
3.7. Summary .......................................................................................................... 38
4. JPA-based Project ..................................................................................................... 39
4.1. JPA Project Structure ........................................................................................ 39
4.2. Generating Schema from JPA Persistence Unit .................................................. 42
4.3. Summary .......................................................................................................... 45
5. Hibernate Migration Errors ........................................................................................ 47
5.1. Missing hibernate-entitymanager ........................................................................ 47
5.1.1. Symptom: NoClassDefFoundError: org.hibernate.cfg.Configuration ............ 47
5.1.2. Cause: Missing dependency on hibernate-entitymanager .......................... 47
5.1.3. Solution: Declare plugin dependency on hibernate-entitymanager .............. 48
5.2. Mixed Hibernate Versions with plugin and JPA ................................................... 48
5.2.1. Symptom: NoSuchMethodException:
org.hibernate.validator.ClassValidator.<init>(...) .................................................. 48
5.2.2. Cause: Using JPAConfiguration and version mis-matches ......................... 48
5.2.3. Solution: Declare plugin dependency on hibernate-entitymanager .............. 49
5.3. slf4j version mis-matches with later versions of Hibernate .................................... 49
5.3.1. Symptom: NoClassDefFoundError: org.slf4j.helpers.NOPLoggerFactory .... 49
5.3.2. Cause: plugin dependency on hibernate-entitymanager causes slf4j-api
version mis-match ............................................................................................ 50
5.3.3. Solution: Exclude slf4j-api from plugin dependency ................................... 50
5.4. Summary .......................................................................................................... 51
![Page 4: Hibernate Migration - webdev home pagewebdev.jhuep.com/.../content/pdf/hibernate-migration.pdf · 2014-03-07 · Chapter 1. Hibernate Legacy P... 2 4. Customer extends Person and](https://reader030.fdocuments.in/reader030/viewer/2022041017/5ec9985628e0741c1957f138/html5/thumbnails/4.jpg)
iv
![Page 5: Hibernate Migration - webdev home pagewebdev.jhuep.com/.../content/pdf/hibernate-migration.pdf · 2014-03-07 · Chapter 1. Hibernate Legacy P... 2 4. Customer extends Person and](https://reader030.fdocuments.in/reader030/viewer/2022041017/5ec9985628e0741c1957f138/html5/thumbnails/5.jpg)
v
Purpose
Many other topics on this site are centered on how to work with the modern APIs. This topic is
centered on how best to work with the legacy form of a Hibernate project and migrate it gradually
to modern JPA constructs. The Hibernate Session will still be in place -- under the hood as acting
as the provider -- and accessible through a legal JPA call when needed. However, we will start
benefiting from using a standard API (and Hibernate extensions) to express mappings.
During this topic we will...
• Demonstrate options to upgrade a legacy Hibernate project to include
• Migrate from from Hibernate Session to JPA EntityManager by replacing descriptor files
• Mix use of Hibernate Session with JPA EntityManager
• Migrate away from Hibernate HBM files to Java annotated classes
• Override Java annotated classes within Hibernate Session
• Fully migrate to JPA Entity Manager, class annotations, and ORM.xml overrides
• Demonstrate how to automatically generate database schema for a project based on
• Hibernate Session and 2.x version of hibernate3-maven-plugin
• JPA EntityManager and 2.x version of hibernate3-maven-plugin
• Hibernate Session and 3.x version of hibernate3-maven-plugin
• JPA EntityManager and 3.x version of hibernate3-maven-plugin
![Page 6: Hibernate Migration - webdev home pagewebdev.jhuep.com/.../content/pdf/hibernate-migration.pdf · 2014-03-07 · Chapter 1. Hibernate Legacy P... 2 4. Customer extends Person and](https://reader030.fdocuments.in/reader030/viewer/2022041017/5ec9985628e0741c1957f138/html5/thumbnails/6.jpg)
vi
![Page 7: Hibernate Migration - webdev home pagewebdev.jhuep.com/.../content/pdf/hibernate-migration.pdf · 2014-03-07 · Chapter 1. Hibernate Legacy P... 2 4. Customer extends Person and](https://reader030.fdocuments.in/reader030/viewer/2022041017/5ec9985628e0741c1957f138/html5/thumbnails/7.jpg)
Chapter 1.
1
Hibernate Legacy ProjectThis chapter describes a starting point for our sample legacy Hibernate project. It is based on an
un-annotated class model, HBM files, a hibernate.cfg.xml configuration, and a Hibernate Session
at runtime.
1.1. Class Model
The example legacy model consists of four classes (Person, Clerk, Customer, Sale) and an enum
(CustomerLevel). Each of the classes is meant to be used with FIELD access and each overrides
hashCode/equals to provide a stable and unique identity for use within Sets. Since these aspects
are not central to the migration -- they have been left out of this write-up but are available in the
source code repository.
1.
src/main
|-- java
| `-- ejava
| `-- jpa
| `-- hibernatemigration
| `-- legacyhbm
| |-- Clerk.java
| |-- Customer.java
| |-- CustomerLevel.java
| |-- Person.java
| `-- Sale.java
2. One of the simpler classes is Person. It is a base class to Customer and Clerk. It supplies an
id and name property for its derived classes.
package ejava.jpa.hibernatemigration.legacyhbm;
...
public class Person {
private int id;
private String name;
3. Clerk extends Person and adds a few temporal attributes for when they were hired and
terminated. Clerk also contains a Set of Sales which is part of a Many-to-Many collection with
Sale where Clerk will be the inverse side.
package ejava.jpa.hibernatemigration.legacyhbm;
...
public class Clerk extends Person {
private Set<Sale> sales;
private Date hireDate;
private Date termDate;
![Page 8: Hibernate Migration - webdev home pagewebdev.jhuep.com/.../content/pdf/hibernate-migration.pdf · 2014-03-07 · Chapter 1. Hibernate Legacy P... 2 4. Customer extends Person and](https://reader030.fdocuments.in/reader030/viewer/2022041017/5ec9985628e0741c1957f138/html5/thumbnails/8.jpg)
Chapter 1. Hibernate Legacy P...
2
4. Customer extends Person and adds an enum and String string attribute. It also contains a Set
of Sales which is part of a One-to-Many relation where Customer will be the inverse side.
package ejava.jpa.hibernatemigration.legacyhbm;
...
public class Customer extends Person {
private Set<Sale> purchases;
private String email;
private CustomerLevel level=CustomerLevel.BRONZE;
5. Sale is identified by a business-assigned primary key value -- implemented here as a UUID
String. Sale provides tracking of floating point information, a timestamp. Sale also has a Many-
to-One relation with Customer and a Many-to-Many relation with Clerk. In both cases -- Sale
will be the owning side.
public class Sale {
private String id;
private BigDecimal amount;
private Date dateTime;
private Set<Clerk> salesClerks;
private Customer customer;
public Sale() {
this(UUID.randomUUID().toString());
}
public Sale(String id) {
this.id = id;
}
That completes the key aspects of the example class model used in the application. Next we will
describe the Hibernate setup.
1.2. Hibernate Configuration
The following files make-up the Hibernate configuration. It consists of individual Hibernate
Mapping (HBM) files, a Hibernate Session configuration XML (hibernate.cfg.xml) and properties
(hibernate.properties) file. Although all can be placed in either the XML or properties file, the
structure of the session is expressed in the XML file in the src/main branch and the database
connection properties were expressed in the properties file in the src/test branch. That permits
the Session definition to be distributed without concern of the runtime properties being embedded
from the test environment.
1.
src
|-- main
| |-- java
| `-- resources
| |-- hibernate
![Page 9: Hibernate Migration - webdev home pagewebdev.jhuep.com/.../content/pdf/hibernate-migration.pdf · 2014-03-07 · Chapter 1. Hibernate Legacy P... 2 4. Customer extends Person and](https://reader030.fdocuments.in/reader030/viewer/2022041017/5ec9985628e0741c1957f138/html5/thumbnails/9.jpg)
Hibernate Configuration
3
| | |-- Clerk.hbm.xml
| | |-- Customer.hbm.xml
| | `-- Sale.hbm.xml
| `-- hibernate.cfg.xml
`-- test
`-- resources
`-- hibernate.properties
2. The Clerk mapping maps the entity to the HMIG_CLERK table and assigns a strategy
of IDENTITY for database assigned primary keys. It provides column size and optional
specifications for individual properties and expresses the granularity of the java.lang.Date-s
being persisted to be down to the DATE level. It defines a Many-to-Many relationship with Sale
where the Customer is the inverse side.
src/main/resources/hibernate/Clerk.hbm.xml
::::::::::::::
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="ejava.jpa.hibernatemigration.legacyhbm">
<class name="Clerk" table="HMIG_CLERK">
<id name="id" access="field">
<generator class="identity"/>
</id>
<property name="name"
access="field"
not-null="true"
length="32"/>
<property name="hireDate"
access="field"
not-null="true"
type="date"
column="HIRE_DATE"/>
<property name="termDate"
access="field"
type="date"
column="TERM_DATE"/>
<set name="sales" table="HMIG_SALE_CLERK" access="field" inverse="true">
<key column="CLERK_ID"/>
<many-to-many column="SALE_ID" class="Sale"/>
</set>
</class>
3. Customer assigns the table name and database identity generation the same as Clerk. Also
of note -- both Customer and Clerk have modeled their relationship with Person as a table per
concrete class. Customer uses a very odd syntax to map the String name of the enum to the
database [http://stackoverflow.com/questions/1896666/adding-an-enum-as-a-class-property-
in-hbm] table. The value 12 is the value for VARCHAR in the java.sql.Types [http://
docs.oracle.com/javase/1.5.0/docs/api/constant-values.html#java.sql.Types.VARCHAR] class
![Page 10: Hibernate Migration - webdev home pagewebdev.jhuep.com/.../content/pdf/hibernate-migration.pdf · 2014-03-07 · Chapter 1. Hibernate Legacy P... 2 4. Customer extends Person and](https://reader030.fdocuments.in/reader030/viewer/2022041017/5ec9985628e0741c1957f138/html5/thumbnails/10.jpg)
Chapter 1. Hibernate Legacy P...
4
(JPA has a much cleaner syntax for expressing enums). The Customer maps the inverse side
of a one-to-many with the Sale.
src/main/resources/hibernate/Customer.hbm.xml
::::::::::::::
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="ejava.jpa.hibernatemigration.legacyhbm">
<class name="Customer" table="HMIG_CUSTOMER">
<id name="id" access="field">
<generator class="identity"/>
</id>
<property name="name"
access="field"
not-null="true"
length="32"/>
<property name="email"
access="field"
length="32"/>
<property name="level"
access="field"
length="8">
<type name="org.hibernate.type.EnumType">
<param name="enumClass">ejava.jpa.hibernatemigration.legacyhbm.CustomerLevel</param>
<param name="type">12</param>
</type>
</property>
<set name="purchases" access="field" inverse="true">
<key column="CUSTOMER_ID"/>
<one-to-many class="Sale"/>
</set>
</class>
</hibernate-mapping>
4. The Sale mapping defines a manually assigned primary key, a decimal amount for the price, and
a temporal granularity of TIMESTAMP for the dateTime of sale. It defines the two relationships
with Custome and Clerk -- where Sale is the owner of both.
src/main/resources/hibernate/Sale.hbm.xml
::::::::::::::
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="ejava.jpa.hibernatemigration.legacyhbm">
<class name="Sale" table="HMIG_SALE">
<id name="id" access="field" length="36"/>
![Page 11: Hibernate Migration - webdev home pagewebdev.jhuep.com/.../content/pdf/hibernate-migration.pdf · 2014-03-07 · Chapter 1. Hibernate Legacy P... 2 4. Customer extends Person and](https://reader030.fdocuments.in/reader030/viewer/2022041017/5ec9985628e0741c1957f138/html5/thumbnails/11.jpg)
Hibernate Configuration
5
<property name="amount"
access="field"
not-null="true"
precision="7"
scale="2"/>
<property name="dateTime"
access="field"
not-null="true"
type="timestamp"
column="SALE_TIME"/>
<many-to-one name="customer" access="field"
class="Customer"
column="CUSTOMER_ID"
not-null="true"/>
<set name="salesClerks" access="field" table="HMIG_SALE_CLERK">
<key column="SALE_ID"/>
<many-to-many column="CLERK_ID" class="Clerk"/>
</set>
</class>
</hibernate-mapping>
5. Although the HBM files can be placed anywhere in the application, the default location for the
hibernate.cfg.xml file is in the root directory. Although not required -- this document can define
the runtime properties with the database (commented out below) and may reference the HBM
or other mapping constructs. If they are not listed here, they can be manually added through
calls to the Hibernate Configuration object constructed by the application.
src/main/resources/hibernate.cfg.xml
::::::::::::::
<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<!-- defined in src/test/resources/hibernate.properties
<property name="connection.driver_class">org.h2.Driver</property>
<property name="connection.url">jdbc:h2:/home/jenkins/workspace/javaee-class-deploy/jpa/jpa-providers/jpa-
hibernate/hibernate-migration/hibernate-migration-docbook/target/h2db/ejava</property>
<property name="connection.username">sa</property>
<property name="connection.password"></property>
<property name="connection.pool_size">1</property>
<property name="dialect">org.hibernate.dialect.H2Dialect</property>
<property name="show_sql">true</property>
<property name="hbm2ddl.auto">create</property>
<property name="current_session_context_class">thread</property>
<property name="cache.provider_class">org.hibernate.cache.NoCacheProvider</property>
-->
![Page 12: Hibernate Migration - webdev home pagewebdev.jhuep.com/.../content/pdf/hibernate-migration.pdf · 2014-03-07 · Chapter 1. Hibernate Legacy P... 2 4. Customer extends Person and](https://reader030.fdocuments.in/reader030/viewer/2022041017/5ec9985628e0741c1957f138/html5/thumbnails/12.jpg)
Chapter 1. Hibernate Legacy P...
6
<mapping resource="hibernate/Clerk.hbm.xml"/>
<mapping resource="hibernate/Sale.hbm.xml"/>
<mapping resource="hibernate/Customer.hbm.xml"/>
</session-factory>
</hibernate-configuration>
6. The above resulted in the following database schema using the
org.hibernate.dialect.HSQLDialect hibernate dialect.
create table HMIG_CLERK (
id integer generated by default as identity (start with 1),
name varchar(32) not null,
HIRE_DATE date not null,
TERM_DATE date,
primary key (id)
);
create table HMIG_CUSTOMER (
id integer generated by default as identity (start with 1),
name varchar(32) not null,
email varchar(32),
level varchar(8),
primary key (id)
);
create table HMIG_SALE (
id varchar(36) not null,
amount numeric not null,
SALE_TIME timestamp not null,
CUSTOMER_ID integer not null,
primary key (id)
);
create table HMIG_SALE_CLERK (
CLERK_ID integer not null,
SALE_ID varchar(36) not null,
primary key (SALE_ID, CLERK_ID)
);
alter table HMIG_SALE
add constraint FK862A2223AE3F6B6
foreign key (CUSTOMER_ID)
references HMIG_CUSTOMER;
alter table HMIG_SALE_CLERK
add constraint FK33F2DF19B837D55E
foreign key (CLERK_ID)
references HMIG_CLERK;
alter table HMIG_SALE_CLERK
add constraint FK33F2DF198C45F016
foreign key (SALE_ID)
references HMIG_SALE;
![Page 13: Hibernate Migration - webdev home pagewebdev.jhuep.com/.../content/pdf/hibernate-migration.pdf · 2014-03-07 · Chapter 1. Hibernate Legacy P... 2 4. Customer extends Person and](https://reader030.fdocuments.in/reader030/viewer/2022041017/5ec9985628e0741c1957f138/html5/thumbnails/13.jpg)
Hibernate Session API
7
7. We placed the runtime properties of the Session in hibernate.properties within the src/test
branch of the tree so it would not be part of the delivered artifact with out test properties. You will
notice the file leverages filtering -- where each ${variable} can be replaced during compilation
$ cat src/test/resources/hibernate.properties
hibernate.dialect=org.hibernate.dialect.H2Dialect
hibernate.connection.url=jdbc:h2:/home/jenkins/workspace/javaee-class-deploy/jpa/jpa-providers/jpa-hibernate/
hibernate-migration/hibernate-migration-docbook/target/h2db/ejava
hibernate.connection.driver_class=org.h2.Driver
hibernate.connection.password=
hibernate.connection.username=sa
hibernate.connection.pool_size=1
hibernate.hbm2ddl.auto=create
hibernate.show_sql=true
hibernate.format_sql=true
#hibernate.jdbc.batch_size=0
hibernate.current_session_context_class=thread
hibernate.cache.provider_class=org.hibernate.cache.NoCacheProvider
8. This is what a listing of the final archive(s) look like with the above src/main information.
ddl/hibernate-hbm-createHBM.ddl
ddl/hibernate-hbm-dropHBM.ddl
ejava/jpa/hibernatemigration/legacyhbm/Clerk.class
ejava/jpa/hibernatemigration/legacyhbm/Customer.class
ejava/jpa/hibernatemigration/legacyhbm/CustomerLevel.class
ejava/jpa/hibernatemigration/legacyhbm/Person.class
ejava/jpa/hibernatemigration/legacyhbm/Sale.class
hibernate.cfg.xml
hibernate/Clerk.hbm.xml
hibernate/Customer.hbm.xml
hibernate/Sale.hbm.xml
You have finished taking a look at the descriptor files behind most legacy Hibernate approaches.
Next we will look at how the application can obtain references to Hibernate API -- which will use
the above information to access the database.
1.3. Hibernate Session API
We will demonstrate access to the Hibernate API through sub-classes of a JUnit testcase that we
will detail in the next section. Here we will show the extension points and how they where used
to obtain access to and use the Hibernate API. This same framework will be used in all of the
testcases demonstrated in this migration topic.
1. The methods below are all callback methods for JUnit or concrete implementations for abstract
methods defined in the base testcase.
src/test/java/ejava/jpa/hibernatemigration/legacyhbm/LegacyHBMTest.java
![Page 14: Hibernate Migration - webdev home pagewebdev.jhuep.com/.../content/pdf/hibernate-migration.pdf · 2014-03-07 · Chapter 1. Hibernate Legacy P... 2 4. Customer extends Person and](https://reader030.fdocuments.in/reader030/viewer/2022041017/5ec9985628e0741c1957f138/html5/thumbnails/14.jpg)
Chapter 1. Hibernate Legacy P...
8
::::::::::::::
package ejava.jpa.hibernatemigration.legacyhbm;
...
public class LegacyHBMTest extends BaseMigrationTest {
2. Access to the Hibernate API is through a Session. A Session is obtained from a SessionFactory
and a SessionFactory is built from a Configuration. The Configuration processes the information
we covered in the XML files above. You can see we have access to the Configuration object
during the following calls but have chosen to just let it have its default values from the supplied
XML files.
private static SessionFactory sessionFactory;
@BeforeClass
public static void setUpClass() {
log.debug("creating sessionFactory");
sessionFactory=new Configuration().configure().buildSessionFactory();
}
3. The Session is generally created to support a single transaction but may support many
depending on how long-lived you can make it. In the following setUp for each testMethod we
create a Session from the SessionFactory and start a transaction.
private Session session;
@Before
public void setUp() {
log.debug("creating session");
session = sessionFactory.getCurrentSession();
session.beginTransaction();
}
4. At the end of each testMethod the Session's transaction is committed and the session is closed.
@After
public void tearDown() {
if (session != null) {
if (session.getTransaction().isActive()) {
session.getTransaction().commit();
}
}
}
5. At the termination of the testcase, the SessionFactory is closed.
@AfterClass
public static void tearDownClass() {
![Page 15: Hibernate Migration - webdev home pagewebdev.jhuep.com/.../content/pdf/hibernate-migration.pdf · 2014-03-07 · Chapter 1. Hibernate Legacy P... 2 4. Customer extends Person and](https://reader030.fdocuments.in/reader030/viewer/2022041017/5ec9985628e0741c1957f138/html5/thumbnails/15.jpg)
Test Case
9
if (sessionFactory!=null) {
sessionFactory.close();
}
}
6. The remaining methods defined support the abstract methods of the base testcase covered
next. You will notice that all actions are based off the Session and the SessionFactory is nice
enough to let us know which is the current session.
@Override
protected void save(Object entity) { session.save(entity); }
@Override
protected void flush() { session.flush(); }
@Override
protected void clear() { session.clear(); }
@Override
@SuppressWarnings("unchecked")
protected <T> T get(Class<T> clazz, Serializable pk) { return (T)session.get(clazz, pk); }
@Override
protected void beginTransaction() { sessionFactory.getCurrentSession().beginTransaction(); }
@Override
protected void commitTransaction() { sessionFactory.getCurrentSession().getTransaction().commit(); }
You have finished looking at extending the testcase for Hibernate-specific implementation. Next
we will look at the base testcase that makes calls to what was just covered above.
1.4. Test Case
In this section will take the only look at the base testcase that is used across all this and
downstream examples. The testcase builds a sample instance of the class model described
above, persists the model, and retrieves it back from the database.
1. The calls in the testcase are encapsulated in the following JUnit test.
public abstract class BaseMigrationTest {
private final Log log = LogFactory.getLog(getClass());
protected abstract void save(Object entity);
protected abstract void flush();
protected abstract void clear();
protected abstract <T> T get(Class<T> clazz, Serializable pk);
protected abstract void beginTransaction();
protected abstract void commitTransaction();
@Test
public void testPersist() {
log.info("*** testPersist ***");
...
}
}
![Page 16: Hibernate Migration - webdev home pagewebdev.jhuep.com/.../content/pdf/hibernate-migration.pdf · 2014-03-07 · Chapter 1. Hibernate Legacy P... 2 4. Customer extends Person and](https://reader030.fdocuments.in/reader030/viewer/2022041017/5ec9985628e0741c1957f138/html5/thumbnails/16.jpg)
Chapter 1. Hibernate Legacy P...
10
2. First the test wires up instances in the class model using standard POJO calls.
//create our customer
Customer customer = new Customer();
customer.setName("joe");
customer.setEmail("[email protected]");
customer.setLevel(CustomerLevel.SILVER);
//create two clerks for the sale
Clerk clerk1 = new Clerk();
clerk1.setName("tom");
clerk1.setHireDate(new GregorianCalendar(2010, Calendar.JANUARY, 1).getTime());
//create the sale
Clerk clerk2 = new Clerk();
clerk2.setName("mary");
clerk2.setHireDate(new GregorianCalendar(2012, Calendar.JULY, 1).getTime());
Sale sale = new Sale();
sale.setDateTime(new Date());
sale.setAmount(new BigDecimal(100.12));
//associate the entities
sale.setCustomer(customer);
customer.setPurchaes(sale);
sale.addSalesClerk(clerk1);
clerk1.addSale(sale);
sale.addSalesClerk(clerk2);
clerk2.addSale(sale);
3. In the following segment, the instances are persisted in the session and later flushed to the
database to simulate a transaction ending.
//persist objects
log.info("(prior to persist) sale=" + sale);
save(customer);
save(clerk1);
save(clerk2);
save(sale);
//flushing session to database
flush();
log.info("(after flush) sale=" + sale);
4. Next we obtain new instances of the objects through their relationships -- starting with the Sale.
//get a new instance of sale
clear();
Sale sale2 = get(Sale.class, sale.getId());
![Page 17: Hibernate Migration - webdev home pagewebdev.jhuep.com/.../content/pdf/hibernate-migration.pdf · 2014-03-07 · Chapter 1. Hibernate Legacy P... 2 4. Customer extends Person and](https://reader030.fdocuments.in/reader030/viewer/2022041017/5ec9985628e0741c1957f138/html5/thumbnails/17.jpg)
Maven Build
11
//verify state and relationships were persisted
assertNotNull("could not locate sale", sale2);
assertEquals("unexpected amount", sale.getAmount().intValue(), sale2.getAmount().intValue());
5. We perform a sanity check of the other instances after finishing up with the sale.
//test the sale/customer many-to-one collection mapping from owning side
assertNotNull("no customer found", sale2.getCustomer());
assertEquals("unexpected sale.customer.id", sale.getCustomer().getId(), sale2.getCustomer().getId());
assertEquals("unexpected customer name", customer.getName(), sale2.getCustomer().getName());
//test the sale/customer many-to-one collection mapping from inverse side
assertEquals("unexpected purchase count", 1, sale2.getCustomer().getPurchases().size());
assertEquals("unexpected saleId", sale.getId(), sale2.getCustomer().getPurchases().iterator().next().getId());
//test the sale/clerk many-to-many collection from owning side
assertEquals("unexpected number of clerks", 2, sale2.getSalesClerks().size());
assertTrue("could not locate clerk1", sale2.getSalesClerks().contains(clerk1));
assertTrue("could not locate clerk2", sale2.getSalesClerks().contains(clerk2));
//test the sale/clerk many-to-many collection from inverse side
for (Clerk clerk: sale2.getSalesClerks()) {
assertEquals("unexpected number if sales", 1, clerk.getSales().size());
assertTrue("sale not found in clerk", clerk.getSales().contains(sale));
}
You have finished looking at the generic portion of the testcase that is used for this and all
downstream examples. It is a simple test -- but one that will help achieve our primary goal of
demonstrating the migration.
1.5. Maven Build
The above artifacts go nowhere without being built. To do that, they have been assembled into
a single Maven project. To make sure the demonstration was as realistic as possible, an old
version of Hibernate (dating back to 2007) was used for the legacy versions of the project. The real
example used multiple modules to build the solutions in order to optimize re-use across solution
approaches. We will show the solution here as a single logical module for simplicity.
1. Our legacy example uses a version of Hibernate that dates back to ~2007. This should provide
some comfort to users with older versions of Hibernate that what is demonstrated is not beyond
your reach.
<properties>
<!-- hibernate 3.2.0.ga was released to ibiblio 2007-01-04 -->
<legacy-hibernate.version>3.2.0.ga</legacy-hibernate.version>
...
</properties>
2. Besides the standard dependencies like commons-logging, junit, and log4j, the only
dependency required for this first example is the hibernate-entity-manager. It brings in several
![Page 18: Hibernate Migration - webdev home pagewebdev.jhuep.com/.../content/pdf/hibernate-migration.pdf · 2014-03-07 · Chapter 1. Hibernate Legacy P... 2 4. Customer extends Person and](https://reader030.fdocuments.in/reader030/viewer/2022041017/5ec9985628e0741c1957f138/html5/thumbnails/18.jpg)
Chapter 1. Hibernate Legacy P...
12
other dependencies (like hibernate-annotations) and makes it simple to obtain all that we need.
We are currently marking it as scope=provided to prevent a specific dependency on hibernate
when most of the hibernate dependency is within the tests and runtime and not the component
itself.
<dependencies>
...
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<version>${legacy-hibernate.version}</version>
<scope>provided</scope>
</dependency>
...
</dependencies>
3. You saw earlier where the hibernate.cfg.xml and hibernate.properties files in the src/main and
src/test trees leveraged property filtering. The following build construct sets up the filtering when
copying from the src to target tree. Filtering replaces ${variable} references with values from
the build. The values come from a System property or property within the pom.
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<excludes>
<exclude>hibernate.cfg.xml</exclude>
</excludes>
</resource>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>hibernate.cfg.xml</include>
</includes>
<filtering>true</filtering>
</resource>
</resources>
<testResources>
<testResource>
<directory>src/test/resources</directory>
<excludes>
<exclude>hibernate.properties</exclude>
</excludes>
</testResource>
<testResource>
<directory>src/test/resources</directory>
<includes>
<include>hibernate.properties</include>
</includes>
<filtering>true</filtering>
![Page 19: Hibernate Migration - webdev home pagewebdev.jhuep.com/.../content/pdf/hibernate-migration.pdf · 2014-03-07 · Chapter 1. Hibernate Legacy P... 2 4. Customer extends Person and](https://reader030.fdocuments.in/reader030/viewer/2022041017/5ec9985628e0741c1957f138/html5/thumbnails/19.jpg)
Maven Build
13
</testResource>
</testResources>
...
</build>
4. The properties for the specific database information is provided through a default profile. An
embedded file version of Hypersonic is being used for this demonstration. That means there is
no database to start/stop/manage as part of running these tests.
<profiles>
<profile>
<id>hsqldb</id> <!-- Hypersonic server-based DB -->
<activation>
<property>
<name>!jdbcdb</name>
</property>
</activation>
<properties>
<jdbc.driver>org.hsqldb.jdbcDriver</jdbc.driver>
<jdbc.url>jdbc:hsqldb:/home/jenkins/workspace/javaee-class-deploy/jpa/jpa-providers/jpa-hibernate/
hibernate-migration/hibernate-migration-docbook/target/hsqldb/ejava</jdbc.url>
<jdbc.user>sa</jdbc.user>
<jdbc.password/>
<hibernate.dialect>
org.hibernate.dialect.HSQLDialect
</hibernate.dialect>
</properties>
<dependencies>
<dependency>
<groupId>org.hsqldb</groupId>
<artifactId>hsqldb</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</profile>
...
<profiles>
Using Alternate Profiles
You can switch to an alternate profile by turning off the default profile (-P\!
hsqldb) and turning on an alternate profile (-Phsqlsrv) -- also supplied in the
pom. Alternate profiles can be used to switch between embedded and server
versions of the same database as well as switching between different types of
databases.
5. You can look at the contents of the database after the test runs by executing the following jar
file and entering the file based URL specified above and the Standalone option.
$ java -jar ~/.m2/repository/org/hsqldb/hsqldb/2.2.8/hsqldb-2.2.8.jar
![Page 20: Hibernate Migration - webdev home pagewebdev.jhuep.com/.../content/pdf/hibernate-migration.pdf · 2014-03-07 · Chapter 1. Hibernate Legacy P... 2 4. Customer extends Person and](https://reader030.fdocuments.in/reader030/viewer/2022041017/5ec9985628e0741c1957f138/html5/thumbnails/20.jpg)
Chapter 1. Hibernate Legacy P...
14
6. You can build the model using standard Maven commands or import into your IDE and run.
$ mvn clean test
...
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
You have finished looking at the key maven aspects for building the legacy project. Most of the
remaining details are standard Maven constructs. However, there is one more important thing to
cover before we leave the legacy application and start migrating. We want to generate schema
from the supplied mappings so we can validate we have mapped things correctly.
1.6. Generating Schema from HBM files
Whether you use auto-generated schema to directly defined your database schema or simply use
it as a guide, it is quite valuable to generate schema form the entity mappings of your Hibernate
and JPA applications so you can sanity check the results and more easily spot errors that can go
undetected until late into runtime. We are going to leverage Hibernate's ability to generate schema
through the hibernate3-maven-plugin. Unfortunately the plugin went through a major release
change (from 2.2 to 3.0) sometime around 2012 and the configurations changed drastically. You
are going to be shown the legacy 2.x syntax here to stick with our theme of "older versions" for
the legacy project We will use the 3.x syntax in follow-on projects to get practice with both styles.
There is no reason to use the older version of the plugin if you have access to the new version.
The definition for the plugin can be quite lengthy in total, but can be reduced when factored into
a pluginManagement section in a shared parent pom.
1. Define the hibernate3-maven-plugin core structure. The version used in this case is 2.2.
<build>
<plugins>
<!-- generates a DDL file for persistence unit using an older version of the plugin -->
<plugin>
<artifactId>hibernate3-maven-plugin</artifactId>
<groupId>org.codehaus.mojo</groupId>
<version>${legacy-hibernate3-maven-plugin.version}</version>
<dependencies>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<version>${legacy-hibernate.version}</version>
</dependency>
</dependencies>
<configuration>
<components>
<component>
<name>hbm2ddl</name>
<outputDirectory>target/classes/ddl</outputDirectory>
![Page 21: Hibernate Migration - webdev home pagewebdev.jhuep.com/.../content/pdf/hibernate-migration.pdf · 2014-03-07 · Chapter 1. Hibernate Legacy P... 2 4. Customer extends Person and](https://reader030.fdocuments.in/reader030/viewer/2022041017/5ec9985628e0741c1957f138/html5/thumbnails/21.jpg)
Generating Schema from HBM files
15
</component>
</components>
<componentProperties>
<configurationfile>target/classes/hibernate.cfg.xml</configurationfile>
<export>false</export>
<format>true</format>
</componentProperties>
</configuration>
<executions>
...
</executions>
</plugin>
</plugins>
</build>
2. Generate the drop and create scripts. Run them in a maven phase that assures you the classes
exist prior to running the plugin.
<execution>
<id>generate-drop-hbm</id>
<phase>process-test-resources</phase>
<goals>
<goal>hbm2ddl</goal>
</goals>
<configuration>
<componentProperties>
<outputfilename>hibernate-migration-docbook-dropHBM.ddl</outputfilename>
<drop>true</drop>
<create>false</create>
</componentProperties>
</configuration>
</execution>
<execution>
<id>generate-create-hbm</id>
<phase>process-test-resources</phase>
<goals>
<goal>hbm2ddl</goal>
</goals>
<configuration>
<componentProperties>
<outputfilename>hibernate-migration-docbook-createHBM.ddl</outputfilename>
<drop>false</drop>
<create>true</create>
</componentProperties>
</configuration>
</execution>
3. The above plugin generates the following two files that express creating the complete schema
and dropping it from the database.
![Page 22: Hibernate Migration - webdev home pagewebdev.jhuep.com/.../content/pdf/hibernate-migration.pdf · 2014-03-07 · Chapter 1. Hibernate Legacy P... 2 4. Customer extends Person and](https://reader030.fdocuments.in/reader030/viewer/2022041017/5ec9985628e0741c1957f138/html5/thumbnails/22.jpg)
Chapter 1. Hibernate Legacy P...
16
target/classes/ddl
|-- hibernate-hbm-createHBM.ddl
`-- hibernate-hbm-dropHBM.ddl
You have finished looking through how schema can be generated with the legacy hibernate3-
maven-plugin version using hibernate-specific techniques to define the session. In the next
chapter we will use the same version of the plugin to process a JPA persistence unit.
1.7. Summary
In this chapter we took a look at a legacy Hibernate application that we wish to migrate to JPA
through one of a couple possible first steps. This part of the example defined the class model, a
legacy database schema through the supplied mappings, a maven build and unit test, and schema
generation. I know of some projects that would be happy with just that!
![Page 23: Hibernate Migration - webdev home pagewebdev.jhuep.com/.../content/pdf/hibernate-migration.pdf · 2014-03-07 · Chapter 1. Hibernate Legacy P... 2 4. Customer extends Person and](https://reader030.fdocuments.in/reader030/viewer/2022041017/5ec9985628e0741c1957f138/html5/thumbnails/23.jpg)
Chapter 2.
17
JPA Persistence Unit Using
ORM.xml Mapping FilesThis chapter describes a stepping stone for those that wish to replace Hibernate-specific calls
with JPA standard calls or even use a mix of the two. We will show how the same legacy object
model is made available through JPA and also show how the legacy Hibernate Session can still
be obtained when needed.
2.1. Going from HBM to ORM mapping files
This may not be the sexiest part of the migration but it can get you one step closer to using a JPA
persistence unit when you cannot modify the source code of the entity classes being modeled.
We will create a set of JPA Object/Relational (ORM) XML files that will replace the HBM files.
1. The hibernate.cfg.xml file will get replaced by a META-INF/persistence.xml. The HBM files will
get replaced by orm.xml variants but notice there is an extra mapping file for the Person base
class. The hibernate.properties file we factored out in the legacy application can stay as defined
previously. Hibernate will pick that up.
src
|-- main
| |-- java
| `-- resources
| |-- jpa
| | |-- Clerk-orm.xml
| | |-- Customer-orm.xml
| | |-- Person-orm.xml
| | `-- Sale-orm.xml
| `-- META-INF
| `-- persistence.xml
`-- test
`-- resources
`-- hibernate.properties
2. With JPA we are able to create a reusable definition for the base Person class using a mapped-
superclass. This will end up being a table-per-concrete-class approach once complete. The
mapped-superclass is used to define reused properties as well as a primary key and generation
strategy.
<?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">
![Page 24: Hibernate Migration - webdev home pagewebdev.jhuep.com/.../content/pdf/hibernate-migration.pdf · 2014-03-07 · Chapter 1. Hibernate Legacy P... 2 4. Customer extends Person and](https://reader030.fdocuments.in/reader030/viewer/2022041017/5ec9985628e0741c1957f138/html5/thumbnails/24.jpg)
Chapter 2. JPA Persistence Un...
18
<mapped-superclass class="ejava.jpa.hibernatemigration.legacyhbm.Person"
access="FIELD">
<attributes>
<id name="id">
<generated-value strategy="IDENTITY"/>
</id>
<basic name="name" optional="false">
<column length="32"/>
</basic>
</attributes>
</mapped-superclass>
</entity-mappings>
3. The Customer mapping extends the Person mapping and details the remaining properties. One
thing to note that is different between HBM and ORM.xml files -- unmapped properties in HBM
are @Transitent by default. Unmapped properties in JPA take on the default mapping properties
of the JPA Spec [http://download.oracle.com/otndocs/jcp/persistence-2.0-fr-eval-oth-JSpec/].
You must specifically annotate a property as transient in order for it to be ignored by JPA.
<?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">
<!-- id and name mapped in superclass ORM -->
<entity class="ejava.jpa.hibernatemigration.legacyhbm.Customer"
access="FIELD">
<table name="HMIG_CUSTOMER"/>
<attributes>
<basic name="email">
<column length="32"/>
</basic>
<basic name="level">
<column length="8"/>
<enumerated>STRING</enumerated>
</basic>
<one-to-many name="purchases" mapped-by="customer"/>
</attributes>
</entity>
</entity-mappings>
Another key point is demonstrated above with respect to enums. Remember the cryptic syntax
used by Hibernate to map the STRING representation of the CustomerLevel enum to the
database? JPA uses a more straight forward enumerated element to do the same thing. (Of
course once we switch to annotations -- this argument becomes a very minor point)
![Page 25: Hibernate Migration - webdev home pagewebdev.jhuep.com/.../content/pdf/hibernate-migration.pdf · 2014-03-07 · Chapter 1. Hibernate Legacy P... 2 4. Customer extends Person and](https://reader030.fdocuments.in/reader030/viewer/2022041017/5ec9985628e0741c1957f138/html5/thumbnails/25.jpg)
Going from HBM to ORM mapping files
19
4. Clerk also extends the mapping of Person and adds some specifics of its own to match the HBM
mappings. Note the "mapped-by" denotes the "inverse" side in JPA. The mapped-by element
references the property in the owning entity that defines the mapping to the database.
<?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">
<!-- id and name mapped in superclass ORM -->
<entity class="ejava.jpa.hibernatemigration.legacyhbm.Clerk"
access="FIELD">
<table name="HMIG_CLERK"/>
<attributes>
<basic name="hireDate" optional="false">
<column name="HIRE_DATE"/>
<temporal>DATE</temporal>
</basic>
<basic name="termDate">
<column name="TERM_DATE"/>
<temporal>DATE</temporal>
</basic>
<many-to-many name="sales" mapped-by="salesClerks"/>
</attributes>
</entity>
</entity-mappings>
5. Sale is demonstrating a few extra constructs offered by JPA where we can assigned the default
package and access type for entities within that package. This can be helpful if you package
multiple entities from the same package in to the same file.
src/main/resources/jpa/Sale-orm.xml
::::::::::::::
<?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>ejava.jpa.hibernatemigration.legacyhbm</package>
<access>FIELD</access>
<entity class="Sale">
<table name="HMIG_SALE"/>
<attributes>
<id name="id">
<column length="36"/>
</id>
<basic name="amount" optional="false">
![Page 26: Hibernate Migration - webdev home pagewebdev.jhuep.com/.../content/pdf/hibernate-migration.pdf · 2014-03-07 · Chapter 1. Hibernate Legacy P... 2 4. Customer extends Person and](https://reader030.fdocuments.in/reader030/viewer/2022041017/5ec9985628e0741c1957f138/html5/thumbnails/26.jpg)
Chapter 2. JPA Persistence Un...
20
<column precision="7" scale="2"/>
</basic>
<basic name="dateTime" optional="false">
<column name="SALE_TIME"/>
<temporal>TIMESTAMP</temporal>
</basic>
<many-to-one name="customer" optional="false">
<join-column name="CUSTOMER_ID"/>
</many-to-one>
<many-to-many name="salesClerks">
<join-table name="HMIG_SALE_CLERK">
<join-column name="SALE_ID"/>
<inverse-join-column name="CLERK_ID"/>
</join-table>
</many-to-many>
</attributes>
</entity>
</entity-mappings>
6. Like with the hibernare.cfg.xml, the persistence unit can defined properties of the connection
and vendor-specific properties about the provider (all commented out) as well as references
to the mapping files. One additional thing to point out with JPA -- mapping files augment and
override classes and their annotations. With HBM files -- it is one or the other. With JPA,
ORM files can augment and override the class annotations as well as instruct the provider to
ignore the class annotations (with "metadata-complete"). This allows the developer to place
core mappings within the Java class and leverage filterable ORM.xml files to change what is
volatile.
<?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="hibernate-migration-sales">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<mapping-file>jpa/Person-orm.xml</mapping-file>
<mapping-file>jpa/Customer-orm.xml</mapping-file>
<mapping-file>jpa/Clerk-orm.xml</mapping-file>
<mapping-file>jpa/Sale-orm.xml</mapping-file>
<properties>
<!-- properties moved to hibernate.properties file
<property name="connection.driver_class" value="org.h2.Driver"/>
<property name="connection.url" value="jdbc:h2:/home/jenkins/workspace/javaee-class-deploy/jpa/jpa-
providers/jpa-hibernate/hibernate-migration/hibernate-migration-docbook/target/h2db/ejava"/>
<property name="connection.username" value="sa"/>
<property name="connection.password" value=""/>
<property name="connection.pool_size" value="1"/>
![Page 27: Hibernate Migration - webdev home pagewebdev.jhuep.com/.../content/pdf/hibernate-migration.pdf · 2014-03-07 · Chapter 1. Hibernate Legacy P... 2 4. Customer extends Person and](https://reader030.fdocuments.in/reader030/viewer/2022041017/5ec9985628e0741c1957f138/html5/thumbnails/27.jpg)
JPA EntityManager API
21
<property name="dialect" value="org.hibernate.dialect.H2Dialect"/>
<property name="show_sql" value="true"/>
<property name="hbm2ddl.auto" value="create"/>
<property name="current_session_context_class" value="thread"/>
<property name="cache.provider_class" value="org.hibernate.cache.NoCacheProvider"/>
-->
</properties>
</persistence-unit>
</persistence>
You have finished looking at the migration from HBM to ORM.xml files. As stated, we can form
a JPA persistence unit with ORM.xml mappings (and class mappings later on). With Hibernate,
all unmapped properties are transient. With JPA -- all unmapped properties have their JPA Spec-
defined mappings defaults applied and must be specifically marked as transient to be ignored.
ORM.xml mappings can augment or replace metadata expressed in the entity classes. With
straight Hibernate, you can only use the HBM file or the entity class annotations -- not both.
2.2. JPA EntityManager API
In this section we will demonstrate how to access the JPA API for interacting with the persistence
unit. As done previously, we will show access to the API through extension points in our testcase.
1. The persistence unit is represented at runtime by a persistence context and accessed through
the EntityManager. An EntityManager is created from an EntityManagerFactory and the
EntityManagerFactory is configured through the persistence unit we put together above. Each
persistence.xml can define multiple persistence units -- so we must pass in the name of the
persistence unit when creating the EntityManagerFactory.
public class ORMMappingTest extends BaseMigrationTest {
private static final String PERSISTENCE_UNIT_NAME = "hibernate-migration-sales";
private static EntityManagerFactory emf;
@BeforeClass
public static void setUpClass() {
log.debug("creating entityManagerFactory");
emf = Persistence.createEntityManagerFactory(PERSISTENCE_UNIT_NAME);
}
2. EntityManagers are usually associated with a single transaction or many transactions
for applications that can keep them open long enough. In the testcase, we create the
EntityManager and start a transaction prior to each testcase.
private EntityManager em;
@Before
public void setUp() {
log.debug("creating session");
em = emf.createEntityManager();
![Page 28: Hibernate Migration - webdev home pagewebdev.jhuep.com/.../content/pdf/hibernate-migration.pdf · 2014-03-07 · Chapter 1. Hibernate Legacy P... 2 4. Customer extends Person and](https://reader030.fdocuments.in/reader030/viewer/2022041017/5ec9985628e0741c1957f138/html5/thumbnails/28.jpg)
Chapter 2. JPA Persistence Un...
22
em.getTransaction().begin();
}
3. The transaction is committed and the EntityManager is closed at the end of the testcase.
@After
public void tearDown() {
if (em != null) {
if (em.getTransaction().isActive()) {
em.getTransaction().commit();
}
em.close();
}
}
4. The EntityManagerFactory is closed at the end of the testcase.
@AfterClass
public static void tearDownClass() {
if (emf!=null) {
emf.close();
}
}
5. The rest of the concrete methods that map the abstract testcase calls to the JPA API are shown
below. Note there is a near one-to-one mapping between what Hibernate and JPA need to do
in each case.
@Override
protected void save(Object entity) { em.persist(entity); }
@Override
protected void flush() { em.flush(); }
@Override
protected void clear() { em.clear(); }
@Override
protected <T> T get(Class<T> clazz, Serializable pk) { return em.find(clazz, pk); }
@Override
protected void beginTransaction() {
if (em!=null) { em.getTransaction().begin(); }
}
@Override
protected void commitTransaction() {
if (em!=null) { em.getTransaction().commit(); }
}
![Page 29: Hibernate Migration - webdev home pagewebdev.jhuep.com/.../content/pdf/hibernate-migration.pdf · 2014-03-07 · Chapter 1. Hibernate Legacy P... 2 4. Customer extends Person and](https://reader030.fdocuments.in/reader030/viewer/2022041017/5ec9985628e0741c1957f138/html5/thumbnails/29.jpg)
Obtaining HIbernate Session from JPA
23
2.3. Obtaining HIbernate Session from JPA
JPA is a standard that freely admits it may not cover all cases addressed by the providers that
implement it. There are official back doors added for SQL database access and access to the raw
provider implementation behind the EntityManager (i.e., the Hibernate Session).
1. The following call can be made to obtain a Hibernate Session object from behind the JPA
EntityManager facade.
protected Session getCurrentSession() { return (em==null)?null : (Session)em.getDelegate(); }
In this quick section we showed how a client can gain access to the legacy/raw Hibernate Session
object after migrating to a JPA interface. This can be useful to make provider-specific calls. In the
next section we will show a more hybrid approach where some of the entities were mapped with
JPA and some with Hibernate.
2.4. Mixing HBM and JPA definitions
In this section we will backup a half step and show how to model a partion of the class model in
HBM files and the remaining portion in ORM files and have the Hibernate-specific mapped entities
be used with the JPA-mapped entities. The only requirement is that the Hibernate Session used
must be the one obtained from the EntityManager.getDelegate() call.
1. Our mapping tree looks like the following. We are using a Hibernate-specific HBM file for
both Clerk and Customer and a JPA orm.xml file for Sale. Both a hibernate.cfg.xml and
persistence.xml are also supplied.
src
|-- main
| |-- java
| `-- resources
| |-- hibernate
| | |-- Clerk.hbm.xml
| | `-- Customer.hbm.xml
| |-- hibernate.cfg.xml
| |-- jpa
| | `-- Sale-orm.xml
| `-- META-INF
| `-- persistence.xml
`-- test
`-- resources
`-- hibernate.properties
2. The hibernate.cfg.xml file references the two HBM files used to map the Clerk and Customer.
<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
![Page 30: Hibernate Migration - webdev home pagewebdev.jhuep.com/.../content/pdf/hibernate-migration.pdf · 2014-03-07 · Chapter 1. Hibernate Legacy P... 2 4. Customer extends Person and](https://reader030.fdocuments.in/reader030/viewer/2022041017/5ec9985628e0741c1957f138/html5/thumbnails/30.jpg)
Chapter 2. JPA Persistence Un...
24
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<mapping resource="hibernate/Clerk.hbm.xml"/>
<mapping resource="hibernate/Customer.hbm.xml"/>
<!-- mapped with JPA
<mapping resource="hibernate/Sale.hbm.xml"/>
-->
</session-factory>
3. The persistence.xml provides a file reference to the ORM.xml file used to map the Sale.
<?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="hibernate-migration-sales">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<!-- mapped with HBM
<mapping-file>jpa/Person-orm.xml</mapping-file>
<mapping-file>jpa/Customer-orm.xml</mapping-file>
<mapping-file>jpa/Clerk-orm.xml</mapping-file>
-->
<mapping-file>jpa/Sale-orm.xml</mapping-file>
</persistence-unit>
</persistence>
In this section we took a half step back and opened the door for a partial migration from Hibernate
HBM to JPA ORM.xml files. This option option is obviously appealing for modules with highly
complex HBM file declarations. With this approach, one can use the JPA API while retaining
their 100% Hibernate defined mapping to the database. We will finish up in the next section by
generating schema using the JPA instead of HBM files.
2.5. Generating Schema for JPA files
In this section we will describe the only part of the Maven build that is unique to this section --
generating schema from a JPA persistence unit versus a Hibernate Session configuration.
1. To keep the document short, we are only going to show the important differences between the
HBM schema generation and the JPA approach. Notice how -- in the configuration section of the
plugin -- a jpaconfiguration implementation is being expressed and the componentProperties
section provides the name of the persistence unit. That is all we should need to process the
ORM.xml files.
![Page 31: Hibernate Migration - webdev home pagewebdev.jhuep.com/.../content/pdf/hibernate-migration.pdf · 2014-03-07 · Chapter 1. Hibernate Legacy P... 2 4. Customer extends Person and](https://reader030.fdocuments.in/reader030/viewer/2022041017/5ec9985628e0741c1957f138/html5/thumbnails/31.jpg)
Generating Schema for JPA files
25
<configuration>
<components>
<component>
<name>hbm2ddl</name>
<implementation>jpaconfiguration</implementation>
<outputDirectory>target/classes/ddl</outputDirectory>
</component>
</components>
<componentProperties>
<persistenceunit>hibernate-migration-sales</persistenceunit>
<export>false</export>
<format>true</format>
</componentProperties>
</configuration>
2. The following is an example of what was produced.
create table HMIG_CLERK (
id integer generated by default as identity (start with 1),
name varchar(32) not null,
HIRE_DATE date not null,
TERM_DATE date,
primary key (id)
);
create table HMIG_CUSTOMER (
id integer generated by default as identity (start with 1),
name varchar(32) not null,
email varchar(32),
level varchar(8),
primary key (id)
);
create table HMIG_SALE (
id varchar(36) not null,
amount numeric not null,
SALE_TIME timestamp not null,
CUSTOMER_ID integer not null,
primary key (id)
);
create table HMIG_SALE_CLERK (
SALE_ID varchar(36) not null,
CLERK_ID integer not null,
primary key (SALE_ID, CLERK_ID)
);
alter table HMIG_SALE
add constraint FK862A2223AE3F6B6
foreign key (CUSTOMER_ID)
references HMIG_CUSTOMER;
![Page 32: Hibernate Migration - webdev home pagewebdev.jhuep.com/.../content/pdf/hibernate-migration.pdf · 2014-03-07 · Chapter 1. Hibernate Legacy P... 2 4. Customer extends Person and](https://reader030.fdocuments.in/reader030/viewer/2022041017/5ec9985628e0741c1957f138/html5/thumbnails/32.jpg)
Chapter 2. JPA Persistence Un...
26
alter table HMIG_SALE_CLERK
add constraint FK33F2DF198C45F016
foreign key (SALE_ID)
references HMIG_SALE;
alter table HMIG_SALE_CLERK
add constraint FK33F2DF19B837D55E
foreign key (CLERK_ID)
references HMIG_CLERK;
You have finished looking at how to generate database schema from a JPA persistence unit
definition and the 2.x version of the hibernate3-maven-plugin. In the follow-on sections we will
switch to using the newer 3.x implementation/configuration.
2.6. Summary
In this chapter we took an approach that would get us to a JPA API without changing the
Java classes. We showed and approach where the hibernate.cfg.xml was replaced by the
persistence.xml to express the persistence unit. We saw where the hbm.xml mappings were
replaced by the orm.xml mappings to allow for vendor neutral mappings and a definition usuable by
the persistence unit. We also kept the door open to raw Hibernate usage. At one level we showed
how we can simply ask for the Hibernate Session from the JPA EntityManager. At another level we
showed how -- since the provider in this case is Hibernate -- we can leave hibernate.cfg.xml and
hbm.xml files in place to reference entities we have not yet migrated. They can be stored/accessed
by the outer JPA EntityManager and the Hibernate Session configured from the EntityManager.
![Page 33: Hibernate Migration - webdev home pagewebdev.jhuep.com/.../content/pdf/hibernate-migration.pdf · 2014-03-07 · Chapter 1. Hibernate Legacy P... 2 4. Customer extends Person and](https://reader030.fdocuments.in/reader030/viewer/2022041017/5ec9985628e0741c1957f138/html5/thumbnails/33.jpg)
Chapter 3.
27
Adding Metadata thru Class
AnnotationsThis chapter describes a migration increment where we get rid of verbose Hibernate HBM files
and replace the XML source of metadata with class annotations. This permits class design details
to be expressed in one location and not in separate Java class and XML files. However -- there
is a catch. There is debate whether some of the metadata annotations are appropriate to place
in a Java class. JPA solves this issue by allowing the entity class to express a default and that
can be augmented or replaced by metadata within the ORM.xml. Hibernate Session -- however
is one or the other. You can use annotations or HBM files and not a combination of both. This
section will demonstrate how the entity annotations processed by the Hibernate Session can be
overridden by the application.
3.1. Entity Class Annotations
In this section we will migrate the HBM or ORM mappings from their XML files to the entity classes.
This makes for a very concise and readable design.
1. To get started we are going to create a new version of the example class model and leave
the older one in tact.
src/main
|-- java
| `-- ejava
| `-- jpa
| `-- hibernatemigration
| |-- annotated
| | |-- Clerk.java
| | |-- Customer.java
| | |-- CustomerLevel.java
| | |-- Person.java
| | `-- Sale.java
2. The annotations we see below should map 1:1 with the annotations we defined within the
ORM.xml files in the previous section. In this case the Person entity class is declaring it as an
@MappedSuperclass and defining a few properties inherited by Clerk and Customer.
@MappedSuperclass
public class Person {
@Id @GeneratedValue(strategy=GenerationType.IDENTITY)
private int id;
@Basic(optional=false)
@Column(length=32)
private String name;
![Page 34: Hibernate Migration - webdev home pagewebdev.jhuep.com/.../content/pdf/hibernate-migration.pdf · 2014-03-07 · Chapter 1. Hibernate Legacy P... 2 4. Customer extends Person and](https://reader030.fdocuments.in/reader030/viewer/2022041017/5ec9985628e0741c1957f138/html5/thumbnails/34.jpg)
Chapter 3. Adding Metadata th...
28
3. One nice aspect of using class annotations is that most information is type-safe. In defining the
DATE granularity for the hire/termDate, the developer cannot make a spelling or syntax error
without the compiler complaining.
@Entity
@Table(name="HMIG_CLERK")
public class Clerk extends Person {
@ManyToMany(mappedBy="salesClerks")
private Set<Sale> sales;
@Basic(optional=false)
@Temporal(TemporalType.DATE)
@Column(name="HIRE_DATE")
private Date hireDate;
@Temporal(TemporalType.DATE)
@Column(name="TERM_DATE")
private Date termDate;
4. Even though we have spent a decent amount of effort on defining VARCHAR lengths and
dateTime accuracy for the database schema -- realize that most of the mapping information
is not used beyond optional schema creation or validation. A JPA provider will not check that
a String attribute is within @Column.length constraints. These types of checks are left to the
database to enforce.
@Entity
@Table(name="HMIG_CUSTOMER")
public class Customer extends Person {
@OneToMany(mappedBy="customer")
private Set<Sale> purchases;
@Column(length=32)
private String email;
@Enumerated(EnumType.STRING)
@Column(length=8)
private CustomerLevel level=CustomerLevel.BRONZE;
5. Sale was left un-mapped by entity class annotations and will be required to use an HBM
mapping. This will provide an example of a hybrid approach that mixes class annotations and
HBM file(s).
public class Sale {
private String id;
private BigDecimal amount;
private Date dateTime;
private Set<Clerk> salesClerks;
private Customer customer;
You have finished migrating from HBM mappings to entity class annotations. Hopefully you can
see the benefits and risks associated with placing information directly within the class mapped to
![Page 35: Hibernate Migration - webdev home pagewebdev.jhuep.com/.../content/pdf/hibernate-migration.pdf · 2014-03-07 · Chapter 1. Hibernate Legacy P... 2 4. Customer extends Person and](https://reader030.fdocuments.in/reader030/viewer/2022041017/5ec9985628e0741c1957f138/html5/thumbnails/35.jpg)
Using Annotated Classes with Hibernate Configuration
29
the database. Next we will look at a few remaining mapping issues before our application is ready
to run with this new approach.
3.2. Using Annotated Classes with Hibernate
Configuration
In this section we will look at what is required to use the annotated classes with Hibernate. For the
most part, the main difference is using a different Configuration class -- that is Annotation-aware.
This class is provided in the hibernate-annotations artifact.
1. Remember we left one of the classes unmapped from class annotations so we have to provide a
mapping for that class in an HBM file. This is the same mapping you have seen for Sale earlier.
src/main
|-- java
`-- resources
|-- hibernate
| `-- Sale.hbm.xml
`-- hibernate.cfg.xml
2. The hibernate.xfg.xml looks a little different from what you last saw -- but I am sure the changes
present here are very obvious. We have traded an HBM reference for a class reference for the
Clerk and Customer classes. Sale still uses a reference to an HBM mapping definition.
<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<!-- some of the classes use annotations -->
<mapping class="ejava.jpa.hibernatemigration.annotated.Clerk"/>
<mapping class="ejava.jpa.hibernatemigration.annotated.Customer"/>
<!-- this class does not use annotations -->
<mapping resource="hibernate/Sale.hbm.xml"/>
</session-factory>
</hibernate-configuration>
You have finished going through the Hibernate configuration for using annotated classes. The
main difference is that the classes are listed versus the HBM mappings in the hibernate.cfg.xml
(or API equivalent of the Configuration). Next we will look at the API changes we need at start-up.
![Page 36: Hibernate Migration - webdev home pagewebdev.jhuep.com/.../content/pdf/hibernate-migration.pdf · 2014-03-07 · Chapter 1. Hibernate Legacy P... 2 4. Customer extends Person and](https://reader030.fdocuments.in/reader030/viewer/2022041017/5ec9985628e0741c1957f138/html5/thumbnails/36.jpg)
Chapter 3. Adding Metadata th...
30
3.3. Accessing Annotated Classes with Hibernate
Session
There is only a single change required when adding annotated classes to the Hibernate Session.
Instead of instantiating a normal Configuration class when building a SessionFactory -- we
instantiate an AnnotationConfiguration instead. The rest is identical to what you saw in the legacy
HBM approach.
1.
@BeforeClass
public static void setUpClass() {
log.debug("creating sessionFactory");
sessionFactory=new AnnotationConfiguration().configure().buildSessionFactory();
}
You have finished going through the few changes necessary to access the annotated classes
as entities using Hibernate Session. At this point we may be feeling good -- especially since we
can mix annotated and non-annotated approaches. However, the mixture is at the Session level
and not within a specific entity class. Hibernate provides no means to override the entity class
annotations using the HBM file. In fact, some of the elements in the HBM schema are required
and cannot be left out. The next section shows a first option in achieving an annotation override.
3.4. Adding Overrides thru Custom Configuration
For all the great things one can do with entity class annotations and all the good one can optionally
do with JPA mapping file overrides, Hibernate does not offer that override capability through its
HBM mapping construct. You must do so through API calls. We will start with the first of two
options -- custom Configuration
1. Lets start with the end of the story and work backwards since it is easier to see that way. Notice
what we have done to the Configuration. We have replaced the Hibernate call with a version
we have customized for our own use.
public class CustomizedConfigurationHBMTest extends BaseAnnotatedMigrationTest {
...
@BeforeClass
public static void setUpClass() {
log.debug("creating sessionFactory");
sessionFactory=new CustomizedConfiguration().configure().buildSessionFactory();
}
2. The class is implemented as an extension of the AnnotationConfiguration class since it is the
entity class annotations we primarily wish to override.
public class CustomizedConfiguration extends AnnotationConfiguration {
![Page 37: Hibernate Migration - webdev home pagewebdev.jhuep.com/.../content/pdf/hibernate-migration.pdf · 2014-03-07 · Chapter 1. Hibernate Legacy P... 2 4. Customer extends Person and](https://reader030.fdocuments.in/reader030/viewer/2022041017/5ec9985628e0741c1957f138/html5/thumbnails/37.jpg)
Adding Overrides thru Custom Configuration
31
private static final long serialVersionUID = 1L;
private static final Log log = LogFactory.getLog(CustomizedConfiguration.class);
private Map<String, String> tableMap = new HashMap<String, String>();
...
}
3. The overridden call to configure() calls the parent and then looks for any properties in the
session configuration that expresses a table name override for a particular class. Once found
-- it is stored in a map for a follow-on callback.
@Override
public Configuration configure() throws HibernateException {
log.info(AnnotationConfiguration.class.getResource("AnnotationConfiguration.class"));
Configuration config = super.configure();
for (Object o : getProperties().keySet()) {
String key = (String)o;
log.info("checking " + o);
//different versions of hibernate express key property differently
if (key.matches("(hibernate.)*(tableName:)+.*")) {
String[] tokens = key.split(":");
if (tokens.length != 2) {
log.warn("bad tableName key:" + key);
continue;
}
String className = tokens[1];
String tableName = getProperty(key);
if (tableName==null || tableName.length()==0) {
log.warn("empty tableName value:" + key);
continue;
}
tableMap.put(className, tableName);
}
}
return config;
}
4. After the secondPassCompile callback is complete, all classes have a PersistClass associated
with them and this class houses the class' mapping to the database. If we can find the call we
are configured to use -- we have succeeded in overriding at least one type of annotation.
@Override
protected void secondPassCompile() throws MappingException {
super.secondPassCompile();
for (Entry<String, String> e: tableMap.entrySet()) {
String className = e.getKey();
String tableName = e.getValue();
PersistentClass pc = getClassMapping(className);
if (pc == null) {
log.warn("entity class " + tableName + " not found in session configuration");
continue;
}
![Page 38: Hibernate Migration - webdev home pagewebdev.jhuep.com/.../content/pdf/hibernate-migration.pdf · 2014-03-07 · Chapter 1. Hibernate Legacy P... 2 4. Customer extends Person and](https://reader030.fdocuments.in/reader030/viewer/2022041017/5ec9985628e0741c1957f138/html5/thumbnails/38.jpg)
Chapter 3. Adding Metadata th...
32
String oldName = pc.getTable().getName();
if (!tableName.equals(oldName)) {
pc.getTable().setName(tableName);
log.info(String.format("changed %s tableName from %s to %s",
className, oldName, tableName));
}
}
}
5. To demonstrate our override we add a tableName property to the hibernate.cfg.xml properties.
<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<!-- custom overrides for annotated classes -->
<property name="tableName:ejava.jpa.hibernatemigration.annotated.Clerk">HMIG_CLERK_OVERRIDE</
property>
<!-- some of the classes use annotations -->
<mapping class="ejava.jpa.hibernatemigration.annotated.Clerk"/>
<mapping class="ejava.jpa.hibernatemigration.annotated.Customer"/>
<!-- this class does not use annotations -->
<mapping resource="hibernate/Sale.hbm.xml"/>
</session-factory>
</hibernate-configuration>
6. During the configure step our class recognizes the pattern, parses the tokens and stores the
className and tableName for after the secondPassCompile.
-checking tableName:ejava.jpa.hibernatemigration.annotated.Clerk
7. After the secondPassCompile you can see Hibernate print what it determined was going to be
the proper table mappings and then our override comes in at the end.
-Mapping class: ejava.jpa.hibernatemigration.annotated.Sale -> HMIG_SALE
-Mapping collection: ejava.jpa.hibernatemigration.annotated.Sale.salesClerks -> HMIG_SALE_CLERK
-Binding entity from annotated class: ejava.jpa.hibernatemigration.annotated.Clerk
-Bind entity ejava.jpa.hibernatemigration.annotated.Clerk on table HMIG_CLERK
-Binding entity from annotated class: ejava.jpa.hibernatemigration.annotated.Customer
-Bind entity ejava.jpa.hibernatemigration.annotated.Customer on table HMIG_CUSTOMER
-Mapping collection: ejava.jpa.hibernatemigration.annotated.Customer.purchases -> HMIG_SALE
-changed ejava.jpa.hibernatemigration.annotated.Clerk tableName from HMIG_CLERK to
HMIG_CLERK_OVERRIDE
![Page 39: Hibernate Migration - webdev home pagewebdev.jhuep.com/.../content/pdf/hibernate-migration.pdf · 2014-03-07 · Chapter 1. Hibernate Legacy P... 2 4. Customer extends Person and](https://reader030.fdocuments.in/reader030/viewer/2022041017/5ec9985628e0741c1957f138/html5/thumbnails/39.jpg)
Adding Overrides thru Custom NamingStrategy
33
8. In the debug output for the SQL exchanges with the database, we can verify the tableName
has been changed.
Hibernate:
insert
into
HMIG_CLERK_OVERRIDE
(id, name, HIRE_DATE, TERM_DATE)
values
(null, ?, ?, ?)
9. Life is good! right? Not so fast. Although the Hibernate Session authors may have been open to
us extending Configuration and changing things -- the tool writers didn't get that same memo.
When generating schema the generation configuration does not allow us to express anything
beyind a straight configuration, annotationconfiguration, or one of the other classes supported
by Hibernate. For that reason, we get the followingun-customized mapping generated during
database schema generation.
create table HMIG_CLERK (
id integer generated by default as identity (start with 1),
name varchar(32) not null,
HIRE_DATE date not null,
TERM_DATE date,
primary key (id)
);
You are done looking at our first attempt at implementing a property override when using a
Hibernate Session and entity class annotations. We achieved most of our goal but fell short of tool
integration. Luckily there is another option that is supported by DDL generation. In the next section
we will take a look at providing the given Configuration a NamingStrategy rather than extending
the Configuration.
3.5. Adding Overrides thru Custom NamingStrategy
Hibernate provides the option of overriding its DefaultNamingStrategy with a few built-in versions
as well as your own custom override. This class is consulted for names for entities, tables,
columns, join-columns, etc. We can clearly jump in there. The only down-side is that it class does
not receive any callback with the configuration. You may have to cook something up yourself (like
we did here).
1. We start off by extending the default Hibernate naming strategy class. This class will accept a
configuration mapping from class-to-table and and override mapping from table-to-table. The
former is called when there is no table specification on the class. The later is called when there
is a table specification and gives us a chance to change it.
public class CustomizedNamingStrategy extends DefaultNamingStrategy {
![Page 40: Hibernate Migration - webdev home pagewebdev.jhuep.com/.../content/pdf/hibernate-migration.pdf · 2014-03-07 · Chapter 1. Hibernate Legacy P... 2 4. Customer extends Person and](https://reader030.fdocuments.in/reader030/viewer/2022041017/5ec9985628e0741c1957f138/html5/thumbnails/40.jpg)
Chapter 3. Adding Metadata th...
34
private static final Log log = LogFactory.getLog(CustomizedNamingStrategy.class);
//mapping from className to tableName
private Map<String, String> classTableMap = new HashMap<String, String>();
//tableName override
private Map<String, String> tableMap = new HashMap<String, String>();
...
}
2. We add some methods to allow our application to configure the overrides
public CustomizedNamingStrategy addClassTableMapping(String className, String tableName) {
classTableMap.put(className, tableName);
return this;
}
public CustomizedNamingStrategy addTableMapping(String oldName, String newName) {
tableMap.put(oldName, newName);
return this;
}
3. We implement the callback method when the provider is looking for a table name and there
was none provided in the class annotations.
@Override
public String classToTableName(String className) {
log.debug("classToTableName(" + className + ")");
String tableName = super.classToTableName(className);
String newName = classTableMap.get(className);
if (newName != null) {
log.info(String.format("updating %s from tableName: %s to %s",
className, tableName, newName));
tableName = newName;
}
return tableName;
}
4. We implement the callback method when the provider is looking for a table name and there
was one provided by the class annotation. In this case we are given a chance to override what
the configuration was going to use.
@Override
public String tableName(String tableName) {
log.debug("tableName(" + tableName + ")");
String newName = tableMap.get(tableName);
if (newName != null) {
log.info(String.format("updating tableName from %s to %s",
tableName, newName));
tableName = newName;
}
return tableName;
![Page 41: Hibernate Migration - webdev home pagewebdev.jhuep.com/.../content/pdf/hibernate-migration.pdf · 2014-03-07 · Chapter 1. Hibernate Legacy P... 2 4. Customer extends Person and](https://reader030.fdocuments.in/reader030/viewer/2022041017/5ec9985628e0741c1957f138/html5/thumbnails/41.jpg)
Adding Overrides thru Custom NamingStrategy
35
}
5. One more step is to create a class that sets the mapping values. Clearly this could be driven
off of anything and was hard-coded here for quick implementation.
public class ProjectNamingStrategy extends CustomizedNamingStrategy {
public ProjectNamingStrategy() {
//this is in case the class metadata did not specify a tableName
addClassTableMapping(Customer.class.getName(), "HMIG_CUSTOMER_STRATEGY");
//this is in case the class metadata did spec a tableName we want to override
addTableMapping("HMIG_CUSTOMER", "HMIG_CUSTOMER_STRATEGY");
}
}
6. We now set an instance of our NamingStrategy as the naming strategy for the configuration.
@BeforeClass
public static void setUpClass() {
log.debug("creating sessionFactory");
sessionFactory=new AnnotationConfiguration()
.setNamingStrategy(new ProjectNamingStrategy())
.configure().buildSessionFactory();
}
7. During the SessionFactory creation -- we can see our naming strategy get called and get a
chance to override our targeted table name.
-updating tableName from HMIG_CUSTOMER to HMIG_CUSTOMER_STRATEGY
-Bind entity ejava.jpa.hibernatemigration.annotated.Customer on table HMIG_CUSTOMER_STRATEGY
8. Like with the previous strategy, we can now see our override taking place.
Hibernate:
insert
into
HMIG_CUSTOMER_STRATEGY
(id, name, email, level)
values
(null, ?, ?, ?)
9. Unlike our previous strategy, we can also provide this NamingStrategy to the DLL generation
tool. This looks different from before since we have switched to the new hibernate3-maven-
plugin API in this example. More details later -- but notice we can provide a specification to
our NamingStrategy.
<hibernatetool>
![Page 42: Hibernate Migration - webdev home pagewebdev.jhuep.com/.../content/pdf/hibernate-migration.pdf · 2014-03-07 · Chapter 1. Hibernate Legacy P... 2 4. Customer extends Person and](https://reader030.fdocuments.in/reader030/viewer/2022041017/5ec9985628e0741c1957f138/html5/thumbnails/42.jpg)
Chapter 3. Adding Metadata th...
36
<annotationconfiguration configurationfile="/home/jenkins/workspace/javaee-class-deploy/jpa/jpa-providers/jpa-
hibernate/hibernate-migration/hibernate-migration-docbook/target/classes/hibernate.cfg.xml"
namingstrategy="ejava.jpa.hibernatemigration.ProjectNamingStrategy"/>
<hbm2ddl export="false" create="true" drop="false" format="true"
outputfilename="hibernate-migration-docbook-createNAM.ddl"/>
</hibernatetool>
10.The following is an example of what is generated from the DDL plugin.
create table HMIG_CUSTOMER_STRATEGY (
id integer generated by default as identity (start with 1),
name varchar(32) not null,
email varchar(32),
level varchar(8),
primary key (id)
);
...
alter table HMIG_SALE
add constraint FK862A2223AB739428
foreign key (CUSTOMER_ID)
references HMIG_CUSTOMER_STRATEGY;
We have finished looking at the custom NamingStrategy option. Both this and the custom
Configuration option gave us most of what we wanted, but this one added a small amount of tool
support that could be quite useful. Next we will look at the full hibernate3-maven-plugin that made
this happen since we are now switching to the new 3.x release.
3.6. Generating Schema from Class Annotations and
NamingStrategy
As a move forward, we are going to switch to the 3.x version of the hibernate3-maven-plugin.
This upgrade wraps Hibernate Ant tasks and just serves as a delegation wrapper. Most of
the documentation is at the Ant level [http://docs.jboss.org/tools/latest/en/hibernatetools/html/
ant.html].
1. My success varied with this plugin and versions required. You will notice it provides the ability to
declare a separate plugin dependency on the hibernate-entitymanager. I found this useful when
my application used hibernate4 and the plugin required hibernate3. However, if the application
uses hibernate3 -- then the version used by the plugin and pom dependency must be the
same. In that case, you can simply leave the dependency on hibernate-entitymanager out of
the plugin#dependencies.
<plugin>
<artifactId>hibernate3-maven-plugin</artifactId>
<groupId>org.codehaus.mojo</groupId>
<version>3.0</version>
<extensions>true</extensions>
<dependencies>
![Page 43: Hibernate Migration - webdev home pagewebdev.jhuep.com/.../content/pdf/hibernate-migration.pdf · 2014-03-07 · Chapter 1. Hibernate Legacy P... 2 4. Customer extends Person and](https://reader030.fdocuments.in/reader030/viewer/2022041017/5ec9985628e0741c1957f138/html5/thumbnails/43.jpg)
Generating Schema from Class Annotations and NamingStrategy
37
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<version>${legacy-hibernate.version}</version>
</dependency>
</dependencies>
<configuration>
<hibernatetool destdir="target/classes/ddl">
<classpath>
<path location="/home/jenkins/workspace/javaee-class-deploy/jpa/jpa-providers/jpa-hibernate/
hibernate-migration/hibernate-migration-docbook/target/classes" />
<path location="/home/jenkins/workspace/javaee-class-deploy/jpa/jpa-providers/jpa-hibernate/
hibernate-migration/hibernate-migration-docbook/target/test-classes" />
</classpath>
</hibernatetool>
</configuration>
<executions>
...
</executions>
</plugin>
2. The configuration for the schema generation is defined by a Hibernate Configuration -- which is
represented by the annotationconfiguration element shown below. Note we have also assigned
the namingstrategy for the configuration to our customer strategy.
<execution>
<id>generate-drop-hbm</id>
<phase>process-test-resources</phase>
<goals>
<goal>run</goal>
</goals>
<configuration>
<hibernatetool>
<annotationconfiguration configurationfile="/home/jenkins/workspace/javaee-class-deploy/jpa/jpa-providers/
jpa-hibernate/hibernate-migration/hibernate-migration-docbook/target/classes/hibernate.cfg.xml"
namingstrategy="ejava.jpa.hibernatemigration.ProjectNamingStrategy"/>
<hbm2ddl export="false" create="false" drop="true" format="true"
outputfilename="hibernate-migration-docbook-dropNAM.ddl"/>
</hibernatetool>
</configuration>
</execution>
3. We still need to create two executions; one to generate the drops and the other to generate
the creates.
<execution>
<id>generate-create-hbm</id>
<phase>process-test-resources</phase>
<goals>
<goal>run</goal>
</goals>
<configuration>
![Page 44: Hibernate Migration - webdev home pagewebdev.jhuep.com/.../content/pdf/hibernate-migration.pdf · 2014-03-07 · Chapter 1. Hibernate Legacy P... 2 4. Customer extends Person and](https://reader030.fdocuments.in/reader030/viewer/2022041017/5ec9985628e0741c1957f138/html5/thumbnails/44.jpg)
Chapter 3. Adding Metadata th...
38
<hibernatetool>
<annotationconfiguration configurationfile="/home/jenkins/workspace/javaee-class-deploy/jpa/jpa-providers/
jpa-hibernate/hibernate-migration/hibernate-migration-docbook/target/classes/hibernate.cfg.xml"
namingstrategy="ejava.jpa.hibernatemigration.ProjectNamingStrategy"/>
<hbm2ddl export="false" create="true" drop="false" format="true"
outputfilename="hibernate-migration-docbook-createNAM.ddl"/>
</hibernatetool>
</configuration>
</execution>
Note
The above shows an example of using a hibernate.cfg.xml file. If you simply
have HBM files and, at most, a hibernate.properties file, you can add references
to those files using
<hibernatetool destdir="${build.dir}/generated">
<configuration propertyfile="target/test-classes/hibernate.properties">
<fileset dir="target/classes/hibernate">
<include name="**/*.hbm.xml"/>
</fileset>
</configuration>
You have finished looking at schema generation for a Hibernate Session that has overrides for
the annotated classes. This represents the last section within this topic.
3.7. Summary
In this chapter we replaced verbose XML mapping files with Java class annotations. This permits
us to place the information and mapping design in a single location. The down-side, however, is
that class annotations cannot be mixed with HBM files within the same class. No fear. We simply
needed to write a small set of classes to manipulate the Hibernate Configuration to supply the
overrides. This wraps up our coverage of incremental steps moving from Hibernate Sessions to
JPA. The next chapter shows the end state where we have fully migrated the application away
from HBM files, to class annotations, and to a JPA EntityManager API.
![Page 45: Hibernate Migration - webdev home pagewebdev.jhuep.com/.../content/pdf/hibernate-migration.pdf · 2014-03-07 · Chapter 1. Hibernate Legacy P... 2 4. Customer extends Person and](https://reader030.fdocuments.in/reader030/viewer/2022041017/5ec9985628e0741c1957f138/html5/thumbnails/45.jpg)
Chapter 4.
39
JPA-based ProjectThis chapter describes describes the final stage of the migration where the classes, descriptors,
and APIs have all been switched to JPA. If we do encounter apsects of the legacy mapping that is
not supported in JPA -- we know from the previous chapters that we can fully leverage the legacy
Hibernate mappings where necessary or desired.
4.1. JPA Project Structure
In this pass we are going to treat the annotated entity classes as an external library and provide
overrides for table names specific to our application. Note too that the Sales class does not provide
any Java annotations.
1. Our application supplies a persistence.xml that describes how this application will use the
persistence unit. For example, some applications use a direct database connection and others
borrow a connection from a javax.sql.DataSource. In this case, our persistence unit is defining
some application-specific overrides for the two of the entities (Clerk and Customer) and
providing the full mapping for the third entity (Sale) because that class does not supply any
metadata.
src
|-- main
| |-- java
| `-- resources
| |-- jpa
| | |-- Clerk-orm.xml
| | |-- Customer-orm.xml
| | `-- Sale-orm.xml
| `-- META-INF
| `-- persistence.xml
`-- test
`-- resources
`-- hibernate.properties
2. The Customer ORM entity definition overrides the table name used in the class annotations
to be something specific to this application. Although not needed for our simple mapping
requirements, we have also switched the schema references to JPA 2.0.
<?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_2_0.xsd"
version="2.0">
<entity class="ejava.jpa.hibernatemigration.annotated.Customer">
![Page 46: Hibernate Migration - webdev home pagewebdev.jhuep.com/.../content/pdf/hibernate-migration.pdf · 2014-03-07 · Chapter 1. Hibernate Legacy P... 2 4. Customer extends Person and](https://reader030.fdocuments.in/reader030/viewer/2022041017/5ec9985628e0741c1957f138/html5/thumbnails/46.jpg)
Chapter 4. JPA-based Project
40
<table name="HMIG_CUSTOMER_ORM"/>
</entity>
3. The Clerk ORM provides the same type of table override and to simply things -- we could have
placed the simple overrides for Customer and Clerk into a single ORM file with multiple entity
elements.
<?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_2_0.xsd"
version="2.0">
<entity class="ejava.jpa.hibernatemigration.annotated.Clerk">
<table name="HMIG_CLERK_ORM"/>
</entity>
</entity-mappings>
4. The Sale ORM file provides the full mapping to the database because the class does not provide
any mapping annotations and many of the mappings are too complicated for standard JPA
Entity defaults to solve.
<?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_2_0.xsd"
version="2.0">
<package>ejava.jpa.hibernatemigration.annotated</package>
<access>FIELD</access>
<entity class="Sale">
<table name="HMIG_SALE_ORM"/>
<attributes>
<id name="id">
<column length="36"/>
</id>
<basic name="amount" optional="false">
<column precision="7" scale="2"/>
</basic>
<basic name="dateTime" optional="false">
<column name="SALE_TIME"/>
<temporal>TIMESTAMP</temporal>
</basic>
<many-to-one name="customer" optional="false">
<join-column name="CUSTOMER_ID"/>
</many-to-one>
<many-to-many name="salesClerks">
<join-table name="HMIG_SALE_CLERK">
![Page 47: Hibernate Migration - webdev home pagewebdev.jhuep.com/.../content/pdf/hibernate-migration.pdf · 2014-03-07 · Chapter 1. Hibernate Legacy P... 2 4. Customer extends Person and](https://reader030.fdocuments.in/reader030/viewer/2022041017/5ec9985628e0741c1957f138/html5/thumbnails/47.jpg)
JPA Project Structure
41
<join-column name="SALE_ID"/>
<inverse-join-column name="CLERK_ID"/>
</join-table>
</many-to-many>
</attributes>
</entity>
</entity-mappings>
5. The persistence unit is defined to use the Hibernate provider (in case there are multiple in the
classpath) and include our three ORM mapping files.
<?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_2_0.xsd"
version="2.0">
<persistence-unit name="hibernate-migration-sales">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<mapping-file>jpa/Customer-orm.xml</mapping-file>
<mapping-file>jpa/Clerk-orm.xml</mapping-file>
<mapping-file>jpa/Sale-orm.xml</mapping-file>
</persistence-unit>
</persistence>
6. The hibernate.properties file has not changed from the original legacy project. We optionally
separate it from the persistence.xml because it defines many runtime properties that may be
specific to our current environment (like database URL and credentials). If we do think that some
of the properties are better associated with the persistence unit (e.g., hibernate.cache.provider)
we can move that to the properties section of the persistence.xml.
hibernate.dialect=org.hibernate.dialect.H2Dialect
hibernate.connection.url=jdbc:h2:/home/jenkins/workspace/javaee-class-deploy/jpa/jpa-providers/jpa-hibernate/
hibernate-migration/hibernate-migration-docbook/target/h2db/ejava
hibernate.connection.driver_class=org.h2.Driver
hibernate.connection.password=
hibernate.connection.username=sa
hibernate.connection.pool_size=1
hibernate.hbm2ddl.auto=create
hibernate.show_sql=true
hibernate.format_sql=true
#hibernate.jdbc.batch_size=0
hibernate.current_session_context_class=thread
hibernate.cache.provider_class=org.hibernate.cache.NoCacheProvider
![Page 48: Hibernate Migration - webdev home pagewebdev.jhuep.com/.../content/pdf/hibernate-migration.pdf · 2014-03-07 · Chapter 1. Hibernate Legacy P... 2 4. Customer extends Person and](https://reader030.fdocuments.in/reader030/viewer/2022041017/5ec9985628e0741c1957f138/html5/thumbnails/48.jpg)
Chapter 4. JPA-based Project
42
4.2. Generating Schema from JPA Persistence Unit
This section will cover database schema generation from a persistence unit. It is very similar to
what we did in the previous section when we used the 3.x version of the hibernate3-maven-plugin
except this time we will use a jpaconfiguration element.
1. We start off with a modest upgrade to our JPA library so that it supports JPA2 constructs.
Versions of Hibernate with JPA2 support have been in place since mid-2010. You should be
able to locate versions newer than what is used here.
<properties>
<!-- hibernate 3.5.0-Final was released to ibiblio April 2010 -->
<jpa2-hibernate.version>3.5.0-Final</jpa2-hibernate.version>
<hibernate-slf4j.version>1.5.8</hibernate-slf4j.version>
</properties>
2. A the project dependency needs to reference the newer hibernate-entitymanager version. Be
sure to also include a dependency on slf4j-log4j12 and make sure it is a compatible version
with the version used by hibernate.
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<version>${jpa2-hibernate.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>${hibernate-slf4j.version}</version>
<scope>test</scope>
</dependency>
3. We add a plugin dependency on hibernate-entitymanager to force the plugin to use the same
version of the entitymanager as the application. If the dependency above was scope=compile,
this would not have been necessary. The exclusion for the slf4j-api removes a conflicting
dependency later versions of the entitymanager have with the 3.x version of the hibernate3-
maven-plugin.
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>hibernate3-maven-plugin</artifactId>
<version>3.0</version>
<extensions>true</extensions>
<dependencies>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
![Page 49: Hibernate Migration - webdev home pagewebdev.jhuep.com/.../content/pdf/hibernate-migration.pdf · 2014-03-07 · Chapter 1. Hibernate Legacy P... 2 4. Customer extends Person and](https://reader030.fdocuments.in/reader030/viewer/2022041017/5ec9985628e0741c1957f138/html5/thumbnails/49.jpg)
Generating Schema from JPA Persistence Unit
43
<version>${jpa2-hibernate.version}</version>
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
<configuration>
<hibernatetool destdir="target/classes/ddl">
<classpath>
<path location="/home/jenkins/workspace/javaee-class-deploy/jpa/jpa-providers/jpa-hibernate/
hibernate-migration/hibernate-migration-docbook/target/classes" />
<path location="/home/jenkins/workspace/javaee-class-deploy/jpa/jpa-providers/jpa-hibernate/
hibernate-migration/hibernate-migration-docbook/target/test-classes" />
</classpath>
</hibernatetool>
</configuration>
<executions>
...
</executions>
</plugin>
4. A jpaconfiguration and persistenceunit name is used to locate the persistence unit definition
and define the entities to Hibernate.
<execution>
<id>generate-drop-hbm</id>
<phase>process-test-resources</phase>
<goals>
<goal>run</goal>
</goals>
<configuration>
<hibernatetool>
<jpaconfiguration persistenceunit="hibernate-migration-sales"
propertyfile="/home/jenkins/workspace/javaee-class-deploy/jpa/jpa-providers/jpa-hibernate/hibernate-
migration/hibernate-migration-docbook/target/test-classes/hibernate.properties" />
<hbm2ddl export="false" create="false" drop="true" format="true"
outputfilename="hibernate-migration-docbook-dropJPA.ddl"/>
</hibernatetool>
</configuration>
</execution>
5. The create script execution uses the same technique.
<execution>
<id>generate-create-hbm</id>
<phase>process-test-resources</phase>
<goals>
<goal>run</goal>
</goals>
![Page 50: Hibernate Migration - webdev home pagewebdev.jhuep.com/.../content/pdf/hibernate-migration.pdf · 2014-03-07 · Chapter 1. Hibernate Legacy P... 2 4. Customer extends Person and](https://reader030.fdocuments.in/reader030/viewer/2022041017/5ec9985628e0741c1957f138/html5/thumbnails/50.jpg)
Chapter 4. JPA-based Project
44
<configuration>
<hibernatetool>
<jpaconfiguration persistenceunit="hibernate-migration-sales"
propertyfile="/home/jenkins/workspace/javaee-class-deploy/jpa/jpa-providers/jpa-hibernate/hibernate-
migration/hibernate-migration-docbook/target/test-classes/hibernate.properties" />
<hbm2ddl export="false" create="true" drop="false" format="true"
outputfilename="hibernate-migration-docbook-createJPA.ddl"/>
</hibernatetool>
</configuration>
</execution>
6. The following lists the generated DDL from the hibernate3-maven-plugin, our configurations,
and definitions.
create table HMIG_CLERK_ORM (
id integer generated by default as identity (start with 1),
name varchar(32) not null,
HIRE_DATE date not null,
TERM_DATE date,
primary key (id)
);
create table HMIG_CUSTOMER_ORM (
id integer generated by default as identity (start with 1),
name varchar(32) not null,
email varchar(32),
level varchar(8),
primary key (id)
);
create table HMIG_SALE_CLERK (
SALE_ID varchar(36) not null,
CLERK_ID integer not null,
primary key (SALE_ID, CLERK_ID)
);
create table HMIG_SALE_ORM (
id varchar(36) not null,
amount numeric not null,
SALE_TIME timestamp not null,
CUSTOMER_ID integer not null,
primary key (id)
);
alter table HMIG_SALE_CLERK
add constraint FK33F2DF1955121688
foreign key (SALE_ID)
references HMIG_SALE_ORM;
alter table HMIG_SALE_CLERK
add constraint FK33F2DF198F07D2C
foreign key (CLERK_ID)
references HMIG_CLERK_ORM;
![Page 51: Hibernate Migration - webdev home pagewebdev.jhuep.com/.../content/pdf/hibernate-migration.pdf · 2014-03-07 · Chapter 1. Hibernate Legacy P... 2 4. Customer extends Person and](https://reader030.fdocuments.in/reader030/viewer/2022041017/5ec9985628e0741c1957f138/html5/thumbnails/51.jpg)
Summary
45
alter table HMIG_SALE_ORM
add constraint FK4262BAAEAB739428
foreign key (CUSTOMER_ID)
references HMIG_CUSTOMER_ORM;
You have finished going through the specifics for setting up the hibernate3-maven-plugin to
generate database schema for our JPA module. That wraps up what is needed to cover the final
leg of the migration to the JPA-centric approach.
4.3. Summary
In this chapter we defined use of our application through the JPA interface -- the same interface
that was used during the ORM.xml file section. However, in this case we leveraged a mixture of
Java class annotations and ORM.xml files to define the persistence unit.
![Page 52: Hibernate Migration - webdev home pagewebdev.jhuep.com/.../content/pdf/hibernate-migration.pdf · 2014-03-07 · Chapter 1. Hibernate Legacy P... 2 4. Customer extends Person and](https://reader030.fdocuments.in/reader030/viewer/2022041017/5ec9985628e0741c1957f138/html5/thumbnails/52.jpg)
46
![Page 53: Hibernate Migration - webdev home pagewebdev.jhuep.com/.../content/pdf/hibernate-migration.pdf · 2014-03-07 · Chapter 1. Hibernate Legacy P... 2 4. Customer extends Person and](https://reader030.fdocuments.in/reader030/viewer/2022041017/5ec9985628e0741c1957f138/html5/thumbnails/53.jpg)
Chapter 5.
47
Hibernate Migration ErrorsThis chapter describes describes a few of the problems, causes, and solutions found when
migrating from a legacy Hibernate project to a JPA project. Most of the issues involved integration
with hibernate3-maven-plugin.
5.1. Missing hibernate-entitymanager
This error occurs when using the hibernate3-maven-plugin and the project does not declare a
dependency on the hibernate-entitymanager.
5.1.1. Symptom: NoClassDefFoundError:
org.hibernate.cfg.Configuration
[ERROR] Failed to execute goal org.codehaus.mojo:hibernate3-maven-plugin:3.0:run (generate-drop-hbm) on project
hibernate-hbm2:
There was an error creating the AntRun task. An Ant BuildException has occured: java.lang.NoClassDefFoundError:
org/hibernate/cfg/Configuration: org.hibernate.cfg.Configuration
5.1.2. Cause: Missing dependency on hibernate-entitymanager
The error occurs because the plugin has no hibernate artifact to provide it the necessary classes.
That could be due to....
• The dependency on hibernate-entitymanager was either missing or declared scope=test or
provided.
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<version>${legacy-hibernate.version}</version>
<scope>test</scope>
</dependency>
• The plugin did not declare a dependency on hibernate-entitymanager to compensate for the
module not having a scope=compile dependency.
<build>
<plugins>
<plugin>
<artifactId>hibernate3-maven-plugin</artifactId>
<groupId>org.codehaus.mojo</groupId>
<version>3.0</version>
<extensions>true</extensions>
<dependencies>
</dependencies>
...
![Page 54: Hibernate Migration - webdev home pagewebdev.jhuep.com/.../content/pdf/hibernate-migration.pdf · 2014-03-07 · Chapter 1. Hibernate Legacy P... 2 4. Customer extends Person and](https://reader030.fdocuments.in/reader030/viewer/2022041017/5ec9985628e0741c1957f138/html5/thumbnails/54.jpg)
Chapter 5. Hibernate Migratio...
48
5.1.3. Solution: Declare plugin dependency on hibernate-
entitymanager
Either the module or the module plugin must have a dependency on hibernate-entitymanager to
have the missing class(es) be resolved for DDL generation.
<plugin>
<artifactId>hibernate3-maven-plugin</artifactId>
<groupId>org.codehaus.mojo</groupId>
<version>3.0</version>
<extensions>true</extensions>
<dependencies>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<version>${legacy-hibernate.version}</version>
</dependency>
</dependencies>
5.2. Mixed Hibernate Versions with plugin and JPA
This error is caused when there is a version of hibernate in your project that conflicts with the
default version used by the hibernate3-maven-plugin.
5.2.1. Symptom: NoSuchMethodException:
org.hibernate.validator.ClassValidator.<init>(...)
When using the JPA aspects of the plugin you may notice the following.
[INFO] --- hibernate3-maven-plugin:2.2:hbm2ddl (generate-drop-hbm) @ hibernate-orm ---
-Hibernate Annotations 3.4.0.GA
-Hibernate 3.3.1.GA
Failed to execute goal org.codehaus.mojo:hibernate3-maven-plugin:2.2:hbm2ddl (generate-drop-hbm) on project
hibernate-orm:
Execution generate-drop-hbm of goal org.codehaus.mojo:hibernate3-maven-plugin:2.2:hbm2ddl failed:
[PersistenceUnit: hibernate-migration-sales] Unable to configure EntityManagerFactory:
java.lang.NoSuchMethodException: org.hibernate.validator.ClassValidator.<init>(java.lang.Class,
java.util.ResourceBundle, org.hibernate.validator.MessageInterpolator, java.util.Map,
org.hibernate.annotations.common.reflection.ReflectionManager)
5.2.2. Cause: Using JPAConfiguration and version mis-matches
This error is caused by using the JPA configuration of the plugin and not having all dependencies
aligned.
![Page 55: Hibernate Migration - webdev home pagewebdev.jhuep.com/.../content/pdf/hibernate-migration.pdf · 2014-03-07 · Chapter 1. Hibernate Legacy P... 2 4. Customer extends Person and](https://reader030.fdocuments.in/reader030/viewer/2022041017/5ec9985628e0741c1957f138/html5/thumbnails/55.jpg)
Solution: Declare plugin dependency on hibernate-entitymanager
49
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<version>${legacy-hibernate.version}</version>
<scope>provided</scope>
</dependency>
<plugin>
<artifactId>hibernate3-maven-plugin</artifactId>
<groupId>org.codehaus.mojo</groupId>
<version>${legacy-hibernate3-maven-plugin.version}</version>
<dependencies>
</dependencies>
5.2.3. Solution: Declare plugin dependency on hibernate-
entitymanager
Declare a dependency on hibernate-entitymanager within the plugin to control the version brought
in when using the JPA extentions.
<plugin>
<artifactId>hibernate3-maven-plugin</artifactId>
<groupId>org.codehaus.mojo</groupId>
<version>3.0</version>
<extensions>true</extensions>
<dependencies>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<version>${legacy-hibernate.version}</version>
</dependency>
</dependencies>
5.3. slf4j version mis-matches with later versions of
Hibernate
Issues with hibernate and slf4j start appearing with some of the later versions of hibernate 3.x.
where they switched dependencies from slf4j1.5.8 to 1.6.1.
5.3.1. Symptom: NoClassDefFoundError:
org.slf4j.helpers.NOPLoggerFactory
[ERROR] Failed to execute goal org.codehaus.mojo:hibernate3-maven-plugin:3.0:run (generate-drop-hbm) on project
hibernate-annotated-jpa:
![Page 56: Hibernate Migration - webdev home pagewebdev.jhuep.com/.../content/pdf/hibernate-migration.pdf · 2014-03-07 · Chapter 1. Hibernate Legacy P... 2 4. Customer extends Person and](https://reader030.fdocuments.in/reader030/viewer/2022041017/5ec9985628e0741c1957f138/html5/thumbnails/56.jpg)
Chapter 5. Hibernate Migratio...
50
There was an error creating the AntRun task. An Ant BuildException has occured: java.lang.NoClassDefFoundError: org/
slf4j/helpers/NOPLoggerFactory:
org.slf4j.helpers.NOPLoggerFactory
5.3.2. Cause: plugin dependency on hibernate-entitymanager
causes slf4j-api version mis-match
In this case we have created a plugin dependency on hibernate-entitymanager for the plugin using
version 3.5.0-Final. This brought in slf4j-api version 1.5.8 which collided with logging done within
the plugin.
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>hibernate3-maven-plugin</artifactId>
<version>3.0</version>
<extensions>true</extensions>
<dependencies>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<version>${jpa2-hibernate.version}</version>
</dependency>
</dependencies>
5.3.3. Solution: Exclude slf4j-api from plugin dependency
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>hibernate3-maven-plugin</artifactId>
<version>3.0</version>
<extensions>true</extensions>
<dependencies>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<version>${jpa2-hibernate.version}</version>
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
![Page 57: Hibernate Migration - webdev home pagewebdev.jhuep.com/.../content/pdf/hibernate-migration.pdf · 2014-03-07 · Chapter 1. Hibernate Legacy P... 2 4. Customer extends Person and](https://reader030.fdocuments.in/reader030/viewer/2022041017/5ec9985628e0741c1957f138/html5/thumbnails/57.jpg)
Summary
51
5.4. Summary
In this chapter we listed some error messages, described the causes, and provided solutions.
When in doubt, you can also take a look at the source modules that were used to build the
examples provided.
![Page 58: Hibernate Migration - webdev home pagewebdev.jhuep.com/.../content/pdf/hibernate-migration.pdf · 2014-03-07 · Chapter 1. Hibernate Legacy P... 2 4. Customer extends Person and](https://reader030.fdocuments.in/reader030/viewer/2022041017/5ec9985628e0741c1957f138/html5/thumbnails/58.jpg)
52