This guide discusses migration to Hibernate ORM version 8.0. For migration from earlier versions, see any other pertinent migration guides as well.

Requirements

See the website for the list of requirements for the 8.0 series.

Jakarta Persistence 4.0

One specific requirement change that is important to call out is the move to from Jakarta Persistence version 3.2 to 4.0 which has a number of impacts, many of which are discussed below.

See this issue for more details.

New Features

See the website for the list of new features in the 8.0 series.

Changes to API

This section describes changes to contracts (classes, interfaces, methods, etc.) which are considered API.

StatelessSession

Jakarta Persistence now defines a contract for "stateless" processing, named EntityAgent, similar to Hibernate’s StatelessSession. Hibernate’s StatelessSession now implements EntityAgent. 2 methods on EntityAgent clash with methods already defined on StatelessSession -

  • insert() - EntityAgent defines a void return type, whereas Hibernate has historically returned the identifier of the inserted entity.

  • fetch() - EntityAgent defines that the fetched value be returned, whereas StatelessSession has historically defined a void return type.

In both cases, StatelessSession has been changed to match the EntityAgent signatures.

Query and Transaction Timeouts

Historically, both Hibernate and Jakarta Persistence have defined timeouts as integer values. Confusingly, Hibernate generally used second precision while Jakarta Persistence used millisecond precision. Starting in 3.2, Jakarta Persistence added a new Timeout class which helps alleviate this potential confusion. Originally this new Timeout type was not exposed on any API directly, so there was no impact from an API perspective. However, this has changed a bit in 4.0 where Timeout is now exposed on certain APIs. This causes a signature conflict with a few of Hibernate API methods; as part of fixing those conflicts, it was decided to change all exposures of timeout in Hibernate APIs to use Timeout as this helps clarify these confusions.

Query API

One of the biggest changes in Jakarta Persistence 4.0 is the better modeling of "queries" into selections (TypedQuery) and mutations (its new Statement contract), aligning closely with Hibernate’s already existing SelectionQuery and MutationQuery contracts. At the same time, it deprecated all "operation methods" from its "raw" Query contract.

Hibernate’s Query contracts implement the Jakarta Persistence ones, so changes were needed here.

  • Hibernate’s Query interface is still typed, but it now extends from JPA’s Query rather than TypedQuery.

  • Hibernate’s SelectionQuery now implements TypedQuery[1].

  • Hibernate’s MutationQuery now implements the new Statement contract[2].

Another impact is that @NamedQuery and @NamedNativeQuery (as well as Hibernate’s variants) may no longer be used to define mutation queries -

  • @NamedQuery - A SelectionQuery defined using HQL/JPQL

  • @NamedStatement - A MutationQuery defined using HQL/JPQL

  • @NamedNativeQuery - A SelectionQuery defined using native SQL

  • @NamedNativeStatement - A MutationQuery defined using native SQL

AttributeNode Subgraphs

As part of its support for "entity graphs", Hibernate’s org.hibernate.graph.AttributeNode contract extends fropm the Jakarta Persistence jakarta.persistence.AttributeNode. Starting in version 4.0, Jakarta Persistence has "fixed" the use of raw types for the AttributeNode#getSubgraphs and AttributeNode#getKeySubgraphs methods. Hibernate has therefore needed to do the same in its org.hibernate.graph.AttributeNode.

Join and Fetch in Criteria

Jakarta Persistence has changed/fixed the type signature of methods in the Criteria API which return Join and Fetch based on the String name of attributes. This can lead to compilation issues if an application uses these methods in certain ways.

Changes to SPI

This section describes changes to contracts (classes, interfaces, methods, etc.) which are considered SPI.

Classmate removal

The dependency on Classmate was removed, which had a minor impact on certain SPIs. In particular, ClassmateContext was completely removed.

Raw types in JPA Bootstrap

Raw Map types were eliminated from the signatures of methods of the class org.hibernate.jpa.boot.spi.Bootstrap.

Query Memento

Hibernate uses a number of implementations of its NamedQueryMemento contract to model "named queries". Starting in version 3.2, Jakarta Persistence added the TypedQueryReference contract intended to serve the much the same goal. Hibernate’s NamedQueryMemento implementations were changed to extend from TypedQueryReference.

In version 4.0, Jakarta Persistence has added some additional methods to TypedQueryReference which now conflict with some of Hibernate’s existing methods requiring a rename. Notably, the addition of TypedQueryReference#getParameterTypes caused conflict’s with Hibernate’s NamedSqmQueryMemento#getParameterTypes. To address this conflict, we’ve renamed the NamedSqmQueryMemento method to #getAnticipatedParameterTypes.

Changes in Behavior

This section describes changes in behavior that applications should be aware of.

Collections belonging to read-only entities

Previously, collections belonging to an entity loaded in read-only mode were not marked as read-only and could be modified. This behavior was surprising and significantly undermined the benefits of the read-only mode. A collection is now set to read-only when its owning entity is read-only, and modifications to the collection result in an error.

Result deduplication

In Hibernate 6.x query result lists with duplicate results were handled in an ad hoc and inconsistent way by getSingleResult() and getSingleResultOrNull(). As of Hibernate 7.3, these methods always throw when the result list contains more than one element (which is faithful to the documented semantics of these methods). If automatic deduplication is required, use:

query.setResultListTransformer(ResultListTransformer.uniqueResultTransformer())

which collapses duplicate results according to value equality.

Session.get

Jakarta Persistence now defines a series of overloaded EntityHandler.get() methods as corollaries to EntityHandler.find(). These methods are defined to throw an EntityNotFoundException rather than return null. This operates quite differently from the older Hibernate Session.get() methods which

  • still returned null if no entity with that is was found

  • force initialized the entity, if there was one and it was previously uninitialized.

Applications which use(d) Session.get() should be aware of this change in behavior.

Changes in XSD

This section describes changes in XML Schema Descriptors

[[xsd-comments] === Table and Column Comments

Previous versions of the mapping.xsd defined table and column comments (for schema export) using XSD attributes. This was a decision made at the time to facilitate users migrating from hbm.xml mapping format. In the intervening period, Jakarta Persistence has also added comments to its table and column XSD types, but using dedicated element.

We now align with the Jakarta Persistence approach of using elements. This will require changes any mapping.xml documents which define table or column comments. E.g.,

<entity ...>
    <table ... comment="some comment"/>
</entity>

would need to be changed to

<entity ...>
    <table>
         <comment>some comment</comment>
    </table>
</entity>

Changes to DDL generation

This section describes changes to DDL generated by the schema export tooling. Such changes typically do not impact programs using a relational schema managed externally to Hibernate.

Changes in Dependencies

This section describes changes to dependencies used by Hibernate ORM.


1. Unfortunately that means `SelectionQuery` now inherits the `executeUpdate()` method from JPA’s `Query`, but as mentioned that method is deprecated.
2. Unfortunately that means `MutationQuery` now inherits `getResultList()`, and other such methods from JPA’s `Query`, but as mentioned these methods are all deprecated.