Skip to content

Upgrade to Hibernate ORM 7 #41310

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 26 commits into from
Jun 10, 2025
Merged

Upgrade to Hibernate ORM 7 #41310

merged 26 commits into from
Jun 10, 2025

Conversation

yrodiere
Copy link
Member

@yrodiere yrodiere commented Jun 19, 2024

This upgrades Quarkus to Hibernate ORM 7.

Based on #41359, which must be merged first. => Done

Migration guide entry:

== Jakarta Persistence / Hibernate ORM

=== Upgrade to Hibernate ORM 7.0 / Jakarta Persistence 3.2

The Quarkus extension for Hibernate ORM was upgraded to Hibernate ORM 7.0 / Jakarta Persistence 3.2.

Hibernate ORM 7.0 is for the most part backwards-compatible with Hibernate ORM 6.6, and comes with [many improvements and new features, as well as a switch from the LGPL license to ASL 2](https://docs.jboss.org/hibernate/orm/7.0/whats-new/whats-new.html).

However, as with any major version, a few breaking changes are to be expected. Below are the ones most likely to affect existing applications.

Refer to the https://docs.jboss.org/hibernate/orm/7.0/migration-guide/migration-guide.html[Hibernate ORM 7.0 migration guide] for more information.

=== API changes

* https://docs.jboss.org/hibernate/orm/7.0/migration-guide/migration-guide.html#defer-to-jpa[Various deprecated `Session` methods have been removed in favor of JPA equivalents]. In particular: `load(...)` => `getReference(...)`, `get(...)` => `find(...)`, `delete(...)` => `remove(...)`, `save(...)` => `persist(...)`, `update(...)` => `merge(...)`, `saveOrUpdate(...)` => `persist` (new entity)/`merge` (persisted, then detached entity).
* https://docs.jboss.org/hibernate/orm/7.0/migration-guide/migration-guide.html#removal-annotations[Various deprecated annotations methods have been removed in favor of JPA equivalents]. In particular: `@Table` = `@jakarta.persistence.Table`, `@Where`/`@WhereJoinTable` => `@SQLRestriction`/`@SQLJoinTableRestriction`, `@OrderBy` => `@SQLOrder` or `@jakarta.persistence.OrderBy`, `@Index` => `@jakarta.persistence.Index`, `@IndexColumn` => `@OrderColumn`.
* Hibernate's `@Cascade` and `CascadeType` are deprecated in favor of JPA equivalents (e.g. `@OneToMany(cascade = ...)`).
* https://docs.jboss.org/hibernate/orm/7.0/migration-guide/migration-guide.html#proxy-annotation[Proxy customization changed significantly]. If you were using `@Proxy, consider `@ConcreteProxy` instead, or taking advantage of `Session#getReference`/`Hibernate#unproxy` as necessary.
* https://docs.jboss.org/hibernate/orm/7.0/migration-guide/migration-guide.html#misc-api[`org.hibernate.Metamodel` was removed] in favor of `org.hibernate.metamodel.model.domain.JpaMetamodel`.
* https://docs.jboss.org/hibernate/orm/7.0/migration-guide/migration-guide.html#usertype[`UserType` and `CompositeType` had some method signature change] to no longer refer to internal/SPI types.
* https://docs.jboss.org/hibernate/orm/7.0/migration-guide/migration-guide.html#misc-spi[Various JDBC types were moved to an internal package]. Use `@JdbcTypeCode` instead of `@JdbcType` to map your attributes to these types.
* https://docs.jboss.org/hibernate/orm/7.0/migration-guide/migration-guide.html#lock-options[`LockOptions` was deprecated]; impacted methods have alternatives involving `LockMode`.

=== Behavior changes

* https://docs.jboss.org/hibernate/orm/7.0/migration-guide/migration-guide.html#model-validation[Many misplaced mapping annotations will now result in an exception], instead of being ignored. This includes for example conflicting `@Basic`/`@ManyToOne` annotations on the same attribute, but also using attribute converters on `@Id`/`@Version`/associations/etc., which was never supported and was effectively ignored.
* https://docs.jboss.org/hibernate/orm/7.0/migration-guide/migration-guide.html#stateless-session-cache[`StatelessSession`] now takes advantage of the second-level cache.
* https://docs.jboss.org/hibernate/orm/7.0/migration-guide/migration-guide.html#stateless-session-jdbc-batching[`StatelessSession`] no longer complies with [quarkus.hibernate-orm.jdbc.statement-fetch-size](https://quarkus.io/guides/hibernate-orm#quarkus-hibernate-orm_quarkus-hibernate-orm-jdbc-statement-fetch-size). Instead, you can use explicit batch operations such as `insertMultiple()`.
* https://docs.jboss.org/hibernate/orm/7.0/migration-guide/migration-guide.html#create-query[Some ambiguous query strings are now disallowed]. This should mainly impact type-unsafe query creation, when not passing a class to `Session#createQuery`, or when using Panache to create a query. Relevant query strings are those without a `select` clause, but with a (non-fetch) join. For example `from Person p left join p.address` should become one of `from Person p`, `select p, a from p left join p.address a`, or `from p left join fetch p.address`, depending on the desired behavior.
* https://docs.jboss.org/hibernate/orm/7.0/migration-guide/migration-guide.html#datetime-native[Native queries now return `java.time` types instead of `java.sql` types for date/time values] in the absence of specific type instructions.

=== DDL/schema changes

Quoting behavior, which suffered from a regression in Hibernate ORM 6.x, was fixed in 7.0 as part of https://hibernate.atlassian.net/browse/HHH-16516[HHH-16516]. Custom database initialization script, in particular on H2, may need to be adapted to avoid use of quotes.

The following changes will require updating the database schema, and manually updating data:

* https://docs.jboss.org/hibernate/orm/7.0/migration-guide/migration-guide.html#array-mapping-changes-on-db2-sap-hana-sql-server-and-sybase-ase[Basic arrays (e.g. `String[]`) are now mapped to proper array structures in database] instead of being serialized as binary data. This behavior can be reverted by setting `quarkus.hibernate-orm.unsupported-properties."hibernate.type.preferred_array_jdbc_type"` to `VARBINARY`.

The following changes should not require a database schema or data update, as SQL generated by Hibernate should to work even with an older schema:

* https://docs.jboss.org/hibernate/orm/7.0/migration-guide/migration-guide.html#mysql-varchar[`char`/`Character` attributes are mapped to `varchar(1)`] instead of `char(1)`.
* On Oracle and Microsoft SQL Server, https://docs.jboss.org/hibernate/orm/7.0/migration-guide/migration-guide.html#ddl-implicit-datatype-timestamp[timestamp attributes have a different default sub-second precision].
* On Oracle, https://docs.jboss.org/hibernate/orm/7.0/migration-guide/migration-guide.html#float-mapping-changes-oracle[`float`/`double` attributes are mapped to `binary_float`/`binary_double`] instead of `float(p)`/`real`/`double precision` types.

=== Annotation processor artifact relocation 

Hibernate ORM 7.0 changes the Maven coordinates of its annotation processor responsible for the generation of the static metamodel and Jakarta Data repositories from `org.hibernate.orm:hibernate-jpamodelgen` to `org.hibernate.orm:hibernate-processor`. Make sure to update your `annotationProcessorPath` in Maven, or `annotationProcessor` instruction in Gradle.

Additionally, the annotation processor `org.hibernate.jpamodelgen.JPAMetaModelEntityProcessor` is now deprecated
in favor of `org.hibernate.processor.HibernateProcessor`. If your build script was explicitly referring to the processor by name, e.g. with the `annotationProcessors` tag of `maven-compiler-plugin`, make sure to replace the deprecated processor name with the new one.

=== CDI restrictions for Hibernate ORM components

Some pluggable components, that are potentially retrieved before CDI is initialized, can no longer be CDI beans. This includes in particular:

* `org.hibernate.type.descriptor.jdbc.JdbcType`
* `org.hibernate.type.descriptor.java.BasicJavaType`
* `org.hibernate.type.descriptor.java.JavaType`
* `org.hibernate.usertype.UserType`
* `org.hibernate.usertype.UserCollectionType`
* `org.hibernate.usertype.CompositeUserType`
* `org.hibernate.type.descriptor.java.MutabilityPlan`
* `org.hibernate.metamodel.spi.EmbeddableInstantiator`
* `org.hibernate.generator.Generator` and its subclasses `org.hibernate.id.IdentifierGenerator`, `org.hibernate.generator.AnnotationBasedGenerator`, etc.
* `org.hibernate.envers.RevisionListener`

If you need to provide a custom implementation of such components, and need access to CDI within that implementation, consider retrieving other beans when first needed, using `Arc.container().instance(OtherBean.class).get()`.
 
== Elasticsearch

Default connection pool sizes have been bumped https://hibernate.atlassian.net/issues/HSEARCH-5045[to provide a better experience with Hibernate Search], in particular when mass indexing:

* `quarkus.elasticsearch.max-connections` now defaults to `40` instead of `20`.
* `quarkus.elasticsearch.max-connections-per-route` now defaults to `20` instead of `10`.

=== Upgrade to Hibernate Search 8.0

The Quarkus extensions for Hibernate Search were upgraded to Hibernate Search 8.0.

Hibernate ORM 8.0 is for the most part backwards-compatible with Hibernate Search 7.2, and comes with https://hibernate.org/search/releases/8.0/#whats-new[many improvements and new features], in particular a https://hibernate.org/search/releases/8.0/#static-metamodel[static metamodel]

However, as with any major version, a few breaking changes are to be expected.
Below are the ones most likely to affect existing applications.

Refer to the the https://docs.jboss.org/hibernate/search/8.0/migration/html_single/[Hibernate Search 8.0 migration guide] for more information.

* Deprecated classes have been removed in favor of their recommended alternatives, in particular `org.hibernate.search.mapper.orm.massindexing.MassIndexingMonitor` => `org.hibernate.search.mapper.pojo.massindexing.MassIndexingMonitor`.
* `MassIndexingMonitor#addToTotalCount` is now deprecated in favor of the more flexible `MassIndexingMonitor#typeGroupMonitor(..)`
* `multi()` methods in the projection DSL are deprecated in favor of `.list()`/`.set()`/`sortedSet()`/`collector(...)`.
* Logging categories have been overhauled. See https://docs.jboss.org/hibernate/search/8.0/reference/en-US/html_single/#logging-categories-aggregated[here for a list of available categories]. In particular, the `org.hibernate.search.elasticsearch.request` logging category, used for logging every request sent to Elasticsearch, has been renamed to `org.hibernate.search.elasticsearch.client.request`.
* Many Search DSL interfaces now have an extra `SR` type argument to accomodate for the new static metamodel. This mostly affects `*Step` interfaces which should generally not be used in application code.
* The format of mass indexing logs has changed -- for the better, as more information is presented in a more condensed format.

== Dev Services

Several Dev Services default images have been updated:

* Elasticsearch from 8.18 to 9.0
* OpenSearch from 2.16 to 3.0

NOTE: You can configure Quarkus explicitly to use a specific image for each Dev Service, e.g. see https://quarkus.io/guides/elasticsearch-dev-services#configuring-the-image[here for Elasticsearch/OpenSearch].

Status / next steps:

@quarkus-bot quarkus-bot bot added area/dependencies Pull requests that update a dependency file area/hibernate-orm Hibernate ORM area/hibernate-reactive Hibernate Reactive area/persistence OBSOLETE, DO NOT USE labels Jun 21, 2024
@yrodiere yrodiere changed the title Upgrade to Hibernate ORM 7 [WIP] Upgrade to Hibernate ORM 7 Jun 25, 2024
@yrodiere yrodiere force-pushed the orm7 branch 2 times, most recently from 85327ca to 8d25fb0 Compare June 28, 2024 14:28
@quarkus-bot quarkus-bot bot added area/documentation area/panache area/spring Issues relating to the Spring integration labels Jun 28, 2024
@gsmet
Copy link
Member

gsmet commented Sep 4, 2024

Should we try to coordinate the Jakarta EE 11 updates?

@yrodiere
Copy link
Member Author

yrodiere commented Sep 5, 2024

Should we try to coordinate the Jakarta EE 11 updates?

Quarkus definitely should plan for that, yes. I don't know the full implications for Quarkus, but I think at least CDI, Narayana and Validator (so probably EL too?) will need to be upgraded before or at the same time as we upgrade to Hibernate ORM 7.0. As well as Search and Reactive, of course.
Upgrading every Jakarta component to Jakarta 11 would probably be simpler than trying to mix Jakarta 10 and 11, but that's up to you.

Fair warning though:

  1. ORM 7.0 is not ready yet -- there's no clear date set for the release at the moment.
  2. I'm only just getting back to this, trying to get things to compile ( ✔️ ) and basic tests to pass ( ❌ ), so that I can report any bugs upstream.

I'll set a reminder to ping you when I have a clearer view of what works and what doesn't in Quarkus itself.

@yrodiere yrodiere force-pushed the orm7 branch 2 times, most recently from 464af78 to 5f014d5 Compare September 16, 2024 12:18
@quarkus-bot quarkus-bot bot added area/devtools Issues/PR related to maven, gradle, platform and cli tooling/plugins area/jdbc Issues related to the JDBC extensions labels Sep 16, 2024
Copy link

github-actions bot commented Sep 16, 2024

🙈 The PR is closed and the preview is expired.

@yrodiere
Copy link
Member Author

I identified the Kotlin failures as a bug in hibernate-models: hibernate/hibernate-models#99
Looking into the other failures...

@yrodiere
Copy link
Member Author

The XML mapping issue seems caused by https://hibernate.atlassian.net/browse/HHH-18662.

@yrodiere
Copy link
Member Author

Alright, I think I did all I could at this point. I will need new Beta releases of Hibernate ORM / Search / Reactive to go further.

yrodiere and others added 16 commits June 10, 2025 09:51
And remove Hibernate Commons Annotations, which isn't needed by any
Hibernate project anymore.
to match the one used in Hibernate Search
…(proxyClass = ...)`

This is the recommended approach to migrate.
That, or using `Hibernate.unproxy()` if the impact of
`@ConcreteProxy` on SQL performance is not acceptable.

See https://hibernate.zulipchat.com/#narrow/channel/132094-hibernate-orm-dev/topic/HHH-18194/near/467597335
This means we' temporarily misaligned with the version used in ORM
7.0.0.Final, but that version is a CR3 so we don't want it in Quarkus,
and anyway to misalignment should be fine as no change was necessary in
ORM for the upgrade:
https://github.com/hibernate/hibernate-orm/pull/10282/files
Hibernate Search complies with jboss.log-version, see io.quarkus.runtime.logging.JBossVersion
@yrodiere
Copy link
Member Author

Thanks for the review. I addressed comments and rebased on main. Let's wait for CI and merge, the deadline is close :]

@yrodiere yrodiere added the triage/waiting-for-ci Ready to merge when CI successfully finishes label Jun 10, 2025
@lucamolteni
Copy link
Contributor

@lucamolteni would you mind reviewing the migration guide, to check if it makes sense?

It makes sense thanks!

Copy link

quarkus-bot bot commented Jun 10, 2025

Status for workflow Quarkus Documentation CI

This is the status report for running Quarkus Documentation CI on commit 78b5979.

✅ The latest workflow run for the pull request has completed successfully.

It should be safe to merge provided you have a look at the other checks in the summary.

Warning

There are other workflow runs running, you probably need to wait for their status before merging.

Copy link

quarkus-bot bot commented Jun 10, 2025

Status for workflow Quarkus CI

This is the status report for running Quarkus CI on commit 78b5979.

✅ The latest workflow run for the pull request has completed successfully.

It should be safe to merge provided you have a look at the other checks in the summary.

You can consult the Develocity build scans.


Flaky tests - Develocity

⚙️ JVM Tests - JDK 17

📦 extensions/smallrye-reactive-messaging/deployment

io.quarkus.smallrye.reactivemessaging.hotreload.ConnectorChangeTest.testUpdatingConnector - History

  • Expecting actual: ["-6","-7","-9","-10","-11","-12","-13","-14"] to start with: ["-6", "-7", "-8", "-9"] - java.lang.AssertionError
java.lang.AssertionError: 

Expecting actual:
  ["-6","-7","-9","-10","-11","-12","-13","-14"]
to start with:
  ["-6", "-7", "-8", "-9"]

	at io.quarkus.smallrye.reactivemessaging.hotreload.ConnectorChangeTest.testUpdatingConnector(ConnectorChangeTest.java:41)

📦 extensions/websockets-next/deployment

io.quarkus.websockets.next.test.broadcast.BroadcastOnOpenTest.testLo - History

  • Messages: [c2:client1] ==> expected: <true> but was: <false> - org.opentest4j.AssertionFailedError
org.opentest4j.AssertionFailedError: Messages: [c2:client1] ==> expected: <true> but was: <false>
	at org.junit.jupiter.api.AssertionFailureBuilder.build(AssertionFailureBuilder.java:151)
	at org.junit.jupiter.api.AssertionFailureBuilder.buildAndThrow(AssertionFailureBuilder.java:132)
	at org.junit.jupiter.api.AssertTrue.failNotTrue(AssertTrue.java:63)
	at org.junit.jupiter.api.AssertTrue.assertTrue(AssertTrue.java:36)
	at org.junit.jupiter.api.Assertions.assertTrue(Assertions.java:214)
	at io.quarkus.websockets.next.test.broadcast.BroadcastOnOpenTest.assertBroadcast(BroadcastOnOpenTest.java:105)
	at io.quarkus.websockets.next.test.broadcast.BroadcastOnOpenTest.testLo(BroadcastOnOpenTest.java:45)

⚙️ Gradle Tests - JDK 17 Windows

📦 integration-tests/gradle

io.quarkus.gradle.devmode.IncludedKotlinBuildDevModeTest.main - History

  • Condition with Lambda expression in io.quarkus.test.devmode.util.DevModeClient was not fulfilled within 1 minutes 30 seconds. - org.awaitility.core.ConditionTimeoutException
org.awaitility.core.ConditionTimeoutException: Condition with Lambda expression in io.quarkus.test.devmode.util.DevModeClient was not fulfilled within 1 minutes  30 seconds.
	at app//org.awaitility.core.ConditionAwaiter.await(ConditionAwaiter.java:167)
	at app//org.awaitility.core.CallableCondition.await(CallableCondition.java:78)
	at app//org.awaitility.core.CallableCondition.await(CallableCondition.java:26)
	at app//org.awaitility.core.ConditionFactory.until(ConditionFactory.java:1160)
	at app//org.awaitility.core.ConditionFactory.until(ConditionFactory.java:1129)
	at app//io.quarkus.test.devmode.util.DevModeClient.getHttpResponse(DevModeClient.java:164)
	at app//io.quarkus.gradle.devmode.QuarkusDevGradleTestBase.getHttpResponse(QuarkusDevGradleTestBase.java:165)

⚙️ JVM Integration Tests - JDK 17

📦 integration-tests/opentelemetry

io.quarkus.it.opentelemetry.LoggingResourceTest.testException - History

  • Condition with Lambda expression in io.quarkus.it.opentelemetry.LoggingResourceTest was not fulfilled within 2 minutes. - org.awaitility.core.ConditionTimeoutException
org.awaitility.core.ConditionTimeoutException: Condition with Lambda expression in io.quarkus.it.opentelemetry.LoggingResourceTest was not fulfilled within 2 minutes.
	at org.awaitility.core.ConditionAwaiter.await(ConditionAwaiter.java:167)
	at org.awaitility.core.CallableCondition.await(CallableCondition.java:78)
	at org.awaitility.core.CallableCondition.await(CallableCondition.java:26)
	at org.awaitility.core.ConditionFactory.until(ConditionFactory.java:1160)
	at org.awaitility.core.ConditionFactory.until(ConditionFactory.java:1129)
	at io.quarkus.it.opentelemetry.LoggingResourceTest.testException(LoggingResourceTest.java:113)
	at java.base/java.lang.reflect.Method.invoke(Method.java:569)

⚙️ JVM Integration Tests - JDK 21

📦 integration-tests/opentelemetry

io.quarkus.it.opentelemetry.LoggingResourceTest.testException - History

  • Condition with Lambda expression in io.quarkus.it.opentelemetry.LoggingResourceTest was not fulfilled within 2 minutes. - org.awaitility.core.ConditionTimeoutException
org.awaitility.core.ConditionTimeoutException: Condition with Lambda expression in io.quarkus.it.opentelemetry.LoggingResourceTest was not fulfilled within 2 minutes.
	at org.awaitility.core.ConditionAwaiter.await(ConditionAwaiter.java:167)
	at org.awaitility.core.CallableCondition.await(CallableCondition.java:78)
	at org.awaitility.core.CallableCondition.await(CallableCondition.java:26)
	at org.awaitility.core.ConditionFactory.until(ConditionFactory.java:1160)
	at org.awaitility.core.ConditionFactory.until(ConditionFactory.java:1129)
	at io.quarkus.it.opentelemetry.LoggingResourceTest.testException(LoggingResourceTest.java:113)
	at java.base/java.lang.reflect.Method.invoke(Method.java:580)

@gsmet gsmet merged commit 561f912 into quarkusio:main Jun 10, 2025
60 checks passed
@github-project-automation github-project-automation bot moved this from Reviewer approved to Done in Quarkus Documentation Jun 10, 2025
@quarkus-bot quarkus-bot bot added this to the 3.24 - main milestone Jun 10, 2025
@quarkus-bot quarkus-bot bot added kind/enhancement New feature or request and removed triage/waiting-for-ci Ready to merge when CI successfully finishes labels Jun 10, 2025
@yrodiere
Copy link
Member Author

Thank you! I added the relevant information to the migrationg guide: https://github.com/quarkusio/quarkus/wiki/Migration-Guide-3.24#jakarta-persistence-hibernate-orm

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area/dependencies Pull requests that update a dependency file area/devtools Issues/PR related to maven, gradle, platform and cli tooling/plugins area/documentation area/elasticsearch area/gradle Gradle area/hibernate-orm Hibernate ORM area/hibernate-reactive Hibernate Reactive area/hibernate-search Hibernate Search area/jdbc Issues related to the JDBC extensions area/maven area/panache area/persistence OBSOLETE, DO NOT USE area/spring Issues relating to the Spring integration kind/enhancement New feature or request release/breaking-change release/noteworthy-feature triage/flaky-test
Projects
5 participants