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

Jakarta Persistence 3.2

7.0 migrates to Jakarta Persistence 3.2 which is fairly disruptive, mainly around:

  • type parameters

    • Affects much of the Criteria API - especially roots, joins, paths

    • Affects much of the Graph API -

      • org.hibernate.graph.Graph.addAttributeNode(java.lang.String) defines a return while jakarta.persistence.Graph.addAttributeNode(java.lang.String) does not.

  • new JPA features colliding with previous Hibernate extension features

    • Nulls (JPA) v. NullPrecedence (Hibernate), including JPA’s new Order#getNullPrecedence() returning Nulls colliding with Hibernate’s SqmSortSpecification#getNullPrecedence returning NullPrecedence. Hibernate’s form was renamed to SqmSortSpecification#getHibernateNullPrecedence to avoid the collision.

    • SchemaManager is now also a JPA contract exposed as EntityManagerFactory#getSchemaManager which leads to type issues for Hibernate’s SessionFactory#getSchemaManager. Hibernate’s SchemaManager now extends the new JPA SchemaManager. But that is a bytecode incompatibility.

    • JPA has added support in its Graph API for things Hibernate has supported for some time. Some of those are collisions requiring changes to the Hibernate API.

    • Transaction#getTimeout. JPA 3.2 adds #getTimeout but uses Integer whereas Hibernate has historically used int. Note that this raises the possibility of a NullPointerException during migration if, e.g., performing direct comparisons on the timeout value against an in (auto unboxing).

See this blog post for a good discussion of the changes in Jakarta Persistence 3.2.

Hibernate Models

For many years Hibernate has used the Hibernate Commons Annotations (HCANN) library for handling various low-level tasks related to understanding the structure of an application domain model, reading annotations and weaving in XML mapping documents.

However, HCANN suffers from a number of limitations that continue to be problematic. And given the use of HCANN across multiple projects, doing the needed refactoring was simply not possible.

The Hibernate Models project was developed to be a better alternative to HCANN. Hibernate Models is essentially an abstraction over reflection (Type, Class, Member, …​) and annotations. Check out its project page for complete details.

7.0 uses Hibernate Models in place of HCANN.

Currently, the hibernate-envers module still uses HCANN. That will change during continued 7.0 development.

Annotation Validations

7.0 adds many more checks about illegal use of annotations.

PersistentAttributeType

As of 7.0, Hibernate applies much better validation of an attribute specifying multiple PersistentAttributeTypes. Jakarta Persistence 3.2 has clarified this in the specification. E.g., the following examples are all now illegal -

@Basic
@ManyToOne
private Employee manager;

or

@Lob
@ManyToOne
private Employee manager;

Misplaced Annotations

7.0 does much more in-depth checking that annotations appear in the proper place. While previous versions did not necessarily throw errors, in most cases these annotations were simply ignored. E.g.

@Entity
class Book {
	// defines FIELD access-type
    @Id
    Integer id;

	// previously ignored, this is an error now
    @Column(name="category")
    String getType() { ... }

    ...
}

JavaBean Conventions

Previous versions allowed some questionable (at best) attribute naming patterns. These are no longer supported. E.g.

@Basic
String isDefault();

Some Cleanup

  • Removed SqmQualifiedJoin. All joins are qualified.

  • Removed AdditionalJaxbMappingProducer, deprecated in favor of AdditionalMappingContributor

  • Removed MetadataContributor, deprecated in favor of AdditionalMappingContributor

  • Removed @Persister.

  • Removed hibernate.mapping.precedence and friends

Default precision for timestamp on some databases

The default precision for Oracle timestamps was changed to 9 i.e. nanosecond precision. The default precision for SQL Server timestamps was changed to 7 i.e. 100 nanosecond precision.

SessionFactory Name (and JNDI)

Hibernate defines SessionFactory#getName (specified via cfg.xml or hibernate.session_factory_name) which is used to help with (de)serializing a SessionFactory. It is also, unless hibernate.session_factory_name_is_jndi is set to false, used in biding the SessionFactory into JNDI.

This SessionFactory#getName method pre-dates Jakarta Persistence (and JPA). It now implements EntityManagerFactory#getName inherited from Jakarta Persistence, which states that this name should come from the persistence-unit name. To align with Jakarta Persistence (the 3.2 TCK tests this), Hibernate now considers the persistence-unit name if no hibernate.session_factory_name is specified.

However, because hibernate.session_factory_name is also a trigger to attempt to bind the SessionFactory into JNDI, this change to consider persistence-unit name, means that each SessionFactory created through Jakarta Persistence now have a name and Hibernate attempted to bind these to JNDI.

To work around this we have introduced a new hibernate.session_factory_jndi_name setting that can be used to explicitly specify a name for JNDI binding. The new behavior is as follows (assuming hibernate.session_factory_name_is_jndi is not explicitly configured):

  • If hibernate.session_factory_jndi_name is specified, the name is used to bind into JNDI

  • If hibernate.session_factory_name is specified, the name is used to bind into JNDI

Hibernate can use the persistence-unit name for binding into JNDI as well, but hibernate.session_factory_name_is_jndi must be explicitly set to true.

Todos (dev)

  • Look for todo (jpa 3.2) comments

  • Look for todo (7.0) comments