Describes the new features and capabilities added to Hibernate ORM in 8.0.
| If migrating from earlier versions, be sure to also check out the Migration Guide for discussion of impactful changes. |
Jakarta Persistence 4.0
This release introduces support for Jakarta Persistence 4.0, including the following headline features:
-
EntityAgent, which finally standardizes Hibernate’sStatelessSession, -
programmatic SQL result set mappings for more elegant native SQL queries,
-
static query annotations for use with Jakarta Data,
-
@Fetchannotation, andFetchOptions for entity graphs, -
settable default fetch mode for collections,
-
streamlined Criteria query API,
-
@ExcludedFromVersioning, -
@EntityListenerand related improvements to lifecycle callback listeners, -
Criteria query creation from HQL,
-
Statementand related APIs, clearly distinguishing statements which modify data from queries which return data, along withStatementOrTypedQueryas a migration path for existing code, -
improved
StoredProcedureQuery, -
specialized
Optiontypes forEntityManager,EntityAgent,TypedQuery,Statement,StoredProcedureQuery, andCreationOptiontypes forEntityManagerandEntityAgent.
See our blog for discussion of the changes in version 4.0.
Package- and module-level entity listeners
@EntityListeners may now be declared on package-info.java or module-info.java, applying listeners to entities in that package or module without repeating the declaration on each entity.
Module-level listeners run before package-level listeners, followed by listeners declared on the entity hierarchy.
@ExcludeDefaultListeners does not suppress package- or module-level listeners.
Persistence unit lifecycle callbacks
The new @PostCreate and @PreClose callbacks observe creation and closing of an EntityManagerFactory, EntityManager, or EntityAgent.
Declare these methods on a class annotated @EntityListener and register the class with the persistence unit.
Each callback returns void and accepts one parameter of the corresponding factory, manager, or agent type.
Lock modes in stateless sessions
StatelessSession and EntityAgent now support all LockModeType values for entity loading and queries, including streamed results.
Optimistic modes obtain protection immediately instead of deferring a version check until commit.
Both OPTIMISTIC_FORCE_INCREMENT and PESSIMISTIC_FORCE_INCREMENT increment the version immediately.
See the Migration Guide for database requirements.
Nullability annotations
Jakarta @Nonnull and @Nullable annotations now cover more of the query, Criteria, restriction, and range APIs, along with mapping, loading, and configuration SPIs.
These annotations make nullability contracts available to IDEs and static analysis tools.
Jakarta Data 1.1
Hibernate Data Repositories now implements Jakarta Data 1.1, including support for:
-
integration with JPA4 static queries, including
@QueryOptions, -
restrictions and constraints,
-
@Selectprojections -
stateful repositories, and
-
asynchronous repositories backed by Jakarta Concurrency or Hibernate Reactive.
Default list semantics by package or module
The new @DefaultListSemantics annotation selects how Hibernate interprets eligible java.util.List
attributes declared in a package or module: BAG does not persist element positions, while LIST
uses an implicit order column.
For example, declare the following in package-info.java:
@DefaultListSemantics(LIST)
package org.example.domain;
import org.hibernate.annotations.DefaultListSemantics;
import static org.hibernate.annotations.DefaultListSemantics.Classification.LIST;
A package annotation overrides the module annotation and applies only to that exact package, not its subpackages.
Explicit collection mapping metadata continues to take precedence. Lists ordered by @OrderBy or @SQLOrder,
and unowned to-many associations, retain bag semantics unless explicit list-index metadata is present.
See the User Guide for the classification rules and
Migration Guide for replacing the deprecated
hibernate.mapping.default_list_semantics setting.
Graph-based Flushing
8.0 introduces graph-based flush coordination that plans insert, update, delete, and collection work using the mapped relational constraints of the domain model. Instead of relying primarily on operation ordering heuristics, the graph queue builds a dependency model for each flush and executes work in an order that better reflects foreign keys, uniqueness constraints, optional tables, secondary tables, and other mapping relationships.
The goal is both correctness and performance: fewer special-case ordering failures, more predictable batching, and a clearer foundation for future flush-time optimizations. The new graph approach is designed to handle complex object graphs more naturally, especially in applications with deeply related entities, mixed entity and collection changes, and database schemas where constraint ordering matters.
The new graph-based flush coordination is enabled by default, but the legacy strategy remains temporarily available by configuration using
hibernate.flush.queue.type=legacy
org.hibernate.cfg.FlushSettings defines a number of new settings for controlling the graph-based flush coordination.
UuidCapableJavaType
UuidCapableJavaType is a new capability in the JavaType SPI family which makes it easier to hook non-java.util.UUID UUID types into id/value generation. It defines 2 hooks -
-
A value-transformer to transform between the custom UUID values and
java.util.UUID. -
Whether the
UuidCapableJavaTypeshould be applied injakarta.persistence.GenerationType#AUTOcases.
AdjustableSettings
SessionFactory now exposes the new org.hibernate.settings.AdjustableSettings contract as a way to adjust a limited set of settings at runtime.
SessionFactory factory = ...;
AdjustableSettings adjuster = factory.getAdjustableSettings();
adjuster.setShowSql(true);
Improvements to ProcedureCall
In addition to the Jakarta Persistence 4.0 API enhancements to StoredProcedureQuery, a number of improvements and additions have been made to Hibernate’s
ProcedureCall, ProcedureOutputs and Output.
Output Casting
Previous versions of Hibernate required explicit casting of the Output references. E.g.
ProcedureCall call = session.createProcedureCall( "getRegionsAndInitiatives", Region.class);
ProcedureOutputs outputs = call.getOutputs();
List<Region> regions = ( (ResultSetOutput<Region>) outputs.getCurrent() )
.getResultList();
8.0 offers method-driven casting -
ProcedureCall call = session.createProcedureCall( "getRegionsAndInitiatives");
ProcedureOutputs outputs = call.getOutputs();
List<Region> regions = outputs.getCurrent()
.asResultSetOutput( Region.class )
.getResultList();
ResultSet Mapping
Building on top of fixing a long-standing bug and the improvements to output casting, 8.0 adds the ability to lazily declare ResultSet mapping rather than up front during ProcedureCall creation.
var call = session.createProcedureCall( "getRegionsAndInitiatives");
var outputs = call.getOutputs();
List<Region> regions = outputs.getCurrent()
.asResultSetOutput(Region.class)
.getResultList();
outputs.goToNext();
List<Initiative> initiatives = outputs.getCurrent()
.asResultSetOutput(Initiative.class)
.getResultList();
Discriminator-Based Multi-Tenancy and Row-Level Security
On databases with built-in support for row-level security, Hibernate now uses row-level security to enforce the visibility rules implied by discriminator-based multi-tenancy.
In this release, row-level security is already supported on PostgreSQL, Db2, SQL Server, and CockroachDB.
Tenant parameters in custom update and delete SQL
For discriminator-based multi-tenancy, Hibernate now restricts all SQL mutations by the tenant id.
@SQLUpdate and @SQLDelete may now declare an extra JDBC parameter for the session tenant identifier when the affected table has a tenant column outside its primary key.
Place this parameter after all existing parameters and include the tenant predicate explicitly, for example, and tenant_id=coalesce(?,tenant_id).
Hibernate binds null for a root tenant.
Existing statements without the extra parameter remain supported.
Session and Query Options
Jakarta Persistence 4.0 features the ability to specify type safe vendor-specific options directly from the Jakarta Persistence API.
Session Creation Options
Implementations of EntityManager.CreationOption and EntityAgent.CreationOption define options specified during creation of the stateful or stateless session. Hibernate supports the following creation options:
-
org.hibernate.SessionCreationOption.TenantId -
org.hibernate.SessionCreationOption.EffectiveChangeset -
org.hibernate.SessionCreationOption.EffectiveAt -
org.hibernate.SessionCreationOption.EnabledFilter -
org.hibernate.SessionCreationOption.FetchBatchSize -
org.hibernate.SessionCreationOption.PreferredFetchMethod -
org.hibernate.SessionCreationOption.JdbcBatchSize -
org.hibernate.StatementObserver(see StatementObserver) -
org.hibernate.Interceptor -
jakarta.persistence.SynchronizationType
Session Options
Implementations of EntityManager.Option and EntityAgent.Option define settings which are mutable throughout the lifetime of the session or stateless session, though they may also be used as creation options:
-
org.hibernate.CacheMode -
jakarta.persistence.CacheStoreMode -
jakarta.persistence.CacheRetrieveMode -
org.hibernate.FlushMode -
jakarta.persistence.FlushModeType -
org.hibernate.BatchSize -
org.hibernate.ReadOnlyMode -
org.hibernate.EnabledFetchProfile
E.g.
var entityManager = entityManagerFactory.createEntityManager(
new TenantId("acme"),
new EffectiveAt(now().minus(1,YEARS)),
ReadOnlyMode.READ_ONLY
);
Query Options
Finally, implementations of TypedQuery.Option and Statement.Option define settings affecting the execution of queries and statements:
-
org.hibernate.query.QueryOption.ResultSetCache -
org.hibernate.query.QueryOption.JdbcFetchSize -
org.hibernate.query.QueryOption.Comment -
org.hibernate.EnabledFetchProfile -
org.hibernate.ReadOnlyMode -
org.hibernate.CacheMode -
jakarta.persistence.CacheStoreMode -
jakarta.persistence.CacheRetrieveMode -
jakarta.persistence.QueryFlushMode -
jakarta.persistence.LockModeType -
jakarta.persistence.PessimisticLockScope
getReference() by Natural Id
8.0 adds the ability to get a reference (Session#getReference) based on the natural id of an entity.
var isbn = ...;
var book = session.getReference(Book.class, isbn, KeyType.NATURAL);
StatementObserver
8.0 introduces the new StatementObserver contract, allowing observation of all JDBC statements Hibernate performs.
Safe Mode Validator
8.0 introduces an opt-in "safe mode" for HQL and Criteria queries, designed to restrict potentially unsafe query operations. This feature is particularly valuable for applications that expose Hibernate’s SessionFactory to Large Language Models (LLMs) through various integrations, as well as for security-conscious organizations and multi-tenant applications.
When safe mode is enabled, Hibernate blocks the following operations:
-
The
sql()function - prevents arbitrary SQL syntax execution at runtime -
The
function()function - blocks explicit arbitrary function calls -
The
column()function - prevents arbitrary table column access -
Unknown function calls - Hibernate will reject any function call that hasn’t been explicitly registered with the
Dialect
To use custom functions in safe mode, they must be explicitly registered via org.hibernate.boot.model.FunctionContributor.
Safe mode is disabled by default and can be enabled using:
hibernate.query.safe_mode_enabled=true
When safe mode is enabled and an unsafe operation is attempted, Hibernate throws an exception indicating which function or operation is not allowed.
Flush-Time Bidirectionality Management
Hibernate can now optionally manage bidirectional associations in the managed object graph during flush preparation. When enabled with hibernate.bidirectionality_management=true, Hibernate treats the owning side as authoritative and synchronizes inverse-side references and initialized collections for managed entities as if application code had made those inverse-side changes before flushing.
Uninitialized lazy inverse collections are not initialized solely for bidirectionality management. This is also the important second-level cache boundary: initialized inverse collections participate in normal flush processing and collection cache invalidation, but uninitialized inverse collections are not dirtied or evicted by bidirectionality management alone. If an application changes only the owning side while a cacheable inverse collection remains unloaded, hibernate.cache.auto_evict_collection_cache=true is still the setting which evicts that inverse collection cache entry.
The deprecated bytecode-enhancement setting hibernate.enhancer.enableAssociationManagement=true is also recognized as an alias when the new setting is not specified, making migration to the runtime model straightforward.
|
Subselect Fetching
The following major enhancements were made to subselect fetching.
-
To-one associations are now eligible for bulk select fetching. Previously, only many-valued associations could be fetched in bulk.
-
FetchMethodwas introduced as a JPA 4FetchOptionenumerating the basic fetching methodsBY_ID,JOIN, andBY_SUBQUERY. To request bulk select fetching for anAttributeNodeof anEntityGraph, callnode.addOption(FetchMethod.BY_SUBQUERY).Note that batch fetching may be requested using the standard JPA 4 fetch option
BatchSize.
These changes finally make bulk select fetching a first-class citizen.
JSON/XML functions out of incubation
As of 8.0, the JSON and XML functions are out of incubation and hence are available by default.
The configuration settings hibernate.query.hql.json_functions_enabled and hibernate.query.hql.xml_functions_enabled
were removed.
Security annotations on Jakarta Data repositories
The annotation processor now propagates security annotations from the jakarta.annotation.security package (@DeclareRoles, @DenyAll, @PermitAll, @RolesAllowed, @RunAs) from repository interfaces to generated implementations, allowing Jakarta EE containers to enforce role-based access control on repositories.
This behavior may be disabled by passing -AsuppressJakartaDataSecurityAnnotations=true to the annotation processor.
See jakartaee/data#1293.
Module-level annotations
Annotations such as @NamedQuery, @FilterDef, @FetchProfile, and type registration annotations can now be placed on module-info.java, in addition to package-info.java and entity classes.
Modules are registered via MetadataSources#addModuleDescriptor(Module).
HBM XML transformation
HbmXmlTransformer more faithfully preserves legacy hbm.xml mappings when converting them to Hibernate’s extended orm.xml format.
Improvements cover composite identifiers, inheritance, associations, collections, custom types, constraints, and stored procedure mappings.
Client enhancement
Client enhancement rewrites direct access to entity fields from application classes so that those accesses participate in Hibernate’s lazy loading and dirty tracking.
Enable it with enableClientEnhancement in the Gradle, Maven, or Ant enhancement tooling; it is disabled by default.
The target entity classes must also be enhanced.
See the Migration Guide for configuration compatibility and container integration details.
Expanded SQL restriction support
@SQLRestriction now supports references to columns outside an entity’s primary table, including inherited columns in joined inheritance mappings.
It also supports @ManyToOne associations mapped through a @JoinTable.
These improvements allow static SQL restrictions to be used with a wider range of entity and association mappings.
Explicit extension contracts
The new org.hibernate.SPI annotation identifies supported contracts for integration providers and makes their intended use explicit:
-
USE: consume a contract. -
IMPLEMENT: implement an interface, subclass a class, or override a method. -
SUPPLY: provide an implementation, instance, or value to Hibernate.
These roles are independent; none implies another.
For non-incubating SPIs, compatibility expectations apply across maintenance releases of the same X.Y release family.
Dialect stabilization
The contracts used to implement and contribute dialects now have explicit SPI classifications, clarifying which types and methods providers may use, implement, or supply.
This includes Dialect and the supporting contracts for database-specific behavior such as locking, pagination, and mutation handling.
Providers should extend Dialect or another type explicitly classified for implementation; a built-in dialect being available for selection does not by itself make it a supported subclass base.
Individual contracts marked @Incubating retain their incubating status.
SQL AST and translator stabilization
The central SQL AST and translator SPIs are now out of incubation, including translator factories and typed requests, JdbcParameterFactory, and JdbcOperations builders.
Their supported provider roles now carry the normal SPI compatibility expectations within an X.Y release family.
Some specialized contracts remain incubating; see the Migration Guide for details.