Short Tutorial: Migration from EJB Entity to Hibernate
Case
- let’s consider an EJB Bean AnimalBean, linked to a table JL_Animal
- let’s have a human understandable name for the Pojo, let’s say: Animal
- let an EJB entity have following finders:
* @ejb.finder * signature = "Collection findByBirthDate(java.lang.Integer birthDate)" * query = "SELECT OBJECT(o) FROM AnimalBean AS o WHERE o.birthDate = ?1" * * @ejb.finder * signature = "Collection findByCountryAndBirthDate(java.lang.String from,java.lang.Integer birthDate)" * query = "SELECT OBJECT(o) FROM AnimalBean AS o WHERE o.country = ?1 AND o.birthDate = ?2"
Create a DAO interface
In the interface AnimalDAO
, we must have:
Collection findByBirthDate(Integer birthDate); Collection findByCountryAndBirthDate(String from,Integer birthDate);
By the way: EJB do not accept Java 5 generics, but Hibernate does. Therefore, we improve the methods signature, using generics:
Collection findByBirthDate(Integer birthDate); Collection<Animal> findByCountryAndBirthDate(String from,Integer birthDate);
Hibernate mapping
Let’s create a Hibernate mapping file:
Primary key:
the first element of the XML file will be this:
<class name="my.personnal.package.Animal" table="JL_Animal">
if the EJB contains:
* @ejb.bean * jndi-name = "xxxxxxxxxxxxxx" * local-jndi-name = "xxxxxxxxxxxxxx" * description = xxxxxxxxxxxxxxx" * view-type = "local" * type = "CMP" * cmp-version = "2.x" * schema = "AnimalBean" * primkey-field = "animalId" * * (...) * * @ejb.pk * class = "java.lang.Integer" * generate = "False" * * @ejb.persistence * table-name = "JL_Animal" * * @weblogic.automatic-key-generation * generator-type = "XXXXXXX" * generator-name = "JL_Animal_SEQ" * key-cache-size = "10"
then the XML file will contain:
<id name="animalId" type="integer"> <generator> <param name="sequence">JL_Animal_SEQ</param> <param name="max_lo">10</param> </generator> </id>
The primary key may be set owing to a sequence, a class, may be assigned, etc.
Version
If the Bean contained:
* @weblogic.persistence * verify-columns = "Timestamp" * optimistic-column = "OptimisticTimestamp"
or something like:
* @weblogic.cache-ref * cache-name = "primeweb.entity-cache" * concountry-strategy = "Optimistic" * cache-between-transactions = "True"
then add this line to your XML file:
<version column="optimisticTimestamp" name="optimisticTimestamp" type="timestamp"/>
The version may be determined by column
, name
, node
, access
, type
…
Fields
For simple types, you may only write the names of the fields
<property name="country" column="countryId"/>
Attribute name
is mandatory, others are not: class
, column
, etc.
This corresponds to an property described in the entity like this:
/** * @ejb.persistence * column-name = "countryId" * @ejb.interface-method */ public abstract String getcountry(); /** @ejb.interface-method */ public abstract void setcountry(String country);
One of best Hibernate features is the ability to make joints between tables. Related keywords are many-to-one, one-to-many, one-to-one, etc. Migration from EJB to Hibernate for this kind of joints is out from this tutorial scope, we leave it at a later post.
Hibernate implementation of DAO
For CRUD methods (create/delete/update), a simple call to sessionFactory should be sufficient:
sessionFactory.getCurrentSession().persist(entity);
For more complex methods, if in the Bean you find:
* @ejb.finder * signature = "Collection findByCountryAndBirthDate(java.lang.String from,java.lang.Integer birthDate)" * query = "SELECT OBJECT(o) FROM AnimalBean AS o WHERE o.country = ?1 AND o.birthDate = ?2"
then in Hibernate you will have:
private static final String BY_birthDate = "FROM Animal WHERE birthDate = :birthDate order by country" public Collection<Animal> findByBirthDate(Integer birthDate) { final Query query; PreCondition.assertNotNull("birthDate", birthDate); query = getSessionFactory().getCurrentSession().createQuery(BY_birthDate); query.setInteger("birthDate", birthDate); return query.list(); }
Misc
- we added a “order by” clause: this is to follow a determistic behaviour on testing
- as stated above, we used generics, even though original query did not
- sometimes, create/update/delete methods in EJBs contain logic code. Do not forget to reproduce this logic in the Hibernate implementation
- take care of
ObjectNotFoundException
andFinderException
raised by EJB! Hibernate may return null objects rather than raising exceptions, this must be taken in account. A common practice is to add specific Exception in DAO, for instanceAnimalNotFoundException
, to be raised when the object to be returned is null. - In some EJBs,
optimistictimestamp
s are not used, therefore they remain at null. This may have consequences on migrating onto Hibernate. Thus, think of setting alloptimistictimestamp
at current date before releasing the migration. In Oracle, the command is:
update JL_Animal set OPTIMISTICTIMESTAMP = SYSDATE where OPTIMISTICTIMESTAMP is null;