Hibernate Core Migration Guide : 3.0

This document describes the changes between Hibernate 2.1 and Hibernate 3.0 that will affect existing applications, and mentions certain new features of Hibernate 3.0 that might be useful to existing applications.  Hibernate 3.0 is not source-compatible with Hibernate 2.1, nor is it intended as a drop-in replacement for 2.1. However, the changes made in 3.0 were carefully designed to allow straightforward migration of both code and metadata. Most projects will not experience many difficulties migrating.  Note that it is possible to run Hibernate 2 and Hibernate 3 side by side in the same application.

 

Changes in this migration guide are classified into:

 

Additionally, see the extra section about issue using Hibernate3 with WebLogic.

 


API Changes

  • Package naming - The Hibernate3 package structure is rooted at org.hibernate instead of net.sf.hibernate. This renaming was done to allow Hibernate2 and Hibernate3 to run side by side in the same application. The first step in Hibernate3 migration is a global text search/replace, ie. s/net.sf.hibernate/org.hibernate.  The net.sf.hibernate.expression package was renamed org.hibernate.criterion. Applications using Criteria queries require a further text/search replace to accommodate this change.  Be careful if you use external software that references Hibernate packages. For example, EHCache has its own CacheProvider in net.sf.ehcache.hibernate.Provider. Until all external software updates its references, you might have to patch and work around this issue. For EHCache you may also use the built-in provider in Hibernate: org.hibernate.cache.EhCacheProvider
  • org.hibernate.classic package - Certain interfaces that have been deprecated in Hibernate3 were moved to the org.hibernate.classic package.   
    • Session interface - Certain redundant methods were deprecated and removed from the org.hibernate.Session interface. However, to make migration easier, these methods are still available, via the org.hibernate.classic.Session subinterface.  Existing applications may continue to use the deprecated methods if they wish.  These deprecated methods are:   
      • query execution methods: find(), iterate(), filter(), delete()
        • createQuery() should be used instead. 
      • Note that DELETE queries respect the EJB3 semantic which is slightly different from the deprecated delete(hqlSelectQuery), and thus is not a straight replacement (esp when associations are involved). Note that delete(object) still exists and can be used to delete a single persistent instance including performing cascading of the delete operation to dependent entities. This can be used in conjunction with a selection query to get the same semantics/result as the now depreacated delete(hqlSelectQuery) methods.
      • saveOrUpdateCopy()
        • merge() should be used as the replacement for saveOrUpdateCopy()
      • createSQLQuery()

        • The overloaded forms of createSQLQuery() which took arrays have been deprecated and moved to org.hibernate.classic.Session. There is a new SQLQuery interface which provides equivalent functionality (and more).
    • Lifecycle and Validatable interfaces - The Lifecycle and Validatable interfaces were deprecated in Hibernate3 and moved to the org.hibernate.classic package. The Hibernate team does not consider it good practice to have domain model classes depend upon persistence-specific APIs. Hibernate3 applications should use Interceptor or the new Hibernate3 event framework. Existing applications may continue to use Lifecycle and Validatable.
  • Dependencies - Please have a look at the required 3rd party libraries in lib/README.txt, some have been updated, some have been removed, and some have been newly added.
  • Exception model - HibernateException and all other Hibernate exceptions are now unchecked runtime exceptions.
  • Interceptor interface - Two new methods were added to the Interceptor interface. Existing interceptors will need to be ugraded to provide empty implementations of the two new methods. The signature of instantiate() was modified to take a String-valued entity name instead of a Class object. The isUnsaved() method was renamed isTransient().  To avoid issues with Interceptor migration (whether 2.x -> 3.x, or moving forward), just extend the new EmptyInterceptor class instead of writing your own empty implementation for all methods you don't need.
  • UserType and CompositeUserType interfaces - Both UserType and CompositeUserType had several methods added, to support new functionality of Hibernate3. They were moved to the package org.hibernate.usertype. Existing user type classes will need to be upgraded to implement the new methods.  Note: Hibernate3 provides the ParameterizedType interface to allow better re-useability of user type implementations.
  • FetchMode - FetchMode.LAZY and FetchMode.EAGER were deprecated. The more accurately named FetchMode.SELECT and FetchMode.JOIN have the same affect.
  • PersistentEnum - The deprecated PersistentEnum was removed in Hibernate3. Existing applications should use UserType to handle persistent enumerated types.
  • Blob and Clob support - Hibernate now wraps Blob and Clob instances, to allow classes with a property of type Blob or Clob to be detached, serialized, deserialized, and passed to merge(). However, this means that the Blob or Clob cannot be cast to a vendor specific type (eg. oracle.sql.CLOB). You must use the getWrappedClob() or getWrappedBlob() methods:
    clob = (oracle.sql.CLOB) ( (org.hibernate.lob.SerializableClob) foo.getText() ).getWrappedClob();
  • Changes to extension APIs - The org.hibernate.criterion, org.hibernate.mapping, org.hibernate.persister and org.hibernate.collection packages feature heavy refactoring. Most Hibernate 2.1 applications do not depend upon these packages, and will not be affected. If your application does extend classes in these packages, you will need to carefully migrate the affected code.

 

Metadata Changes

  • Association fetching strategies - Since it is best practice to map almost all classes and collections using lazy="true", that is now the default. Existing applications will need to explicitly specify lazy="false" on all non-lazy class and collection mappings. The outer-join attribute is deprecated.   Use fetch="join" and fetch="select" instead of outer-join="true" and outer-join="false". Existing applications may continue to use the outer-join attribute, or may use a text search/replace to migrate to use of the fetch attribute.  Beware, this means you have to put lazy="false" on all collection-mappings and classes which previously did not have a "lazy"-attribute.  A quick and dirty alternative for migration is also to put default-lazy="false" on all your hibernate-mapping elements.
  • Identifier mappings - The unsaved-value attribute is now optional, in most cases. Hibernate will use unsaved-value="0" as the default, where that is sensible.  Note: In Hibernate3, it is no longer necessary to implement Interceptor.isUnsaved() when using natural keys (assigned identifiers or composite identifiers) and detached objects. In the absence of any "hints", Hibernate will query the database to determine if an object is new or detached. However, the use of Interceptor.isUnsaved() might result in higher performance, since the database query can be avoided.
  • Collection mappings - The <index> element is semi-deprecated, <list-index> and <map-key> are now preferred. <map-key-many-to-many> is preferred to <key-many-to-many>. <composite-map-key> is preferred to <composite-index>.
  • DTD - Update the DTD reference in your hbm XML files. Change http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd to http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd in the DOCTYPE. If your application took 5 seconds to startup and now takes 50 with Hibernate3, you forgot to change the DTD. Hibernate will then try to lookup (and timeout) the DTD on the Internet for every mapping file instead of its JAR file.

 

Query Language Changes

  • New Parser - Hibernate3 comes with a brand-new, ANTLR-based HQL/SQL query translator. However, the Hibernate 2.1 query parser is still available. The query parser may be selected by setting the Hibernate property hibernate.query.factory_class. The possible values are org.hibernate.hql.ast.ASTQueryTranslatorFactory, for the new query parser, and org.hibernate.hql.classic.ClassicQueryTranslatorFactory, for the old parser. We are working hard to make the new query parser support all queries allowed by Hibernate 2.1. However, we expect that many existing applications will need to use the Hibernate 2.1 parser during the migration phase.  The Hibernate 1.x syntax "from f in class bar.Foo" is no longer supported, use "from bar.Foo as f" or "from bar.Foo f". Don't use dots in named HQL parameter names.  Note: there is a known bug affecting dialects with theta-style outer joins (eg. OracleDialect for Oracle 8i, TimesTen dialect, Sybase11Dialect). Try to use a dialect which supports ANSI-style joins (eg. Oracle9Dialect), or fall back to the old query parser if you experience problems.
  • indices() and elements() functions -  The indices() and elements() constructs may no longer appear in the HQL select clause (the semantics of this was very confusing to users). They may still be used in the where() clause. Use an explicit join instead of select elements(...).

 

Configuration changes

  • N/A

 

WebLogic issues

Hibernate3 uses ANTLR for the new query parser. Unfortunately BEA Weblogic includes a version of ANTLR in the system classpath which will be loaded before any application libraries and, because Weblogic doesn't seem to support proper class loader isolation, will not see the Hibernate classes in the application's context. BEA seems to solve this issue by prefixing package names, but the distributed ANTLR doesn't have this prefix. Another source for this issue is the usage of Class.forName() in ANTLR itself.

Until both parties have solved these issues we can only provide workarounds: Place all your Hibernate and dependent libraries on the application server's boot classpath or use the old query parser as described above.

The Hibernate Team has sent a fix for this issue to the ANTLR developers, and it should be included in the next release. We'll distribute this new version with a minor release of Hibernate in the next few weeks or months. For now we distribute a patched version of ANTLR with Hibernate 3.0 which uses the context classloader instead of Class.forName().

On the Weblogic side, this has since been resolved in Weblogic 9.2+. In the weblogic-application.xml descriptor, put the following:

<prefer-application-packages>
<package-name>antlr.*</package-name>
</prefer-application-packages>