Run on JPA 3.2 and 4, from a single artifact. - #4307
Open
oscarfanchin wants to merge 22 commits into
Open
Conversation
oscarfanchin
force-pushed
the
gh-4197-impl
branch
from
August 4, 2026 07:10
494fe46 to
9ee83f9
Compare
4 tasks
Signed-off-by: Oscar Fanchin <oscar.fanchin@gmail.com>
Signed-off-by: Oscar Fanchin <oscar.fanchin@gmail.com>
Signed-off-by: Oscar Fanchin <oscar.fanchin@gmail.com>
See https://hibernate.atlassian.net/browse/HHH-20753 Signed-off-by: Oscar Fanchin <oscar.fanchin@gmail.com>
Signed-off-by: Oscar Fanchin <oscar.fanchin@gmail.com>
Signed-off-by: Oscar Fanchin <oscar.fanchin@gmail.com>
Split the reflective Hibernate glue into Hibernate7Adapter and Hibernate8Adapter behind a common HibernateAdapter contract. The adapter is selected by type presence rather than by the declared version, which is not reliable in shaded or repackaged distributions, and missing types degrade to the legacy path instead of failing during class initialization. The adapters cover the differences that are structural and permanent: the SQM access point and the named query mementos Hibernate 8 renamed and relocated, and the MutationOrSelectionQuery indirection that selection queries now go through. Methods are resolved against the implementation class, because Hibernate 8's SqmStatementAccess does not declare getQueryString(), and are cached per class instead of being looked up on every call. Hibernate 7 keeps the inherited null answer for asSelectionQuery(...): on that generation selection queries implement SelectionQuery directly and the caller's instanceof check already covers them. Signed-off-by: Oscar Fanchin <oscar.fanchin@gmail.com>
Signed-off-by: Oscar Fanchin <oscar.fanchin@gmail.com>
Signed-off-by: Oscar Fanchin <oscar.fanchin@gmail.com>
Signed-off-by: Oscar Fanchin <oscar.fanchin@gmail.com>
Signed-off-by: Oscar Fanchin <oscar.fanchin@gmail.com>
Signed-off-by: Oscar Fanchin <oscar.fanchin@gmail.com>
Signed-off-by: Oscar Fanchin <oscar.fanchin@gmail.com>
Signed-off-by: Oscar Fanchin <oscar.fanchin@gmail.com>
Signed-off-by: Oscar Fanchin <oscar.fanchin@gmail.com>
Signed-off-by: Oscar Fanchin <oscar.fanchin@gmail.com>
Signed-off-by: Oscar Fanchin <oscar.fanchin@gmail.com>
Jakarta Persistence 4 changes the return type of the untyped query factory methods on EntityManager from Query to StatementOrTypedQuery, which breaks binary compatibility with code compiled against 3.2. Introduce an adapter that resolves those methods at runtime and invokes them reflectively, so a single binary works against both API generations. The overloads whose signature is unchanged, such as createQuery(CriteriaSelect), are called directly and are not routed through reflection. Signed-off-by: Oscar Fanchin <oscar.fanchin@gmail.com>
Replace the direct calls to the EntityManager methods whose return type changed in Jakarta Persistence 4 with calls to JpaPortableQueries, including the query creation emitted by the AOT repository contributor. EntityManagerFactory.createEntityManager() has no counterpart in Jakarta Persistence 4; the Map overload survives with an unchanged signature and is used instead. Signed-off-by: Oscar Fanchin <oscar.fanchin@gmail.com>
Generated repositories are compiled against the user's own classpath, so their query creation would work against either Jakarta Persistence generation without help. They are routed through JpaPortableQueries only so that the generated path stays identical to the runtime one and cannot drift from it later. Nothing depends on this: dropping this commit makes the contributor emit the EntityManager calls directly again, and the test suite stays green. Signed-off-by: Oscar Fanchin <oscar.fanchin@gmail.com>
Test sources cannot name the untyped query factory methods directly and stay compilable against both API generations, so stubbing and verification go through EntityManagerTestUtils, which resolves them at runtime. The helper deliberately does not delegate to the production adapter: stubbing, exercising and verifying through the same code would make a defect in it undetectable. Mockito.verify(...) stays at the call sites because arguments are evaluated before the call, and a matcher passed as a parameter would be registered before verification starts. Signed-off-by: Oscar Fanchin <oscar.fanchin@gmail.com>
Signed-off-by: Oscar Fanchin <oscar.fanchin@gmail.com>
oscarfanchin
force-pushed
the
gh-4197-impl
branch
from
August 25, 2026 06:47
9ee83f9 to
2bc7122
Compare
Contributor
Author
|
Hi @mp911de Rebased after the 4.2.0-M1 release. The branch now builds against Hibernate 7.4.5 and EclipseLink 5.0.1, and the suites are green on the default profile and on the Hibernate 8 ones. One commit dropped in the rebase: the EclipseLink test filtering is already handled on main. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Handling interoperability between generations turned into two distinct problems.
Hibernate's changes to SPIs and classes are handled by two reflective adapters, one per Hibernate
generation. The binary incompatibility between the Jakarta Persistence 3.2 and 4.0 signatures is
handled by a bridge. On 3.2, which is the baseline, the calls go through directly; on 4.0 they rely
on reflection.
Hibernate 8.x is used through opt-in profiles and the snapshot repository is declared inside them,
so the default build resolves nothing from it.
I tried to make the way I worked visible in the commits: cross-version compilation first, then the
build and the tests obtained by recompiling, with the behaviour changes documented as they came up.
The point is where this ends up: a build made only against Jakarta Persistence 3.2 and Hibernate 7
runs under both profiles, without recompiling.
Three of these changes are deliberately standalone, so any one of them can be dropped without
affecting the others: the temporary artifact versions, the AOT generation change, and the workaround
for Hibernate 8 named queries. I tried it, and they come out easily.
Rationale in #4197.