diff --git a/.github/dependabot.yml b/.github/dependabot.yml
new file mode 100644
index 000000000..4d1c7e327
--- /dev/null
+++ b/.github/dependabot.yml
@@ -0,0 +1,18 @@
+# To get started with Dependabot version updates, you'll need to specify which
+# package ecosystems to update and where the package manifests are located.
+# Please see the documentation for all configuration options:
+# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
+
+version: 2
+updates:
+ - package-ecosystem: "github-actions"
+ directory: "/"
+ schedule:
+ interval: "monthly"
+ groups:
+ workflow-actions:
+ patterns:
+ - "*"
+ allow:
+ - dependency-name: "actions/*"
+ - dependency-name: "redhat-actions/*"
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 6c90f0b9c..f818b94e8 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -5,12 +5,20 @@ on:
branches:
- 'main'
- 'wip/**'
+ - '2.*'
+ - '3.*'
+ - '4.*'
tags:
- '2.*'
+ - '3.*'
+ - '4.*'
pull_request:
branches:
- 'main'
- 'wip/**'
+ - '2.*'
+ - '3.*'
+ - '4.*'
# For building snapshots
workflow_call:
inputs:
@@ -45,7 +53,7 @@ jobs:
# Label used to access the service container
mysql:
# Docker Hub image
- image: mysql:8.4.0
+ image: mysql:9.2.0
env:
MYSQL_ROOT_PASSWORD: hreact
MYSQL_DATABASE: hreact
@@ -61,7 +69,7 @@ jobs:
- 3306:3306
postgres:
# Docker Hub image
- image: postgres:16.3
+ image: postgres:17.4
env:
POSTGRES_DB: hreact
POSTGRES_USER: hreact
@@ -76,7 +84,7 @@ jobs:
- 5432:5432
steps:
- name: Checkout ${{ inputs.branch }}
- uses: actions/checkout@v2
+ uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
ref: ${{ inputs.branch }}
- name: Get year/month for cache key
@@ -85,7 +93,7 @@ jobs:
echo "::set-output name=yearmonth::$(/bin/date -u "+%Y-%m")"
shell: bash
- name: Cache Gradle downloads
- uses: actions/cache@v2
+ uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
id: cache-gradle
with:
path: |
@@ -95,16 +103,23 @@ jobs:
# refresh cache every month to avoid unlimited growth
key: gradle-examples-${{ matrix.db }}-${{ steps.get-date.outputs.yearmonth }}
- name: Set up JDK 11
- uses: actions/setup-java@v2.2.0
+ if: ${{ startsWith( inputs.branch, 'wip/2' ) }}
+ uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # v4.7.1
with:
distribution: 'temurin'
java-version: 11
+ - name: Set up JDK 17
+ if: ${{ !startsWith( inputs.branch, 'wip/2' ) }}
+ uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # v4.7.1
+ with:
+ distribution: 'temurin'
+ java-version: 17
- name: Print the effective ORM version used
run: ./gradlew :${{ matrix.example }}:dependencyInsight --dependency org.hibernate.orm:hibernate-core
- name: Run examples in '${{ matrix.example }}' on ${{ matrix.db }}
run: ./gradlew :${{ matrix.example }}:runAllExamplesOn${{ matrix.db }}
- name: Upload reports (if build failed)
- uses: actions/upload-artifact@v4
+ uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
if: failure()
with:
name: reports-examples-${{ matrix.db }}
@@ -118,7 +133,7 @@ jobs:
db: [ 'MariaDB', 'MySQL', 'PostgreSQL', 'MSSQLServer', 'CockroachDB', 'Db2', 'Oracle' ]
steps:
- name: Checkout ${{ inputs.branch }}
- uses: actions/checkout@v2
+ uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
ref: ${{ inputs.branch }}
- name: Get year/month for cache key
@@ -127,7 +142,7 @@ jobs:
echo "::set-output name=yearmonth::$(/bin/date -u "+%Y-%m")"
shell: bash
- name: Cache Gradle downloads
- uses: actions/cache@v2
+ uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
id: cache-gradle
with:
path: |
@@ -137,16 +152,24 @@ jobs:
# refresh cache every month to avoid unlimited growth
key: gradle-db-${{ matrix.db }}-${{ steps.get-date.outputs.yearmonth }}
- name: Set up JDK 11
- uses: actions/setup-java@v2.2.0
+ if: ${{ startsWith( inputs.branch, 'wip/2' ) }}
+ uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # v4.7.1
with:
distribution: 'temurin'
java-version: 11
+ - name: Set up JDK 17
+ if: ${{ !startsWith( inputs.branch, 'wip/2' ) }}
+ uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # v4.7.1
+
+ with:
+ distribution: 'temurin'
+ java-version: 17
- name: Print the effective ORM version used
run: ./gradlew :hibernate-reactive-core:dependencyInsight --dependency org.hibernate.orm:hibernate-core
- name: Build and Test with ${{ matrix.db }}
run: ./gradlew build -PshowStandardOutput -Pdocker -Pdb=${{ matrix.db }}
- name: Upload reports (if build failed)
- uses: actions/upload-artifact@v4
+ uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
if: failure()
with:
name: reports-db-${{ matrix.db }}
@@ -165,19 +188,17 @@ jobs:
# To see the available versions and download links on jdk.java.net:
# https://github.com/oracle-actions/setup-java/blob/main/jdk.java.net-uri.properties
java:
- - { name: "11", java_version_numeric: 11 }
- { name: "17", java_version_numeric: 17 }
# We want to enable preview features when testing newer builds of OpenJDK:
# even if we don't use these features, just enabling them can cause side effects
# and it's useful to test that.
- { name: "20", java_version_numeric: 20, jvm_args: '--enable-preview' }
- { name: "21", java_version_numeric: 21, jvm_args: '--enable-preview' }
- - { name: "23", java_version_numeric: 23, from: 'jdk.java.net', jvm_args: '--enable-preview' }
- - { name: "24-ea", java_version_numeric: 24, from: 'jdk.java.net', jvm_args: '--enable-preview' }
+ - { name: "24", java_version_numeric: 24, from: 'jdk.java.net', jvm_args: '--enable-preview' }
- { name: "25-ea", java_version_numeric: 25, from: 'jdk.java.net', jvm_args: '--enable-preview' }
steps:
- name: Checkout ${{ inputs.branch }}
- uses: actions/checkout@v2
+ uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
ref: ${{ inputs.branch }}
- name: Get year/month for cache key
@@ -198,7 +219,7 @@ jobs:
echo "buildtool-cache-key=${ROOT_CACHE_KEY}-${CURRENT_MONTH}-${CURRENT_BRANCH}-${CURRENT_DAY}" >> $GITHUB_OUTPUT
- name: Cache Maven/Gradle Dependency/Dist Caches
id: cache-maven
- uses: actions/cache@v4
+ uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
# if it's not a pull request, we restore and save the cache
if: github.event_name != 'pull_request'
with:
@@ -215,7 +236,7 @@ jobs:
${{ steps.cache-key.outputs.buildtool-monthly-branch-cache-key }}-
${{ steps.cache-key.outputs.buildtool-monthly-cache-key }}-
- name: Restore Maven/Gradle Dependency/Dist Caches
- uses: actions/cache/restore@v4
+ uses: actions/cache/restore@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
# if it's a pull request, we restore the cache, but we don't save it
if: github.event_name == 'pull_request'
with:
@@ -231,13 +252,13 @@ jobs:
- name: Set up latest JDK ${{ matrix.java.name }} from jdk.java.net
if: matrix.java.from == 'jdk.java.net'
- uses: oracle-actions/setup-java@v1
+ uses: oracle-actions/setup-java@2e744f723b003fdd759727d0ff654c8717024845 # v1.4.0
with:
website: jdk.java.net
release: ${{ matrix.java.java_version_numeric }}
- name: Set up latest JDK ${{ matrix.java.name }} from Adoptium
if: matrix.java.from == '' || matrix.java.from == 'adoptium.net'
- uses: actions/setup-java@v2.2.0
+ uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # v4.7.1
with:
distribution: 'temurin'
java-version: ${{ matrix.java.java_version_numeric }}
@@ -245,13 +266,20 @@ jobs:
- name: Export path to JDK ${{ matrix.java.name }}
id: testjdk-exportpath
run: echo "::set-output name=path::${JAVA_HOME}"
- # Always use JDK 11 to build the main code: that's what we use for releases.
- name: Set up JDK 11
- uses: actions/setup-java@v2.2.0
+ if: ${{ startsWith( inputs.branch, 'wip/2' ) }}
+ uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # v4.7.1
with:
distribution: 'temurin'
java-version: 11
check-latest: true
+ - name: Set up JDK 17
+ if: ${{ !startsWith( inputs.branch, 'wip/2' ) }}
+ uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # v4.7.1
+ with:
+ distribution: 'temurin'
+ java-version: 17
+ check-latest: true
- name: Export path to JDK 11
id: mainjdk-exportpath
run: echo "::set-output name=path::${JAVA_HOME}"
@@ -266,7 +294,7 @@ jobs:
-Porg.gradle.java.installations.paths=${{ steps.mainjdk-exportpath.outputs.path }},${{ steps.testjdk-exportpath.outputs.path }} \
${{ matrix.java.jvm_args && '-Ptest.jdk.launcher.args=' }}${{ matrix.java.jvm_args }}
- name: Upload reports (if build failed)
- uses: actions/upload-artifact@v4
+ uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
if: failure()
with:
name: reports-java${{ matrix.java.name }}
diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml
index 584de137b..0be7d261f 100644
--- a/.github/workflows/codeql.yml
+++ b/.github/workflows/codeql.yml
@@ -2,7 +2,7 @@ name: "CodeQL"
on:
push:
- branches: [ "main", "1.0", "jakarta/main" ]
+ branches: [ "main", "4.0", "3.0", "2.4" ]
pull_request:
branches: [ "main" ]
schedule:
@@ -24,24 +24,24 @@ jobs:
steps:
- name: Checkout
- uses: actions/checkout@v3
+ uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- name: Setup Java
- uses: actions/setup-java@v3
+ uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # v4.7.1
with:
distribution: temurin
- java-version: 11
+ java-version: 17
- name: Initialize CodeQL
- uses: github/codeql-action/init@v2
+ uses: github/codeql-action/init@7e3036b9cd87fc26dd06747b7aa4b96c27aaef3a # v3.28.4
with:
languages: ${{ matrix.language }}
queries: +security-and-quality
- name: Autobuild
- uses: github/codeql-action/autobuild@v2
+ uses: github/codeql-action/autobuild@7e3036b9cd87fc26dd06747b7aa4b96c27aaef3a # v3.28.4
- name: Perform CodeQL Analysis
- uses: github/codeql-action/analyze@v2
+ uses: github/codeql-action/analyze@7e3036b9cd87fc26dd06747b7aa4b96c27aaef3a # v3.28.4
with:
category: "/language:${{ matrix.language }}"
diff --git a/.github/workflows/scheduler.yml b/.github/workflows/scheduler.yml
index 01f827e22..24299c8a7 100644
--- a/.github/workflows/scheduler.yml
+++ b/.github/workflows/scheduler.yml
@@ -11,7 +11,7 @@ jobs:
build-snapshots:
strategy:
matrix:
- branch: [ 'wip/2.3', 'wip/2.4' ]
+ branch: [ 'wip/2.4', 'wip/3.0', 'wip/4.0' ]
uses: ./.github/workflows/build.yml
with:
branch: ${{ matrix.branch }}
diff --git a/.gitignore b/.gitignore
index 8016117ce..750319d47 100644
--- a/.gitignore
+++ b/.gitignore
@@ -43,6 +43,3 @@ bin
# Vim
*.swp
*.swo
-
-# Release scripts downloaded from hibernate/hibernate-release-scripts
-.release
diff --git a/.idea/icon.svg b/.idea/icon.svg
new file mode 100644
index 000000000..2b19df67f
--- /dev/null
+++ b/.idea/icon.svg
@@ -0,0 +1,11 @@
+
+
+
+
\ No newline at end of file
diff --git a/.release/.gitignore b/.release/.gitignore
new file mode 100644
index 000000000..cdd9a17d6
--- /dev/null
+++ b/.release/.gitignore
@@ -0,0 +1,3 @@
+# The folder into which we checkout our release scripts into
+*
+!.gitignore
\ No newline at end of file
diff --git a/AUTHORS.txt b/AUTHORS.txt
new file mode 100644
index 000000000..caf0817d1
--- /dev/null
+++ b/AUTHORS.txt
@@ -0,0 +1,39 @@
+# This file lists copyright owners of the project.
+# The list is not exhaustive: other copyright owners exist.
+# See CONTRIBUTING.md for instructions regarding how to be added to this list.
+
+# Corporate contributors
+
+Red Hat, Inc.
+
+# Individual contributors
+
+Andrea Boriero
+Andrew Guibert
+Barry LaFond
+Thinking Chen (cdmikechen)
+Coding Xu (codingxu97)
+Conor Farrell
+Davide D'Alto
+Derick Hermanson
+Eric Dalquist
+Eric Deandrea
+Gail Badner
+Gavin King
+George Gastaldi
+Georgios Andrianakis
+Jay Erb
+Julien Ponge
+Marko Bekhta
+Max Rydahl Andersen
+(meepown)
+Nesrin Aşan
+Ravi Khadiwala
+Renar Narubin
+Sanne Grinovero
+Scott Marlow
+Stephane Epardaud
+Steve Ebersole
+Stuart Douglas
+Thomas Segismont
+Yoann Rodière
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
new file mode 100644
index 000000000..bb825420f
--- /dev/null
+++ b/CONTRIBUTING.md
@@ -0,0 +1,113 @@
+# Contributing
+
+Contributions from the community are essential in keeping Hibernate (and any Open Source
+project really) strong and successful.
+
+# Legal
+
+All original contributions to Hibernate are licensed under the
+[Apache 2.0 license](https://www.apache.org/licenses/LICENSE-2.0).
+
+The Apache 2.0 license text is included verbatim in the [LICENSE](LICENSE) file in the root directory
+of the Hibernate Reactive repository.
+
+All contributions are subject to the [Developer Certificate of Origin (DCO)](https://developercertificate.org/).
+
+The DCO text is available verbatim in the [dco.txt](dco.txt) file in the root directory
+of the Hibernate Reactive repository.
+
+Copyright owners are listed in [AUTHORS.txt](AUTHORS.txt).
+Contributors with a valid copyright claim can request to be added to that list
+by sending a pull request to the project's GitHub repository,
+listing at least one relevant contribution in the pull request description.
+Note: one-liner or repetitive patches may not be sufficient to claim copyright.
+
+## Guidelines
+
+While we try to keep requirements for contributing to a minimum, there are a few guidelines
+we ask that you mind.
+
+For code contributions, these guidelines include:
+* Respect the project code style - find templates for [IntelliJ IDEA](https://hibernate.org/community/contribute/intellij-idea/) or [Eclipse](https://hibernate.org/community/contribute/eclipse-ide/)
+* Have a corresponding GitHub [issue](https://github.com/hibernate/hibernate-reactive/issues) and be sure to include
+ the key for this issue in your commit messages.
+* Have a set of appropriate tests.
+ For your convenience, a [set of test templates](https://github.com/hibernate/hibernate-test-case-templates/tree/main/reactive)
+ have been made available.
+
+ When submitting bug reports, the tests should reproduce the initially reported bug and illustrate that your solution addresses the issue.
+ For features/enhancements, the tests should demonstrate that the feature works as intended.
+ In both cases, be sure to incorporate your tests into the project to protect against possible regressions.
+* If applicable, documentation should be updated to reflect the introduced changes
+* The code compiles and the tests pass (`./gradlew clean build`)
+
+For documentation contributions, mainly to respect the project code style, especially in regard
+to the use of tabs - as mentioned above, code style templates are available for both IntelliJ IDEA and Eclipse
+IDEs. Ideally, these contributions would also have a corresponding issue, although this
+is less necessary for documentation contributions.
+
+## Getting Started
+
+If you are just getting started with Git, GitHub, and/or contributing to Hibernate via
+GitHub there are a few pre-requisite steps to follow:
+
+* Make sure you have a [GitHub account](https://github.com/signup/free)
+* [Fork](https://help.github.com/articles/fork-a-repo) the Hibernate Reactive repository. As discussed in
+the linked page, this also includes:
+ * [set up your local git install](https://help.github.com/articles/set-up-git)
+ * clone your fork
+* Instruct git to ignore certain commits when using `git blame`. From the directory of your local clone, run this: `git config blame.ignoreRevsFile .git-blame-ignore-revs`
+* See the wiki pages for setting up your IDE, whether you use
+[IntelliJ IDEA](https://hibernate.org/community/contribute/intellij-idea/)
+or [Eclipse](https://hibernate.org/community/contribute/eclipse-ide/)(1).
+
+
+## Create the working (topic) branch
+
+Create a [topic branch](https://git-scm.com/book/en/Git-Branching-Branching-Workflows#Topic-Branches)
+on which you will work. The convention is to incorporate the JIRA issue key in the name of this branch,
+although this is more of a mnemonic strategy than a hard-and-fast rule - but doing so helps:
+* Remember what each branch is for
+* Isolate the work from other contributions you may be working on
+
+_If there is not already a GitHub issue covering the work you want to do, [create one](https://github.com/hibernate/hibernate-reactive/issues/new)._
+
+Assuming you will be working from the `main` branch and working
+on the GitHub issue #123 : `git checkout -b 123 main`
+
+## Code
+
+Do your thing!
+
+
+## Commit
+
+* Make commits of logical units
+* Be sure to start each commit message using the ** GitHub issue key **. For example:
+ ```
+ [#1234] Fix some kind of problem
+ ```
+* Make sure you have added the necessary tests for your changes
+* Run _all_ the tests to ensure nothing else was accidentally broken
+
+_Before committing, if you want to pull in the latest upstream changes (highly
+appreciated btw), please use rebasing rather than merging. Merging creates
+"merge commits" that invariably muck up the project timeline._
+
+## Submit
+
+* Push your changes to the topic branch in your fork of the repository
+* Initiate a [pull request](https://help.github.com/articles/creating-a-pull-request)
+* Adding the sentence `Fix #123`, where `#123` is the issue key, will link the pull request to the corresponding issue
+ and close it accordingly, when the pull request gets merged.
+
+It is important that this topic branch of your fork:
+
+* Is isolated to just the work on this one issue, or multiple issues if they are
+ related and also fixed/implemented by this work. The main point is to not push commits for more than
+ one PR to a single branch - GitHub PRs are linked to a branch rather than specific commits
+* remain until the PR is closed. Once the underlying branch is deleted the corresponding PR will be closed,
+ if not already, and the changes will be lost.
+
+# Notes
+(1) Gradle `eclipse` plugin is no longer supported, so the recommended way to import the project in your IDE is with the proper IDE tools/plugins. Don't try to run `./gradlew clean eclipse --refresh-dependencies` from the command line as you'll get an error because `eclipse` no longer exists
diff --git a/README.md b/README.md
index a44faa31b..743540d6c 100644
--- a/README.md
+++ b/README.md
@@ -1,10 +1,11 @@
[](https://hibernate.org/reactive)
-[](https://github.com/hibernate/hibernate-reactive/actions?query=workflow%3A%22Hibernate+Reactive+CI%22)
-[](https://opensource.org/licenses/Apache-2.0)
-[](https://search.maven.org/search?q=g:org.hibernate.reactive)
-[](https://hibernate.zulipchat.com/#narrow/stream/205413-hibernate-reactive-dev)
-[](https://hibernate.org/reactive/documentation/)
+[](https://github.com/hibernate/hibernate-reactive/actions?query=workflow%3A%22Hibernate+Reactive+CI%22)
+[](https://opensource.org/licenses/Apache-2.0)
+[](https://search.maven.org/search?q=g:org.hibernate.reactive)
+[](https://hibernate.zulipchat.com/#narrow/stream/205413-hibernate-reactive-dev)
+[](https://hibernate.org/reactive/documentation/)
+[](https://github.com/jvm-repo-rebuild/reproducible-central/blob/master/content/org/hibernate/reactive/hibernate-reactive/README.md)
# Hibernate Reactive
@@ -29,20 +30,20 @@ Learn more at .
Hibernate Reactive has been tested with:
-- Java 11, 17, 21, 23
+- Java 17, 21, 24
- PostgreSQL 16
-- MySQL 8
+- MySQL 9
- MariaDB 11
-- Db2 11
+- Db2 12
- CockroachDB v24
- MS SQL Server 2022
- Oracle 23
-- [Hibernate ORM][] 6.6.3.Final
-- [Vert.x Reactive PostgreSQL Client](https://vertx.io/docs/vertx-pg-client/java/) 4.5.11
-- [Vert.x Reactive MySQL Client](https://vertx.io/docs/vertx-mysql-client/java/) 4.5.11
-- [Vert.x Reactive Db2 Client](https://vertx.io/docs/vertx-db2-client/java/) 4.5.11
-- [Vert.x Reactive MS SQL Server Client](https://vertx.io/docs/vertx-mssql-client/java/) 4.5.11
-- [Vert.x Reactive Oracle Client](https://vertx.io/docs/vertx-oracle-client/java/) 4.5.11
+- [Hibernate ORM][] 7.0.0.Final
+- [Vert.x Reactive PostgreSQL Client](https://vertx.io/docs/vertx-pg-client/java/) 5.0.0
+- [Vert.x Reactive MySQL Client](https://vertx.io/docs/vertx-mysql-client/java/) 5.0.0
+- [Vert.x Reactive Db2 Client](https://vertx.io/docs/vertx-db2-client/java/) 5.0.0
+- [Vert.x Reactive MS SQL Server Client](https://vertx.io/docs/vertx-mssql-client/java/) 5.0.0
+- [Vert.x Reactive Oracle Client](https://vertx.io/docs/vertx-oracle-client/java/) 5.0.0
- [Quarkus][Quarkus] via the Hibernate Reactive extension
[PostgreSQL]: https://www.postgresql.org
diff --git a/build.gradle b/build.gradle
index 5aee62970..f927371ef 100644
--- a/build.gradle
+++ b/build.gradle
@@ -12,15 +12,6 @@ group = "org.hibernate.reactive"
// leverage the ProjectVersion which comes from the `local.versions` plugin
version = project.projectVersion.fullName
-ext {
- if ( !project.hasProperty( 'hibernatePublishUsername' ) ) {
- hibernatePublishUsername = null
- }
- if ( !project.hasProperty( 'hibernatePublishPassword' ) ) {
- hibernatePublishPassword = null
- }
-}
-
// Versions which need to be aligned across modules; this also
// allows overriding the build using a parameter, which can be
// useful to monitor compatibility for upcoming versions on CI:
@@ -31,26 +22,14 @@ ext {
// Example:
// ./gradlew build -PvertxSqlClientVersion=4.0.0-SNAPSHOT
if ( !project.hasProperty( 'vertxSqlClientVersion' ) ) {
- vertxSqlClientVersion = '4.5.11'
+ vertxSqlClientVersion = '5.0.0'
}
- testcontainersVersion = '1.20.4'
+ testcontainersVersion = '1.21.0'
logger.lifecycle "Vert.x SQL Client Version: " + project.vertxSqlClientVersion
}
-// To release, see task ciRelease in release/build.gradle
-// To publish on Sonatype (Maven Central):
-// ./gradlew publishToSonatype closeAndReleaseStagingRepository -PhibernatePublishUsername="" -PhibernatePublishPassword=""
-nexusPublishing {
- repositories {
- sonatype {
- username = project.hibernatePublishUsername
- password = project.hibernatePublishPassword
- }
- }
-}
-
subprojects {
apply plugin: 'java-library'
apply plugin: 'com.diffplug.spotless'
@@ -87,7 +66,7 @@ subprojects {
ext.publishScript = rootProject.rootDir.absolutePath + '/publish.gradle'
- tasks.withType( JavaCompile ) {
+ tasks.withType( JavaCompile ).configureEach {
options.encoding = 'UTF-8'
}
diff --git a/ci/compare-build-results.sh b/ci/compare-build-results.sh
new file mode 100644
index 000000000..6b45022ce
--- /dev/null
+++ b/ci/compare-build-results.sh
@@ -0,0 +1,53 @@
+#!/usr/bin/env bash
+
+# This is a simple script to check if builds are reproducible. The steps are:
+# 1. Build Hibernate Reactive with `./gradlew --no-daemon clean publishToMavenLocal --no-build-cache -Dmaven.repo.local=some-path/out/build1`
+# 2. Build Hibernate Reactive with `./gradlew --no-daemon clean publishToMavenLocal --no-build-cache -Dmaven.repo.local=some-path/out/build2` second time pointing to a different local maven repository to publish
+# 3. Compare the build results with sh ./ci/compare-build-results.sh some-path/out/build1 some-path/out/build2
+# 4. The generated .buildcompare file will also contain the diffscope commands to see/compare the problematic build artifacts
+
+outputDir1=$1
+outputDir2=$2
+outputDir1=${outputDir1%/}
+outputDir2=${outputDir2%/}
+
+ok=()
+okFiles=()
+ko=()
+koFiles=()
+
+for f in `find ${outputDir1} -type f | grep -v "javadoc.jar$" | grep -v "maven-metadata-local.xml$" | sort`
+do
+ flocal=${f#$outputDir1}
+ # echo "comparing ${flocal}"
+ sha1=`shasum -a 512 $f | cut -f 1 -d ' '`
+ sha2=`shasum -a 512 $outputDir2$flocal | cut -f 1 -d ' '`
+ # echo "$sha1"
+ # echo "$sha2"
+ if [ "$sha1" = "$sha2" ]; then
+ ok+=($flocal)
+ okFiles+=(${flocal##*/})
+ else
+ ko+=($flocal)
+ koFiles+=(${flocal##*/})
+ fi
+done
+
+# generate .buildcompare
+buildcompare=".buildcompare"
+echo "ok=${#ok[@]}" >> ${buildcompare}
+echo "ko=${#ko[@]}" >> ${buildcompare}
+echo "okFiles=\"${okFiles[@]}\"" >> ${buildcompare}
+echo "koFiles=\"${koFiles[@]}\"" >> ${buildcompare}
+echo "" >> ${buildcompare}
+echo "# see what caused the mismatch in the checksum by executing the following diffscope commands" >> ${buildcompare}
+for f in ${ko[@]}
+do
+ echo "# diffoscope $outputDir1$f $outputDir2$f" >> ${buildcompare}
+done
+
+if [ ${#ko[@]} -eq 0 ]; then
+ exit 0
+else
+ exit 1
+fi
diff --git a/ci/nightly/Jenkinsfile b/ci/nightly/Jenkinsfile
new file mode 100644
index 000000000..945f02606
--- /dev/null
+++ b/ci/nightly/Jenkinsfile
@@ -0,0 +1,49 @@
+/*
+ * SPDX-License-Identifier: Apache-2.0
+ * Copyright Red Hat Inc. and Hibernate Authors
+ */
+
+@Library('hibernate-jenkins-pipeline-helpers') _
+
+pipeline {
+ agent none
+ triggers {
+ cron '@midnight'
+ }
+ tools {
+ jdk 'OpenJDK 17 Latest'
+ }
+ options {
+ buildDiscarder logRotator(daysToKeepStr: '10', numToKeepStr: '3')
+ disableConcurrentBuilds(abortPrevious: true)
+ overrideIndexTriggers(false)
+ }
+ stages {
+ stage('Build reproducibility check') {
+ agent {
+ label 'Worker&&Containers'
+ }
+ steps {
+ timeout(time: 30, unit: 'MINUTES') {
+ script {
+ def tempDir = pwd(tmp: true)
+ def repo1 = tempDir + '/repo1'
+ def repo2 = tempDir + '/repo2'
+ // build Hibernate Reactive two times without any cache and "publish" the resulting artifacts
+ // to different maven repositories, so that we can compare them afterwards:
+ sh "./gradlew --no-daemon clean publishToMavenLocal --no-build-cache -Dmaven.repo.local=${repo1}"
+ sh "./gradlew --no-daemon clean publishToMavenLocal --no-build-cache -Dmaven.repo.local=${repo2}"
+
+ sh "sh ci/compare-build-results.sh ${repo1} ${repo2}"
+ sh "cat .buildcompare"
+ }
+ }
+ }
+ }
+ }
+ post {
+ always {
+ notifyBuildResult maintainers: 'davide@hibernate.org'
+ }
+ }
+}
diff --git a/ci/release/Jenkinsfile b/ci/release/Jenkinsfile
index bb4315fb8..8627950a1 100644
--- a/ci/release/Jenkinsfile
+++ b/ci/release/Jenkinsfile
@@ -58,10 +58,10 @@ def checkoutReleaseScripts() {
pipeline {
agent {
- label 'Worker&&Containers'
+ label 'Release'
}
tools {
- jdk 'OpenJDK 11 Latest'
+ jdk 'OpenJDK 17 Latest'
}
options {
buildDiscarder logRotator(daysToKeepStr: '30', numToKeepStr: '10')
@@ -73,7 +73,7 @@ pipeline {
string(
name: 'RELEASE_VERSION',
defaultValue: '',
- description: 'The version to be released, e.g. 2.4.0.Final. Mandatory for manual releases, to prevent mistakes.',
+ description: 'The version to be released, e.g. 3.0.0.Beta1. Mandatory for manual releases, to prevent mistakes.',
trim: true
)
string(
@@ -119,8 +119,10 @@ pipeline {
echo "Release was triggered automatically"
// Avoid doing an automatic release for commits from a release
- def lastCommitter = sh(script: 'git show -s --format=\'%an\'', returnStdout: true)
- def secondLastCommitter = sh(script: 'git show -s --format=\'%an\' HEAD~1', returnStdout: true)
+ def lastCommitter = sh(script: 'git show -s --format=\'%an\'', returnStdout: true).trim()
+ def secondLastCommitter = sh(script: 'git show -s --format=\'%an\' HEAD~1', returnStdout: true).trim()
+ echo "Last two commits were performed by '${lastCommitter}'/'${secondLastCommitter}'."
+
if (lastCommitter == 'Hibernate-CI' && secondLastCommitter == 'Hibernate-CI') {
print "INFO: Automatic release skipped because last commits were for the previous release"
currentBuild.result = 'ABORTED'
@@ -149,6 +151,7 @@ pipeline {
env.DEVELOPMENT_VERSION = developmentVersion.toString()
// Dry run is not supported at the moment
env.SCRIPT_OPTIONS = params.RELEASE_DRY_RUN ? "-d" : ""
+ env.JRELEASER_DRY_RUN = params.RELEASE_DRY_RUN
// Determine version id to check if Jira version exists
// This step doesn't work for Hibernate Reactive (the project has been created with a different type on JIRA)
@@ -165,24 +168,17 @@ pipeline {
configFile(fileId: 'release.config.ssh', targetLocation: "${env.HOME}/.ssh/config"),
configFile(fileId: 'release.config.ssh.knownhosts', targetLocation: "${env.HOME}/.ssh/known_hosts")
]) {
- withCredentials([
- usernamePassword(credentialsId: 'ossrh.sonatype.org', passwordVariable: 'OSSRH_PASSWORD', usernameVariable: 'OSSRH_USER'),
- usernamePassword(credentialsId: 'gradle-plugin-portal-api-key', passwordVariable: 'PLUGIN_PORTAL_PASSWORD', usernameVariable: 'PLUGIN_PORTAL_USERNAME'),
- file(credentialsId: 'release.gpg.private-key', variable: 'RELEASE_GPG_PRIVATE_KEY_PATH'),
- string(credentialsId: 'release.gpg.passphrase', variable: 'RELEASE_GPG_PASSPHRASE')
- ]) {
- sshagent(['ed25519.Hibernate-CI.github.com', 'hibernate.filemgmt.jboss.org', 'hibernate-ci.frs.sourceforge.net']) {
- // set release version
- // update changelog from JIRA
- // tags the version
- // changes the version to the provided development version
- withEnv([
- "BRANCH=${env.GIT_BRANCH}",
- // Increase the amount of memory for this part since asciidoctor doc rendering consumes a lot of metaspace
- "GRADLE_OPTS=-Dorg.gradle.jvmargs='-Dlog4j2.disableJmx -Xmx4g -XX:MaxMetaspaceSize=768m -XX:+HeapDumpOnOutOfMemoryError -Duser.language=en -Duser.country=US -Duser.timezone=UTC -Dfile.encoding=UTF-8'"
- ]) {
- sh ".release/scripts/prepare-release.sh ${env.PROJECT} ${env.RELEASE_VERSION} ${env.DEVELOPMENT_VERSION}"
- }
+
+ sshagent(['ed25519.Hibernate-CI.github.com', 'hibernate.filemgmt.jboss.org', 'hibernate-ci.frs.sourceforge.net']) {
+ // set release version
+ // update changelog from JIRA
+ // tags the version
+ // changes the version to the provided development version
+ withEnv([
+ // Increase the amount of memory for this part since asciidoctor doc rendering consumes a lot of metaspace
+ "GRADLE_OPTS=-Dorg.gradle.jvmargs='-Dlog4j2.disableJmx -Xmx4g -XX:MaxMetaspaceSize=768m -XX:+HeapDumpOnOutOfMemoryError -Duser.language=en -Duser.country=US -Duser.timezone=UTC -Dfile.encoding=UTF-8'"
+ ]) {
+ sh ".release/scripts/prepare-release.sh -j -b ${env.GIT_BRANCH} -v ${env.DEVELOPMENT_VERSION} ${env.PROJECT} ${env.RELEASE_VERSION}"
}
}
}
@@ -199,16 +195,22 @@ pipeline {
configFile(fileId: 'release.config.ssh.knownhosts', targetLocation: "${env.HOME}/.ssh/known_hosts")
]) {
withCredentials([
- usernamePassword(credentialsId: 'ossrh.sonatype.org', passwordVariable: 'OSSRH_PASSWORD', usernameVariable: 'OSSRH_USER'),
- usernamePassword(credentialsId: 'gradle-plugin-portal-api-key', passwordVariable: 'PLUGIN_PORTAL_PASSWORD', usernameVariable: 'PLUGIN_PORTAL_USERNAME'),
+ // TODO: Once we switch to maven-central publishing (from nexus2) we need to add a new credentials
+ // to use the following env variable names to set the user/password:
+ // - JRELEASER_MAVENCENTRAL_USERNAME
+ // - JRELEASER_MAVENCENTRAL_TOKEN
+ // Also use the new `credentialsId` for Maven Central, e.g.:
+ // usernamePassword(credentialsId: '???????', passwordVariable: 'JRELEASER_MAVENCENTRAL_TOKEN', usernameVariable: 'JRELEASER_MAVENCENTRAL_USERNAME'),
+ usernamePassword(credentialsId: 'ossrh.sonatype.org', passwordVariable: 'JRELEASER_NEXUS2_PASSWORD', usernameVariable: 'JRELEASER_NEXUS2_USERNAME'),
+ gitUsernamePassword(credentialsId: 'username-and-token.Hibernate-CI.github.com', gitToolName: 'Default'),
file(credentialsId: 'release.gpg.private-key', variable: 'RELEASE_GPG_PRIVATE_KEY_PATH'),
- string(credentialsId: 'release.gpg.passphrase', variable: 'RELEASE_GPG_PASSPHRASE'),
- gitUsernamePassword(credentialsId: 'username-and-token.Hibernate-CI.github.com', gitToolName: 'Default')
+ string(credentialsId: 'release.gpg.passphrase', variable: 'JRELEASER_GPG_PASSPHRASE'),
+ string(credentialsId: 'Hibernate-CI.github.com', variable: 'JRELEASER_GITHUB_TOKEN')
]) {
sshagent(['ed25519.Hibernate-CI.github.com', 'hibernate.filemgmt.jboss.org', 'hibernate-ci.frs.sourceforge.net']) {
// performs documentation upload and Sonatype release
// push to github
- sh ".release/scripts/publish.sh ${env.SCRIPT_OPTIONS} ${env.PROJECT} ${env.RELEASE_VERSION} ${env.DEVELOPMENT_VERSION} ${env.GIT_BRANCH}"
+ sh ".release/scripts/publish.sh -j ${env.SCRIPT_OPTIONS} ${env.PROJECT} ${env.RELEASE_VERSION} ${env.DEVELOPMENT_VERSION} ${env.GIT_BRANCH}"
}
}
}
@@ -223,4 +225,4 @@ pipeline {
}
}
}
-}
\ No newline at end of file
+}
diff --git a/ci/snapshot-publish.Jenkinsfile b/ci/snapshot-publish.Jenkinsfile
index c95f6663f..fea160b23 100644
--- a/ci/snapshot-publish.Jenkinsfile
+++ b/ci/snapshot-publish.Jenkinsfile
@@ -10,12 +10,20 @@ if (currentBuild.getBuildCauses().toString().contains('BranchIndexingCause')) {
return
}
+def checkoutReleaseScripts() {
+ dir('.release/scripts') {
+ checkout scmGit(branches: [[name: '*/main']], extensions: [],
+ userRemoteConfigs: [[credentialsId: 'ed25519.Hibernate-CI.github.com',
+ url: 'https://github.com/hibernate/hibernate-release-scripts.git']])
+ }
+}
+
pipeline {
agent {
- label 'Fedora'
+ label 'Release'
}
tools {
- jdk 'OpenJDK 11 Latest'
+ jdk 'OpenJDK 17 Latest'
}
options {
rateLimitBuilds(throttle: [count: 1, durationName: 'hour', userBoost: true])
@@ -30,16 +38,23 @@ pipeline {
}
stage('Publish') {
steps {
- withCredentials([
- usernamePassword(credentialsId: 'ossrh.sonatype.org', usernameVariable: 'hibernatePublishUsername', passwordVariable: 'hibernatePublishPassword'),
- string(credentialsId: 'release.gpg.passphrase', variable: 'SIGNING_PASS'),
- file(credentialsId: 'release.gpg.private-key', variable: 'SIGNING_KEYRING')
- ]) {
- sh '''./gradlew clean publish \
- -PhibernatePublishUsername=$hibernatePublishUsername \
- -PhibernatePublishPassword=$hibernatePublishPassword \
- --no-scan \
- '''
+ script {
+ withCredentials([
+ // https://github.com/gradle-nexus/publish-plugin#publishing-to-maven-central-via-sonatype-ossrh
+ // TODO: Once we switch to maven-central publishing (from nexus2) we need to update credentialsId:
+ // https://docs.gradle.org/current/samples/sample_publishing_credentials.html#:~:text=via%20environment%20variables
+ usernamePassword(credentialsId: 'ossrh.sonatype.org', passwordVariable: 'ORG_GRADLE_PROJECT_snapshotsPassword', usernameVariable: 'ORG_GRADLE_PROJECT_snapshotsUsername'),
+ gitUsernamePassword(credentialsId: 'username-and-token.Hibernate-CI.github.com', gitToolName: 'Default'),
+ string(credentialsId: 'Hibernate-CI.github.com', variable: 'JRELEASER_GITHUB_TOKEN')
+ ]) {
+ checkoutReleaseScripts()
+ def version = sh(
+ script: ".release/scripts/determine-current-version.sh reactive",
+ returnStdout: true
+ ).trim()
+ echo "Current version: '${version}'"
+ sh "bash -xe .release/scripts/snapshot-deploy.sh reactive ${version}"
+ }
}
}
}
@@ -51,4 +66,4 @@ pipeline {
}
}
}
-}
\ No newline at end of file
+}
diff --git a/documentation/src/main/asciidoc/reference/introduction.adoc b/documentation/src/main/asciidoc/reference/introduction.adoc
index 40b4847bc..ee5090c21 100644
--- a/documentation/src/main/asciidoc/reference/introduction.adoc
+++ b/documentation/src/main/asciidoc/reference/introduction.adoc
@@ -89,7 +89,7 @@ Optionally, you might also add any of the following additional features:
| Hibernate Validator | `org.hibernate.validator:hibernate-validator` and `org.glassfish:jakarta.el`
| Compile-time checking for your HQL queries | `org.hibernate:query-validator`
| Second-level cache support via JCache and EHCache | `org.hibernate.orm:hibernate-jcache` along with `org.ehcache:ehcache`
-| SCRAM authentication support for PostgreSQL | `com.ongres.scram:client:2.1`
+| SCRAM authentication support for PostgreSQL | `com.ongres.scram:scram-client:3.1`
|===
You might also add the Hibernate {enhancer}[bytecode enhancer] to your
@@ -578,8 +578,8 @@ custom reactive identifier generator.
=== JSON Mapping
-:orm-json-basic-mapping: https://docs.jboss.org/hibernate/orm/6.6/userguide/html_single/Hibernate_User_Guide.html#basic-mapping-json
-:orm-json-embeddable-mapping: https://docs.jboss.org/hibernate/orm/6.6/userguide/html_single/Hibernate_User_Guide.html#_jsonxml_aggregate_embeddable_mapping
+:orm-json-basic-mapping: https://docs.jboss.org/hibernate/orm/7.0/userguide/html_single/Hibernate_User_Guide.html#basic-mapping-json
+:orm-json-embeddable-mapping: https://docs.jboss.org/hibernate/orm/7.0/userguide/html_single/Hibernate_User_Guide.html#_jsonxml_aggregate_embeddable_mapping
:string-to-json-converter: https://github.com/hibernate/hibernate-reactive/blob/main/hibernate-reactive-core/src/test/java/org/hibernate/reactive/types/StringToJsonConverter.java
Like in Hibernate ORM, it's possible to map a JSON field using the {orm-json-basic-mapping}[SqlTypes.JSON]
diff --git a/examples/native-sql-example/build.gradle b/examples/native-sql-example/build.gradle
index fabdbc7fa..3b650d34a 100644
--- a/examples/native-sql-example/build.gradle
+++ b/examples/native-sql-example/build.gradle
@@ -27,7 +27,7 @@ dependencies {
implementation project( ':hibernate-reactive-core' )
// Hibernate Validator (optional)
- implementation 'org.hibernate.validator:hibernate-validator:8.0.1.Final'
+ implementation 'org.hibernate.validator:hibernate-validator:8.0.2.Final'
runtimeOnly 'org.glassfish.expressly:expressly:5.0.0'
// JPA metamodel generation for criteria queries (optional)
@@ -40,7 +40,7 @@ dependencies {
runtimeOnly "org.apache.logging.log4j:log4j-core:2.20.0"
// Allow authentication to PostgreSQL using SCRAM:
- runtimeOnly 'com.ongres.scram:client:2.1'
+ runtimeOnly 'com.ongres.scram:scram-client:3.1'
}
// Optional: enable the bytecode enhancements
diff --git a/examples/native-sql-example/src/main/resources/META-INF/persistence.xml b/examples/native-sql-example/src/main/resources/META-INF/persistence.xml
index aaa9d3687..686442cb2 100644
--- a/examples/native-sql-example/src/main/resources/META-INF/persistence.xml
+++ b/examples/native-sql-example/src/main/resources/META-INF/persistence.xml
@@ -3,7 +3,7 @@
xsi:schemaLocation="https://jakarta.ee/xml/ns/persistence https://jakarta.ee/xml/ns/persistence/persistence_3_0.xsd"
version="3.0">
-
+ org.hibernate.reactive.provider.ReactivePersistenceProviderorg.hibernate.reactive.example.nativesql.Author
diff --git a/examples/session-example/build.gradle b/examples/session-example/build.gradle
index 7cf7fb5f6..a001112d8 100644
--- a/examples/session-example/build.gradle
+++ b/examples/session-example/build.gradle
@@ -27,7 +27,7 @@ dependencies {
implementation project( ':hibernate-reactive-core' )
// Hibernate Validator (optional)
- implementation 'org.hibernate.validator:hibernate-validator:8.0.1.Final'
+ implementation 'org.hibernate.validator:hibernate-validator:8.0.2.Final'
runtimeOnly 'org.glassfish.expressly:expressly:5.0.0'
// JPA metamodel generation for criteria queries (optional)
@@ -41,7 +41,7 @@ dependencies {
runtimeOnly "org.apache.logging.log4j:log4j-core:2.20.0"
// Allow authentication to PostgreSQL using SCRAM:
- runtimeOnly 'com.ongres.scram:client:2.1'
+ runtimeOnly 'com.ongres.scram:scram-client:3.1'
}
// Optional: enable the bytecode enhancements
diff --git a/examples/session-example/src/main/resources/META-INF/persistence.xml b/examples/session-example/src/main/resources/META-INF/persistence.xml
index 7c2c13900..f3271f251 100644
--- a/examples/session-example/src/main/resources/META-INF/persistence.xml
+++ b/examples/session-example/src/main/resources/META-INF/persistence.xml
@@ -3,7 +3,7 @@
xsi:schemaLocation="https://jakarta.ee/xml/ns/persistence https://jakarta.ee/xml/ns/persistence/persistence_3_0.xsd"
version="3.0">
-
+ org.hibernate.reactive.provider.ReactivePersistenceProviderorg.hibernate.reactive.example.session.Author
diff --git a/gradle.properties b/gradle.properties
index 55ec51fc8..36bc0c5ac 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -35,21 +35,21 @@ org.gradle.java.installations.auto-download=false
#enableMavenLocalRepo = true
# The default Hibernate ORM version (override using `-PhibernateOrmVersion=the.version.you.want`)
-hibernateOrmVersion = 6.6.3.Final
+hibernateOrmVersion = 7.0.0.Final
# Override default Hibernate ORM Gradle plugin version
# Using the stable version because I don't know how to configure the build to download the snapshot version from
# a remote repository
-#hibernateOrmGradlePluginVersion = 6.6.3.Final
+#hibernateOrmGradlePluginVersion = 7.0.0.Final
# If set to true, skip Hibernate ORM version parsing (default is true, if set to null)
# this is required when using intervals or weird versions or the build will fail
#skipOrmVersionParsing = true
# Override default Vert.x Sql client version
-#vertxSqlClientVersion = 4.5.11-SNAPSHOT
+#vertxSqlClientVersion = 5.0.0-SNAPSHOT
# Override default Vert.x Web client and server versions. For integration tests, both default to vertxSqlClientVersion
-#vertxWebVersion = 4.5.11
-#vertxWebtClientVersion = 4.5.11
+#vertxWebVersion = 5.0.0
+#vertxWebtClientVersion = 5.0.0
diff --git a/gradle/version.properties b/gradle/version.properties
index dd20a5fa4..618fb2d72 100644
--- a/gradle/version.properties
+++ b/gradle/version.properties
@@ -1 +1 @@
-projectVersion=2.4.3-SNAPSHOT
\ No newline at end of file
+projectVersion=4.0.0-SNAPSHOT
\ No newline at end of file
diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar
index d64cd4917..a4b76b953 100644
Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index 9355b4155..cea7a793a 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-8.10-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-8.12-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
diff --git a/gradlew b/gradlew
index 1aa94a426..f5feea6d6 100755
--- a/gradlew
+++ b/gradlew
@@ -15,6 +15,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
+# SPDX-License-Identifier: Apache-2.0
+#
##############################################################################
#
@@ -55,7 +57,7 @@
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
-# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
+# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
@@ -84,7 +86,8 @@ done
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
-APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
+APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s
+' "$PWD" ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
diff --git a/gradlew.bat b/gradlew.bat
index 6689b85be..9b42019c7 100644
--- a/gradlew.bat
+++ b/gradlew.bat
@@ -13,6 +13,8 @@
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
+@rem SPDX-License-Identifier: Apache-2.0
+@rem
@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@@ -43,11 +45,11 @@ set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if %ERRORLEVEL% equ 0 goto execute
-echo.
-echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
-echo.
-echo Please set the JAVA_HOME variable in your environment to match the
-echo location of your Java installation.
+echo. 1>&2
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
+echo. 1>&2
+echo Please set the JAVA_HOME variable in your environment to match the 1>&2
+echo location of your Java installation. 1>&2
goto fail
@@ -57,11 +59,11 @@ set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto execute
-echo.
-echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
-echo.
-echo Please set the JAVA_HOME variable in your environment to match the
-echo location of your Java installation.
+echo. 1>&2
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
+echo. 1>&2
+echo Please set the JAVA_HOME variable in your environment to match the 1>&2
+echo location of your Java installation. 1>&2
goto fail
diff --git a/hibernate-reactive-core/build.gradle b/hibernate-reactive-core/build.gradle
index bbcbc9e6c..26a4de751 100644
--- a/hibernate-reactive-core/build.gradle
+++ b/hibernate-reactive-core/build.gradle
@@ -10,21 +10,22 @@ dependencies {
api "org.hibernate.orm:hibernate-core:${hibernateOrmVersion}"
- api 'io.smallrye.reactive:mutiny:2.7.0'
+ api 'io.smallrye.reactive:mutiny:2.9.0'
//Logging
- implementation 'org.jboss.logging:jboss-logging:3.5.0.Final'
- compileOnly 'org.jboss.logging:jboss-logging-annotations:2.2.1.Final'
+ implementation 'org.jboss.logging:jboss-logging:3.6.1.Final'
+ annotationProcessor 'org.jboss.logging:jboss-logging:3.6.1.Final'
+
+ compileOnly 'org.jboss.logging:jboss-logging-annotations:3.0.4.Final'
+ annotationProcessor 'org.jboss.logging:jboss-logging-annotations:3.0.4.Final'
+ annotationProcessor 'org.jboss.logging:jboss-logging-processor:3.0.4.Final'
- annotationProcessor 'org.jboss.logging:jboss-logging:3.5.0.Final'
- annotationProcessor 'org.jboss.logging:jboss-logging-annotations:2.2.1.Final'
- annotationProcessor 'org.jboss.logging:jboss-logging-processor:2.2.1.Final'
//Specific implementation details of Hibernate Reactive:
implementation "io.vertx:vertx-sql-client:${vertxSqlClientVersion}"
// Testing
- testImplementation 'org.assertj:assertj-core:3.26.3'
+ testImplementation 'org.assertj:assertj-core:3.27.3'
testImplementation "io.vertx:vertx-junit5:${vertxSqlClientVersion}"
// Drivers
@@ -38,23 +39,23 @@ dependencies {
testImplementation "io.vertx:vertx-micrometer-metrics:${vertxSqlClientVersion}"
// Optional dependency of vertx-pg-client, essential when connecting via SASL SCRAM
- testImplementation 'com.ongres.scram:client:2.1'
+ testImplementation 'com.ongres.scram:scram-client:3.1'
// JUnit Jupiter
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.11.3'
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.11.3'
// JDBC driver to test with ORM and PostgreSQL
- testRuntimeOnly "org.postgresql:postgresql:42.7.4"
+ testRuntimeOnly "org.postgresql:postgresql:42.7.5"
// JDBC driver for Testcontainers with MS SQL Server
- testRuntimeOnly "com.microsoft.sqlserver:mssql-jdbc:12.8.1.jre11"
+ testRuntimeOnly "com.microsoft.sqlserver:mssql-jdbc:12.10.0.jre11"
// JDBC driver for Testcontainers with MariaDB Server
- testRuntimeOnly "org.mariadb.jdbc:mariadb-java-client:3.5.1"
+ testRuntimeOnly "org.mariadb.jdbc:mariadb-java-client:3.5.3"
// JDBC driver for Testcontainers with MYSQL Server
- testRuntimeOnly "com.mysql:mysql-connector-j:9.1.0"
+ testRuntimeOnly "com.mysql:mysql-connector-j:9.3.0"
// JDBC driver for Db2 server, for testing
testRuntimeOnly "com.ibm.db2:jcc:12.1.0.0"
@@ -80,6 +81,15 @@ dependencies {
testImplementation "org.testcontainers:oracle-xe:${testcontainersVersion}"
}
+// Reproducible Builds
+
+// https://docs.gradle.org/current/userguide/working_with_files.html#sec:reproducible_archives
+// Configure archive tasks to produce reproducible archives:
+tasks.withType(AbstractArchiveTask).configureEach {
+ preserveFileTimestamps = false
+ reproducibleFileOrder = true
+}
+
// Print a summary of the results of the tests (number of failures, successes and skipped)
def loggingSummary(db, result, desc) {
if ( !desc.parent ) { // will match the outermost suite
diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/engine/internal/ReactivePersistenceContextAdapter.java b/hibernate-reactive-core/src/main/java/org/hibernate/engine/internal/ReactivePersistenceContextAdapter.java
new file mode 100644
index 000000000..6d87416b4
--- /dev/null
+++ b/hibernate-reactive-core/src/main/java/org/hibernate/engine/internal/ReactivePersistenceContextAdapter.java
@@ -0,0 +1,799 @@
+/* Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * Copyright: Red Hat Inc. and Hibernate Authors
+ */
+package org.hibernate.engine.internal;
+
+import java.io.Serializable;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.CompletionStage;
+import java.util.function.BiConsumer;
+import java.util.function.Consumer;
+import java.util.function.Supplier;
+
+import org.hibernate.HibernateException;
+import org.hibernate.Internal;
+import org.hibernate.LockMode;
+import org.hibernate.collection.spi.PersistentCollection;
+import org.hibernate.engine.spi.BatchFetchQueue;
+import org.hibernate.engine.spi.CollectionEntry;
+import org.hibernate.engine.spi.CollectionKey;
+import org.hibernate.engine.spi.EntityEntry;
+import org.hibernate.engine.spi.EntityHolder;
+import org.hibernate.engine.spi.EntityKey;
+import org.hibernate.engine.spi.EntityUniqueKey;
+import org.hibernate.engine.spi.NaturalIdResolutions;
+import org.hibernate.engine.spi.PersistenceContext;
+import org.hibernate.engine.spi.PersistentAttributeInterceptable;
+import org.hibernate.engine.spi.SessionImplementor;
+import org.hibernate.engine.spi.SharedSessionContractImplementor;
+import org.hibernate.engine.spi.Status;
+import org.hibernate.event.service.spi.EventListenerGroup;
+import org.hibernate.event.spi.PostLoadEvent;
+import org.hibernate.event.spi.PostLoadEventListener;
+import org.hibernate.persister.collection.CollectionPersister;
+import org.hibernate.persister.entity.EntityPersister;
+import org.hibernate.reactive.engine.impl.ReactiveCallbackImpl;
+import org.hibernate.reactive.engine.spi.ReactiveSharedSessionContractImplementor;
+import org.hibernate.reactive.logging.impl.Log;
+import org.hibernate.reactive.persister.entity.impl.ReactiveEntityPersister;
+import org.hibernate.sql.exec.spi.Callback;
+import org.hibernate.sql.results.graph.entity.EntityInitializer;
+import org.hibernate.sql.results.jdbc.spi.JdbcValuesSourceProcessingState;
+import org.hibernate.sql.results.spi.LoadContexts;
+
+import static java.lang.invoke.MethodHandles.lookup;
+import static org.hibernate.reactive.logging.impl.LoggerFactory.make;
+import static org.hibernate.reactive.util.impl.CompletionStages.completedFuture;
+import static org.hibernate.reactive.util.impl.CompletionStages.loop;
+import static org.hibernate.reactive.util.impl.CompletionStages.voidFuture;
+
+/**
+ * Add reactive methods to a {@link PersistenceContext}.
+ */
+public class ReactivePersistenceContextAdapter implements PersistenceContext {
+
+ private static final Log LOG = make( Log.class, lookup() );
+
+ private final PersistenceContext delegate;
+
+ /**
+ * Constructs a PersistentContext, bound to the given session.
+ */
+ public ReactivePersistenceContextAdapter(PersistenceContext persistenceContext) {
+ this.delegate = persistenceContext;
+ }
+
+ public CompletionStage reactiveInitializeNonLazyCollections() throws HibernateException {
+ final NonLazyCollectionInitializer initializer = new NonLazyCollectionInitializer();
+ delegate.initializeNonLazyCollections( initializer );
+ return initializer.stage;
+ }
+
+ private class NonLazyCollectionInitializer implements Consumer> {
+ CompletionStage stage = voidFuture();
+
+ @Override
+ public void accept(PersistentCollection> nonLazyCollection) {
+ if ( !nonLazyCollection.wasInitialized() ) {
+ stage = stage.thenCompose( v ->
+ ( (ReactiveSharedSessionContractImplementor) getSession() )
+ .reactiveInitializeCollection( nonLazyCollection, false ) );
+ }
+ }
+ }
+
+ /**
+ * @deprecated use {@link #reactiveInitializeNonLazyCollections} instead.
+ */
+ @Deprecated
+ @Override
+ public void initializeNonLazyCollections() {
+ // still called by ResultSetProcessorImpl, so can't throw UnsupportedOperationException
+ }
+
+ @Override
+ public void initializeNonLazyCollections(Consumer> initializeAction) {
+ throw LOG.nonReactiveMethodCall( "reactiveInitializeNonLazyCollection" );
+ }
+
+ @Deprecated
+ @Override
+ public Object[] getDatabaseSnapshot(Object id, EntityPersister persister) throws HibernateException {
+ throw LOG.nonReactiveMethodCall( "reactiveGetDatabaseSnapshot" );
+ }
+
+ private static final Object[] NO_ROW = new Object[] {StatefulPersistenceContext.NO_ROW};
+
+ public CompletionStage
+ // One thing to be careful of here is a "bare" original collection
+ // in which case we should never ever ever reset the dirty flag
+ // on the target because we simply do not know...
+ if ( original instanceof PersistentCollection> originalCollection
+ && result instanceof PersistentCollection> resultCollection ) {
+ return preserveSnapshot(
+ originalCollection, resultCollection,
+ elemType, owner, copyCache, session
+ ).thenApply( v -> {
+ if ( !originalCollection.isDirty() ) {
+ resultCollection.clearDirty();
+ }
+ return result;
+ } );
+ }
+ else {
+ return completedFuture( result );
+ }
+ }
+
+ private static CompletionStage replaceMapTypeElements(
+ CollectionType type,
+ Map, ?> original,
+ Map target,
+ Object owner,
+ Map copyCache,
+ SharedSessionContractImplementor session) {
+ final CollectionPersister persister =
+ session.getFactory().getRuntimeMetamodels().getMappingMetamodel()
+ .getCollectionDescriptor( type.getRole() );
+ target.clear();
+ return loop(
+ original.entrySet(), entry -> {
+ final Map.Entry, ?> me = entry;
+ return getReplace( persister.getIndexType(), me.getKey(), owner, session, copyCache )
+ .thenCompose( key -> getReplace(
+ persister.getElementType(),
+ me.getValue(),
+ owner,
+ session,
+ copyCache
+ ).thenAccept( value -> target.put( key, value ) )
+ );
+ }
+ ).thenApply( unused -> target);
+ }
+
+ private static CompletionStage replaceArrayTypeElements(
+ CollectionType type,
+ Object original,
+ Object target,
+ Object owner,
+ Map copyCache,
+ SharedSessionContractImplementor session) {
+ final Object result;
+ final int length = Array.getLength( original );
+ if ( length != Array.getLength( target ) ) {
+ //note: this affects the return value!
+ result = ( (ArrayType) type ).instantiateResult( original );
+ }
+ else {
+ result = target;
+ }
+
+ final Type elemType = type.getElementType( session.getFactory() );
+ return loop( 0, length,
+ i -> getReplace( elemType, Array.get( original, i ), owner, session, copyCache )
+ .thenApply( o -> {
+ Array.set( result, i, o );
+ return result;
+ } )
+ ).thenApply( unused -> result );
+ }
+
+ private static CompletionStage getReplace(
+ Type elemType,
+ Object o,
+ Object owner,
+ SharedSessionContractImplementor session,
+ Map copyCache) {
+ return getReplace( elemType, o, null, owner, session, copyCache );
+ }
+
+ private static CompletionStage getReplace(
+ Type elemType,
+ Object object,
+ Object target,
+ Object owner,
+ SharedSessionContractImplementor session,
+ Map copyCache) {
+ return elemType instanceof EntityType entityType
+ ? EntityTypes.replace( entityType, object, target, session, owner, copyCache )
+ : completedFuture( elemType.replace( object, target, session, owner, copyCache) );
+ }
+
+ /**
+ * @see CollectionType#preserveSnapshot(PersistentCollection, PersistentCollection, Type, Object, Map, SharedSessionContractImplementor)
+ */
+ private static CompletionStage preserveSnapshot(
+ PersistentCollection> original,
+ PersistentCollection> result,
+ Type elemType,
+ Object owner,
+ Map copyCache,
+ SharedSessionContractImplementor session) {
+ final CollectionEntry ce = session.getPersistenceContextInternal().getCollectionEntry( result );
+ if ( ce != null ) {
+ return createSnapshot( original, result, elemType, owner, copyCache, session )
+ .thenAccept( serializable -> ce.resetStoredSnapshot( result, serializable ) );
+ }
+ else {
+ return voidFuture();
+ }
+ }
+
+ /**
+ * @see CollectionType#createSnapshot(PersistentCollection, PersistentCollection, Type, Object, Map, SharedSessionContractImplementor)
+ */
+ private static CompletionStage createSnapshot(
+ PersistentCollection> original,
+ PersistentCollection> result,
+ Type elemType,
+ Object owner,
+ Map copyCache,
+ SharedSessionContractImplementor session) {
+ final Serializable originalSnapshot = original.getStoredSnapshot();
+ if ( originalSnapshot instanceof List> list ) {
+ return createListSnapshot( list, elemType, owner, copyCache, session );
+ }
+ else if ( originalSnapshot instanceof Map, ?> map ) {
+ return createMapSnapshot( map, result, elemType, owner, copyCache, session );
+ }
+ else if ( originalSnapshot instanceof Object[] array ) {
+ return createArraySnapshot( array, elemType, owner, copyCache, session );
+ }
+ else {
+ // retain the same snapshot
+ return completedFuture( result.getStoredSnapshot() );
+ }
+ }
+
+ /**
+ * @see CollectionType#createArraySnapshot(Object[], Type, Object, Map, SharedSessionContractImplementor)
+ */
+ private static CompletionStage createArraySnapshot(
+ Object[] array,
+ Type elemType,
+ Object owner,
+ Map copyCache,
+ SharedSessionContractImplementor session) {
+ return loop( 0, array.length,
+ i -> getReplace( elemType, array[i], owner, session, copyCache )
+ .thenAccept( o -> array[i] = o )
+ ).thenApply( unused -> array );
+ }
+
+ /**
+ * @see CollectionType#createMapSnapshot(Map, PersistentCollection, Type, Object, Map, SharedSessionContractImplementor)
+ */
+ private static CompletionStage createMapSnapshot(
+ Map map,
+ PersistentCollection> result,
+ Type elemType,
+ Object owner,
+ Map copyCache,
+ SharedSessionContractImplementor session) {
+ final Map, ?> resultSnapshot = (Map, ?>) result.getStoredSnapshot();
+ final Map targetMap =
+ map instanceof SortedMap sortedMap
+ ? new TreeMap<>( sortedMap.comparator() )
+ : mapOfSize(map.size());
+ return loop( map.entrySet(),
+ entry -> getReplace( elemType, entry.getValue(), resultSnapshot, owner, session, copyCache )
+ .thenAccept( newValue -> {
+ final K key = entry.getKey();
+ final V value = entry.getValue();
+ //noinspection unchecked
+ targetMap.put( key == value ? (K) newValue : key, (V) newValue );
+ } )
+ ).thenApply( v -> (Serializable) targetMap );
+ }
+
+ /**
+ * @see CollectionType#createListSnapshot(List, Type, Object, Map, SharedSessionContractImplementor)
+ */
+ private static CompletionStage createListSnapshot(
+ List> list,
+ Type elemType,
+ Object owner,
+ Map copyCache,
+ SharedSessionContractImplementor session) {
+ final ArrayList targetList = new ArrayList<>( list.size() );
+ return loop( list,
+ obj -> getReplace( elemType, obj, owner, session, copyCache )
+ .thenAccept( targetList::add )
+ ).thenApply( unused -> targetList );
+ }
+
+ /**
+ * @see CollectionType#instantiateResultIfNecessary(Object, Object)
+ */
+ private static Object instantiateResultIfNecessary(CollectionType type, Object original, Object target) {
+ // for a null target, or a target which is the same as the original,
+ // we need to put the merged elements in a new collection
+ // by default just use an unanticipated capacity since we don't
+ // know how to extract the capacity to use from original here...
+ return target == null
+ || target == original
+ || target == UNFETCHED_PROPERTY
+ || target instanceof PersistentCollection> collection && collection.isWrapper( original )
+ ? type.instantiate( -1 )
+ : target;
+ }
+}
diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/engine/impl/EntityTypes.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/engine/impl/EntityTypes.java
index 879f7ddc8..504830150 100644
--- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/engine/impl/EntityTypes.java
+++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/engine/impl/EntityTypes.java
@@ -16,15 +16,16 @@
import org.hibernate.engine.spi.PersistenceContext;
import org.hibernate.engine.spi.PersistentAttributeInterceptor;
import org.hibernate.engine.spi.SessionFactoryImplementor;
-import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.metamodel.mapping.AttributeMapping;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.proxy.HibernateProxy;
import org.hibernate.proxy.LazyInitializer;
+import org.hibernate.reactive.engine.spi.ReactiveSharedSessionContractImplementor;
import org.hibernate.reactive.persister.entity.impl.ReactiveEntityPersister;
+import org.hibernate.reactive.session.ReactiveQueryProducer;
import org.hibernate.reactive.session.impl.ReactiveQueryExecutorLookup;
-import org.hibernate.reactive.session.impl.ReactiveSessionImpl;
+import org.hibernate.type.CollectionType;
import org.hibernate.type.EntityType;
import org.hibernate.type.ForeignKeyDirection;
import org.hibernate.type.OneToOneType;
@@ -75,8 +76,7 @@ public static CompletionStage resolve(EntityType entityType, Object idOr
* @see OneToOneType#isNull(Object, SharedSessionContractImplementor)
*/
static boolean isNull(EntityType entityType, Object owner, SharedSessionContractImplementor session) {
- if ( entityType instanceof OneToOneType ) {
- OneToOneType type = (OneToOneType) entityType;
+ if ( entityType instanceof OneToOneType type ) {
String propertyName = type.getPropertyName();
if ( propertyName != null ) {
final EntityPersister ownerPersister = session.getFactory()
@@ -125,7 +125,7 @@ static CompletionStage loadByUniqueKey(
entityName,
uniqueKeyPropertyName,
key,
- entityType.getIdentifierOrUniqueKeyType( factory ),
+ entityType.getIdentifierOrUniqueKeyType( factory.getRuntimeMetamodels() ),
factory
);
@@ -137,7 +137,7 @@ static CompletionStage loadByUniqueKey(
else {
return persister
.reactiveLoadByUniqueKey( uniqueKeyPropertyName, key, session )
- .thenApply( ukResult -> loadHibernateProxyEntity( ukResult, session )
+ .thenCompose( ukResult -> loadHibernateProxyEntity( ukResult, session )
.thenApply( targetUK -> {
persistenceContext.addEntity( euk, targetUK );
return targetUK;
@@ -154,46 +154,12 @@ public static CompletionStage replace(
final Object[] original,
final Object[] target,
final Type[] types,
- final SessionImplementor session,
+ final SharedSessionContractImplementor session,
final Object owner,
final Map copyCache) {
Object[] copied = new Object[original.length];
- for ( int i = 0; i < types.length; i++ ) {
- if ( original[i] == UNFETCHED_PROPERTY || original[i] == UNKNOWN ) {
- copied[i] = target[i];
- }
- else {
- if ( !( types[i] instanceof EntityType ) ) {
- copied[i] = types[i].replace(
- original[i],
- target[i] == UNFETCHED_PROPERTY ? null : target[i],
- session,
- owner,
- copyCache
- );
- }
- }
- }
return loop( 0, types.length,
- i -> original[i] != UNFETCHED_PROPERTY && original[i] != UNKNOWN
- && types[i] instanceof EntityType,
- i -> replace(
- (EntityType) types[i],
- original[i],
- target[i] == UNFETCHED_PROPERTY ? null : target[i],
- session,
- owner,
- copyCache
- ).thenCompose( copy -> {
- if ( copy instanceof CompletionStage ) {
- return ( (CompletionStage>) copy )
- .thenAccept( nonStageCopy -> copied[i] = nonStageCopy );
- }
- else {
- copied[i] = copy;
- return voidFuture();
- }
- } )
+ i -> replace( original, target, types, session, owner, copyCache, i, copied )
).thenApply( v -> copied );
}
@@ -204,48 +170,13 @@ public static CompletionStage replace(
final Object[] original,
final Object[] target,
final Type[] types,
- final SessionImplementor session,
+ final SharedSessionContractImplementor session,
final Object owner,
final Map copyCache,
final ForeignKeyDirection foreignKeyDirection) {
Object[] copied = new Object[original.length];
- for ( int i = 0; i < types.length; i++ ) {
- if ( original[i] == UNFETCHED_PROPERTY || original[i] == UNKNOWN ) {
- copied[i] = target[i];
- }
- else {
- if ( !( types[i] instanceof EntityType ) ) {
- copied[i] = types[i].replace(
- original[i],
- target[i] == UNFETCHED_PROPERTY ? null : target[i],
- session,
- owner,
- copyCache,
- foreignKeyDirection
- );
- }
- }
- }
return loop( 0, types.length,
- i -> original[i] != UNFETCHED_PROPERTY && original[i] != UNKNOWN
- && types[i] instanceof EntityType,
- i -> replace(
- (EntityType) types[i],
- original[i],
- target[i] == UNFETCHED_PROPERTY ? null : target[i],
- session,
- owner,
- copyCache,
- foreignKeyDirection
- ).thenCompose( copy -> {
- if ( copy instanceof CompletionStage ) {
- return ( (CompletionStage>) copy ).thenAccept( nonStageCopy -> copied[i] = nonStageCopy );
- }
- else {
- copied[i] = copy;
- return voidFuture();
- }
- } )
+ i -> replace( original, target, types, session, owner, copyCache, foreignKeyDirection, i, copied )
).thenApply( v -> copied );
}
@@ -256,7 +187,7 @@ private static CompletionStage replace(
EntityType entityType,
Object original,
Object target,
- SessionImplementor session,
+ SharedSessionContractImplementor session,
Object owner,
Map copyCache,
ForeignKeyDirection foreignKeyDirection)
@@ -272,11 +203,11 @@ private static CompletionStage replace(
/**
* @see EntityType#replace(Object, Object, SharedSessionContractImplementor, Object, Map)
*/
- private static CompletionStage replace(
+ protected static CompletionStage replace(
EntityType entityType,
Object original,
Object target,
- SessionImplementor session,
+ SharedSessionContractImplementor session,
Object owner,
Map copyCache) {
if ( original == null ) {
@@ -322,7 +253,7 @@ private static CompletionStage replace(
private static CompletionStage resolveIdOrUniqueKey(
EntityType entityType,
Object original,
- SessionImplementor session,
+ SharedSessionContractImplementor session,
Object owner,
Map copyCache) {
return getIdentifier( entityType, original, session )
@@ -336,15 +267,16 @@ private static CompletionStage resolveIdOrUniqueKey(
// as a ComponentType. In the case that the entity is unfetched, we need to
// explicitly fetch it here before calling replace(). (Note that in Hibernate
// ORM this is unnecessary due to transparent lazy fetching.)
- return ( (ReactiveSessionImpl) session ).reactiveFetch( id, true )
+ return ( (ReactiveQueryProducer) session )
+ .reactiveFetch( id, true )
.thenCompose( fetched -> {
- Object idOrUniqueKey = entityType.getIdentifierOrUniqueKeyType( session.getFactory() )
+ Object idOrUniqueKey = entityType
+ .getIdentifierOrUniqueKeyType( session.getFactory().getRuntimeMetamodels() )
.replace( fetched, null, session, owner, copyCache );
if ( idOrUniqueKey instanceof CompletionStage ) {
return ( (CompletionStage>) idOrUniqueKey )
.thenCompose( key -> resolve( entityType, key, owner, session ) );
}
-
return resolve( entityType, idOrUniqueKey, owner, session );
} );
} );
@@ -356,7 +288,7 @@ private static CompletionStage resolveIdOrUniqueKey(
private static CompletionStage getIdentifier(
EntityType entityType,
Object value,
- SessionImplementor session) {
+ SharedSessionContractImplementor session) {
if ( entityType.isReferenceToIdentifierProperty() ) {
// tolerates nulls
return getEntityIdentifierIfNotUnsaved( entityType.getAssociatedEntityName(), value, session );
@@ -407,10 +339,11 @@ private static CompletionStage getIdentifierFromHibernateProxy(
EntityType entityType,
HibernateProxy proxy,
SharedSessionContractImplementor session) {
- LazyInitializer initializer = proxy.getHibernateLazyInitializer();
+ final LazyInitializer initializer = proxy.getHibernateLazyInitializer();
final String entityName = initializer.getEntityName();
final Object identifier = initializer.getIdentifier();
- return ( (ReactiveSessionImpl) session ).reactiveImmediateLoad( entityName, identifier )
+ return ( (ReactiveSharedSessionContractImplementor) session )
+ .reactiveImmediateLoad( entityName, identifier )
.thenApply( entity -> {
checkEntityFound( session, entityName, identifier, entity );
initializer.setSession( session );
@@ -424,11 +357,11 @@ private static CompletionStage getIdentifierFromHibernateProxy(
// an entity type, in which case we need to resolve its identifier
final AttributeMapping type = entityPersister.findAttributeMapping( uniqueKeyPropertyName );
if ( type.isEntityIdentifierMapping() ) {
- propertyValue = getIdentifier( (EntityType) type, propertyValue, (SessionImplementor) session );
+ propertyValue = getIdentifier( (EntityType) type, propertyValue, session );
}
- return completedFuture( propertyValue );
+ return propertyValue;
}
- return nullFuture();
+ return null;
} );
}
@@ -439,7 +372,8 @@ private static CompletionStage loadHibernateProxyEntity(
LazyInitializer initializer = ( (HibernateProxy) entity ).getHibernateLazyInitializer();
final String entityName = initializer.getEntityName();
final Object identifier = initializer.getIdentifier();
- return ( (ReactiveSessionImpl) session ).reactiveImmediateLoad( entityName, identifier )
+ return ( (ReactiveSharedSessionContractImplementor) session )
+ .reactiveImmediateLoad( entityName, identifier )
.thenApply( result -> {
checkEntityFound( session, entityName, identifier, result );
return result;
@@ -450,4 +384,100 @@ private static CompletionStage loadHibernateProxyEntity(
}
}
+ private static CompletionStage replace(
+ Object[] original,
+ Object[] target,
+ Type[] types,
+ SharedSessionContractImplementor session,
+ Object owner,
+ Map copyCache,
+ int i,
+ Object[] copied) {
+ if ( original[i] == UNFETCHED_PROPERTY || original[i] == UNKNOWN ) {
+ copied[i] = target[i];
+ return voidFuture();
+ }
+ else if ( types[i] instanceof CollectionType ) {
+ return CollectionTypes.replace(
+ (CollectionType) types[i],
+ original[i],
+ target[i] == UNFETCHED_PROPERTY ? null : target[i],
+ session,
+ owner,
+ copyCache
+ ).thenAccept( copy -> copied[i] = copy );
+ }
+ else if ( types[i] instanceof EntityType ) {
+ return replace(
+ (EntityType) types[i],
+ original[i],
+ target[i] == UNFETCHED_PROPERTY ? null : target[i],
+ session,
+ owner,
+ copyCache
+ ).thenAccept( copy -> copied[i] = copy );
+ }
+ else {
+ final Type type = types[i];
+ copied[i] = type.replace(
+ original[i],
+ target[i] == UNFETCHED_PROPERTY ? null : target[i],
+ session,
+ owner,
+ copyCache
+ );
+ return voidFuture();
+ }
+ }
+
+ private static CompletionStage replace(
+ Object[] original,
+ Object[] target,
+ Type[] types,
+ SharedSessionContractImplementor session,
+ Object owner,
+ Map copyCache,
+ ForeignKeyDirection foreignKeyDirection,
+ int i,
+ Object[] copied) {
+ if ( original[i] == UNFETCHED_PROPERTY || original[i] == UNKNOWN ) {
+ copied[i] = target[i];
+ return voidFuture();
+ }
+ else if ( types[i] instanceof CollectionType ) {
+ return CollectionTypes.replace(
+ (CollectionType) types[i],
+ original[i],
+ target[i] == UNFETCHED_PROPERTY ? null : target[i],
+ session,
+ owner,
+ copyCache,
+ foreignKeyDirection
+ ).thenAccept( copy -> copied[i] = copy );
+ }
+ else if ( types[i] instanceof EntityType ) {
+ return replace(
+ (EntityType) types[i],
+ original[i],
+ target[i] == UNFETCHED_PROPERTY ? null : target[i],
+ session,
+ owner,
+ copyCache,
+ foreignKeyDirection
+ ).thenAccept( copy -> copied[i] = copy );
+ }
+ else {
+ copied[i] = types[i].replace(
+ original[i],
+ target[i] == UNFETCHED_PROPERTY ? null : target[i],
+ session,
+ owner,
+ copyCache,
+ foreignKeyDirection
+ );
+ return voidFuture();
+ }
+ }
+
+
}
diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/engine/impl/ForeignKeys.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/engine/impl/ForeignKeys.java
index 5a77bd9f6..87078f87f 100644
--- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/engine/impl/ForeignKeys.java
+++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/engine/impl/ForeignKeys.java
@@ -11,10 +11,10 @@
import org.hibernate.TransientObjectException;
import org.hibernate.bytecode.enhance.spi.LazyPropertyInitializer;
import org.hibernate.engine.internal.NonNullableTransientDependencies;
+import org.hibernate.engine.internal.ReactivePersistenceContextAdapter;
import org.hibernate.engine.spi.EntityEntry;
import org.hibernate.engine.spi.PersistenceContext;
import org.hibernate.engine.spi.SelfDirtinessTracker;
-import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.internal.util.StringHelper;
import org.hibernate.persister.entity.EntityPersister;
@@ -47,7 +47,7 @@ public final class ForeignKeys {
public static class Nullifier {
private final boolean isDelete;
private final boolean isEarlyInsert;
- private final SessionImplementor session;
+ private final SharedSessionContractImplementor session;
private final Object self;
private final EntityPersister persister;
@@ -64,7 +64,7 @@ public Nullifier(
final Object self,
final boolean isDelete,
final boolean isEarlyInsert,
- final SessionImplementor session,
+ final SharedSessionContractImplementor session,
final EntityPersister persister) {
this.isDelete = isDelete;
this.isEarlyInsert = isEarlyInsert;
@@ -269,7 +269,7 @@ private CompletionStage isNullifiable(final String entityName, Object o
*
* @return {@code true} if the given entity is not transient (meaning it is either detached/persistent)
*/
- public static CompletionStage isNotTransient(String entityName, Object entity, Boolean assumed, SessionImplementor session) {
+ public static CompletionStage isNotTransient(String entityName, Object entity, Boolean assumed, SharedSessionContractImplementor session) {
if ( isHibernateProxy( entity ) ) {
return trueFuture();
}
@@ -296,7 +296,7 @@ public static CompletionStage isNotTransient(String entityName, Object
*
* @return {@code true} if the given entity is transient (unsaved)
*/
- public static CompletionStage isTransient(String entityName, Object entity, Boolean assumed, SessionImplementor session) {
+ public static CompletionStage isTransient(String entityName, Object entity, Boolean assumed, SharedSessionContractImplementor session) {
if ( entity == LazyPropertyInitializer.UNFETCHED_PROPERTY ) {
// an unfetched association can only point to
// an entity that already exists in the db
@@ -349,7 +349,7 @@ public static CompletionStage isTransient(String entityName, Object ent
public static CompletionStage getEntityIdentifierIfNotUnsaved(
final String entityName,
final Object object,
- final SessionImplementor session) throws TransientObjectException {
+ final SharedSessionContractImplementor session) throws TransientObjectException {
if ( object == null ) {
return nullFuture();
}
@@ -386,7 +386,7 @@ public static CompletionStage findNonNullableT
final EntityPersister persister = session.getEntityPersister( entityName, entity );
final Type[] types = persister.getPropertyTypes();
- final Nullifier nullifier = new Nullifier( entity, false, isEarlyInsert, (SessionImplementor) session, persister );
+ final Nullifier nullifier = new Nullifier( entity, false, isEarlyInsert, session, persister );
final String[] propertyNames = persister.getPropertyNames();
final boolean[] nullability = persister.getPropertyNullability();
final NonNullableTransientDependencies nonNullableTransientEntities = new NonNullableTransientDependencies();
diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/engine/impl/ReactiveCallbackImpl.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/engine/impl/ReactiveCallbackImpl.java
new file mode 100644
index 000000000..609f021ba
--- /dev/null
+++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/engine/impl/ReactiveCallbackImpl.java
@@ -0,0 +1,70 @@
+/* Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * Copyright: Red Hat Inc. and Hibernate Authors
+ */
+package org.hibernate.reactive.engine.impl;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.CompletionStage;
+
+import org.hibernate.engine.spi.SharedSessionContractImplementor;
+import org.hibernate.loader.ast.spi.AfterLoadAction;
+import org.hibernate.metamodel.mapping.EntityMappingType;
+import org.hibernate.reactive.loader.ast.spi.ReactiveAfterLoadAction;
+import org.hibernate.reactive.logging.impl.Log;
+import org.hibernate.sql.exec.spi.Callback;
+
+import static java.lang.invoke.MethodHandles.lookup;
+import static org.hibernate.reactive.logging.impl.LoggerFactory.make;
+import static org.hibernate.reactive.util.impl.CompletionStages.loop;
+
+/**
+ * Reactive equivalent of {@link org.hibernate.sql.exec.internal.CallbackImpl}
+ */
+public class ReactiveCallbackImpl implements Callback {
+ private static final Log LOG = make( Log.class, lookup() );
+
+ private final List afterLoadActions;
+
+ public ReactiveCallbackImpl() {
+ this.afterLoadActions = new ArrayList<>( 1 );
+ }
+
+ @Override
+ public void registerAfterLoadAction(AfterLoadAction afterLoadAction) {
+ throw LOG.nonReactiveMethodCall( "registerReactiveAfterLoadAction(ReactiveCallbackImpl)" );
+ }
+
+ public void registerReactiveAfterLoadAction(ReactiveAfterLoadAction afterLoadAction) {
+ afterLoadActions.add( afterLoadAction );
+ }
+
+ @Override
+ public void invokeAfterLoadActions(
+ Object entity,
+ EntityMappingType entityMappingType,
+ SharedSessionContractImplementor session) {
+ throw LOG.nonReactiveMethodCall( "invokeAfterLoadActions(Object, EntityMappingType, SharedSessionContractImplementor)" );
+ }
+
+ /**
+ * Reactive version of {@link org.hibernate.sql.exec.internal.CallbackImpl#invokeAfterLoadActions(Object, EntityMappingType, SharedSessionContractImplementor)}
+ */
+ public CompletionStage invokeReactiveLoadActions(
+ Object entity,
+ EntityMappingType entityMappingType,
+ SharedSessionContractImplementor session) {
+ return loop(
+ afterLoadActions, afterLoadAction ->
+ afterLoadAction.reactiveAfterLoad( entity, entityMappingType, session )
+ );
+ }
+
+ @Override
+ public boolean hasAfterLoadActions() {
+ return !afterLoadActions.isEmpty();
+ }
+
+}
diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/engine/impl/ReactiveCollectionRecreateAction.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/engine/impl/ReactiveCollectionRecreateAction.java
index 008755086..37f8eaa7e 100644
--- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/engine/impl/ReactiveCollectionRecreateAction.java
+++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/engine/impl/ReactiveCollectionRecreateAction.java
@@ -56,7 +56,7 @@ public void execute() throws HibernateException {
}
private void preRecreate() {
- getFastSessionServices()
+ getEventListenerGroups()
.eventListenerGroup_PRE_COLLECTION_RECREATE
.fireLazyEventOnEachListener( this::newPreCollectionRecreateEvent, PreCollectionRecreateEventListener::onPreRecreateCollection );
}
@@ -66,7 +66,7 @@ private PreCollectionRecreateEvent newPreCollectionRecreateEvent() {
}
private void postRecreate() {
- getFastSessionServices()
+ getEventListenerGroups()
.eventListenerGroup_POST_COLLECTION_RECREATE
.fireLazyEventOnEachListener( this::newPostCollectionRecreateEvent, PostCollectionRecreateEventListener::onPostRecreateCollection );
}
diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/engine/impl/ReactiveCollectionRemoveAction.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/engine/impl/ReactiveCollectionRemoveAction.java
index 4b086cf34..0f2bdefea 100644
--- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/engine/impl/ReactiveCollectionRemoveAction.java
+++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/engine/impl/ReactiveCollectionRemoveAction.java
@@ -100,7 +100,8 @@ public void execute() throws HibernateException {
}
private void preRemove() {
- getFastSessionServices().eventListenerGroup_PRE_COLLECTION_REMOVE
+ getEventListenerGroups()
+ .eventListenerGroup_PRE_COLLECTION_REMOVE
.fireLazyEventOnEachListener( this::newPreCollectionRemoveEvent,
PreCollectionRemoveEventListener::onPreRemoveCollection );
}
@@ -115,7 +116,8 @@ private PreCollectionRemoveEvent newPreCollectionRemoveEvent() {
}
private void postRemove() {
- getFastSessionServices().eventListenerGroup_POST_COLLECTION_REMOVE
+ getEventListenerGroups()
+ .eventListenerGroup_POST_COLLECTION_REMOVE
.fireLazyEventOnEachListener( this::newPostCollectionRemoveEvent,
PostCollectionRemoveEventListener::onPostRemoveCollection );
}
diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/engine/impl/ReactiveCollectionUpdateAction.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/engine/impl/ReactiveCollectionUpdateAction.java
index eae872d56..8806b3e9d 100644
--- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/engine/impl/ReactiveCollectionUpdateAction.java
+++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/engine/impl/ReactiveCollectionUpdateAction.java
@@ -118,7 +118,8 @@ public void execute() throws HibernateException {
}
private void preUpdate() {
- getFastSessionServices().eventListenerGroup_PRE_COLLECTION_UPDATE
+ getEventListenerGroups()
+ .eventListenerGroup_PRE_COLLECTION_UPDATE
.fireLazyEventOnEachListener( this::newPreCollectionUpdateEvent,
PreCollectionUpdateEventListener::onPreUpdateCollection );
}
@@ -132,7 +133,8 @@ private PreCollectionUpdateEvent newPreCollectionUpdateEvent() {
}
private void postUpdate() {
- getFastSessionServices().eventListenerGroup_POST_COLLECTION_UPDATE
+ getEventListenerGroups()
+ .eventListenerGroup_POST_COLLECTION_UPDATE
.fireLazyEventOnEachListener( this::newPostCollectionUpdateEvent,
PostCollectionUpdateEventListener::onPostUpdateCollection );
}
diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/engine/impl/ReactiveEntityInsertAction.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/engine/impl/ReactiveEntityInsertAction.java
index 4838e6971..3f40cdb86 100644
--- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/engine/impl/ReactiveEntityInsertAction.java
+++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/engine/impl/ReactiveEntityInsertAction.java
@@ -16,7 +16,6 @@
import org.hibernate.engine.spi.EntityHolder;
import org.hibernate.engine.spi.EntityKey;
import org.hibernate.engine.spi.PersistenceContext;
-import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.engine.spi.Status;
import org.hibernate.persister.entity.EntityPersister;
@@ -64,7 +63,7 @@ public interface ReactiveEntityInsertAction extends ReactiveExecutable, Comparab
// @see org.hibernate.action.internal.AbstractEntityInsertAction#nullifyTransientReferencesIfNotAlready()
default CompletionStage reactiveNullifyTransientReferencesIfNotAlready() {
if ( !areTransientReferencesNullified() ) {
- return new ForeignKeys.Nullifier( getInstance(), false, isEarlyInsert(), (SessionImplementor) getSession(), getPersister() )
+ return new ForeignKeys.Nullifier( getInstance(), false, isEarlyInsert(), getSession(), getPersister() )
.nullifyTransientReferences( getState() )
.thenAccept( v -> {
new Nullability( getSession() ).checkNullability( getState(), getPersister(), false );
diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/engine/impl/ReactiveEntityRegularInsertAction.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/engine/impl/ReactiveEntityRegularInsertAction.java
index 062f0374f..977179c73 100644
--- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/engine/impl/ReactiveEntityRegularInsertAction.java
+++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/engine/impl/ReactiveEntityRegularInsertAction.java
@@ -63,7 +63,7 @@ public CompletionStage reactiveExecute() throws HibernateException {
final ReactiveEntityPersister reactivePersister = (ReactiveEntityPersister) persister;
final PersistenceContext persistenceContext = session.getPersistenceContextInternal();
return stage
- .thenCompose( v -> reactivePersister.insertReactive( id, getState(), instance, session, false ) )
+ .thenCompose( v -> reactivePersister.insertReactive( id, getState(), instance, session ) )
.thenCompose( generatedValues -> {
final EntityEntry entry = persistenceContext.getEntry( instance );
if ( entry == null ) {
diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/engine/impl/ReactivePersistenceContextAdapter.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/engine/impl/ReactivePersistenceContextAdapter.java
deleted file mode 100644
index 33750cc0d..000000000
--- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/engine/impl/ReactivePersistenceContextAdapter.java
+++ /dev/null
@@ -1,134 +0,0 @@
-/* Hibernate, Relational Persistence for Idiomatic Java
- *
- * SPDX-License-Identifier: Apache-2.0
- * Copyright: Red Hat Inc. and Hibernate Authors
- */
-package org.hibernate.reactive.engine.impl;
-
-import java.io.Serializable;
-import java.util.HashMap;
-import java.util.concurrent.CompletionStage;
-import java.util.function.Consumer;
-
-import org.hibernate.HibernateException;
-import org.hibernate.collection.spi.PersistentCollection;
-import org.hibernate.engine.internal.StatefulPersistenceContext;
-import org.hibernate.engine.spi.EntityKey;
-import org.hibernate.engine.spi.PersistenceContext;
-import org.hibernate.engine.spi.SessionImplementor;
-import org.hibernate.engine.spi.SharedSessionContractImplementor;
-import org.hibernate.persister.entity.EntityPersister;
-import org.hibernate.reactive.logging.impl.Log;
-import org.hibernate.reactive.persister.entity.impl.ReactiveEntityPersister;
-import org.hibernate.reactive.session.ReactiveSession;
-
-import static java.lang.invoke.MethodHandles.lookup;
-import static org.hibernate.pretty.MessageHelper.infoString;
-import static org.hibernate.reactive.logging.impl.LoggerFactory.make;
-import static org.hibernate.reactive.util.impl.CompletionStages.completedFuture;
-import static org.hibernate.reactive.util.impl.CompletionStages.voidFuture;
-
-/**
- * Add reactive methods to a {@link PersistenceContext}.
- */
-public class ReactivePersistenceContextAdapter extends StatefulPersistenceContext {
-
- private static final Log LOG = make( Log.class, lookup() );
-
- private HashMap entitySnapshotsByKey;
-
- /**
- * Constructs a PersistentContext, bound to the given session.
- *
- * @param session The session "owning" this context.
- */
- public ReactivePersistenceContextAdapter(SharedSessionContractImplementor session) {
- super( session );
- }
-
- public CompletionStage reactiveInitializeNonLazyCollections() throws HibernateException {
- final NonLazyCollectionInitializer initializer = new NonLazyCollectionInitializer();
- initializeNonLazyCollections( initializer );
- return initializer.stage;
- }
-
- private class NonLazyCollectionInitializer implements Consumer> {
- CompletionStage stage = voidFuture();
-
- @Override
- public void accept(PersistentCollection> nonLazyCollection) {
- if ( !nonLazyCollection.wasInitialized() ) {
- stage = stage.thenCompose( v -> ( (ReactiveSession) getSession() )
- .reactiveInitializeCollection( nonLazyCollection, false ) );
- }
- }
- }
-
- /**
- * @deprecated use {@link #reactiveInitializeNonLazyCollections} instead.
- */
- @Deprecated
- @Override
- public void initializeNonLazyCollections() {
- // still called by ResultSetProcessorImpl, so can't throw UnsupportedOperationException
- }
-
- @Deprecated
- @Override
- public Object[] getDatabaseSnapshot(Object id, EntityPersister persister) throws HibernateException {
- throw LOG.nonReactiveMethodCall( "reactiveGetDatabaseSnapshot" );
- }
-
- private static final Object[] NO_ROW = new Object[]{ StatefulPersistenceContext.NO_ROW };
-
- public CompletionStage reactiveGetDatabaseSnapshot(Object id, EntityPersister persister)
- throws HibernateException {
-
- SessionImplementor session = (SessionImplementor) getSession();
- final EntityKey key = session.generateEntityKey( id, persister );
- final Object[] cached = entitySnapshotsByKey == null ? null : entitySnapshotsByKey.get( key );
- if ( cached != null ) {
- return completedFuture( cached == NO_ROW ? null : cached );
- }
- else {
- return ( (ReactiveEntityPersister) persister )
- .reactiveGetDatabaseSnapshot( id, session )
- .thenApply( snapshot -> {
- if ( entitySnapshotsByKey == null ) {
- entitySnapshotsByKey = new HashMap<>( 8 );
- }
- entitySnapshotsByKey.put( key, snapshot == null ? NO_ROW : snapshot );
- return snapshot;
- } );
- }
- }
-
- //All below methods copy/pasted from superclass because entitySnapshotsByKey is private:
-
- @Override
- public Object[] getCachedDatabaseSnapshot(EntityKey key) {
- final Object[] snapshot = entitySnapshotsByKey == null ? null : entitySnapshotsByKey.get( key );
- if ( snapshot == NO_ROW ) {
- throw new IllegalStateException(
- "persistence context reported no row snapshot for "
- + infoString( key.getEntityName(), key.getIdentifier() )
- );
- }
- return snapshot;
- }
-
- @Override
- public void clear() {
- super.clear();
- entitySnapshotsByKey = null;
- }
-
- @Override
- public Object removeEntity(EntityKey key) {
- Object result = super.removeEntity(key);
- if (entitySnapshotsByKey != null ) {
- entitySnapshotsByKey.remove(key);
- }
- return result;
- }
-}
diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/engine/jdbc/dialect/internal/ReactiveStandardDialectResolver.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/engine/jdbc/dialect/internal/ReactiveStandardDialectResolver.java
index 9964ffe93..d12791e5f 100644
--- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/engine/jdbc/dialect/internal/ReactiveStandardDialectResolver.java
+++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/engine/jdbc/dialect/internal/ReactiveStandardDialectResolver.java
@@ -8,61 +8,25 @@
import org.hibernate.dialect.CockroachDialect;
import org.hibernate.dialect.Database;
import org.hibernate.dialect.Dialect;
-import org.hibernate.dialect.DialectDelegateWrapper;
import org.hibernate.engine.jdbc.dialect.spi.DialectResolutionInfo;
import org.hibernate.engine.jdbc.dialect.spi.DialectResolver;
-import org.hibernate.engine.spi.SessionFactoryImplementor;
-import org.hibernate.persister.entity.mutation.EntityMutationTarget;
-import org.hibernate.reactive.dialect.ReactiveOracleSqlAstTranslator;
-import org.hibernate.sql.ast.SqlAstTranslator;
-import org.hibernate.sql.ast.SqlAstTranslatorFactory;
-import org.hibernate.sql.ast.spi.StandardSqlAstTranslatorFactory;
-import org.hibernate.sql.ast.tree.Statement;
-import org.hibernate.sql.exec.spi.JdbcOperation;
-import org.hibernate.sql.model.MutationOperation;
-import org.hibernate.sql.model.internal.OptionalTableUpdate;
-import static org.hibernate.dialect.CockroachDialect.parseVersion;
public class ReactiveStandardDialectResolver implements DialectResolver {
@Override
public Dialect resolveDialect(DialectResolutionInfo info) {
- // Hibernate ORM runs an extra query to recognize CockroachDB from PostgreSQL
- // We've already done it, so we are trying to skip that step
+ // Hibernate ORM runs an extra query to recognize CockroachDB from PostgresSQL
+ // We already did it when we created the DialectResolutionInfo in NoJdbcEnvironmentInitiator,
+ // so we can skip that step here.
if ( info.getDatabaseName().startsWith( "Cockroach" ) ) {
- return new CockroachDialect( parseVersion( info.getDatabaseVersion() ) );
+ return new CockroachDialect( info );
}
-
for ( Database database : Database.values() ) {
if ( database.matchesResolutionInfo( info ) ) {
- Dialect dialect = database.createDialect( info );
- if ( info.getDatabaseName().toUpperCase().startsWith( "ORACLE" ) ) {
- return new DialectDelegateWrapper( dialect ) {
- @Override
- public MutationOperation createOptionalTableUpdateOperation(
- EntityMutationTarget mutationTarget,
- OptionalTableUpdate optionalTableUpdate,
- SessionFactoryImplementor factory) {
- return new ReactiveOracleSqlAstTranslator<>( factory, optionalTableUpdate )
- .createMergeOperation( optionalTableUpdate );
- }
-
- @Override
- public SqlAstTranslatorFactory getSqlAstTranslatorFactory() {
- return new StandardSqlAstTranslatorFactory() {
- @Override
- protected SqlAstTranslator buildTranslator(SessionFactoryImplementor sessionFactory, Statement statement) {
- return new ReactiveOracleSqlAstTranslator<>( sessionFactory, statement );
- }
- };
- }
- };
- }
- return dialect;
+ return database.createDialect( info );
}
}
-
return null;
}
}
diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/engine/jdbc/env/internal/ReactiveJdbcEnvironment.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/engine/jdbc/env/internal/ReactiveJdbcEnvironment.java
deleted file mode 100644
index a8fd73a6a..000000000
--- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/engine/jdbc/env/internal/ReactiveJdbcEnvironment.java
+++ /dev/null
@@ -1,31 +0,0 @@
-/* Hibernate, Relational Persistence for Idiomatic Java
- *
- * SPDX-License-Identifier: Apache-2.0
- * Copyright: Red Hat Inc. and Hibernate Authors
- */
-package org.hibernate.reactive.engine.jdbc.env.internal;
-
-import java.sql.DatabaseMetaData;
-import java.sql.SQLException;
-
-import org.hibernate.dialect.Dialect;
-import org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentImpl;
-import org.hibernate.service.spi.ServiceRegistryImplementor;
-import org.hibernate.sql.ast.SqlAstTranslatorFactory;
-
-public class ReactiveJdbcEnvironment extends JdbcEnvironmentImpl {
-
- public ReactiveJdbcEnvironment(ServiceRegistryImplementor registry, Dialect dialect) {
- super( registry, dialect );
- }
-
- @Deprecated
- public ReactiveJdbcEnvironment(ServiceRegistryImplementor registry, Dialect dialect, DatabaseMetaData metaData) throws SQLException {
- super( registry, dialect, metaData );
- }
-
- @Override
- public SqlAstTranslatorFactory getSqlAstTranslatorFactory() {
- return super.getSqlAstTranslatorFactory();
- }
-}
diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/engine/jdbc/env/internal/ReactiveMutationExecutor.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/engine/jdbc/env/internal/ReactiveMutationExecutor.java
index fe9873791..3253be9dd 100644
--- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/engine/jdbc/env/internal/ReactiveMutationExecutor.java
+++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/engine/jdbc/env/internal/ReactiveMutationExecutor.java
@@ -10,7 +10,6 @@
import org.hibernate.dialect.DB2Dialect;
import org.hibernate.dialect.Dialect;
-import org.hibernate.dialect.DialectDelegateWrapper;
import org.hibernate.dialect.MySQLDialect;
import org.hibernate.dialect.OracleDialect;
import org.hibernate.dialect.SQLServerDialect;
@@ -104,15 +103,14 @@ default CompletionStage performReactiveBatchedOperations(
private static String createInsert(String insertSql, String identifierColumnName, Dialect dialect) {
String sql = insertSql;
final String sqlEnd = " returning " + identifierColumnName;
- Dialect realDialect = DialectDelegateWrapper.extractRealDialect( dialect );
- if ( realDialect instanceof MySQLDialect ) {
+ if ( dialect instanceof MySQLDialect ) {
// For some reason ORM generates a query with an invalid syntax
int index = sql.lastIndexOf( sqlEnd );
return index > -1
? sql.substring( 0, index )
: sql;
}
- if ( realDialect instanceof SQLServerDialect ) {
+ if ( dialect instanceof SQLServerDialect ) {
int index = sql.lastIndexOf( sqlEnd );
// FIXME: this is a hack for HHH-16365
if ( index > -1 ) {
@@ -128,12 +126,12 @@ private static String createInsert(String insertSql, String identifierColumnName
}
return sql;
}
- if ( realDialect instanceof DB2Dialect ) {
+ if ( dialect instanceof DB2Dialect ) {
// ORM query: select id from new table ( insert into IntegerTypeEntity values ( ))
// Correct : select id from new table ( insert into LongTypeEntity (id) values (default))
return sql.replace( " values ( ))", " (" + identifierColumnName + ") values (default))" );
}
- if ( realDialect instanceof OracleDialect ) {
+ if ( dialect instanceof OracleDialect ) {
final String valuesStr = " values ( )";
int index = sql.lastIndexOf( sqlEnd );
// remove "returning id" since it's added via
diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/engine/jdbc/mutation/internal/ReactiveMutationExecutorStandard.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/engine/jdbc/mutation/internal/ReactiveMutationExecutorStandard.java
index 80e24fac7..0a09ff3a1 100644
--- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/engine/jdbc/mutation/internal/ReactiveMutationExecutorStandard.java
+++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/engine/jdbc/mutation/internal/ReactiveMutationExecutorStandard.java
@@ -5,10 +5,7 @@
*/
package org.hibernate.reactive.engine.jdbc.mutation.internal;
-import java.lang.invoke.MethodHandles;
-import java.sql.SQLException;
-import java.util.concurrent.CompletionStage;
-
+import org.hibernate.engine.jdbc.batch.spi.Batch;
import org.hibernate.engine.jdbc.mutation.JdbcValueBindings;
import org.hibernate.engine.jdbc.mutation.OperationResultChecker;
import org.hibernate.engine.jdbc.mutation.ParameterUsage;
@@ -24,6 +21,7 @@
import org.hibernate.persister.entity.mutation.EntityTableMapping;
import org.hibernate.reactive.adaptor.impl.PrepareStatementDetailsAdaptor;
import org.hibernate.reactive.adaptor.impl.PreparedStatementAdaptor;
+import org.hibernate.reactive.engine.jdbc.ResultsCheckerUtil;
import org.hibernate.reactive.engine.jdbc.env.internal.ReactiveMutationExecutor;
import org.hibernate.reactive.generator.values.ReactiveGeneratedValuesMutationDelegate;
import org.hibernate.reactive.logging.impl.Log;
@@ -36,9 +34,16 @@
import org.hibernate.sql.model.TableMapping;
import org.hibernate.sql.model.ValuesAnalysis;
+import java.lang.invoke.MethodHandles;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.CompletionStage;
+
import static org.hibernate.engine.jdbc.mutation.internal.ModelMutationHelper.checkResults;
import static org.hibernate.reactive.logging.impl.LoggerFactory.make;
import static org.hibernate.reactive.util.impl.CompletionStages.failedFuture;
+import static org.hibernate.reactive.util.impl.CompletionStages.loop;
import static org.hibernate.reactive.util.impl.CompletionStages.nullFuture;
import static org.hibernate.reactive.util.impl.CompletionStages.voidFuture;
import static org.hibernate.sql.model.ModelMutationLogging.MODEL_MUTATION_LOGGER;
@@ -72,10 +77,64 @@ private ReactiveConnection connection(SharedSessionContractImplementor session)
@Override
public CompletionStage performReactiveBatchedOperations(
ValuesAnalysis valuesAnalysis,
- TableInclusionChecker inclusionChecker, OperationResultChecker resultChecker,
+ TableInclusionChecker inclusionChecker,
+ OperationResultChecker resultChecker,
SharedSessionContractImplementor session) {
- return ReactiveMutationExecutor.super
- .performReactiveBatchedOperations( valuesAnalysis, inclusionChecker, resultChecker, session);
+ final PreparedStatementGroup batchedMutationOperationGroup = getBatchedPreparedStatementGroup();
+ if ( batchedMutationOperationGroup != null ) {
+ final List preparedStatementDetailsList = new ArrayList<>(
+ batchedMutationOperationGroup.getNumberOfStatements() );
+ batchedMutationOperationGroup.forEachStatement( (tableName, statementDetails) -> preparedStatementDetailsList
+ .add( statementDetails ) );
+ return loop( preparedStatementDetailsList, statementDetails -> {
+ if ( statementDetails == null ) {
+ return voidFuture();
+ }
+ final JdbcValueBindings valueBindings = getJdbcValueBindings();
+ final TableMapping tableDetails = statementDetails.getMutatingTableDetails();
+ if ( inclusionChecker != null && !inclusionChecker.include( tableDetails ) ) {
+ if ( MODEL_MUTATION_LOGGER.isTraceEnabled() ) {
+ MODEL_MUTATION_LOGGER.tracef(
+ "Skipping execution of secondary insert : %s",
+ tableDetails.getTableName()
+ );
+ }
+ return voidFuture();
+ }
+
+ // If we get here the statement is needed - make sure it is resolved
+ final Object[] paramValues = PreparedStatementAdaptor.bind( statement -> {
+ PreparedStatementDetails details = new PrepareStatementDetailsAdaptor(
+ statementDetails,
+ statement,
+ session.getJdbcServices()
+ );
+ valueBindings.beforeStatement( details );
+ } );
+
+ final ReactiveConnection reactiveConnection = ( (ReactiveConnectionSupplier) session ).getReactiveConnection();
+ final String sql = statementDetails.getSqlString();
+ return reactiveConnection.update(
+ sql,
+ paramValues,
+ true,
+ (rowCount, batchPosition, query) -> ResultsCheckerUtil.checkResults(
+ session,
+ statementDetails,
+ resultChecker,
+ rowCount,
+ batchPosition
+ )
+ ).whenComplete( (o, throwable) -> { //TODO: is this part really needed?
+ if ( statementDetails.getStatement() != null ) {
+ statementDetails.releaseStatement( session );
+ }
+ valueBindings.afterStatement( tableDetails );
+ } );
+ }
+ );
+ }
+ return voidFuture();
}
@Override
@@ -99,7 +158,8 @@ protected void performSelfExecutingOperations(
@Override
protected void performBatchedOperations(
ValuesAnalysis valuesAnalysis,
- TableInclusionChecker inclusionChecker) {
+ TableInclusionChecker inclusionChecker,
+ Batch.StaleStateMapper staleStateMapper) {
throw LOG.nonReactiveMethodCall( "performReactiveBatchedOperations" );
}
@@ -157,6 +217,23 @@ public CompletionStage performReactiveNonBatchedOperations(
}
}
+ @Override
+ public CompletionStage performReactiveSelfExecutingOperations(
+ ValuesAnalysis valuesAnalysis,
+ TableInclusionChecker inclusionChecker,
+ SharedSessionContractImplementor session) {
+ if ( getSelfExecutingMutations() == null || getSelfExecutingMutations().isEmpty() ) {
+ return voidFuture();
+ }
+
+ return loop( getSelfExecutingMutations(), operation -> {
+ if ( inclusionChecker.include( operation.getTableDetails() ) ) {
+ operation.performMutation( getJdbcValueBindings(), valuesAnalysis, session );
+ }
+ return voidFuture();
+ });
+ }
+
private class OperationsForEach {
private final Object id;
@@ -208,6 +285,7 @@ public CompletionStage buildLoop() {
return loop;
}
}
+
@Override
public CompletionStage performReactiveNonBatchedMutation(
PreparedStatementDetails statementDetails,
diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/engine/spi/ReactiveSharedSessionContractImplementor.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/engine/spi/ReactiveSharedSessionContractImplementor.java
index 1ab340380..9bdc5742a 100644
--- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/engine/spi/ReactiveSharedSessionContractImplementor.java
+++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/engine/spi/ReactiveSharedSessionContractImplementor.java
@@ -9,6 +9,7 @@
import java.util.concurrent.CompletionStage;
+import org.hibernate.collection.spi.PersistentCollection;
import org.hibernate.engine.spi.PersistenceContext;
import static org.hibernate.reactive.util.impl.CompletionStages.falseFuture;
@@ -22,5 +23,9 @@ default CompletionStage reactiveAutoFlushIfRequired(Set querySp
return falseFuture();
}
+ CompletionStage reactiveImmediateLoad(String entityName, Object id);
+
+ CompletionStage reactiveInitializeCollection(PersistentCollection> collection, boolean writing);
+
PersistenceContext getPersistenceContext();
}
diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/event/ReactiveResolveNaturalIdEventListener.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/event/ReactiveResolveNaturalIdEventListener.java
deleted file mode 100644
index fe0fbb96a..000000000
--- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/event/ReactiveResolveNaturalIdEventListener.java
+++ /dev/null
@@ -1,29 +0,0 @@
-/* Hibernate, Relational Persistence for Idiomatic Java
- *
- * SPDX-License-Identifier: Apache-2.0
- * Copyright: Red Hat Inc. and Hibernate Authors
- */
-package org.hibernate.reactive.event;
-
-import org.hibernate.event.spi.ResolveNaturalIdEvent;
-
-import java.util.concurrent.CompletionStage;
-
-/**
- * Defines the contract for handling of resolve natural id events generated from a session.
- *
- * @author Eric Dalquist
- * @author Steve Ebersole
- *
- * @see org.hibernate.event.spi.ResolveNaturalIdEventListener
- */
-public interface ReactiveResolveNaturalIdEventListener {
-
- /**
- * Handle the given resolve natural id event.
- *
- * @param event The resolve natural id event to be handled.
- */
- CompletionStage onReactiveResolveNaturalId(ResolveNaturalIdEvent event);
-
-}
diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/event/impl/AbstractReactiveFlushingEventListener.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/event/impl/AbstractReactiveFlushingEventListener.java
index 2772cc15d..9e4ac049d 100644
--- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/event/impl/AbstractReactiveFlushingEventListener.java
+++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/event/impl/AbstractReactiveFlushingEventListener.java
@@ -74,7 +74,7 @@ private ReactiveActionQueue actionQueue(EventSource session) {
/**
* Coordinates the processing necessary to get things ready for executions
- * as db calls by preping the session caches and moving the appropriate
+ * as db calls by prepping the session caches and moving the appropriate
* entities and collections to their respective execution queues.
*
* @param event The flush event.
@@ -139,9 +139,8 @@ protected void logFlushResults(FlushEvent event) {
session.getActionQueue().numberOfCollectionRemovals(),
persistenceContext.getCollectionEntriesSize()
);
- new EntityPrinter( session.getFactory() ).toString(
- persistenceContext.getEntityHoldersByKey().entrySet()
- );
+ new EntityPrinter( session.getFactory() )
+ .logEntities( persistenceContext.getEntityHoldersByKey().entrySet() );
}
/**
@@ -227,7 +226,7 @@ private int flushEntities(final FlushEvent event, final PersistenceContext persi
final EventSource source = event.getSession();
final Iterable flushListeners =
source.getFactory()
- .getFastSessionServices()
+ .getEventListenerGroups()
.eventListenerGroup_FLUSH_ENTITY
.listeners();
diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/event/impl/AbstractReactiveSaveEventListener.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/event/impl/AbstractReactiveSaveEventListener.java
index e9d68b00e..6ca8a8ec2 100644
--- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/event/impl/AbstractReactiveSaveEventListener.java
+++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/event/impl/AbstractReactiveSaveEventListener.java
@@ -25,7 +25,7 @@
import org.hibernate.event.spi.EventSource;
import org.hibernate.generator.BeforeExecutionGenerator;
import org.hibernate.generator.Generator;
-import org.hibernate.id.Assigned;
+import org.hibernate.id.CompositeNestedGeneratedValueGenerator;
import org.hibernate.id.IdentifierGenerationException;
import org.hibernate.jpa.event.spi.CallbackRegistry;
import org.hibernate.jpa.event.spi.CallbackRegistryConsumer;
@@ -134,7 +134,7 @@ protected CompletionStage reactiveSaveWithGeneratedId(
// and is not yet available
generatedId = null;
}
- else if ( generator instanceof Assigned ) {
+ else if ( !generator.generatesOnInsert() ) {
// get it from the entity later, since we need
// the @PrePersist callback to happen first
generatedId = null;
@@ -144,55 +144,57 @@ else if ( generator instanceof Assigned ) {
// the entity instance, so it will be available
// to the entity in the @PrePersist callback
if ( generator instanceof ReactiveIdentifierGenerator ) {
- return ( (ReactiveIdentifierGenerator>) generator )
- .generate( ( ReactiveConnectionSupplier ) source, entity )
- .thenApply( id -> castToIdentifierType( id, persister ) )
- .thenCompose( gid -> performSaveWithId(
- entity,
- context,
- source,
- persister,
- generator,
- gid,
- requiresImmediateIdAccess,
- false
- ) );
+ return generateId( entity, source, (ReactiveIdentifierGenerator>) generator, persister )
+ .thenCompose( gid -> {
+ if ( gid == SHORT_CIRCUIT_INDICATOR ) {
+ source.getIdentifier( entity );
+ return voidFuture();
+ }
+ persister.setIdentifier( entity, gid, source );
+ return reactivePerformSave(
+ entity,
+ gid,
+ persister,
+ generatedOnExecution,
+ context,
+ source,
+ false
+ );
+ } );
}
generatedId = ( (BeforeExecutionGenerator) generator ).generate( source, entity, null, INSERT );
+ if ( generatedId == SHORT_CIRCUIT_INDICATOR ) {
+ source.getIdentifier( entity );
+ return voidFuture();
+ }
+ persister.setIdentifier( entity, generatedId, source );
}
final Object id = castToIdentifierType( generatedId, persister );
- return reactivePerformSave( entity, id, persister, generatedOnExecution, context, source, requiresImmediateIdAccess );
+ final boolean delayIdentityInserts = !source.isTransactionInProgress() && !requiresImmediateIdAccess && generatedOnExecution;
+ return reactivePerformSave( entity, id, persister, generatedOnExecution, context, source, delayIdentityInserts );
}
- private CompletionStage performSaveWithId(
+ private CompletionStage generateId(
Object entity,
- C context,
EventSource source,
- EntityPersister persister,
- Generator generator,
- Object generatedId,
- boolean requiresImmediateIdAccess,
- boolean generatedOnExecution) {
- if ( generatedId == null ) {
- throw new IdentifierGenerationException( "null id generated for: " + entity.getClass() );
- }
- if ( generatedId == SHORT_CIRCUIT_INDICATOR ) {
- source.getIdentifier( entity );
- return voidFuture();
- }
- if ( LOG.isDebugEnabled() ) {
- LOG.debugf(
- "Generated identifier: %s, using strategy: %s",
- persister.getIdentifierType().toLoggableString( generatedId, source.getFactory() ),
- generator.getClass().getName()
- );
- }
- final boolean delayIdentityInserts =
- !source.isTransactionInProgress()
- && !requiresImmediateIdAccess
- && generatedOnExecution;
- return reactivePerformSave( entity, generatedId, persister, false, context, source, delayIdentityInserts );
+ ReactiveIdentifierGenerator> generator,
+ EntityPersister persister) {
+ return generator.generate( (ReactiveConnectionSupplier) source, entity )
+ .thenApply( id -> {
+ final Object generatedId = castToIdentifierType( id, persister );
+ if ( generatedId == null ) {
+ throw new IdentifierGenerationException( "null id generated for: " + entity.getClass() );
+ }
+ if ( LOG.isDebugEnabled() ) {
+ LOG.debugf(
+ "Generated identifier: %s, using strategy: %s",
+ persister.getIdentifierType().toLoggableString( generatedId, source.getFactory() ),
+ generator.getClass().getName()
+ );
+ }
+ return generatedId;
+ } );
}
/**
@@ -229,13 +231,11 @@ protected CompletionStage reactivePerformSave(
processIfSelfDirtinessTracker( entity, SelfDirtinessTracker::$$_hibernate_clearDirtyAttributes );
processIfManagedEntity( entity, managedEntity -> managedEntity.$$_hibernate_setUseTracker( true ) );
- if ( persister.getGenerator() instanceof Assigned ) {
+ final Generator generator = persister.getGenerator();
+ if ( !generator.generatesOnInsert() || generator instanceof CompositeNestedGeneratedValueGenerator ) {
id = persister.getIdentifier( entity, source );
if ( id == null ) {
- throw new IdentifierGenerationException(
- "Identifier of entity '" + persister.getEntityName()
- + "' must be manually assigned before calling 'persist()'"
- );
+ return failedFuture( new IdentifierGenerationException( "Identifier of entity '" + persister.getEntityName() + "' must be manually assigned before calling 'persist()'" ) );
}
}
@@ -420,7 +420,7 @@ private CompletionStage addInsertAction(
boolean useIdentityColumn,
EventSource source,
boolean shouldDelayIdentityInserts) {
- final ReactiveActionQueue actionQueue = source.unwrap( ReactiveSession.class ).getReactiveActionQueue();
+ final ReactiveActionQueue actionQueue = source.unwrap(ReactiveSession.class).getReactiveActionQueue();
if ( useIdentityColumn ) {
final ReactiveEntityIdentityInsertAction insert = new ReactiveEntityIdentityInsertAction(
values, entity, persister, false, source, shouldDelayIdentityInserts
diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/event/impl/DefaultReactiveDeleteEventListener.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/event/impl/DefaultReactiveDeleteEventListener.java
index 66151f03b..1dbf6db02 100644
--- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/event/impl/DefaultReactiveDeleteEventListener.java
+++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/event/impl/DefaultReactiveDeleteEventListener.java
@@ -13,7 +13,6 @@
import org.hibernate.TransientObjectException;
import org.hibernate.bytecode.enhance.spi.LazyPropertyInitializer;
import org.hibernate.bytecode.spi.BytecodeEnhancementMetadata;
-import org.hibernate.classic.Lifecycle;
import org.hibernate.engine.internal.CascadePoint;
import org.hibernate.engine.internal.Nullability;
import org.hibernate.engine.spi.EntityEntry;
@@ -22,13 +21,13 @@
import org.hibernate.engine.spi.Status;
import org.hibernate.event.internal.OnUpdateVisitor;
import org.hibernate.event.internal.PostDeleteEventListenerStandardImpl;
+import org.hibernate.event.service.spi.EventListenerGroups;
import org.hibernate.event.service.spi.JpaBootstrapSensitive;
import org.hibernate.event.spi.DeleteContext;
import org.hibernate.event.spi.DeleteEvent;
import org.hibernate.event.spi.DeleteEventListener;
import org.hibernate.event.spi.EventSource;
import org.hibernate.internal.EmptyInterceptor;
-import org.hibernate.internal.FastSessionServices;
import org.hibernate.jpa.event.spi.CallbackRegistry;
import org.hibernate.jpa.event.spi.CallbackRegistryConsumer;
import org.hibernate.jpa.event.spi.CallbackType;
@@ -48,6 +47,7 @@
import org.hibernate.reactive.event.ReactiveDeleteEventListener;
import org.hibernate.reactive.logging.impl.Log;
import org.hibernate.reactive.logging.impl.LoggerFactory;
+import org.hibernate.reactive.session.ReactiveQueryProducer;
import org.hibernate.reactive.session.ReactiveSession;
import org.hibernate.type.CollectionType;
import org.hibernate.type.CompositeType;
@@ -199,23 +199,12 @@ private CompletionStage fetchAndDelete(DeleteEvent event, DeleteContext tr
}
//Object entity = persistenceContext.unproxyAndReassociate( event.getObject() );
- return ( (ReactiveSession) source )
+ return ( (ReactiveQueryProducer) source )
.reactiveFetch( objectEvent, true )
.thenCompose( entity -> delete( event, transientEntities, entity ) );
}
- protected boolean invokeDeleteLifecycle(EventSource session, Object entity, EntityPersister persister) {
- if ( persister.implementsLifecycle() ) {
- LOG.debug( "Calling onDelete()" );
- if ( ( (Lifecycle) entity ).onDelete( session ) ) {
- LOG.debug( "Deletion vetoed by onDelete()" );
- return true;
- }
- }
- return false;
- }
-
private CompletionStage deleteTransientInstance(DeleteEvent event, DeleteContext transientEntities, Object entity) {
LOG.trace( "Entity was not persistent in delete processing" );
@@ -291,23 +280,20 @@ private CompletionStage delete(
Object version,
EntityEntry entry) {
callbackRegistry.preRemove( entity );
- if ( !invokeDeleteLifecycle( source, entity, persister ) ) {
- return deleteEntity(
- source,
- entity,
- entry,
- event.isCascadeDeleteEnabled(),
- event.isOrphanRemovalBeforeUpdates(),
- persister,
- transientEntities
- )
- .thenAccept( v -> {
- if ( source.getFactory().getSessionFactoryOptions().isIdentifierRollbackEnabled() ) {
- persister.resetIdentifier( entity, id, version, source );
- }
- } );
- }
- return voidFuture();
+ return deleteEntity(
+ source,
+ entity,
+ entry,
+ event.isCascadeDeleteEnabled(),
+ event.isOrphanRemovalBeforeUpdates(),
+ persister,
+ transientEntities
+ )
+ .thenAccept( v -> {
+ if ( source.getFactory().getSessionFactoryOptions().isIdentifierRollbackEnabled() ) {
+ persister.resetIdentifier( entity, id, version, source );
+ }
+ } );
}
/**
@@ -315,7 +301,6 @@ private CompletionStage delete(
*/
private boolean canBeDeletedWithoutLoading(EventSource source, EntityPersister persister) {
return source.getInterceptor() == EmptyInterceptor.INSTANCE
- && !persister.implementsLifecycle()
&& !persister.hasSubclasses() //TODO: should be unnecessary, using EntityPersister.getSubclassPropertyTypeClosure(), etc
&& !persister.hasCascadeDelete()
&& !persister.hasNaturalIdentifier()
@@ -325,7 +310,7 @@ private boolean canBeDeletedWithoutLoading(EventSource source, EntityPersister p
}
private static boolean hasCustomEventListeners(EventSource source) {
- final FastSessionServices fss = source.getFactory().getFastSessionServices();
+ final EventListenerGroups fss = source.getFactory().getEventListenerGroups();
// Bean Validation adds a PRE_DELETE listener
// and Envers adds a POST_DELETE listener
return fss.eventListenerGroup_PRE_DELETE.count() > 0
@@ -452,11 +437,8 @@ protected CompletionStage deleteEntity(
persister
).nullifyTransientReferences( entityEntry.getDeletedState() )
.thenAccept( vv -> {
- new Nullability( session ).checkNullability(
- entityEntry.getDeletedState(),
- persister,
- Nullability.NullabilityCheckType.DELETE
- );
+ new Nullability( session, Nullability.NullabilityCheckType.DELETE )
+ .checkNullability( entityEntry.getDeletedState(), persister );
persistenceContext.registerNullifiableEntityKey( key );
final ReactiveActionQueue actionQueue = actionQueue( session );
diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/event/impl/DefaultReactiveInitializeCollectionEventListener.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/event/impl/DefaultReactiveInitializeCollectionEventListener.java
index 20466abd2..5547fcc74 100644
--- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/event/impl/DefaultReactiveInitializeCollectionEventListener.java
+++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/event/impl/DefaultReactiveInitializeCollectionEventListener.java
@@ -23,9 +23,9 @@
import org.hibernate.reactive.logging.impl.Log;
import org.hibernate.reactive.logging.impl.LoggerFactory;
import org.hibernate.reactive.persister.collection.impl.ReactiveCollectionPersister;
-import org.hibernate.sql.results.internal.ResultsHelper;
import org.hibernate.stat.spi.StatisticsImplementor;
+import static org.hibernate.event.internal.DefaultInitializeCollectionEventListener.handlePotentiallyEmptyCollection;
import static org.hibernate.pretty.MessageHelper.collectionInfoString;
import static org.hibernate.reactive.util.impl.CompletionStages.failedFuture;
import static org.hibernate.reactive.util.impl.CompletionStages.voidFuture;
@@ -59,7 +59,8 @@ public CompletionStage onReactiveInitializeCollection(InitializeCollection
final CollectionPersister loadedPersister = ce.getLoadedPersister();
final Object loadedKey = ce.getLoadedKey();
if ( LOG.isTraceEnabled() ) {
- LOG.tracev( "Initializing collection {0}", collectionInfoString( loadedPersister, collection, loadedKey, source ) );
+ LOG.tracev( "Initializing collection {0}",
+ collectionInfoString( loadedPersister, collection, loadedKey, source ) );
LOG.trace( "Checking second-level cache" );
}
@@ -76,11 +77,8 @@ public CompletionStage onReactiveInitializeCollection(InitializeCollection
}
return ( (ReactiveCollectionPersister) loadedPersister )
.reactiveInitialize( loadedKey, source )
- .thenApply( list -> {
- handlePotentiallyEmptyCollection( collection, source, ce, loadedPersister );
- return list;
- } )
- .thenAccept( list -> {
+ .thenAccept( v -> {
+ handlePotentiallyEmptyCollection( collection, source.getPersistenceContext(), ce, loadedPersister );
if ( LOG.isTraceEnabled() ) {
LOG.trace( "Collection initialized" );
}
@@ -93,23 +91,6 @@ public CompletionStage onReactiveInitializeCollection(InitializeCollection
}
}
- private void handlePotentiallyEmptyCollection(
- PersistentCollection> collection,
- SessionImplementor source,
- CollectionEntry ce,
- CollectionPersister loadedPersister) {
- if ( !collection.wasInitialized() ) {
- collection.initializeEmptyCollection( loadedPersister );
- ResultsHelper.finalizeCollectionLoading(
- source.getPersistenceContext(),
- loadedPersister,
- collection,
- ce.getLoadedKey(),
- true
- );
- }
- }
-
/**
* Try to initialize a collection from the cache
*
diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/event/impl/DefaultReactiveLoadEventListener.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/event/impl/DefaultReactiveLoadEventListener.java
index 8f821a986..9804a02f6 100644
--- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/event/impl/DefaultReactiveLoadEventListener.java
+++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/event/impl/DefaultReactiveLoadEventListener.java
@@ -27,8 +27,7 @@
import org.hibernate.event.spi.EventSource;
import org.hibernate.event.spi.LoadEvent;
import org.hibernate.event.spi.LoadEventListener;
-import org.hibernate.loader.ast.internal.CacheEntityLoaderHelper;
-import org.hibernate.loader.ast.internal.CacheEntityLoaderHelper.PersistenceContextEntry;
+import org.hibernate.loader.internal.CacheLoadHelper;
import org.hibernate.metamodel.mapping.AttributeMapping;
import org.hibernate.metamodel.mapping.AttributeMappingsList;
import org.hibernate.metamodel.mapping.CompositeIdentifierMapping;
@@ -40,7 +39,6 @@
import org.hibernate.proxy.HibernateProxy;
import org.hibernate.proxy.LazyInitializer;
import org.hibernate.reactive.event.ReactiveLoadEventListener;
-import org.hibernate.reactive.loader.entity.ReactiveCacheEntityLoaderHelper;
import org.hibernate.reactive.logging.impl.Log;
import org.hibernate.reactive.logging.impl.LoggerFactory;
import org.hibernate.reactive.persister.entity.impl.ReactiveEntityPersister;
@@ -49,7 +47,10 @@
import static org.hibernate.engine.internal.ManagedTypeHelper.asPersistentAttributeInterceptable;
import static org.hibernate.engine.internal.ManagedTypeHelper.isPersistentAttributeInterceptable;
+import static org.hibernate.loader.internal.CacheLoadHelper.loadFromSecondLevelCache;
+import static org.hibernate.loader.internal.CacheLoadHelper.loadFromSessionCache;
import static org.hibernate.pretty.MessageHelper.infoString;
+import static org.hibernate.proxy.HibernateProxy.extractLazyInitializer;
import static org.hibernate.reactive.session.impl.SessionUtil.checkEntityFound;
import static org.hibernate.reactive.session.impl.SessionUtil.throwEntityNotFound;
import static org.hibernate.reactive.util.impl.CompletionStages.completedFuture;
@@ -399,7 +400,7 @@ private static CompletionStage loadWithProxyFactory(LoadEvent event, Ent
if ( proxy != null ) {
LOG.trace( "Entity proxy found in session cache" );
- if ( LOG.isDebugEnabled() && HibernateProxy.extractLazyInitializer( proxy ).isUnwrap() ) {
+ if ( LOG.isDebugEnabled() && extractLazyInitializer( proxy ).isUnwrap() ) {
LOG.debug( "Ignoring NO_PROXY to honor laziness" );
}
@@ -429,7 +430,7 @@ private static PersistentAttributeInterceptable createBatchLoadableEnhancedProxy
}
private static Object proxyOrCached(LoadEvent event, EntityPersister persister, EntityKey keyToLoad) {
- final Object cachedEntity = CacheEntityLoaderHelper.INSTANCE.loadFromSecondLevelCache(
+ final Object cachedEntity = loadFromSecondLevelCache(
event.getSession(),
null,
LockMode.NONE,
@@ -450,7 +451,7 @@ private static Object proxyOrCached(LoadEvent event, EntityPersister persister,
return options.isCheckDeleted() && wasDeleted( persistenceContext, existing ) ? null : existing;
}
if ( persister.hasSubclasses() ) {
- final Object cachedEntity = CacheEntityLoaderHelper.INSTANCE.loadFromSecondLevelCache(
+ final Object cachedEntity = loadFromSecondLevelCache(
event.getSession(),
null,
LockMode.NONE,
@@ -652,9 +653,9 @@ private CompletionStage doLoad(
return nullFuture();
}
else {
- final PersistenceContextEntry persistenceContextEntry =
- ReactiveCacheEntityLoaderHelper.INSTANCE.loadFromSessionCache( event, keyToLoad, options );
- final Object entity = persistenceContextEntry.getEntity();
+ final CacheLoadHelper.PersistenceContextEntry persistenceContextEntry =
+ loadFromSessionCache( keyToLoad, event.getLockOptions(), options, event.getSession() );
+ final Object entity = persistenceContextEntry.entity();
if ( entity != null ) {
return persistenceContextEntry.isManaged() ? initializeIfNecessary( entity ) : nullFuture();
}
@@ -668,9 +669,7 @@ private static CompletionStage initializeIfNecessary(Object entity) {
if ( isPersistentAttributeInterceptable( entity ) ) {
final PersistentAttributeInterceptable interceptable = asPersistentAttributeInterceptable( entity );
final PersistentAttributeInterceptor interceptor = interceptable.$$_hibernate_getInterceptor();
- if ( interceptor instanceof EnhancementAsProxyLazinessInterceptor) {
- final EnhancementAsProxyLazinessInterceptor lazinessInterceptor =
- (EnhancementAsProxyLazinessInterceptor) interceptor;
+ if ( interceptor instanceof EnhancementAsProxyLazinessInterceptor lazinessInterceptor ) {
final SharedSessionContractImplementor session = lazinessInterceptor.getLinkedSession();
if ( session == null ) {
throw LOG.sessionClosedLazyInitializationException();
@@ -691,7 +690,8 @@ private CompletionStage loadFromCacheOrDatasource(
EntityPersister persister,
EntityKey keyToLoad) {
final EventSource session = event.getSession();
- final Object entity = CacheEntityLoaderHelper.INSTANCE.loadFromSecondLevelCache(event, persister, keyToLoad);
+ final Object entity = session
+ .loadFromSecondLevelCache( persister, keyToLoad, event.getInstanceToLoad(), event.getLockMode() );
if ( entity != null ) {
if ( LOG.isTraceEnabled() ) {
LOG.tracev(
@@ -740,6 +740,10 @@ private void cacheNaturalId(LoadEvent event, EntityPersister persister, EventSou
* @return The object loaded from the datasource, or null if not found.
*/
protected CompletionStage loadFromDatasource(LoadEvent event, EntityPersister persister) {
+ if ( LOG.isTraceEnabled() ) {
+ LOG.trace( "Entity not resolved in any cache, loading from datastore: "
+ + infoString( persister, event.getEntityId(), event.getFactory() ) );
+ }
return ( (ReactiveEntityPersister) persister )
.reactiveLoad(
event.getEntityId(),
@@ -754,16 +758,14 @@ protected CompletionStage loadFromDatasource(LoadEvent event, EntityPers
// persister/loader/initializer sensitive to this fact - possibly
// passing LoadType along
- final LazyInitializer lazyInitializer = HibernateProxy.extractLazyInitializer( entity );
- if ( lazyInitializer != null ) {
- entity = lazyInitializer.getImplementation();
- }
+ final LazyInitializer lazyInitializer = extractLazyInitializer( entity );
+ final Object impl = lazyInitializer != null ? lazyInitializer.getImplementation() : entity;
final StatisticsImplementor statistics = event.getSession().getFactory().getStatistics();
if ( event.isAssociationFetch() && statistics.isStatisticsEnabled() ) {
statistics.fetchEntity( event.getEntityClassName() );
}
- return entity;
+ return impl;
} );
}
}
diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/event/impl/DefaultReactiveLockEventListener.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/event/impl/DefaultReactiveLockEventListener.java
index 7832298e0..ffd0fcfde 100644
--- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/event/impl/DefaultReactiveLockEventListener.java
+++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/event/impl/DefaultReactiveLockEventListener.java
@@ -5,7 +5,6 @@
*/
package org.hibernate.reactive.event.impl;
-import java.lang.invoke.MethodHandles;
import java.util.concurrent.CompletionStage;
import org.hibernate.HibernateException;
@@ -20,7 +19,7 @@
import org.hibernate.engine.spi.PersistenceContext;
import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.engine.spi.Status;
-import org.hibernate.event.internal.AbstractReassociateEventListener;
+import org.hibernate.event.internal.DefaultLockEventListener;
import org.hibernate.event.spi.EventSource;
import org.hibernate.event.spi.LockEvent;
import org.hibernate.event.spi.LockEventListener;
@@ -33,19 +32,25 @@
import org.hibernate.reactive.engine.impl.ReactiveEntityVerifyVersionProcess;
import org.hibernate.reactive.event.ReactiveLockEventListener;
import org.hibernate.reactive.logging.impl.Log;
-import org.hibernate.reactive.logging.impl.LoggerFactory;
import org.hibernate.reactive.persister.entity.impl.ReactiveEntityPersister;
+import org.hibernate.reactive.session.ReactiveQueryProducer;
import org.hibernate.reactive.session.ReactiveSession;
+import static java.lang.invoke.MethodHandles.lookup;
import static org.hibernate.pretty.MessageHelper.infoString;
+import static org.hibernate.reactive.logging.impl.LoggerFactory.make;
import static org.hibernate.reactive.util.impl.CompletionStages.completedFuture;
import static org.hibernate.reactive.util.impl.CompletionStages.failedFuture;
import static org.hibernate.reactive.util.impl.CompletionStages.voidFuture;
-public class DefaultReactiveLockEventListener extends AbstractReassociateEventListener
- implements LockEventListener, ReactiveLockEventListener {
+public class DefaultReactiveLockEventListener extends DefaultLockEventListener implements LockEventListener, ReactiveLockEventListener {
- private static final Log LOG = LoggerFactory.make( Log.class, MethodHandles.lookup() );
+ private static final Log LOG = make( Log.class, lookup() );
+
+ @Override
+ public void onLock(LockEvent event) throws HibernateException {
+ throw LOG.nonReactiveMethodCall( "reactiveOnLock" );
+ }
@Override
public CompletionStage reactiveOnLock(LockEvent event) throws HibernateException {
@@ -76,7 +81,7 @@ public CompletionStage reactiveOnLock(LockEvent event) throws HibernateExc
//TODO: if object was an uninitialized proxy, this is inefficient,
// resulting in two SQL selects
- return ( (ReactiveSession) source ).reactiveFetch( event.getObject(), true )
+ return ( (ReactiveQueryProducer) source ).reactiveFetch( event.getObject(), true )
.thenCompose( entity -> reactiveOnLock( event, entity ) );
}
@@ -96,11 +101,13 @@ private CompletionStage lockEntry(
if ( entry == null ) {
final EntityPersister persister = source.getEntityPersister( event.getEntityName(), entity );
final Object id = persister.getIdentifier( entity, source );
- return ForeignKeys.isNotTransient( event.getEntityName(), entity, Boolean.FALSE, source )
+ return ForeignKeys
+ .isNotTransient( event.getEntityName(), entity, Boolean.FALSE, source )
.thenCompose( trans -> {
if ( !trans ) {
return failedFuture( new TransientObjectException(
- "cannot lock an unsaved transient instance: " + persister.getEntityName() ) );
+ "Cannot lock unsaved transient instance of entity '" + persister.getEntityName() + "'"
+ ) );
}
final EntityEntry e = reassociate( event, entity, id, persister );
@@ -227,9 +234,4 @@ private CompletionStage doUpgradeLock(
throw he;
}
}
-
- @Override
- public void onLock(LockEvent event) throws HibernateException {
- throw new UnsupportedOperationException();
- }
}
diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/event/impl/DefaultReactiveMergeEventListener.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/event/impl/DefaultReactiveMergeEventListener.java
index 7f258a1d4..e6cc4cd95 100644
--- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/event/impl/DefaultReactiveMergeEventListener.java
+++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/event/impl/DefaultReactiveMergeEventListener.java
@@ -94,7 +94,9 @@ protected Map getMergeMap(MergeContext context) {
@Override
public CompletionStage reactiveOnMerge(MergeEvent event) throws HibernateException {
final EventSource session = event.getSession();
- final EntityCopyObserver entityCopyObserver = createEntityCopyObserver( session );
+ final EntityCopyObserver entityCopyObserver = session.getFactory()
+ .getEntityCopyObserver()
+ .createEntityCopyObserver();
final MergeContext mergeContext = new MergeContext( session, entityCopyObserver );
return reactiveOnMerge( event, mergeContext )
.thenAccept( v -> entityCopyObserver.topLevelMergeComplete( session ) )
@@ -104,10 +106,6 @@ public CompletionStage reactiveOnMerge(MergeEvent event) throws HibernateE
} );
}
- private EntityCopyObserver createEntityCopyObserver(final EventSource session) {
- return session.getFactory().getFastSessionServices().entityCopyObserverFactory.createEntityCopyObserver();
- }
-
/**
* Handle the given merge event.
*
diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/event/impl/DefaultReactivePostLoadEventListener.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/event/impl/DefaultReactivePostLoadEventListener.java
index 053c8465f..e1af57441 100644
--- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/event/impl/DefaultReactivePostLoadEventListener.java
+++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/event/impl/DefaultReactivePostLoadEventListener.java
@@ -6,7 +6,6 @@
package org.hibernate.reactive.event.impl;
import org.hibernate.AssertionFailure;
-import org.hibernate.classic.Lifecycle;
import org.hibernate.engine.spi.EntityEntry;
import org.hibernate.event.spi.EventSource;
import org.hibernate.event.spi.PostLoadEvent;
@@ -21,7 +20,6 @@
/**
* We do two things here:
*
- *
Call {@link Lifecycle} interface if necessary
*
Perform needed {@link EntityEntry#getLockMode()} related processing
*
*
diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/event/impl/DefaultReactiveRefreshEventListener.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/event/impl/DefaultReactiveRefreshEventListener.java
index f5e5eb1b4..ba3edda4a 100644
--- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/event/impl/DefaultReactiveRefreshEventListener.java
+++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/event/impl/DefaultReactiveRefreshEventListener.java
@@ -37,7 +37,7 @@
import org.hibernate.reactive.logging.impl.Log;
import org.hibernate.reactive.logging.impl.LoggerFactory;
import org.hibernate.reactive.persister.entity.impl.ReactiveAbstractEntityPersister;
-import org.hibernate.reactive.session.ReactiveSession;
+import org.hibernate.reactive.session.ReactiveQueryProducer;
import org.hibernate.type.CollectionType;
import org.hibernate.type.CompositeType;
import org.hibernate.type.Type;
@@ -84,7 +84,7 @@ public CompletionStage reactiveOnRefresh(RefreshEvent event, RefreshContex
// Hibernate Reactive doesn't support detached instances in refresh()
throw new IllegalArgumentException( "Unmanaged instance passed to refresh()" );
}
- return ( (ReactiveSession) source )
+ return ( (ReactiveQueryProducer) source )
.reactiveFetch( event.getObject(), true )
.thenCompose( entity -> reactiveOnRefresh( event, refreshedAlready, entity ) );
}
diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/event/impl/DefaultReactiveResolveNaturalIdEventListener.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/event/impl/DefaultReactiveResolveNaturalIdEventListener.java
deleted file mode 100644
index 1d80f3634..000000000
--- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/event/impl/DefaultReactiveResolveNaturalIdEventListener.java
+++ /dev/null
@@ -1,137 +0,0 @@
-/* Hibernate, Relational Persistence for Idiomatic Java
- *
- * SPDX-License-Identifier: Apache-2.0
- * Copyright: Red Hat Inc. and Hibernate Authors
- */
-package org.hibernate.reactive.event.impl;
-
-import java.lang.invoke.MethodHandles;
-import java.util.concurrent.CompletionStage;
-
-import org.hibernate.HibernateException;
-import org.hibernate.engine.spi.NaturalIdResolutions;
-import org.hibernate.event.internal.AbstractLockUpgradeEventListener;
-import org.hibernate.event.spi.EventSource;
-import org.hibernate.event.spi.ResolveNaturalIdEvent;
-import org.hibernate.event.spi.ResolveNaturalIdEventListener;
-import org.hibernate.persister.entity.EntityPersister;
-import org.hibernate.reactive.event.ReactiveResolveNaturalIdEventListener;
-import org.hibernate.reactive.logging.impl.Log;
-import org.hibernate.reactive.logging.impl.LoggerFactory;
-import org.hibernate.reactive.persister.entity.impl.ReactiveEntityPersister;
-import org.hibernate.stat.spi.StatisticsImplementor;
-
-import static java.util.concurrent.TimeUnit.MILLISECONDS;
-import static java.util.concurrent.TimeUnit.NANOSECONDS;
-import static org.hibernate.pretty.MessageHelper.infoString;
-import static org.hibernate.reactive.util.impl.CompletionStages.completedFuture;
-
-/**
- * A reactific {@link org.hibernate.event.internal.DefaultResolveNaturalIdEventListener}.
- */
-public class DefaultReactiveResolveNaturalIdEventListener extends AbstractLockUpgradeEventListener
- implements ReactiveResolveNaturalIdEventListener, ResolveNaturalIdEventListener {
-
- private static final Log LOG = LoggerFactory.make( Log.class, MethodHandles.lookup() );
-
- @Override
- public void onResolveNaturalId(ResolveNaturalIdEvent event) throws HibernateException {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public CompletionStage onReactiveResolveNaturalId(ResolveNaturalIdEvent event) throws HibernateException {
- return resolveNaturalId( event ).thenAccept( event::setEntityId );
- }
-
- /**
- * Coordinates the efforts to load a given entity. First, an attempt is
- * made to load the entity from the session-level cache. If not found there,
- * an attempt is made to locate it in second-level cache. Lastly, an
- * attempt is made to load it directly from the datasource.
- *
- * @param event The load event
- *
- * @return The loaded entity, or null.
- */
- protected CompletionStage resolveNaturalId(ResolveNaturalIdEvent event) {
- final EntityPersister persister = event.getEntityPersister();
-
- if ( LOG.isTraceEnabled() ) {
- LOG.tracev(
- "Attempting to resolve: {0}#{1}",
- infoString( persister ),
- event.getNaturalIdValues()
- );
- }
-
- final Object entityId = resolveFromCache( event );
- if ( entityId != null ) {
- if ( LOG.isTraceEnabled() ) {
- LOG.tracev(
- "Resolved object in cache: {0}#{1}",
- infoString( persister ),
- event.getNaturalIdValues() );
- }
- return completedFuture( entityId );
- }
-
- if ( LOG.isTraceEnabled() ) {
- LOG.tracev(
- "Object not resolved in any cache: {0}#{1}",
- infoString( persister ),
- event.getNaturalIdValues()
- );
- }
-
- return loadFromDatasource( event );
- }
-
- /**
- * Attempts to resolve the entity id corresponding to the event's natural id values from the session
- *
- * @param event The load event
- * @return The entity from the cache, or null.
- */
- protected Object resolveFromCache(ResolveNaturalIdEvent event) {
- return getNaturalIdResolutions( event )
- .findCachedIdByNaturalId( event.getOrderedNaturalIdValues(), event.getEntityPersister() );
- }
-
- /**
- * Performs the process of loading an entity from the configured
- * underlying datasource.
- *
- * @param event The load event
- *
- * @return The object loaded from the datasource, or null if not found.
- */
- protected CompletionStage loadFromDatasource(ResolveNaturalIdEvent event) {
- final EventSource session = event.getSession();
- final EntityPersister entityPersister = event.getEntityPersister();
- final StatisticsImplementor statistics = session.getFactory().getStatistics();
- final boolean statisticsEnabled = statistics.isStatisticsEnabled();
- final long startTime = statisticsEnabled ? System.nanoTime() : 0;
-
- return ( (ReactiveEntityPersister) entityPersister )
- .reactiveLoadEntityIdByNaturalId( event.getOrderedNaturalIdValues(), event.getLockOptions(), session )
- .thenApply( pk -> {
- if ( statisticsEnabled ) {
- long milliseconds = MILLISECONDS.convert( System.nanoTime() - startTime, NANOSECONDS );
- statistics.naturalIdQueryExecuted( entityPersister.getRootEntityName(), milliseconds );
- }
-
- //PK can be null if the entity doesn't exist
- if ( pk != null ) {
- getNaturalIdResolutions( event )
- .cacheResolutionFromLoad( pk, event.getOrderedNaturalIdValues(), entityPersister );
- }
-
- return pk;
- } );
- }
-
- private static NaturalIdResolutions getNaturalIdResolutions(ResolveNaturalIdEvent event) {
- return event.getSession().getPersistenceContextInternal().getNaturalIdResolutions();
- }
-}
diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/generator/values/ReactiveInsertGeneratedIdentifierDelegate.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/generator/values/ReactiveInsertGeneratedIdentifierDelegate.java
deleted file mode 100644
index 36d85f353..000000000
--- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/generator/values/ReactiveInsertGeneratedIdentifierDelegate.java
+++ /dev/null
@@ -1,116 +0,0 @@
-/* Hibernate, Relational Persistence for Idiomatic Java
- *
- * SPDX-License-Identifier: Apache-2.0
- * Copyright: Red Hat Inc. and Hibernate Authors
- */
-package org.hibernate.reactive.generator.values;
-
-import java.sql.PreparedStatement;
-import java.util.concurrent.CompletionStage;
-
-import org.hibernate.engine.jdbc.mutation.JdbcValueBindings;
-import org.hibernate.engine.jdbc.mutation.group.PreparedStatementDetails;
-import org.hibernate.engine.spi.SessionFactoryImplementor;
-import org.hibernate.engine.spi.SharedSessionContractImplementor;
-import org.hibernate.generator.EventType;
-import org.hibernate.generator.values.GeneratedValues;
-import org.hibernate.id.insert.Binder;
-import org.hibernate.id.insert.InsertGeneratedIdentifierDelegate;
-import org.hibernate.jdbc.Expectation;
-import org.hibernate.metamodel.mapping.BasicEntityIdentifierMapping;
-import org.hibernate.sql.model.ast.builder.TableInsertBuilder;
-import org.hibernate.sql.model.ast.builder.TableMutationBuilder;
-import org.hibernate.sql.results.jdbc.spi.JdbcValuesMappingProducer;
-
-public class ReactiveInsertGeneratedIdentifierDelegate implements InsertGeneratedIdentifierDelegate, ReactiveGeneratedValuesMutationDelegate {
- private final InsertGeneratedIdentifierDelegate delegate;
-
- public ReactiveInsertGeneratedIdentifierDelegate(InsertGeneratedIdentifierDelegate delegate) {
- this.delegate = delegate;
- }
-
- @Override
- public TableInsertBuilder createTableInsertBuilder(
- BasicEntityIdentifierMapping identifierMapping,
- Expectation expectation,
- SessionFactoryImplementor sessionFactory) {
- return delegate.createTableInsertBuilder( identifierMapping, expectation, sessionFactory );
- }
-
- @Override
- public PreparedStatement prepareStatement(String insertSql, SharedSessionContractImplementor session) {
- return delegate.prepareStatement( insertSql, session );
- }
-
- @Override
- public Object performInsert(
- PreparedStatementDetails insertStatementDetails,
- JdbcValueBindings valueBindings,
- Object entity,
- SharedSessionContractImplementor session) {
- return delegate.performInsert( insertStatementDetails, valueBindings, entity, session );
- }
-
- @Override
- public String prepareIdentifierGeneratingInsert(String insertSQL) {
- return delegate.prepareIdentifierGeneratingInsert( insertSQL );
- }
-
- @Override
- public Object performInsert(String insertSQL, SharedSessionContractImplementor session, Binder binder) {
- return delegate.performInsert( insertSQL, session, binder );
- }
-
- @Override
- public GeneratedValues performInsertReturning(
- String insertSQL,
- SharedSessionContractImplementor session,
- Binder binder) {
- return delegate.performInsertReturning( insertSQL, session, binder );
- }
-
- @Override
- public TableMutationBuilder> createTableMutationBuilder(
- Expectation expectation,
- SessionFactoryImplementor sessionFactory) {
- return delegate.createTableMutationBuilder( expectation, sessionFactory );
- }
-
- @Override
- public GeneratedValues performMutation(
- PreparedStatementDetails statementDetails,
- JdbcValueBindings valueBindings,
- Object entity,
- SharedSessionContractImplementor session) {
- return delegate.performMutation( statementDetails, valueBindings, entity, session );
- }
-
- @Override
- public EventType getTiming() {
- return delegate.getTiming();
- }
-
- @Override
- public boolean supportsArbitraryValues() {
- return delegate.supportsArbitraryValues();
- }
-
- @Override
- public boolean supportsRowId() {
- return delegate.supportsRowId();
- }
-
- @Override
- public JdbcValuesMappingProducer getGeneratedValuesMappingProducer() {
- return delegate.getGeneratedValuesMappingProducer();
- }
-
- @Override
- public CompletionStage reactivePerformMutation(
- PreparedStatementDetails singleStatementDetails,
- JdbcValueBindings jdbcValueBindings,
- Object modelReference,
- SharedSessionContractImplementor session) {
- return null;
- }
-}
diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/generator/values/internal/ReactiveGeneratedValuesHelper.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/generator/values/internal/ReactiveGeneratedValuesHelper.java
index 8854f22d8..e842adf11 100644
--- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/generator/values/internal/ReactiveGeneratedValuesHelper.java
+++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/generator/values/internal/ReactiveGeneratedValuesHelper.java
@@ -5,13 +5,6 @@
*/
package org.hibernate.reactive.generator.values.internal;
-import java.sql.PreparedStatement;
-import java.sql.ResultSet;
-import java.sql.SQLException;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.concurrent.CompletionStage;
-
import org.hibernate.HibernateException;
import org.hibernate.Internal;
import org.hibernate.dialect.Dialect;
@@ -48,8 +41,15 @@
import org.hibernate.sql.results.jdbc.spi.JdbcValuesSourceProcessingOptions;
import org.hibernate.type.descriptor.WrapperOptions;
-import static org.hibernate.generator.internal.NaturalIdHelper.getNaturalIdPropertyNames;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.CompletionStage;
+
import static org.hibernate.generator.values.internal.GeneratedValuesHelper.noCustomSql;
+import static org.hibernate.internal.NaturalIdHelper.getNaturalIdPropertyNames;
import static org.hibernate.reactive.sql.results.spi.ReactiveListResultsConsumer.UniqueSemantic.NONE;
/**
@@ -63,14 +63,14 @@ public class ReactiveGeneratedValuesHelper {
*
* @see GeneratedValuesHelper#getGeneratedValuesDelegate(EntityPersister, EventType)
*/
- public static GeneratedValuesMutationDelegate getGeneratedValuesDelegate(
- EntityPersister persister,
- EventType timing) {
+ public static GeneratedValuesMutationDelegate getGeneratedValuesDelegate(EntityPersister persister, EventType timing) {
final boolean hasGeneratedProperties = !persister.getGeneratedProperties( timing ).isEmpty();
final boolean hasRowId = timing == EventType.INSERT && persister.getRowIdMapping() != null;
final Dialect dialect = persister.getFactory().getJdbcServices().getDialect();
- if ( hasRowId && dialect.supportsInsertReturning() && dialect.supportsInsertReturningRowId()
+ if ( hasRowId
+ && dialect.supportsInsertReturning()
+ && dialect.supportsInsertReturningRowId()
&& noCustomSql( persister, timing ) ) {
// Special case for RowId on INSERT, since GetGeneratedKeysDelegate doesn't support it
// make InsertReturningDelegate the preferred method if the dialect supports it
diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/id/ReactiveIdentifierGenerator.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/id/ReactiveIdentifierGenerator.java
index 4e44eb7d0..7121ea5c4 100644
--- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/id/ReactiveIdentifierGenerator.java
+++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/id/ReactiveIdentifierGenerator.java
@@ -6,6 +6,7 @@
package org.hibernate.reactive.id;
import org.hibernate.Incubating;
+import org.hibernate.generator.Generator;
import org.hibernate.id.IdentifierGenerator;
import org.hibernate.reactive.session.ReactiveConnectionSupplier;
@@ -24,7 +25,7 @@
* @see IdentifierGenerator
*/
@Incubating
-public interface ReactiveIdentifierGenerator {
+public interface ReactiveIdentifierGenerator extends Generator {
/**
* Returns a generated identifier, via a {@link CompletionStage}.
diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/id/factory/spi/ReactiveIdentifierGeneratorFactoryInitiator.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/id/factory/spi/ReactiveIdentifierGeneratorFactoryInitiator.java
deleted file mode 100644
index 78eed431d..000000000
--- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/id/factory/spi/ReactiveIdentifierGeneratorFactoryInitiator.java
+++ /dev/null
@@ -1,27 +0,0 @@
-/* Hibernate, Relational Persistence for Idiomatic Java
- *
- * SPDX-License-Identifier: Apache-2.0
- * Copyright: Red Hat Inc. and Hibernate Authors
- */
-package org.hibernate.reactive.id.factory.spi;
-
-import java.util.Map;
-
-import org.hibernate.boot.registry.StandardServiceInitiator;
-import org.hibernate.id.factory.IdentifierGeneratorFactory;
-import org.hibernate.reactive.id.impl.ReactiveIdentifierGeneratorFactory;
-import org.hibernate.service.spi.ServiceRegistryImplementor;
-
-public class ReactiveIdentifierGeneratorFactoryInitiator implements StandardServiceInitiator {
- public static final ReactiveIdentifierGeneratorFactoryInitiator INSTANCE = new ReactiveIdentifierGeneratorFactoryInitiator();
-
- @Override
- public Class getServiceInitiated() {
- return IdentifierGeneratorFactory.class;
- }
-
- @Override
- public IdentifierGeneratorFactory initiateService(Map configurationValues, ServiceRegistryImplementor registry) {
- return new ReactiveIdentifierGeneratorFactory( registry );
- }
-}
diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/id/impl/BlockingIdentifierGenerator.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/id/impl/BlockingIdentifierGenerator.java
index 224410853..329792f28 100644
--- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/id/impl/BlockingIdentifierGenerator.java
+++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/id/impl/BlockingIdentifierGenerator.java
@@ -5,18 +5,18 @@
*/
package org.hibernate.reactive.id.impl;
-import io.vertx.core.Context;
-import io.vertx.core.Vertx;
-import io.vertx.core.net.impl.pool.CombinerExecutor;
-import io.vertx.core.net.impl.pool.Executor;
-import io.vertx.core.net.impl.pool.Task;
+import java.util.Objects;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.CompletionStage;
import org.hibernate.reactive.id.ReactiveIdentifierGenerator;
import org.hibernate.reactive.session.ReactiveConnectionSupplier;
-import java.util.Objects;
-import java.util.concurrent.CompletableFuture;
-import java.util.concurrent.CompletionStage;
+import io.vertx.core.Context;
+import io.vertx.core.Vertx;
+import io.vertx.core.internal.pool.CombinerExecutor;
+import io.vertx.core.internal.pool.Executor;
+import io.vertx.core.internal.pool.Task;
import static org.hibernate.reactive.util.impl.CompletionStages.completedFuture;
@@ -44,14 +44,14 @@ public abstract class BlockingIdentifierGenerator implements ReactiveIdentifierG
//modification access.
//This replaces the synchronization blocks one would see in a similar
//service in Hibernate ORM, but using a non-blocking cooperative design.
- private final CombinerExecutor executor = new CombinerExecutor( state );
+ private final CombinerExecutor executor = new CombinerExecutor<>( state );
/**
* Allocate a new block, by obtaining the next "hi" value from the database
*/
protected abstract CompletionStage nextHiValue(ReactiveConnectionSupplier session);
- //Not strictly necessary to put these fields into a dedicated class, but it help
+ //Not strictly necessary to put these fields into a dedicated class, but it helps
//to reason about what the current state is and what the CombinerExecutor is
//supposed to work on.
private static class GeneratorState {
@@ -138,7 +138,6 @@ public Task execute(GeneratorState state) {
// value in the table, so just increment the lo
// value and return the next id in the block
completedFuture( local ).whenComplete( this::acceptAsReturnValue );
- return null;
}
else {
nextHiValue( connectionSupplier )
@@ -155,8 +154,8 @@ public Task execute(GeneratorState state) {
} );
}
} );
- return null;
}
+ return null;
}
private void acceptAsReturnValue(final Long aLong, final Throwable throwable) {
diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/id/impl/EmulatedSequenceReactiveIdentifierGenerator.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/id/impl/EmulatedSequenceReactiveIdentifierGenerator.java
index 889f3d69a..b973c869b 100644
--- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/id/impl/EmulatedSequenceReactiveIdentifierGenerator.java
+++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/id/impl/EmulatedSequenceReactiveIdentifierGenerator.java
@@ -5,14 +5,20 @@
*/
package org.hibernate.reactive.id.impl;
+import org.hibernate.dialect.CockroachDialect;
+import org.hibernate.dialect.Dialect;
+import org.hibernate.dialect.OracleDialect;
+import org.hibernate.dialect.PostgreSQLDialect;
+import org.hibernate.dialect.SQLServerDialect;
import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment;
import org.hibernate.id.enhanced.SequenceStyleGenerator;
+import org.hibernate.id.enhanced.TableStructure;
+import org.hibernate.metamodel.spi.RuntimeModelCreationContext;
import org.hibernate.service.ServiceRegistry;
import org.hibernate.type.Type;
import java.util.Properties;
-import static org.hibernate.internal.util.config.ConfigurationHelper.getInt;
import static org.hibernate.internal.util.config.ConfigurationHelper.getString;
/**
@@ -25,6 +31,10 @@
*/
public class EmulatedSequenceReactiveIdentifierGenerator extends TableReactiveIdentifierGenerator {
+ public EmulatedSequenceReactiveIdentifierGenerator(TableStructure structure, RuntimeModelCreationContext runtimeModelCreationContext) {
+ super( structure, runtimeModelCreationContext );
+ }
+
@Override
public void configure(Type type, Properties params, ServiceRegistry serviceRegistry) {
super.configure( type, params, serviceRegistry );
@@ -60,16 +70,6 @@ protected String determineSegmentValue(Properties params) {
return null;
}
- @Override
- protected int determineInitialValue(Properties params) {
- return getInt( SequenceStyleGenerator.INITIAL_PARAM, params, SequenceStyleGenerator.DEFAULT_INITIAL_VALUE );
- }
-
- @Override
- protected int determineIncrement(Properties params) {
- return getInt( SequenceStyleGenerator.INCREMENT_PARAM, params, SequenceStyleGenerator.DEFAULT_INCREMENT_SIZE );
- }
-
@Override
protected Object[] updateParameters(long currentValue, long updatedValue) {
return new Object[] { updatedValue, currentValue };
@@ -86,20 +86,44 @@ protected Object[] selectParameters() {
}
@Override
- protected String buildSelectQuery() {
+ protected String buildSelectQuery(Dialect dialect) {
return "select tbl." + valueColumnName + " from " + renderedTableName + " tbl";
}
@Override
- protected String buildUpdateQuery() {
+ protected String buildUpdateQuery(Dialect dialect) {
+ if ( dialect instanceof PostgreSQLDialect || dialect instanceof CockroachDialect ) {
+ return "update " + renderedTableName + " set " + valueColumnName + "=$1"
+ + " where " + valueColumnName + "=$2";
+
+ }
+ if ( dialect instanceof SQLServerDialect ) {
+ return "update " + renderedTableName + " set " + valueColumnName + "=@P1"
+ + " where " + valueColumnName + "=@P2";
+
+ }
+ if ( dialect instanceof OracleDialect ) {
+ return "update " + renderedTableName + " set " + valueColumnName + "=:1"
+ + " where " + valueColumnName + "=:2";
+
+ }
return "update " + renderedTableName + " set " + valueColumnName + "=?"
+ " where " + valueColumnName + "=?";
}
@Override
- protected String buildInsertQuery() {
- return "insert into " + renderedTableName + " (" + valueColumnName + ") "
- + " values (?)";
+ protected String buildInsertQuery(Dialect dialect) {
+ final String sql = "insert into " + renderedTableName + " (" + valueColumnName + ") values ";
+ if ( dialect instanceof PostgreSQLDialect || dialect instanceof CockroachDialect ) {
+ return sql + "($1)";
+ }
+ if ( dialect instanceof SQLServerDialect ) {
+ return sql + "(@P1)";
+ }
+ if ( dialect instanceof OracleDialect ) {
+ return sql + "(:1)";
+ }
+ return sql + "(?)";
}
}
diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/id/impl/ReactiveIdentifierGeneratorFactory.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/id/impl/ReactiveIdentifierGeneratorFactory.java
deleted file mode 100644
index 1e3596294..000000000
--- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/id/impl/ReactiveIdentifierGeneratorFactory.java
+++ /dev/null
@@ -1,143 +0,0 @@
-/* Hibernate, Relational Persistence for Idiomatic Java
- *
- * SPDX-License-Identifier: Apache-2.0
- * Copyright: Red Hat Inc. and Hibernate Authors
- */
-package org.hibernate.reactive.id.impl;
-
-import java.lang.invoke.MethodHandles;
-import java.util.Properties;
-
-import org.hibernate.MappingException;
-import org.hibernate.boot.registry.classloading.spi.ClassLoaderService;
-import org.hibernate.boot.registry.classloading.spi.ClassLoadingException;
-import org.hibernate.engine.config.spi.ConfigurationService;
-import org.hibernate.engine.config.spi.StandardConverters;
-import org.hibernate.generator.BeforeExecutionGenerator;
-import org.hibernate.generator.Generator;
-import org.hibernate.generator.GeneratorCreationContext;
-import org.hibernate.generator.OnExecutionGenerator;
-import org.hibernate.id.Configurable;
-import org.hibernate.id.IdentifierGenerator;
-import org.hibernate.id.PersistentIdentifierGenerator;
-import org.hibernate.id.SelectGenerator;
-import org.hibernate.id.enhanced.DatabaseStructure;
-import org.hibernate.id.enhanced.SequenceStructure;
-import org.hibernate.id.enhanced.SequenceStyleGenerator;
-import org.hibernate.id.enhanced.TableGenerator;
-import org.hibernate.id.enhanced.TableStructure;
-import org.hibernate.id.factory.internal.StandardIdentifierGeneratorFactory;
-import org.hibernate.reactive.id.ReactiveIdentifierGenerator;
-import org.hibernate.reactive.logging.impl.Log;
-import org.hibernate.reactive.logging.impl.LoggerFactory;
-import org.hibernate.reactive.provider.Settings;
-import org.hibernate.service.ServiceRegistry;
-import org.hibernate.type.Type;
-
-public class ReactiveIdentifierGeneratorFactory extends StandardIdentifierGeneratorFactory {
-
- private static final Log LOG = LoggerFactory.make( Log.class, MethodHandles.lookup() );
-
- private final ServiceRegistry serviceRegistry;
-
- public ReactiveIdentifierGeneratorFactory(ServiceRegistry serviceRegistry) {
- super( serviceRegistry );
- this.serviceRegistry = serviceRegistry;
- }
-
- @Override
- public Generator createIdentifierGenerator(String strategy, Type type, GeneratorCreationContext creationContext, Properties config) {
- Object generator;
- try {
- generator = super.createIdentifierGenerator( strategy, type, creationContext, config );
- }
- catch ( MappingException ignored ) {
- try {
- final Class> clazz = generatorClassForName( strategy );
- generator = clazz.getConstructor().newInstance();
- if ( generator instanceof Configurable ) {
- ( (Configurable) generator ).configure( type, config, serviceRegistry );
- }
- }
- catch ( Exception e ) {
- final String entityName = config.getProperty( IdentifierGenerator.ENTITY_NAME );
- throw new MappingException( String.format( "Could not instantiate id generator [entity-name=%s]", entityName ), e );
- }
- }
-
- //FIXME: Not sure why we need all these instanceof
- if ( generator instanceof BeforeExecutionGenerator ) {
- return augmentWithReactiveGenerator( (BeforeExecutionGenerator) generator, type, config );
- }
-
- if ( generator instanceof OnExecutionGenerator ) {
- return augmentWithReactiveGenerator( (OnExecutionGenerator) generator, type, config );
- }
-
- if ( generator instanceof ReactiveIdentifierGenerator ) {
- return new ReactiveGeneratorWrapper( (ReactiveIdentifierGenerator>) generator );
- }
-
- final String entityName = config.getProperty( IdentifierGenerator.ENTITY_NAME );
- throw new MappingException( String.format( "Not an id generator [entity-name=%s]", entityName ) );
- }
-
- protected Class extends Generator> generatorClassForName(String strategy) {
- try {
- return serviceRegistry.getService( ClassLoaderService.class ).classForName( strategy );
- }
- catch ( ClassLoadingException e ) {
- throw new MappingException( String.format( "Could not interpret id generator strategy [%s]", strategy ) );
- }
- }
-
- public Generator augmentWithReactiveGenerator(Generator generator, Type type, Properties params) {
- return augmentWithReactiveGenerator( serviceRegistry, generator, type, params );
- }
-
- public static Generator augmentWithReactiveGenerator(ServiceRegistry serviceRegistry, Generator generator, Type type, Properties params) {
- final ReactiveIdentifierGenerator> reactiveGenerator;
- if ( generator instanceof SequenceStyleGenerator ) {
- final DatabaseStructure structure = ( (SequenceStyleGenerator) generator ).getDatabaseStructure();
- if ( structure instanceof TableStructure ) {
- reactiveGenerator = new EmulatedSequenceReactiveIdentifierGenerator();
- }
- else if ( structure instanceof SequenceStructure ) {
- reactiveGenerator = new ReactiveSequenceIdentifierGenerator();
- }
- else {
- throw LOG.unknownStructureType();
- }
- }
- else if ( generator instanceof TableGenerator ) {
- reactiveGenerator = new TableReactiveIdentifierGenerator();
- }
- else if ( generator instanceof SelectGenerator ) {
- throw LOG.selectGeneratorIsNotSupportedInHibernateReactive();
- }
- else {
- //nothing to do
- return generator;
- }
-
- //this is not the way ORM does this: instead it passes a
- //SqlStringGenerationContext to IdentifierGenerator.initialize()
- final ConfigurationService cs = serviceRegistry.getService( ConfigurationService.class );
- if ( !params.containsKey( PersistentIdentifierGenerator.SCHEMA ) ) {
- final String schema = cs.getSetting( Settings.DEFAULT_SCHEMA, StandardConverters.STRING );
- if ( schema != null ) {
- params.put( PersistentIdentifierGenerator.SCHEMA, schema );
- }
- }
- if ( !params.containsKey( PersistentIdentifierGenerator.CATALOG ) ) {
- final String catalog = cs.getSetting( Settings.DEFAULT_CATALOG, StandardConverters.STRING );
- if ( catalog != null ) {
- params.put( PersistentIdentifierGenerator.CATALOG, catalog );
- }
- }
-
- ( (Configurable) reactiveGenerator ).configure( type, params, serviceRegistry );
- return new ReactiveGeneratorWrapper( reactiveGenerator, (IdentifierGenerator) generator );
- }
-
-}
diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/id/impl/ReactiveSequenceIdentifierGenerator.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/id/impl/ReactiveSequenceIdentifierGenerator.java
index 6331d178b..325a5b662 100644
--- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/id/impl/ReactiveSequenceIdentifierGenerator.java
+++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/id/impl/ReactiveSequenceIdentifierGenerator.java
@@ -19,11 +19,13 @@
import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.id.IdentifierGenerator;
+import org.hibernate.id.enhanced.DatabaseStructure;
import org.hibernate.id.enhanced.ImplicitDatabaseObjectNamingStrategy;
import org.hibernate.id.enhanced.SequenceStyleGenerator;
import org.hibernate.id.enhanced.StandardNamingStrategy;
import org.hibernate.internal.util.StringHelper;
import org.hibernate.internal.util.config.ConfigurationHelper;
+import org.hibernate.metamodel.spi.RuntimeModelCreationContext;
import org.hibernate.reactive.session.ReactiveConnectionSupplier;
import org.hibernate.service.ServiceRegistry;
import org.hibernate.type.Type;
@@ -51,6 +53,16 @@ public class ReactiveSequenceIdentifierGenerator extends BlockingIdentifierGener
private String sql;
private int increment;
+
+ public ReactiveSequenceIdentifierGenerator() {
+ }
+
+ public ReactiveSequenceIdentifierGenerator(DatabaseStructure structure, RuntimeModelCreationContext creationContext) {
+ qualifiedName = structure.getPhysicalName();
+ increment = structure.getIncrementSize();
+ dialect = creationContext.getDialect();
+ }
+
@Override
protected int getBlockSize() {
return increment;
diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/id/impl/TableReactiveIdentifierGenerator.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/id/impl/TableReactiveIdentifierGenerator.java
index a49a04289..21a863b0b 100644
--- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/id/impl/TableReactiveIdentifierGenerator.java
+++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/id/impl/TableReactiveIdentifierGenerator.java
@@ -12,19 +12,22 @@
import org.hibernate.HibernateException;
import org.hibernate.LockMode;
import org.hibernate.LockOptions;
-import org.hibernate.boot.model.relational.Database;
-import org.hibernate.boot.model.relational.SqlStringGenerationContext;
+import org.hibernate.dialect.CockroachDialect;
import org.hibernate.dialect.Dialect;
+import org.hibernate.dialect.OracleDialect;
+import org.hibernate.dialect.PostgreSQLDialect;
+import org.hibernate.dialect.SQLServerDialect;
import org.hibernate.engine.config.spi.ConfigurationService;
import org.hibernate.engine.config.spi.StandardConverters;
import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.id.IdentifierGenerator;
import org.hibernate.id.enhanced.TableGenerator;
+import org.hibernate.id.enhanced.TableStructure;
import org.hibernate.internal.util.StringHelper;
import org.hibernate.jdbc.TooManyRowsAffectedException;
+import org.hibernate.metamodel.spi.RuntimeModelCreationContext;
import org.hibernate.reactive.pool.ReactiveConnection;
-import org.hibernate.reactive.pool.impl.Parameters;
import org.hibernate.reactive.provider.Settings;
import org.hibernate.reactive.session.ReactiveConnectionSupplier;
import org.hibernate.service.ServiceRegistry;
@@ -65,6 +68,60 @@ public class TableReactiveIdentifierGenerator extends BlockingIdentifierGenerato
private String insertQuery;
private String updateQuery;
+ public TableReactiveIdentifierGenerator(TableGenerator generator, RuntimeModelCreationContext runtimeModelCreationContext) {
+ ServiceRegistry serviceRegistry = runtimeModelCreationContext.getServiceRegistry();
+ segmentColumnName = generator.getSegmentColumnName();
+ valueColumnName = generator.getValueColumnName();
+ segmentValue = generator.getSegmentValue();
+ initialValue = generator.getInitialValue();
+ increment = generator.getIncrementSize();
+ storeLastUsedValue = determineStoreLastUsedValue( serviceRegistry );
+ renderedTableName = generator.getTableName();
+
+ JdbcEnvironment jdbcEnvironment = serviceRegistry.getService( JdbcEnvironment.class );
+ Dialect dialect = jdbcEnvironment.getDialect();
+ selectQuery = applyLocksToSelect( dialect, "tbl", buildSelectQuery( dialect ) );
+ updateQuery = buildUpdateQuery( dialect );
+ insertQuery = buildInsertQuery( dialect );
+ }
+
+ public TableReactiveIdentifierGenerator(
+ TableStructure structure,
+ RuntimeModelCreationContext runtimeModelCreationContext) {
+ ServiceRegistry serviceRegistry = runtimeModelCreationContext.getServiceRegistry();
+ JdbcEnvironment jdbcEnvironment = serviceRegistry.getService( JdbcEnvironment.class );
+ Dialect dialect = jdbcEnvironment.getDialect();
+
+ valueColumnName = structure.getLogicalValueColumnNameIdentifier().render( dialect );
+ initialValue = structure.getInitialValue();
+ increment = structure.getIncrementSize();
+ storeLastUsedValue = determineStoreLastUsedValue( serviceRegistry );
+ renderedTableName = structure.getPhysicalName().render();
+ segmentColumnName = null;
+ segmentValue = null;
+
+ selectQuery = applyLocksToSelect( dialect, "tbl", buildSelectQuery( dialect ) );
+ updateQuery = buildUpdateQuery( dialect );
+ insertQuery = buildInsertQuery( dialect );
+ }
+
+ @Override
+ public void configure(Type type, Properties params, ServiceRegistry serviceRegistry) {
+ JdbcEnvironment jdbcEnvironment = serviceRegistry.getService( JdbcEnvironment.class );
+ segmentColumnName = determineSegmentColumnName( params, jdbcEnvironment );
+ valueColumnName = determineValueColumnNameForTable( params, jdbcEnvironment );
+ segmentValue = determineSegmentValue( params );
+ initialValue = determineInitialValue( params );
+ increment = determineIncrement( params );
+ storeLastUsedValue = determineStoreLastUsedValue( serviceRegistry );
+ renderedTableName = determineTableName( type, params, serviceRegistry );
+
+ Dialect dialect = jdbcEnvironment.getDialect();
+ selectQuery = applyLocksToSelect( dialect, "tbl", buildSelectQuery( dialect ) );
+ updateQuery = buildUpdateQuery( dialect );
+ insertQuery = buildInsertQuery( dialect );
+ }
+
@Override
protected int getBlockSize() {
return increment;
@@ -130,32 +187,6 @@ protected CompletionStage nextHiValue(ReactiveConnectionSupplier session)
} );
}
- @Override
- public void configure(Type type, Properties params, ServiceRegistry serviceRegistry) {
- JdbcEnvironment jdbcEnvironment = serviceRegistry.getService( JdbcEnvironment.class );
- segmentColumnName = determineSegmentColumnName( params, jdbcEnvironment );
- valueColumnName = determineValueColumnNameForTable( params, jdbcEnvironment );
- segmentValue = determineSegmentValue( params );
- initialValue = determineInitialValue( params );
- increment = determineIncrement( params );
- storeLastUsedValue = determineStoreLastUsedValue( serviceRegistry );
- renderedTableName = determineTableName( type, params, serviceRegistry );
-
- Dialect dialect = jdbcEnvironment.getDialect();
- Parameters parameters = Parameters.instance( dialect );
- selectQuery = parameters.process( applyLocksToSelect( dialect, "tbl", buildSelectQuery() ) );
- updateQuery = parameters.process( buildUpdateQuery() );
- insertQuery = parameters.process( buildInsertQuery() );
- }
-
- @Override
- public void registerExportables(Database database) {
- }
-
- @Override
- public void initialize(SqlStringGenerationContext context) {
- }
-
@Override
public Object generate(SharedSessionContractImplementor session, Object object) throws HibernateException {
throw new UnsupportedOperationException();
@@ -224,19 +255,48 @@ protected Object[] selectParameters() {
return new Object[]{ segmentValue };
}
- protected String buildSelectQuery() {
- return "select tbl." + valueColumnName + " from " + renderedTableName + " tbl"
- + " where tbl." + segmentColumnName + "=?";
+ protected String buildSelectQuery(Dialect dialect) {
+ final String sql = "select tbl." + valueColumnName + " from " + renderedTableName + " tbl where tbl." + segmentColumnName;
+ if ( dialect instanceof PostgreSQLDialect || dialect instanceof CockroachDialect ) {
+ return sql + "=$1";
+ }
+ if ( dialect instanceof SQLServerDialect ) {
+ return sql + "=@P1";
+ }
+ if ( dialect instanceof OracleDialect ) {
+ return sql + "=:1";
+ }
+ return sql + "=?";
}
- protected String buildUpdateQuery() {
+ protected String buildUpdateQuery(Dialect dialect) {
+ if ( dialect instanceof PostgreSQLDialect || dialect instanceof CockroachDialect ) {
+ return "update " + renderedTableName + " set " + valueColumnName + "=$1"
+ + " where " + valueColumnName + "=$2 and " + segmentColumnName + "=$3";
+ }
+ if ( dialect instanceof SQLServerDialect ) {
+ return "update " + renderedTableName + " set " + valueColumnName + "=@P1"
+ + " where " + valueColumnName + "=@P2 and " + segmentColumnName + "=@P3";
+ }
+ if ( dialect instanceof OracleDialect ) {
+ return "update " + renderedTableName + " set " + valueColumnName + "=:1"
+ + " where " + valueColumnName + "=:2 and " + segmentColumnName + "=:3";
+ }
return "update " + renderedTableName + " set " + valueColumnName + "=?"
+ " where " + valueColumnName + "=? and " + segmentColumnName + "=?";
}
- protected String buildInsertQuery() {
- return "insert into " + renderedTableName + " (" + segmentColumnName + ", " + valueColumnName + ") "
- + " values (?, ?)";
+ protected String buildInsertQuery(Dialect dialect) {
+ final String sql = "insert into " + renderedTableName + " (" + segmentColumnName + ", " + valueColumnName + ") ";
+ if ( dialect instanceof PostgreSQLDialect || dialect instanceof CockroachDialect ) {
+ return sql + " values ($1, $2)";
+ }
+ if ( dialect instanceof SQLServerDialect ) {
+ return sql + " values (@P1, @P2)";
+ }
+ if ( dialect instanceof OracleDialect ) {
+ return sql + " values (:1, :2)";
+ }
+ return sql + " values (?, ?)";
}
-
}
diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/id/insert/ReactiveAbstractReturningDelegate.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/id/insert/ReactiveAbstractReturningDelegate.java
index 42dfddef0..aed2555fe 100644
--- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/id/insert/ReactiveAbstractReturningDelegate.java
+++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/id/insert/ReactiveAbstractReturningDelegate.java
@@ -12,7 +12,6 @@
import org.hibernate.dialect.CockroachDialect;
import org.hibernate.dialect.DB2Dialect;
import org.hibernate.dialect.Dialect;
-import org.hibernate.dialect.DialectDelegateWrapper;
import org.hibernate.dialect.MySQLDialect;
import org.hibernate.dialect.OracleDialect;
import org.hibernate.dialect.SQLServerDialect;
@@ -21,8 +20,8 @@
import org.hibernate.engine.jdbc.spi.JdbcServices;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.generator.values.GeneratedValues;
-import org.hibernate.id.PostInsertIdentityPersister;
import org.hibernate.id.insert.Binder;
+import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.reactive.adaptor.impl.PrepareStatementDetailsAdaptor;
import org.hibernate.reactive.adaptor.impl.PreparedStatementAdaptor;
import org.hibernate.reactive.logging.impl.Log;
@@ -35,7 +34,7 @@ public interface ReactiveAbstractReturningDelegate extends ReactiveInsertGenerat
@Override
PreparedStatement prepareStatement(String insertSql, SharedSessionContractImplementor session);
- PostInsertIdentityPersister getPersister();
+ EntityPersister getPersister();
@Override
default CompletionStage reactivePerformInsertReturning(String sql, SharedSessionContractImplementor session, Binder binder) {
@@ -89,15 +88,14 @@ && getPersister().getFactory().getJdbcServices().getDialect() instanceof Cockroa
private static String createInsert(String insertSql, String identifierColumnName, Dialect dialect) {
String sql = insertSql;
final String sqlEnd = " returning " + identifierColumnName;
- Dialect realDialect = DialectDelegateWrapper.extractRealDialect( dialect );
- if ( realDialect instanceof MySQLDialect ) {
+ if ( dialect instanceof MySQLDialect ) {
// For some reason ORM generates a query with an invalid syntax
int index = sql.lastIndexOf( sqlEnd );
return index > -1
? sql.substring( 0, index )
: sql;
}
- if ( realDialect instanceof SQLServerDialect ) {
+ if ( dialect instanceof SQLServerDialect ) {
int index = sql.lastIndexOf( sqlEnd );
// FIXME: this is a hack for HHH-16365
if ( index > -1 ) {
@@ -113,12 +111,12 @@ private static String createInsert(String insertSql, String identifierColumnName
}
return sql;
}
- if ( realDialect instanceof DB2Dialect ) {
+ if ( dialect instanceof DB2Dialect ) {
// ORM query: select id from new table ( insert into IntegerTypeEntity values ( ))
// Correct : select id from new table ( insert into LongTypeEntity (id) values (default))
return sql.replace( " values ( ))", " (" + identifierColumnName + ") values (default))" );
}
- if ( realDialect instanceof OracleDialect ) {
+ if ( dialect instanceof OracleDialect ) {
final String valuesStr = " values ( )";
int index = sql.lastIndexOf( sqlEnd );
// remove "returning id" since it's added via
diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/id/insert/ReactiveInsertReturningDelegate.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/id/insert/ReactiveInsertReturningDelegate.java
index 79460c546..2b4063173 100644
--- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/id/insert/ReactiveInsertReturningDelegate.java
+++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/id/insert/ReactiveInsertReturningDelegate.java
@@ -21,7 +21,6 @@
import org.hibernate.generator.values.GeneratedValueBasicResultBuilder;
import org.hibernate.generator.values.GeneratedValues;
import org.hibernate.generator.values.internal.TableUpdateReturningBuilder;
-import org.hibernate.id.PostInsertIdentityPersister;
import org.hibernate.id.insert.AbstractReturningDelegate;
import org.hibernate.id.insert.InsertReturningDelegate;
import org.hibernate.id.insert.TableInsertReturningBuilder;
@@ -36,6 +35,7 @@
import org.hibernate.sql.model.ast.builder.TableMutationBuilder;
import static java.sql.Statement.NO_GENERATED_KEYS;
+import static org.hibernate.generator.EventType.INSERT;
import static org.hibernate.generator.values.internal.GeneratedValuesHelper.getActualGeneratedModelPart;
import static org.hibernate.reactive.generator.values.internal.ReactiveGeneratedValuesHelper.getGeneratedValues;
@@ -46,27 +46,26 @@ public class ReactiveInsertReturningDelegate extends AbstractReturningDelegate i
private static final Log LOG = LoggerFactory.make( Log.class, MethodHandles.lookup() );
- private final PostInsertIdentityPersister persister;
+ private final EntityPersister persister;
private final MutatingTableReference tableReference;
private final List generatedColumns;
public ReactiveInsertReturningDelegate(EntityPersister persister, EventType timing) {
- this( (PostInsertIdentityPersister) persister, timing, false );
-
+ this( persister, timing, false );
}
- public ReactiveInsertReturningDelegate(PostInsertIdentityPersister persister, Dialect dialect) {
+ public ReactiveInsertReturningDelegate(EntityPersister persister, Dialect dialect) {
// With JDBC it's possible to enabled GetGeneratedKeys for identity generation.
// Vert.x doesn't have this option, so we always use the same strategy for all database.
// But MySQL requires setting supportsArbitraryValues to false or it's not going to work.
- this( persister, EventType.INSERT, supportsArbitraryValues( dialect ) );
+ this( persister, INSERT, supportsArbitraryValues( dialect ) );
}
private static boolean supportsArbitraryValues( Dialect dialect) {
return !( dialect instanceof MySQLDialect );
}
- private ReactiveInsertReturningDelegate(PostInsertIdentityPersister persister, EventType timing, boolean supportsArbitraryValues) {
+ private ReactiveInsertReturningDelegate(EntityPersister persister, EventType timing, boolean supportsArbitraryValues) {
super(
persister,
timing,
@@ -88,7 +87,7 @@ private ReactiveInsertReturningDelegate(PostInsertIdentityPersister persister, E
public TableMutationBuilder> createTableMutationBuilder(
Expectation expectation,
SessionFactoryImplementor sessionFactory) {
- if ( getTiming() == EventType.INSERT ) {
+ if ( getTiming() == INSERT ) {
return new TableInsertReturningBuilder( persister, tableReference, generatedColumns, sessionFactory );
}
else {
@@ -110,7 +109,7 @@ public PreparedStatement prepareStatement(String sql, SharedSessionContractImple
}
@Override
- public PostInsertIdentityPersister getPersister() {
+ public EntityPersister getPersister() {
return persister;
}
diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/loader/ast/internal/DatabaseSnapshotExecutor.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/loader/ast/internal/DatabaseSnapshotExecutor.java
index 3fdd5acf1..33e8465b2 100644
--- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/loader/ast/internal/DatabaseSnapshotExecutor.java
+++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/loader/ast/internal/DatabaseSnapshotExecutor.java
@@ -79,7 +79,7 @@ class DatabaseSnapshotExecutor {
DatabaseSnapshotExecutor::visitEmptyFetchList,
true,
new LoadQueryInfluencers( sessionFactory ),
- sessionFactory
+ sessionFactory.getSqlTranslationEngine()
);
final NavigablePath rootPath = new NavigablePath( entityDescriptor.getEntityName() );
diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/loader/ast/internal/ReactiveAbstractMultiIdEntityLoader.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/loader/ast/internal/ReactiveAbstractMultiIdEntityLoader.java
index 527d59326..9b7c16395 100644
--- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/loader/ast/internal/ReactiveAbstractMultiIdEntityLoader.java
+++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/loader/ast/internal/ReactiveAbstractMultiIdEntityLoader.java
@@ -10,7 +10,7 @@
import java.util.concurrent.CompletionStage;
import org.hibernate.engine.spi.SessionFactoryImplementor;
-import org.hibernate.event.spi.EventSource;
+import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.loader.ast.spi.MultiIdLoadOptions;
import org.hibernate.metamodel.mapping.EntityIdentifierMapping;
import org.hibernate.metamodel.mapping.EntityMappingType;
@@ -50,7 +50,7 @@ public EntityMappingType getLoadable() {
}
@Override
- public final CompletionStage> reactiveLoad(K[] ids, MultiIdLoadOptions loadOptions, EventSource session) {
+ public final CompletionStage> reactiveLoad(K[] ids, MultiIdLoadOptions loadOptions, SharedSessionContractImplementor session) {
Objects.requireNonNull( ids );
return loadOptions.isOrderReturnEnabled()
@@ -58,8 +58,11 @@ public final CompletionStage> reactiveLoad(K[] ids, MultiIdLoadOptio
: performUnorderedMultiLoad( ids, loadOptions, session );
}
- protected abstract CompletionStage> performOrderedMultiLoad(K[] ids, MultiIdLoadOptions loadOptions, EventSource session);
+ protected abstract CompletionStage> performOrderedMultiLoad(K[] ids, MultiIdLoadOptions loadOptions, SharedSessionContractImplementor session);
- protected abstract CompletionStage> performUnorderedMultiLoad(K[] ids, MultiIdLoadOptions loadOptions, EventSource session);
+ protected abstract CompletionStage> performUnorderedMultiLoad(K[] ids, MultiIdLoadOptions loadOptions, SharedSessionContractImplementor session);
+ protected boolean isIdCoercionEnabled() {
+ return !getSessionFactory().getSessionFactoryOptions().getJpaCompliance().isLoadByIdComplianceEnabled();
+ }
}
diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/loader/ast/internal/ReactiveCollectionBatchLoaderArrayParam.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/loader/ast/internal/ReactiveCollectionBatchLoaderArrayParam.java
index efeafdd02..0960a2ebc 100644
--- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/loader/ast/internal/ReactiveCollectionBatchLoaderArrayParam.java
+++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/loader/ast/internal/ReactiveCollectionBatchLoaderArrayParam.java
@@ -18,9 +18,9 @@
import org.hibernate.loader.ast.internal.LoaderSelectBuilder;
import org.hibernate.loader.ast.internal.MultiKeyLoadHelper;
import org.hibernate.loader.ast.spi.SqlArrayMultiKeyLoader;
+import org.hibernate.metamodel.mapping.ForeignKeyDescriptor;
import org.hibernate.metamodel.mapping.JdbcMapping;
import org.hibernate.metamodel.mapping.PluralAttributeMapping;
-import org.hibernate.metamodel.mapping.internal.SimpleForeignKeyDescriptor;
import org.hibernate.query.spi.QueryOptions;
import org.hibernate.reactive.sql.exec.internal.StandardReactiveSelectExecutor;
import org.hibernate.reactive.sql.results.spi.ReactiveListResultsConsumer;
@@ -34,7 +34,6 @@
import org.hibernate.sql.exec.spi.JdbcParameterBindings;
import org.hibernate.sql.exec.spi.JdbcParametersList;
import org.hibernate.sql.results.internal.RowTransformerStandardImpl;
-import org.hibernate.type.BasicType;
import static org.hibernate.loader.ast.internal.MultiKeyLoadLogging.MULTI_KEY_LOAD_LOGGER;
@@ -65,18 +64,14 @@ public ReactiveCollectionBatchLoaderArrayParam(
);
}
- final SimpleForeignKeyDescriptor keyDescriptor = (SimpleForeignKeyDescriptor) getLoadable().getKeyDescriptor();
-
+ final ForeignKeyDescriptor keyDescriptor = getLoadable().getKeyDescriptor();
+ final JdbcMapping jdbcMapping = keyDescriptor.getSingleJdbcMapping();
+ final Class> jdbcJavaTypeClass = jdbcMapping.getJdbcJavaType().getJavaTypeClass();
arrayElementType = keyDescriptor.getJavaType().getJavaTypeClass();
- Class> arrayClass = Array.newInstance( arrayElementType, 0 ).getClass();
- final BasicType> arrayBasicType = getSessionFactory().getTypeConfiguration()
- .getBasicTypeRegistry()
- .getRegisteredType( arrayClass );
arrayJdbcMapping = MultiKeyLoadHelper.resolveArrayJdbcMapping(
- arrayBasicType,
- keyDescriptor.getJdbcMapping(),
- arrayClass,
+ keyDescriptor.getSingleJdbcMapping(),
+ jdbcJavaTypeClass,
getSessionFactory()
);
diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/loader/ast/internal/ReactiveEntityBatchLoaderArrayParam.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/loader/ast/internal/ReactiveEntityBatchLoaderArrayParam.java
index 9ff3c2ba7..04f971ffd 100644
--- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/loader/ast/internal/ReactiveEntityBatchLoaderArrayParam.java
+++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/loader/ast/internal/ReactiveEntityBatchLoaderArrayParam.java
@@ -10,7 +10,6 @@
import java.util.concurrent.CompletionStage;
import org.hibernate.LockOptions;
-import org.hibernate.engine.internal.BatchFetchQueueHelper;
import org.hibernate.engine.spi.EntityKey;
import org.hibernate.engine.spi.LoadQueryInfluencers;
import org.hibernate.engine.spi.SessionFactoryImplementor;
@@ -63,12 +62,10 @@ public ReactiveEntityBatchLoaderArrayParam(
}
identifierMapping = (BasicEntityIdentifierMapping) getLoadable().getIdentifierMapping();
- final Class> arrayClass =
- Array.newInstance( identifierMapping.getJavaType().getJavaTypeClass(), 0 ).getClass();
+ final Class> idClass = identifierMapping.getJavaType().getJavaTypeClass();
arrayJdbcMapping = MultiKeyLoadHelper.resolveArrayJdbcMapping(
- sessionFactory.getTypeConfiguration().getBasicTypeRegistry().getRegisteredType( arrayClass ),
identifierMapping.getJdbcMapping(),
- arrayClass,
+ idClass,
sessionFactory
);
@@ -162,7 +159,8 @@ private CompletionStage initializeEntities(
continue;
}
// found or not, remove the key from the batch-fetch queue
- BatchFetchQueueHelper.removeBatchLoadableEntityKey( id, getLoadable(), session );
+ session.getPersistenceContextInternal().getBatchFetchQueue()
+ .removeBatchLoadableEntityKey( session.generateEntityKey( id, getLoadable().getEntityPersister() ) );
}
} );
}
diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/loader/ast/internal/ReactiveMultiIdEntityLoaderArrayParam.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/loader/ast/internal/ReactiveMultiIdEntityLoaderArrayParam.java
index fd7cb8794..ef81c828e 100644
--- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/loader/ast/internal/ReactiveMultiIdEntityLoaderArrayParam.java
+++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/loader/ast/internal/ReactiveMultiIdEntityLoaderArrayParam.java
@@ -13,25 +13,22 @@
import org.hibernate.LockMode;
import org.hibernate.LockOptions;
-import org.hibernate.engine.internal.BatchFetchQueueHelper;
import org.hibernate.engine.spi.BatchFetchQueue;
import org.hibernate.engine.spi.EntityEntry;
import org.hibernate.engine.spi.EntityKey;
import org.hibernate.engine.spi.PersistenceContext;
import org.hibernate.engine.spi.SessionFactoryImplementor;
+import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.engine.spi.SubselectFetch;
-import org.hibernate.event.spi.EventSource;
-import org.hibernate.event.spi.LoadEvent;
-import org.hibernate.event.spi.LoadEventListener;
-import org.hibernate.loader.ast.internal.CacheEntityLoaderHelper;
-import org.hibernate.loader.ast.internal.LoaderHelper;
import org.hibernate.loader.ast.internal.LoaderSelectBuilder;
import org.hibernate.loader.ast.internal.MultiIdEntityLoaderArrayParam;
import org.hibernate.loader.ast.internal.MultiKeyLoadLogging;
import org.hibernate.loader.ast.spi.MultiIdLoadOptions;
+import org.hibernate.loader.internal.CacheLoadHelper.PersistenceContextEntry;
import org.hibernate.metamodel.mapping.BasicEntityIdentifierMapping;
import org.hibernate.metamodel.mapping.EntityMappingType;
import org.hibernate.metamodel.mapping.JdbcMapping;
+import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.query.spi.QueryOptions;
import org.hibernate.reactive.sql.exec.internal.StandardReactiveSelectExecutor;
import org.hibernate.reactive.sql.results.spi.ReactiveListResultsConsumer;
@@ -44,11 +41,12 @@
import org.hibernate.sql.exec.spi.JdbcParameterBindings;
import org.hibernate.sql.exec.spi.JdbcParametersList;
import org.hibernate.sql.results.internal.RowTransformerStandardImpl;
-import org.hibernate.type.BasicType;
+import static org.hibernate.event.spi.LoadEventListener.GET;
import static org.hibernate.internal.util.collections.CollectionHelper.arrayList;
import static org.hibernate.internal.util.collections.CollectionHelper.isEmpty;
import static org.hibernate.loader.ast.internal.MultiKeyLoadHelper.resolveArrayJdbcMapping;
+import static org.hibernate.loader.internal.CacheLoadHelper.loadFromSessionCache;
import static org.hibernate.reactive.loader.ast.internal.ReactiveLoaderHelper.loadByArrayParameter;
import static org.hibernate.reactive.util.impl.CompletionStages.completedFuture;
import static org.hibernate.reactive.util.impl.CompletionStages.loop;
@@ -66,16 +64,12 @@ public ReactiveMultiIdEntityLoaderArrayParam(
EntityMappingType entityDescriptor,
SessionFactoryImplementor sessionFactory) {
super( entityDescriptor, sessionFactory );
- final Class> arrayClass = createTypedArray( 0 ).getClass();
- JdbcMapping jdbcMapping = getIdentifierMapping().getJdbcMapping();
- BasicType> registeredType = getSessionFactory().getTypeConfiguration()
- .getBasicTypeRegistry()
- .getRegisteredType( arrayClass );
- JdbcMapping arrayJdbcMapping1 = resolveArrayJdbcMapping( registeredType, jdbcMapping, arrayClass, getSessionFactory() );
-// JavaType objectJavaType = getSessionFactory().getTypeConfiguration()
-// .getJavaTypeRegistry()
-// .resolveDescriptor( ReactiveArrayJdbcType.class );
- arrayJdbcMapping = arrayJdbcMapping1;
+ final Class> idClass = getIdentifierMapping().getJavaType().getJavaTypeClass();
+ arrayJdbcMapping = resolveArrayJdbcMapping(
+ getIdentifierMapping().getJdbcMapping(),
+ idClass,
+ getSessionFactory()
+ );
jdbcParameter = new JdbcParameterImpl( arrayJdbcMapping );
}
@@ -88,7 +82,7 @@ public BasicEntityIdentifierMapping getIdentifierMapping() {
protected CompletionStage> performOrderedMultiLoad(
K[] ids,
MultiIdLoadOptions loadOptions,
- EventSource session) {
+ SharedSessionContractImplementor session) {
if ( MultiKeyLoadLogging.MULTI_KEY_LOAD_LOGGER.isTraceEnabled() ) {
MultiKeyLoadLogging.MULTI_KEY_LOAD_LOGGER.tracef(
"ReactiveMultiIdEntityLoaderArrayParam#performOrderedMultiLoad - %s",
@@ -96,7 +90,7 @@ protected CompletionStage> performOrderedMultiLoad(
);
}
- final boolean coerce = !getSessionFactory().getJpaMetamodel().getJpaCompliance().isLoadByIdComplianceEnabled();
+ final boolean coerce = isIdCoercionEnabled();
final LockOptions lockOptions = ( loadOptions.getLockOptions() == null )
? new LockOptions( LockMode.NONE )
: loadOptions.getLockOptions();
@@ -113,24 +107,17 @@ protected CompletionStage> performOrderedMultiLoad(
final EntityKey entityKey = new EntityKey( id, getLoadable().getEntityPersister() );
if ( loadOptions.isSessionCheckingEnabled() || loadOptions.isSecondLevelCacheCheckingEnabled() ) {
- LoadEvent loadEvent = new LoadEvent(
- id,
- getLoadable().getJavaType().getJavaTypeClass().getName(),
- lockOptions,
- session,
- LoaderHelper.getReadOnlyFromLoadQueryInfluencers( session )
- );
-
Object managedEntity = null;
if ( loadOptions.isSessionCheckingEnabled() ) {
// look for it in the Session first
- final CacheEntityLoaderHelper.PersistenceContextEntry persistenceContextEntry = CacheEntityLoaderHelper.loadFromSessionCacheStatic(
- loadEvent,
+ final PersistenceContextEntry persistenceContextEntry = loadFromSessionCache(
entityKey,
- LoadEventListener.GET
+ lockOptions,
+ GET,
+ session
);
- managedEntity = persistenceContextEntry.getEntity();
+ managedEntity = persistenceContextEntry.entity();
if ( managedEntity != null
&& !loadOptions.isReturnOfDeletedEntitiesEnabled()
@@ -142,12 +129,9 @@ protected CompletionStage> performOrderedMultiLoad(
}
if ( managedEntity == null && loadOptions.isSecondLevelCacheCheckingEnabled() ) {
+ final EntityPersister persister = getLoadable().getEntityPersister();
// look for it in the SessionFactory
- managedEntity = CacheEntityLoaderHelper.INSTANCE.loadFromSecondLevelCache(
- loadEvent,
- getLoadable().getEntityPersister(),
- entityKey
- );
+ managedEntity = session.loadFromSecondLevelCache( persister, entityKey, null, lockOptions.getLockMode() );
}
if ( managedEntity != null ) {
@@ -217,13 +201,11 @@ protected CompletionStage> performOrderedMultiLoad(
} )
.thenApply( ignore -> {
final PersistenceContext persistenceContext = session.getPersistenceContext();
- for ( int i = 0; i < idsToLoadFromDatabaseResultIndexes.size(); i++ ) {
- final Integer resultIndex = idsToLoadFromDatabaseResultIndexes.get( i );
-
+ for ( final Integer resultIndex : idsToLoadFromDatabaseResultIndexes ) {
// the element value at this position in the result List should be
// the EntityKey for that entity - reuse it
final EntityKey entityKey = (EntityKey) result.get( resultIndex );
- BatchFetchQueueHelper.removeBatchLoadableEntityKey( entityKey, session );
+ session.getPersistenceContextInternal().getBatchFetchQueue().removeBatchLoadableEntityKey( entityKey );
Object entity = persistenceContext.getEntity( entityKey );
if ( entity != null && !loadOptions.isReturnOfDeletedEntitiesEnabled() ) {
// make sure it is not DELETED
@@ -245,7 +227,7 @@ protected CompletionStage> performOrderedMultiLoad(
protected CompletionStage> performUnorderedMultiLoad(
K[] ids,
MultiIdLoadOptions loadOptions,
- EventSource session) {
+ SharedSessionContractImplementor session) {
if ( MultiKeyLoadLogging.MULTI_KEY_LOAD_LOGGER.isTraceEnabled() ) {
MultiKeyLoadLogging.MULTI_KEY_LOAD_LOGGER.tracef(
"ReactiveMultiIdEntityLoaderArrayParam#performUnorderedMultiLoad - %s",
@@ -310,7 +292,8 @@ protected CompletionStage> performUnorderedMultiLoad(
continue;
}
// found or not, remove the key from the batch-fetch queue
- BatchFetchQueueHelper.removeBatchLoadableEntityKey( id, getLoadable(), session );
+ session.getPersistenceContextInternal().getBatchFetchQueue()
+ .removeBatchLoadableEntityKey( session.generateEntityKey( id, getLoadable().getEntityPersister() ) );
}
return result;
@@ -322,14 +305,14 @@ protected final K[] processResolvableEntities(
MultiIdEntityLoaderArrayParam.ResolutionConsumer resolutionConsumer,
MultiIdLoadOptions loadOptions,
LockOptions lockOptions,
- EventSource session) {
+ SharedSessionContractImplementor session) {
if ( !loadOptions.isSessionCheckingEnabled()
&& !loadOptions.isSecondLevelCacheCheckingEnabled() ) {
// we'll load all of them from the database
return ids;
}
- final boolean coerce = !getSessionFactory().getJpaMetamodel().getJpaCompliance().isLoadByIdComplianceEnabled();
+ final boolean coerce = isIdCoercionEnabled();
boolean foundAnyResolvedEntities = false;
List nonResolvedIds = null;
@@ -337,32 +320,24 @@ protected final K[] processResolvableEntities(
for ( int i = 0; i < ids.length; i++ ) {
final Object id;
if ( coerce ) {
- //noinspection unchecked
- id = (K) getLoadable().getIdentifierMapping().getJavaType().coerce( ids[i], session );
+ id = getLoadable().getIdentifierMapping().getJavaType().coerce( ids[i], session );
}
else {
id = ids[i];
}
final EntityKey entityKey = new EntityKey( id, getLoadable().getEntityPersister() );
- final LoadEvent loadEvent = new LoadEvent(
- id,
- getLoadable().getJavaType().getJavaTypeClass().getName(),
- lockOptions,
- session,
- LoaderHelper.getReadOnlyFromLoadQueryInfluencers( session )
- );
-
Object resolvedEntity = null;
// look for it in the Session first
- final CacheEntityLoaderHelper.PersistenceContextEntry persistenceContextEntry = CacheEntityLoaderHelper.loadFromSessionCacheStatic(
- loadEvent,
+ final PersistenceContextEntry persistenceContextEntry = loadFromSessionCache(
entityKey,
- LoadEventListener.GET
+ lockOptions,
+ GET,
+ session
);
if ( loadOptions.isSessionCheckingEnabled() ) {
- resolvedEntity = persistenceContextEntry.getEntity();
+ resolvedEntity = persistenceContextEntry.entity();
if ( resolvedEntity != null
&& !loadOptions.isReturnOfDeletedEntitiesEnabled()
@@ -374,11 +349,8 @@ protected final K[] processResolvableEntities(
}
if ( resolvedEntity == null && loadOptions.isSecondLevelCacheCheckingEnabled() ) {
- resolvedEntity = CacheEntityLoaderHelper.INSTANCE.loadFromSecondLevelCache(
- loadEvent,
- getLoadable().getEntityPersister(),
- entityKey
- );
+ final EntityPersister persister = getLoadable().getEntityPersister();
+ resolvedEntity = session.loadFromSecondLevelCache( persister, entityKey, null, lockOptions.getLockMode() );
}
if ( resolvedEntity != null ) {
@@ -391,7 +363,6 @@ protected final K[] processResolvableEntities(
if ( nonResolvedIds == null ) {
nonResolvedIds = new ArrayList<>();
}
- //noinspection unchecked,CastCanBeRemovedNarrowingVariableType
nonResolvedIds.add( (K) id );
}
}
diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/loader/ast/internal/ReactiveMultiIdEntityLoaderStandard.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/loader/ast/internal/ReactiveMultiIdEntityLoaderStandard.java
index 9a87f2359..5661c3493 100644
--- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/loader/ast/internal/ReactiveMultiIdEntityLoaderStandard.java
+++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/loader/ast/internal/ReactiveMultiIdEntityLoaderStandard.java
@@ -20,19 +20,14 @@
import org.hibernate.engine.jdbc.spi.JdbcServices;
import org.hibernate.engine.spi.EntityEntry;
import org.hibernate.engine.spi.EntityKey;
-import org.hibernate.engine.spi.LoadQueryInfluencers;
import org.hibernate.engine.spi.PersistenceContext;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.engine.spi.SubselectFetch;
-import org.hibernate.event.spi.EventSource;
-import org.hibernate.event.spi.LoadEvent;
-import org.hibernate.event.spi.LoadEventListener;
import org.hibernate.internal.util.collections.CollectionHelper;
-import org.hibernate.loader.ast.internal.CacheEntityLoaderHelper;
-import org.hibernate.loader.ast.internal.LoaderHelper;
import org.hibernate.loader.ast.internal.LoaderSelectBuilder;
import org.hibernate.loader.ast.spi.MultiIdLoadOptions;
+import org.hibernate.loader.internal.CacheLoadHelper.PersistenceContextEntry;
import org.hibernate.mapping.PersistentClass;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.query.spi.QueryOptions;
@@ -50,6 +45,8 @@
import org.hibernate.sql.exec.spi.JdbcParametersList;
import org.hibernate.sql.results.internal.RowTransformerStandardImpl;
+import static org.hibernate.event.spi.LoadEventListener.GET;
+import static org.hibernate.loader.internal.CacheLoadHelper.loadFromSessionCache;
import static org.hibernate.reactive.util.impl.CompletionStages.completedFuture;
import static org.hibernate.reactive.util.impl.CompletionStages.loop;
import static org.hibernate.reactive.util.impl.CompletionStages.voidFuture;
@@ -77,7 +74,7 @@ public ReactiveMultiIdEntityLoaderStandard(
protected CompletionStage> performOrderedMultiLoad(
Object[] ids,
MultiIdLoadOptions loadOptions,
- EventSource session) {
+ SharedSessionContractImplementor session) {
if ( LOG.isTraceEnabled() ) {
LOG.tracef( "#performOrderedMultiLoad(`%s`, ..)", getEntityDescriptor().getEntityName() );
}
@@ -106,7 +103,7 @@ protected CompletionStage> performOrderedMultiLoad(
final List idsInBatch = new ArrayList<>();
final List elementPositionsLoadedByBatch = new ArrayList<>();
- final boolean coerce = !getSessionFactory().getJpaMetamodel().getJpaCompliance().isLoadByIdComplianceEnabled();
+ final boolean coerce = isIdCoercionEnabled();
return loop( 0, ids.length, i -> {
final Object id = coerce
? getEntityDescriptor().getIdentifierMapping().getJavaType().coerce( ids[i], session )
@@ -114,24 +111,17 @@ protected CompletionStage> performOrderedMultiLoad(
final EntityKey entityKey = new EntityKey( id, getLoadable().getEntityPersister() );
if ( loadOptions.isSessionCheckingEnabled() || loadOptions.isSecondLevelCacheCheckingEnabled() ) {
- LoadEvent loadEvent = new LoadEvent(
- id,
- getLoadable().getJavaType().getJavaTypeClass().getName(),
- lockOptions,
- session,
- LoaderHelper.getReadOnlyFromLoadQueryInfluencers( session )
- );
-
Object managedEntity = null;
if ( loadOptions.isSessionCheckingEnabled() ) {
// look for it in the Session first
- CacheEntityLoaderHelper.PersistenceContextEntry persistenceContextEntry = CacheEntityLoaderHelper.INSTANCE.loadFromSessionCache(
- loadEvent,
+ PersistenceContextEntry persistenceContextEntry = loadFromSessionCache(
entityKey,
- LoadEventListener.GET
+ lockOptions,
+ GET,
+ session
);
- managedEntity = persistenceContextEntry.getEntity();
+ managedEntity = persistenceContextEntry.entity();
if ( managedEntity != null && !loadOptions.isReturnOfDeletedEntitiesEnabled() && !persistenceContextEntry.isManaged() ) {
// put a null in the result
@@ -141,12 +131,10 @@ protected CompletionStage> performOrderedMultiLoad(
}
if ( managedEntity == null && loadOptions.isSecondLevelCacheCheckingEnabled() ) {
+ final EntityPersister persister = getLoadable().getEntityPersister();
// look for it in the SessionFactory
- managedEntity = CacheEntityLoaderHelper.INSTANCE.loadFromSecondLevelCache(
- loadEvent,
- getLoadable().getEntityPersister(),
- entityKey
- );
+ managedEntity = session
+ .loadFromSecondLevelCache( persister, entityKey, null, lockOptions.getLockMode() );
}
if ( managedEntity != null ) {
@@ -300,7 +288,7 @@ private static List singletonList(Object loaded) {
protected CompletionStage> performUnorderedMultiLoad(
Object[] ids,
MultiIdLoadOptions loadOptions,
- EventSource session) {
+ SharedSessionContractImplementor session) {
assert !loadOptions.isOrderReturnEnabled();
assert ids != null;
@@ -323,35 +311,27 @@ protected CompletionStage> performUnorderedMultiLoad(
boolean foundAnyManagedEntities = false;
final List nonManagedIds = new ArrayList<>();
- final boolean coerce = !getSessionFactory().getJpaMetamodel().getJpaCompliance().isLoadByIdComplianceEnabled();
- for ( int i = 0; i < ids.length; i++ ) {
+ final boolean coerce = isIdCoercionEnabled();
+ for ( Object o : ids ) {
final Object id = coerce
- ? getEntityDescriptor().getIdentifierMapping().getJavaType().coerce( ids[i], session )
- : ids[i];
+ ? getEntityDescriptor().getIdentifierMapping().getJavaType().coerce( o, session )
+ : o;
final EntityKey entityKey = new EntityKey( id, getLoadable().getEntityPersister() );
- LoadEvent loadEvent = new LoadEvent(
- id,
- getLoadable().getJavaType().getJavaTypeClass().getName(),
- lockOptions,
- session,
- getReadOnlyFromLoadQueryInfluencers( session )
- );
-
- Object managedEntity = null;
+ Object cachedEntity = null;
// look for it in the Session first
- CacheEntityLoaderHelper.PersistenceContextEntry persistenceContextEntry = CacheEntityLoaderHelper.INSTANCE
- .loadFromSessionCache(
- loadEvent,
- entityKey,
- LoadEventListener.GET
- );
+ PersistenceContextEntry persistenceContextEntry = loadFromSessionCache(
+ entityKey,
+ lockOptions,
+ GET,
+ session
+ );
if ( loadOptions.isSessionCheckingEnabled() ) {
- managedEntity = persistenceContextEntry.getEntity();
+ cachedEntity = persistenceContextEntry.entity();
- if ( managedEntity != null
+ if ( cachedEntity != null
&& !loadOptions.isReturnOfDeletedEntitiesEnabled()
&& !persistenceContextEntry.isManaged() ) {
foundAnyManagedEntities = true;
@@ -360,18 +340,20 @@ protected CompletionStage> performUnorderedMultiLoad(
}
}
- if ( managedEntity == null && loadOptions.isSecondLevelCacheCheckingEnabled() ) {
- managedEntity = CacheEntityLoaderHelper.INSTANCE.loadFromSecondLevelCache(
- loadEvent,
- getLoadable().getEntityPersister(),
- entityKey
+ if ( cachedEntity == null && loadOptions.isSecondLevelCacheCheckingEnabled() ) {
+ final EntityPersister persister = getLoadable().getEntityPersister();
+ cachedEntity = session.loadFromSecondLevelCache(
+ persister,
+ entityKey,
+ null,
+ lockOptions.getLockMode()
);
}
- if ( managedEntity != null ) {
+ if ( cachedEntity != null ) {
foundAnyManagedEntities = true;
//noinspection unchecked
- result.add( (T) managedEntity );
+ result.add( (T) cachedEntity );
}
else {
nonManagedIds.add( id );
@@ -427,14 +409,4 @@ protected CompletionStage> performUnorderedMultiLoad(
} )
.thenApply( v -> result );
}
-
- private Boolean getReadOnlyFromLoadQueryInfluencers(SharedSessionContractImplementor session) {
- Boolean readOnly = null;
- final LoadQueryInfluencers loadQueryInfluencers = session.getLoadQueryInfluencers();
- if ( loadQueryInfluencers != null ) {
- readOnly = loadQueryInfluencers.getReadOnly();
- }
- return readOnly;
- }
-
}
diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/loader/ast/internal/ReactiveNaturalIdLoaderDelegate.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/loader/ast/internal/ReactiveNaturalIdLoaderDelegate.java
index 56fef5be9..08b83cd47 100644
--- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/loader/ast/internal/ReactiveNaturalIdLoaderDelegate.java
+++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/loader/ast/internal/ReactiveNaturalIdLoaderDelegate.java
@@ -27,6 +27,7 @@
import org.hibernate.metamodel.mapping.NaturalIdMapping;
import org.hibernate.query.internal.SimpleQueryOptions;
import org.hibernate.query.spi.QueryOptions;
+import org.hibernate.reactive.engine.impl.ReactiveCallbackImpl;
import org.hibernate.reactive.loader.ast.spi.ReactiveNaturalIdLoader;
import org.hibernate.reactive.sql.exec.internal.StandardReactiveSelectExecutor;
import org.hibernate.reactive.sql.results.spi.ReactiveListResultsConsumer;
@@ -38,7 +39,6 @@
import org.hibernate.sql.ast.tree.select.QuerySpec;
import org.hibernate.sql.ast.tree.select.SelectStatement;
import org.hibernate.sql.exec.internal.BaseExecutionContext;
-import org.hibernate.sql.exec.internal.CallbackImpl;
import org.hibernate.sql.exec.internal.JdbcParameterBindingsImpl;
import org.hibernate.sql.exec.spi.Callback;
import org.hibernate.sql.exec.spi.JdbcOperationQuerySelect;
@@ -238,7 +238,7 @@ public CompletionStage reactiveSelectByNaturalId(
fetchProcessor,
true,
new LoadQueryInfluencers( sessionFactory ),
- sessionFactory
+ sessionFactory.getSqlTranslationEngine()
);
final TableGroup rootTableGroup = entityDescriptor().createRootTableGroup(
@@ -335,7 +335,7 @@ public NaturalIdLoaderWithOptionsExecutionContext(
QueryOptions queryOptions) {
super( session );
this.queryOptions = queryOptions;
- callback = new CallbackImpl();
+ callback = new ReactiveCallbackImpl();
}
@Override
diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/loader/ast/internal/ReactiveSingleIdEntityLoaderProvidedQueryImpl.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/loader/ast/internal/ReactiveSingleIdEntityLoaderProvidedQueryImpl.java
index 6b849d346..a2b3a384e 100644
--- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/loader/ast/internal/ReactiveSingleIdEntityLoaderProvidedQueryImpl.java
+++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/loader/ast/internal/ReactiveSingleIdEntityLoaderProvidedQueryImpl.java
@@ -7,17 +7,18 @@
import java.util.concurrent.CompletionStage;
-import org.hibernate.FlushMode;
import org.hibernate.LockOptions;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.internal.util.collections.ArrayHelper;
import org.hibernate.metamodel.mapping.EntityMappingType;
+import org.hibernate.query.Query;
+import org.hibernate.query.QueryFlushMode;
import org.hibernate.query.named.NamedQueryMemento;
-import org.hibernate.query.spi.QueryImplementor;
import org.hibernate.reactive.loader.ast.spi.ReactiveSingleIdEntityLoader;
import org.hibernate.reactive.query.ReactiveSelectionQuery;
import jakarta.persistence.Parameter;
+import org.hibernate.type.descriptor.java.JavaType;
import static org.hibernate.reactive.util.impl.CompletionStages.completedFuture;
@@ -30,9 +31,9 @@ public class ReactiveSingleIdEntityLoaderProvidedQueryImpl implements Reactiv
private static final CompletionStage EMPTY_ARRAY_STAGE = completedFuture( ArrayHelper.EMPTY_OBJECT_ARRAY );
private final EntityMappingType entityDescriptor;
- private final NamedQueryMemento namedQueryMemento;
+ private final NamedQueryMemento namedQueryMemento;
- public ReactiveSingleIdEntityLoaderProvidedQueryImpl(EntityMappingType entityDescriptor, NamedQueryMemento namedQueryMemento) {
+ public ReactiveSingleIdEntityLoaderProvidedQueryImpl(EntityMappingType entityDescriptor, NamedQueryMemento namedQueryMemento) {
this.entityDescriptor = entityDescriptor;
this.namedQueryMemento = namedQueryMemento;
}
@@ -42,17 +43,13 @@ public EntityMappingType getLoadable() {
return entityDescriptor;
}
- @Override
+ @Override @SuppressWarnings("unchecked")
public CompletionStage load(Object pkValue, LockOptions lockOptions, Boolean readOnly, SharedSessionContractImplementor session) {
- // noinspection unchecked
- final QueryImplementor query = namedQueryMemento
- .toQuery( session, (Class) entityDescriptor.getMappedJavaType().getJavaTypeClass() );
-
- //noinspection unchecked
+ final JavaType mappedJavaType = (JavaType) entityDescriptor.getMappedJavaType();
+ final Query query = namedQueryMemento.toQuery( session, mappedJavaType.getJavaTypeClass() );
query.setParameter( (Parameter) query.getParameters().iterator().next(), pkValue );
- query.setHibernateFlushMode( FlushMode.MANUAL );
-
- return ( (ReactiveSelectionQuery) query ).reactiveUnique();
+ query.setQueryFlushMode( QueryFlushMode.NO_FLUSH );
+ return ( (ReactiveSelectionQuery) query ).reactiveUnique();
}
@Override
diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/loader/ast/internal/ReactiveSingleIdEntityLoaderStandardImpl.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/loader/ast/internal/ReactiveSingleIdEntityLoaderStandardImpl.java
index 684894cf2..c23a00983 100644
--- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/loader/ast/internal/ReactiveSingleIdEntityLoaderStandardImpl.java
+++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/loader/ast/internal/ReactiveSingleIdEntityLoaderStandardImpl.java
@@ -55,8 +55,7 @@ public CompletionStage load(
SharedSessionContractImplementor session) {
final ReactiveSingleIdLoadPlan loadPlan = (ReactiveSingleIdLoadPlan) resolveLoadPlan(
lockOptions,
- session.getLoadQueryInfluencers(),
- session.getFactory()
+ session.getLoadQueryInfluencers()
);
return loadPlan.load( key, readOnly, true, session );
}
@@ -68,7 +67,7 @@ public CompletionStage load(
LockOptions lockOptions,
Boolean readOnly,
SharedSessionContractImplementor session) {
- final ReactiveSingleIdLoadPlan loadPlan = (ReactiveSingleIdLoadPlan) resolveLoadPlan( lockOptions, session.getLoadQueryInfluencers(), session.getFactory() );
+ final ReactiveSingleIdLoadPlan loadPlan = (ReactiveSingleIdLoadPlan) resolveLoadPlan( lockOptions, session.getLoadQueryInfluencers() );
return loadPlan.load( key, entityInstance, readOnly, false, session );
}
diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/loader/ast/internal/ReactiveSingleIdLoadPlan.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/loader/ast/internal/ReactiveSingleIdLoadPlan.java
index 83c3292f5..3d636eed9 100644
--- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/loader/ast/internal/ReactiveSingleIdLoadPlan.java
+++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/loader/ast/internal/ReactiveSingleIdLoadPlan.java
@@ -20,16 +20,19 @@
import org.hibernate.query.internal.SimpleQueryOptions;
import org.hibernate.query.spi.QueryOptions;
import org.hibernate.query.spi.QueryParameterBindings;
+import org.hibernate.reactive.engine.impl.ReactiveCallbackImpl;
import org.hibernate.reactive.sql.exec.internal.StandardReactiveSelectExecutor;
import org.hibernate.reactive.sql.results.spi.ReactiveListResultsConsumer;
import org.hibernate.resource.jdbc.spi.LogicalConnectionImplementor;
import org.hibernate.sql.ast.tree.select.SelectStatement;
-import org.hibernate.sql.exec.internal.CallbackImpl;
import org.hibernate.sql.exec.internal.JdbcParameterBindingsImpl;
import org.hibernate.sql.exec.spi.Callback;
import org.hibernate.sql.exec.spi.ExecutionContext;
import org.hibernate.sql.exec.spi.JdbcParameterBindings;
import org.hibernate.sql.exec.spi.JdbcParametersList;
+import org.hibernate.sql.results.spi.RowTransformer;
+
+import static org.hibernate.reactive.util.impl.CompletionStages.nullFuture;
public class ReactiveSingleIdLoadPlan extends SingleIdLoadPlan> {
@@ -61,7 +64,7 @@ public CompletionStage load(Object restrictedValue, Object entityInstance, Bo
}
assert offset == getJdbcParameters().size();
final QueryOptions queryOptions = new SimpleQueryOptions( getLockOptions(), readOnly );
- final Callback callback = new CallbackImpl();
+ final ReactiveCallbackImpl callback = new ReactiveCallbackImpl();
EntityMappingType loadable = (EntityMappingType) getLoadable();
ExecutionContext executionContext = executionContext(
restrictedValue,
@@ -73,21 +76,27 @@ public CompletionStage load(Object restrictedValue, Object entityInstance, Bo
);
// FIXME: Should we get this from jdbcServices.getSelectExecutor()?
return StandardReactiveSelectExecutor.INSTANCE
- .list( getJdbcSelect(), jdbcParameterBindings, executionContext, getRowTransformer(), resultConsumer( singleResultExpected ) )
+ .list( getJdbcSelect(), jdbcParameterBindings, executionContext, rowTransformer(), resultConsumer( singleResultExpected ) )
.thenApply( this::extractEntity )
- .thenApply( entity -> {
- invokeAfterLoadActions( callback, session, entity );
- return (T) entity;
- } );
+ .thenCompose( entity -> invokeAfterLoadActions( callback, session, entity ) );
+ }
+
+ private RowTransformer rowTransformer() {
+ // Because of the generics, the compiler expect this to return RowTransformer>
+ // but it actually returns RowTransformer. I don't know at the moment how to fix this in a cleaner way
+ return (RowTransformer) getRowTransformer();
}
- private void invokeAfterLoadActions(Callback callback, SharedSessionContractImplementor session, T entity) {
- if ( entity != null && getLoadable() != null) {
- callback.invokeAfterLoadActions( entity, (EntityMappingType) getLoadable(), session );
+ private CompletionStage invokeAfterLoadActions(ReactiveCallbackImpl callback, SharedSessionContractImplementor session, T entity) {
+ if ( entity != null && getLoadable() != null ) {
+ return callback
+ .invokeReactiveLoadActions( entity, (EntityMappingType) getLoadable(), session )
+ .thenApply( v -> entity );
}
+ return nullFuture();
}
- private Object extractEntity(List> list) {
+ private T extractEntity(List list) {
return list.isEmpty() ? null : list.get( 0 );
}
@@ -156,7 +165,7 @@ public CollectionKey getCollectionKey() {
@Override
public QueryParameterBindings getQueryParameterBindings() {
- return QueryParameterBindings.NO_PARAM_BINDINGS;
+ return QueryParameterBindings.empty();
}
@Override
diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/loader/ast/internal/ReactiveSingleUniqueKeyEntityLoaderStandard.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/loader/ast/internal/ReactiveSingleUniqueKeyEntityLoaderStandard.java
index 62e5d0d44..09490cdad 100644
--- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/loader/ast/internal/ReactiveSingleUniqueKeyEntityLoaderStandard.java
+++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/loader/ast/internal/ReactiveSingleUniqueKeyEntityLoaderStandard.java
@@ -24,13 +24,13 @@
import org.hibernate.metamodel.mapping.SingularAttributeMapping;
import org.hibernate.metamodel.mapping.internal.ToOneAttributeMapping;
import org.hibernate.query.spi.QueryOptions;
+import org.hibernate.reactive.engine.impl.ReactiveCallbackImpl;
import org.hibernate.reactive.loader.ast.spi.ReactiveSingleUniqueKeyEntityLoader;
import org.hibernate.reactive.sql.exec.internal.StandardReactiveSelectExecutor;
import org.hibernate.reactive.sql.results.spi.ReactiveListResultsConsumer;
import org.hibernate.sql.ast.SqlAstTranslatorFactory;
import org.hibernate.sql.ast.tree.select.SelectStatement;
import org.hibernate.sql.exec.internal.BaseExecutionContext;
-import org.hibernate.sql.exec.internal.CallbackImpl;
import org.hibernate.sql.exec.internal.JdbcParameterBindingsImpl;
import org.hibernate.sql.exec.spi.Callback;
import org.hibernate.sql.exec.spi.JdbcOperationQuerySelect;
@@ -179,7 +179,7 @@ public SingleUKEntityLoaderExecutionContext(SharedSessionContractImplementor ses
super( session );
//Careful, readOnly is possibly null
this.queryOptions = readOnly == null ? QueryOptions.NONE : readOnly ? QueryOptions.READ_ONLY : QueryOptions.READ_WRITE;
- callback = new CallbackImpl();
+ callback = new ReactiveCallbackImpl();
}
@Override
diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/loader/ast/internal/ReactiveStandardBatchLoaderFactory.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/loader/ast/internal/ReactiveStandardBatchLoaderFactory.java
index 5d5c03fb5..fa5d075ba 100644
--- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/loader/ast/internal/ReactiveStandardBatchLoaderFactory.java
+++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/loader/ast/internal/ReactiveStandardBatchLoaderFactory.java
@@ -33,7 +33,7 @@ public EntityBatchLoader createEntityBatchLoader(
// NOTE : don't use the EntityIdentifierMapping here because it will not be known until later
final Type identifierType = entityDescriptor.getEntityPersister().getIdentifierType();
- final int idColumnCount = identifierType.getColumnSpan( factory );
+ final int idColumnCount = identifierType.getColumnSpan( factory.getRuntimeMetamodels() );
if ( idColumnCount == 1
&& MultiKeyLoadHelper.supportsSqlArrayType( dialect )
diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/loader/ast/spi/ReactiveAfterLoadAction.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/loader/ast/spi/ReactiveAfterLoadAction.java
new file mode 100644
index 000000000..e7e20d2e8
--- /dev/null
+++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/loader/ast/spi/ReactiveAfterLoadAction.java
@@ -0,0 +1,26 @@
+/* Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * Copyright: Red Hat Inc. and Hibernate Authors
+ */
+package org.hibernate.reactive.loader.ast.spi;
+
+import java.util.concurrent.CompletionStage;
+
+import org.hibernate.engine.spi.SharedSessionContractImplementor;
+import org.hibernate.metamodel.mapping.EntityMappingType;
+
+/**
+ * Reactive version of {@link org.hibernate.loader.ast.spi.AfterLoadAction}
+ */
+public interface ReactiveAfterLoadAction {
+ /**
+ * @see org.hibernate.loader.ast.spi.AfterLoadAction#afterLoad(Object, EntityMappingType, SharedSessionContractImplementor)
+ *
+ * The action trigger - the {@code entity} is being loaded
+ */
+ CompletionStage reactiveAfterLoad(
+ Object entity,
+ EntityMappingType entityMappingType,
+ SharedSessionContractImplementor session);
+}
diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/loader/ast/spi/ReactiveMultiIdEntityLoader.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/loader/ast/spi/ReactiveMultiIdEntityLoader.java
index 47050b139..e0236e361 100644
--- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/loader/ast/spi/ReactiveMultiIdEntityLoader.java
+++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/loader/ast/spi/ReactiveMultiIdEntityLoader.java
@@ -8,7 +8,7 @@
import java.util.List;
import java.util.concurrent.CompletionStage;
-import org.hibernate.event.spi.EventSource;
+import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.loader.ast.spi.MultiIdEntityLoader;
import org.hibernate.loader.ast.spi.MultiIdLoadOptions;
import org.hibernate.reactive.logging.impl.Log;
@@ -22,9 +22,9 @@
public interface ReactiveMultiIdEntityLoader extends MultiIdEntityLoader {
@Override
- default List load(K[] ids, MultiIdLoadOptions options, EventSource session) {
+ default List load(K[] ids, MultiIdLoadOptions options, SharedSessionContractImplementor session) {
throw make( Log.class, lookup() ).nonReactiveMethodCall( "reactiveLoad" );
}
- CompletionStage> reactiveLoad(K[] ids, MultiIdLoadOptions options, EventSource session);
+ CompletionStage> reactiveLoad(K[] ids, MultiIdLoadOptions options, SharedSessionContractImplementor session);
}
diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/loader/entity/ReactiveCacheEntityLoaderHelper.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/loader/entity/ReactiveCacheEntityLoaderHelper.java
deleted file mode 100644
index 703148cd7..000000000
--- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/loader/entity/ReactiveCacheEntityLoaderHelper.java
+++ /dev/null
@@ -1,148 +0,0 @@
-/* Hibernate, Relational Persistence for Idiomatic Java
- *
- * SPDX-License-Identifier: Apache-2.0
- * Copyright: Red Hat Inc. and Hibernate Authors
- */
-package org.hibernate.reactive.loader.entity;
-
-import static org.hibernate.loader.ast.internal.LoaderHelper.upgradeLock;
-import org.hibernate.HibernateException;
-import org.hibernate.LockMode;
-import org.hibernate.LockOptions;
-import org.hibernate.ObjectDeletedException;
-import org.hibernate.cache.spi.access.EntityDataAccess;
-import org.hibernate.cache.spi.access.SoftLock;
-import org.hibernate.engine.spi.EntityEntry;
-import org.hibernate.engine.spi.EntityKey;
-import org.hibernate.engine.spi.SessionImplementor;
-import org.hibernate.engine.spi.Status;
-import org.hibernate.event.spi.EventSource;
-import org.hibernate.event.spi.LoadEvent;
-import org.hibernate.event.spi.LoadEventListener;
-import org.hibernate.internal.CoreLogging;
-import org.hibernate.internal.CoreMessageLogger;
-import org.hibernate.loader.ast.internal.CacheEntityLoaderHelper.EntityStatus;
-import org.hibernate.loader.ast.internal.CacheEntityLoaderHelper.PersistenceContextEntry;
-import org.hibernate.persister.entity.EntityPersister;
-import org.hibernate.reactive.persister.entity.impl.ReactiveEntityPersister;
-import org.hibernate.sql.results.LoadingLogger;
-
-/**
- * @author Gavin King
- *
- * @see org.hibernate.loader.ast.internal.CacheEntityLoaderHelper
- */
-public class ReactiveCacheEntityLoaderHelper {
-
- public static final ReactiveCacheEntityLoaderHelper INSTANCE = new ReactiveCacheEntityLoaderHelper();
-
- private static final CoreMessageLogger LOG = CoreLogging.messageLogger( ReactiveCacheEntityLoaderHelper.class );
-
- private ReactiveCacheEntityLoaderHelper() {}
-
- /**
- * Attempts to locate the entity in the session-level cache.
- *
- * If allowed to return nulls, then if the entity happens to be found in
- * the session cache, we check the entity type for proper handling
- * of entity hierarchies.
- *
- * If checkDeleted was set to true, then if the entity is found in the
- * session-level cache, its current status within the session cache
- * is checked to see if it has previously been scheduled for deletion.
- *
- * @param event The load event
- * @param keyToLoad The EntityKey representing the entity to be loaded.
- * @param options The load options.
- *
- * @return The entity from the session-level cache, or null.
- *
- * @throws HibernateException Generally indicates problems applying a lock-mode.
- */
- public PersistenceContextEntry loadFromSessionCache(
- final LoadEvent event,
- final EntityKey keyToLoad,
- final LoadEventListener.LoadType options) throws HibernateException {
-
- SessionImplementor session = event.getSession();
- Object old = session.getEntityUsingInterceptor( keyToLoad );
-
- if ( old != null ) {
- // this object was already loaded
- EntityEntry oldEntry = session.getPersistenceContext().getEntry( old );
- if ( options.isCheckDeleted() ) {
- if ( oldEntry.getStatus().isDeletedOrGone() ) {
- LoadingLogger.LOGGER.debug(
- "Load request found matching entity in context, but it is scheduled for removal; returning null" );
- return new PersistenceContextEntry( old, EntityStatus.REMOVED_ENTITY_MARKER );
- }
- }
- if ( options.isAllowNulls() ) {
- final EntityPersister persister = event.getSession()
- .getFactory()
- .getRuntimeMetamodels()
- .getMappingMetamodel()
- .getEntityDescriptor( keyToLoad.getEntityName() );
- if ( !persister.isInstance( old ) ) {
- LOG.debug(
- "Load request found matching entity in context, but the matched entity was of an inconsistent return type; returning null"
- );
- return new PersistenceContextEntry( old, EntityStatus.INCONSISTENT_RTN_CLASS_MARKER );
- }
- }
- upgradeLock( old, oldEntry, event.getLockOptions(), event.getSession() );
- }
-
- return new PersistenceContextEntry( old, EntityStatus.MANAGED );
- }
-
- /**
- * see org.hibernate.event.internal.AbstractLockUpgradeEventListener#upgradeLock(Object, EntityEntry, LockOptions, EventSource)
- */
- private static void upgradeLock(Object object, EntityEntry entry, LockOptions lockOptions, EventSource source) {
-
- LockMode requestedLockMode = lockOptions.getLockMode();
- if ( requestedLockMode.greaterThan( entry.getLockMode() ) ) {
- // The user requested a "greater" (i.e. more restrictive) form of pessimistic lock
-
- if ( entry.getStatus() != Status.MANAGED ) {
- throw new ObjectDeletedException(
- "attempted to lock a deleted instance",
- entry.getId(),
- entry.getPersister().getEntityName()
- );
- }
-
- final EntityPersister persister = entry.getPersister();
- final boolean cachingEnabled = persister.canWriteToCache();
- SoftLock lock = null;
- Object ck = null;
- try {
- if ( cachingEnabled ) {
- EntityDataAccess cache = persister.getCacheAccessStrategy();
- ck = cache.generateCacheKey( entry.getId(), persister, source.getFactory(), source.getTenantIdentifier() );
- lock = cache.lockItem( source, ck, entry.getVersion() );
- }
-
- if ( persister.isVersioned() && requestedLockMode == LockMode.PESSIMISTIC_FORCE_INCREMENT ) {
- // todo : should we check the current isolation mode explicitly?
- Object nextVersion = persister.forceVersionIncrement( entry.getId(), entry.getVersion(), source );
- entry.forceLocked( object, nextVersion );
- }
- else {
- ( (ReactiveEntityPersister) persister )
- .reactiveLock( entry.getId(), entry.getVersion(), object, lockOptions, source );
- }
- entry.setLockMode( requestedLockMode );
- }
- finally {
- // the database now holds a lock + the object is flushed from the cache,
- // so release the soft lock
- if ( cachingEnabled ) {
- persister.getCacheAccessStrategy().unlockItem( source, ck, lock );
- }
- }
-
- }
- }
-}
diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/logging/impl/Log.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/logging/impl/Log.java
index 72760a26b..fa29cd8b5 100644
--- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/logging/impl/Log.java
+++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/logging/impl/Log.java
@@ -7,11 +7,13 @@
+import java.sql.SQLException;
import java.sql.SQLWarning;
import jakarta.persistence.PersistenceException;
import org.hibernate.HibernateException;
+import org.hibernate.JDBCException;
import org.hibernate.LazyInitializationException;
import org.hibernate.cache.CacheException;
import org.hibernate.dialect.Dialect;
@@ -24,6 +26,7 @@
import org.jboss.logging.annotations.Message;
import org.jboss.logging.annotations.MessageLogger;
+import static org.jboss.logging.Logger.Level.DEBUG;
import static org.jboss.logging.Logger.Level.ERROR;
import static org.jboss.logging.Logger.Level.INFO;
import static org.jboss.logging.Logger.Level.WARN;
@@ -32,8 +35,8 @@
public interface Log extends BasicLogger {
@LogMessage(level = INFO)
- @Message(id = 1, value = "Hibernate Reactive")
- void startHibernateReactive();
+ @Message(id = 1, value = "Hibernate Reactive version %s")
+ void startHibernateReactive(String version);
@LogMessage(level = INFO)
@Message(id = 2, value = "Vert.x not detected, creating a new instance")
@@ -258,6 +261,15 @@ public interface Log extends BasicLogger {
@Message(id = 80, value = "No results were returned by the query (you can try running it with '.executeUpdate()'): %1$s")
HibernateException noResultException(String sql);
+ @Message(id = 81, value = "The Vert.x SQL client doesn't support the SQL XML data type. If it's the mapping of an array, you can also try setting the property `hibernate.type.preferred_array_jdbc_type`")
+ HibernateException unsupportedXmlType();
+
+ @Message(id = 83, value = "Unexpected request of a non reactive connection")
+ HibernateException unexpectedConnectionRequest();
+
+ @Message(id = 84, value = "The application requested a JDBC connection, but Hibernate Reactive doesn't use JDBC. This could be caused by a bug or the use of an unsupported feature in Hibernate Reactive")
+ SQLException notUsingJdbc();
+
// Same method that exists in CoreMessageLogger
@LogMessage(level = WARN)
@Message(id = 104, value = "firstResult/maxResults specified with collection fetch; applying in memory!" )
@@ -278,6 +290,11 @@ public interface Log extends BasicLogger {
@Message(id = 245, value = "Manipulation query [%s] resulted in [%s] split queries" )
void splitQueries(String sourceQuery, int length);
+ // Same method that exists in CoreMessageLogger
+ @LogMessage(level = INFO)
+ @Message(value = "Could not find any META-INF/persistence.xml file in the classpath", id = 318)
+ void unableToFindPersistenceXmlInClasspath();
+
// Same method that exists in CoreMessageLogger
@LogMessage(level = INFO)
@Message(id = 327, value = "Error performing load command")
@@ -300,4 +317,16 @@ public interface Log extends BasicLogger {
@LogMessage(level = WARN)
@Message(id = 448, value = "Warnings creating temp table : %s")
void warningsCreatingTempTable(SQLWarning warning);
+
+ @LogMessage(level = WARN)
+ @Message( id= 494, value = "Attempt to merge an uninitialized collection with queued operations; queued operations will be ignored: %s")
+ void ignoreQueuedOperationsOnMerge(String collectionInfoString);
+
+ // Same method in ORM
+ @LogMessage(level = DEBUG)
+ @Message(value = "JDBCException was thrown for a transaction marked for rollback. " +
+ " This is probably due to an operation failing fast due to the transaction being marked for rollback.",
+ id = 520)
+ void jdbcExceptionThrownWithTransactionRolledBack(@Cause JDBCException e);
+
}
diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/logging/impl/Version.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/logging/impl/Version.java
new file mode 100644
index 000000000..2ed6d6b9d
--- /dev/null
+++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/logging/impl/Version.java
@@ -0,0 +1,32 @@
+/* Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * Copyright: Red Hat Inc. and Hibernate Authors
+ */
+package org.hibernate.reactive.logging.impl;
+
+/**
+ * Information about the version of Hibernate Reactive.
+ *
+ * @author Steve Ebersole
+ */
+public final class Version {
+
+ private static final String VERSION;
+ static {
+ final String version = Version.class.getPackage().getImplementationVersion();
+ VERSION = version != null ? version : "[WORKING]";
+ }
+
+ private Version() {
+ }
+
+ /**
+ * Access to the Hibernate Reactive version.
+ *
+ * @return The version
+ */
+ public static String getVersionString() {
+ return VERSION;
+ }
+}
diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/metamodel/mapping/internal/ReactiveEmbeddedIdentifierMappingImpl.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/metamodel/mapping/internal/ReactiveEmbeddedIdentifierMappingImpl.java
index 3f5244fa9..204a23d3a 100644
--- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/metamodel/mapping/internal/ReactiveEmbeddedIdentifierMappingImpl.java
+++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/metamodel/mapping/internal/ReactiveEmbeddedIdentifierMappingImpl.java
@@ -13,6 +13,7 @@
import org.hibernate.metamodel.mapping.EmbeddableMappingType;
import org.hibernate.metamodel.mapping.JdbcMapping;
import org.hibernate.metamodel.mapping.internal.EmbeddedIdentifierMappingImpl;
+import org.hibernate.metamodel.mapping.internal.ToOneAttributeMapping;
import org.hibernate.reactive.sql.results.graph.embeddable.internal.ReactiveEmbeddableFetchImpl;
import org.hibernate.spi.NavigablePath;
import org.hibernate.sql.ast.spi.SqlSelection;
@@ -20,6 +21,7 @@
import org.hibernate.sql.results.graph.DomainResultCreationState;
import org.hibernate.sql.results.graph.Fetch;
import org.hibernate.sql.results.graph.FetchParent;
+import org.hibernate.sql.results.graph.Fetchable;
public class ReactiveEmbeddedIdentifierMappingImpl extends AbstractCompositeIdentifierMapping {
@@ -104,4 +106,13 @@ public String getSqlAliasStem() {
public String getFetchableName() {
return delegate.getFetchableName();
}
+
+ @Override
+ public Fetchable getFetchable(int position) {
+ Fetchable fetchable = delegate.getFetchable( position );
+ if ( fetchable instanceof ToOneAttributeMapping ) {
+ return new ReactiveToOneAttributeMapping( (ToOneAttributeMapping) fetchable );
+ }
+ return fetchable;
+ }
}
diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/metamodel/mapping/internal/ReactiveRuntimeModelCreationContext.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/metamodel/mapping/internal/ReactiveRuntimeModelCreationContext.java
new file mode 100644
index 000000000..876312b47
--- /dev/null
+++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/metamodel/mapping/internal/ReactiveRuntimeModelCreationContext.java
@@ -0,0 +1,128 @@
+/* Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * Copyright: Red Hat Inc. and Hibernate Authors
+ */
+package org.hibernate.reactive.metamodel.mapping.internal;
+
+import java.util.Map;
+
+import org.hibernate.boot.model.relational.SqlStringGenerationContext;
+import org.hibernate.boot.spi.BootstrapContext;
+import org.hibernate.boot.spi.MetadataImplementor;
+import org.hibernate.boot.spi.SessionFactoryOptions;
+import org.hibernate.cache.spi.CacheImplementor;
+import org.hibernate.dialect.Dialect;
+import org.hibernate.engine.jdbc.spi.JdbcServices;
+import org.hibernate.engine.spi.SessionFactoryImplementor;
+import org.hibernate.generator.Generator;
+import org.hibernate.mapping.GeneratorSettings;
+import org.hibernate.mapping.PersistentClass;
+import org.hibernate.metamodel.spi.MappingMetamodelImplementor;
+import org.hibernate.metamodel.spi.RuntimeModelCreationContext;
+import org.hibernate.persister.entity.EntityPersister;
+import org.hibernate.query.sqm.function.SqmFunctionRegistry;
+import org.hibernate.reactive.tuple.entity.ReactiveEntityMetamodel;
+import org.hibernate.service.ServiceRegistry;
+import org.hibernate.tuple.entity.EntityMetamodel;
+import org.hibernate.type.descriptor.java.spi.JavaTypeRegistry;
+import org.hibernate.type.spi.TypeConfiguration;
+
+public class ReactiveRuntimeModelCreationContext implements RuntimeModelCreationContext {
+
+ private final RuntimeModelCreationContext delegate;
+
+ public ReactiveRuntimeModelCreationContext(RuntimeModelCreationContext delegate) {
+ this.delegate = delegate;
+ }
+
+ @Override
+ public EntityMetamodel createEntityMetamodel(PersistentClass persistentClass, EntityPersister persister) {
+ return new ReactiveEntityMetamodel( persistentClass, persister, delegate );
+ }
+
+ @Override
+ public SessionFactoryImplementor getSessionFactory() {
+ return delegate.getSessionFactory();
+ }
+
+ @Override
+ public BootstrapContext getBootstrapContext() {
+ return delegate.getBootstrapContext();
+ }
+
+ @Override
+ public MetadataImplementor getBootModel() {
+ return delegate.getBootModel();
+ }
+
+ @Override
+ public MappingMetamodelImplementor getDomainModel() {
+ return delegate.getDomainModel();
+ }
+
+ @Override
+ public TypeConfiguration getTypeConfiguration() {
+ return delegate.getTypeConfiguration();
+ }
+
+ @Override
+ public JavaTypeRegistry getJavaTypeRegistry() {
+ return delegate.getJavaTypeRegistry();
+ }
+
+ @Override
+ public MetadataImplementor getMetadata() {
+ return delegate.getMetadata();
+ }
+
+ @Override
+ public SqmFunctionRegistry getFunctionRegistry() {
+ return delegate.getFunctionRegistry();
+ }
+
+ @Override
+ public Map getSettings() {
+ return delegate.getSettings();
+ }
+
+ @Override
+ public Dialect getDialect() {
+ return delegate.getDialect();
+ }
+
+ @Override
+ public CacheImplementor getCache() {
+ return delegate.getCache();
+ }
+
+ @Override
+ public SessionFactoryOptions getSessionFactoryOptions() {
+ return delegate.getSessionFactoryOptions();
+ }
+
+ @Override
+ public JdbcServices getJdbcServices() {
+ return delegate.getJdbcServices();
+ }
+
+ @Override
+ public SqlStringGenerationContext getSqlStringGenerationContext() {
+ return delegate.getSqlStringGenerationContext();
+ }
+
+ @Override
+ public ServiceRegistry getServiceRegistry() {
+ return delegate.getServiceRegistry();
+ }
+
+ @Override
+ public Map getGenerators() {
+ return delegate.getGenerators();
+ }
+
+ @Override
+ public GeneratorSettings getGeneratorSettings() {
+ return delegate.getGeneratorSettings();
+ }
+}
diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/mutiny/Mutiny.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/mutiny/Mutiny.java
index 65b0ad906..bee3a5c1f 100644
--- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/mutiny/Mutiny.java
+++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/mutiny/Mutiny.java
@@ -5,11 +5,6 @@
*/
package org.hibernate.reactive.mutiny;
-import java.lang.invoke.MethodHandles;
-import java.util.List;
-import java.util.function.BiFunction;
-import java.util.function.Function;
-
import org.hibernate.Cache;
import org.hibernate.CacheMode;
import org.hibernate.Filter;
@@ -18,14 +13,14 @@
import org.hibernate.LockMode;
import org.hibernate.bytecode.enhance.spi.interceptor.EnhancementAsProxyLazinessInterceptor;
import org.hibernate.collection.spi.AbstractPersistentCollection;
-import org.hibernate.collection.spi.PersistentCollection;
import org.hibernate.engine.spi.PersistentAttributeInterceptable;
import org.hibernate.engine.spi.PersistentAttributeInterceptor;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.jpa.internal.util.FlushModeTypeHelper;
import org.hibernate.proxy.HibernateProxy;
-import org.hibernate.query.Order;
import org.hibernate.query.Page;
+import org.hibernate.query.criteria.HibernateCriteriaBuilder;
+import org.hibernate.query.criteria.JpaCriteriaInsert;
import org.hibernate.reactive.common.AffectedEntities;
import org.hibernate.reactive.common.Identifier;
import org.hibernate.reactive.common.ResultSetMapping;
@@ -38,15 +33,21 @@
import jakarta.persistence.CacheRetrieveMode;
import jakarta.persistence.CacheStoreMode;
import jakarta.persistence.EntityGraph;
+import jakarta.persistence.FindOption;
import jakarta.persistence.FlushModeType;
import jakarta.persistence.LockModeType;
import jakarta.persistence.Parameter;
+import jakarta.persistence.TypedQueryReference;
import jakarta.persistence.criteria.CriteriaBuilder;
import jakarta.persistence.criteria.CriteriaDelete;
import jakarta.persistence.criteria.CriteriaQuery;
import jakarta.persistence.criteria.CriteriaUpdate;
import jakarta.persistence.metamodel.Attribute;
import jakarta.persistence.metamodel.Metamodel;
+import java.lang.invoke.MethodHandles;
+import java.util.List;
+import java.util.function.BiFunction;
+import java.util.function.Function;
import static org.hibernate.engine.internal.ManagedTypeHelper.asPersistentAttributeInterceptable;
import static org.hibernate.engine.internal.ManagedTypeHelper.isPersistentAttributeInterceptable;
@@ -358,37 +359,6 @@ default SelectionQuery setLockMode(String alias, LockModeType lockModeType) {
return setLockMode( alias, convertToLockMode(lockModeType) );
}
-// /**
-// * Set the {@link LockOptions} to use for the whole query.
-// *
-// * @see org.hibernate.query.Query#setLockOptions(LockOptions)
-// */
-// Query setLockOptions(LockOptions lockOptions);
-
- /**
- * If the result type of this query is an entity class, add one or more
- * {@linkplain Order rules} for ordering the query results.
- *
- * @param orderList one or more instances of {@link Order}
- *
- * @see Order
- *
- * @see org.hibernate.query.Query#setOrder(List)
- */
- SelectionQuery setOrder(List> orderList);
-
- /**
- * If the result type of this query is an entity class, add a
- * {@linkplain Order rule} for ordering the query results.
- *
- * @param order an instance of {@link Order}
- *
- * @see Order
- *
- * @see org.hibernate.query.Query#setOrder(Order)
- */
- SelectionQuery setOrder(Order super R> order);
-
/**
* Set the {@link EntityGraph} that will be used as a fetch plan for
* the root entity returned by this query.
@@ -515,239 +485,576 @@ default Query setLockMode(String alias, LockModeType lockModeType) {
Query enableFetchProfile(String profileName);
}
-
/**
- * A non-blocking counterpart to the Hibernate {@link org.hibernate.Session}
- * interface, allowing a reactive style of interaction with the database.
- *
- * The semantics of operations on this interface are identical to the
- * semantics of the similarly-named operations of {@code Session}, except
- * that the operations are performed asynchronously, returning a {@link Uni}
- * without blocking the calling thread.
- *
- * Entities associated with an {@code Session} do not support transparent
- * lazy association fetching. Instead, {@link #fetch(Object)} should be used
- * to explicitly request asynchronous fetching of an association, or the
- * association should be fetched eagerly when the entity is first retrieved,
- * for example, by:
- *
- *
- *
{@link #enableFetchProfile(String) enabling a fetch profile},
- *
using an {@link EntityGraph}, or
- *
writing a {@code join fetch} clause in a HQL query.
- *
+ * Operations common to objects which act as factories for instances of
+ * {@link Query}. This is a common supertype of {@link Session} and
+ * {@link StatelessSession}.
*
- * @see org.hibernate.Session
+ * @since 3.0
*/
- interface Session extends Closeable {
-
+ interface QueryProducer {
/**
- * Asynchronously return the persistent instance of the given entity
- * class with the given identifier, or {@code null} if there is no such
- * persistent instance. If the instance is already associated with
- * the session, return the associated instance. This method never
- * returns an uninitialized instance.
- *
- *
+ * Create an instance of {@link SelectionQuery} for the given HQL/JPQL
+ * query string.
*
- * @param entityClass The entity type
- * @param id an identifier
+ * @param queryString The HQL/JPQL query
*
- * @return a persistent instance or null via a {@code Uni}
+ * @return The {@link SelectionQuery} instance for manipulation and execution
*
- * @see jakarta.persistence.EntityManager#find(Class, Object)
+ * @see jakarta.persistence.EntityManager#createQuery(String, Class)
*/
- Uni find(Class entityClass, Object id);
+ SelectionQuery createSelectionQuery(String queryString, Class resultType);
/**
- * Asynchronously return the persistent instance of the given entity
- * class with the given identifier, requesting the given {@link LockMode}.
+ * Create a typed {@link org.hibernate.query.Query} instance for the given typed query reference.
*
- * @param entityClass The entity type
- * @param id an identifier
- * @param lockMode the requested {@link LockMode}
+ * @param typedQueryReference the type query reference
*
- * @return a persistent instance or null via a {@code Uni}
+ * @return The {@link org.hibernate.query.Query} instance for execution
*
- * @see #find(Class, Object)
- * @see #lock(Object, LockMode) this discussion of lock modes
+ * @throws IllegalArgumentException if a query has not been
+ * defined with the name of the typed query reference or if
+ * the query result is found to not be assignable to
+ * result class of the typed query reference
+ *
+ * @see org.hibernate.query.QueryProducer#createQuery(TypedQueryReference)
*/
- Uni find(Class entityClass, Object id, LockMode lockMode);
+ Query createQuery(TypedQueryReference typedQueryReference);
/**
- * Asynchronously return the persistent instance of the given entity
- * class with the given identifier, requesting the given {@link LockModeType}.
+ * Create an instance of {@link MutationQuery} for the given HQL/JPQL
+ * update or delete statement.
*
- * @param entityClass The entity type
- * @param id an identifier
- * @param lockModeType the requested {@link LockModeType}
+ * @param queryString The HQL/JPQL query, update or delete statement
*
- * @return a persistent instance or null via a {@code Uni}
+ * @return The {@link MutationQuery} instance for manipulation and execution
*
- * @see #find(Class, Object)
- * @see #lock(Object, LockMode) this discussion of lock modes
+ * @see jakarta.persistence.EntityManager#createQuery(String)
*/
- default Uni find(Class entityClass, Object id, LockModeType lockModeType) {
- return find( entityClass, id, convertToLockMode( lockModeType ) );
- }
+ MutationQuery createMutationQuery(String queryString);
/**
- * Asynchronously return the persistent instance with the given
- * identifier of an entity class, using the given {@link EntityGraph}
- * as a fetch plan.
+ * Create an instance of {@link MutationQuery} for the given update tree.
*
- * @param entityGraph an {@link EntityGraph} specifying the entity
- * and associations to be fetched
- * @param id an identifier
+ * @param updateQuery the update criteria query
*
- * @see #find(Class, Object)
+ * @return The {@link MutationQuery} instance for manipulation and execution
+ *
+ * @see org.hibernate.query.QueryProducer#createMutationQuery(CriteriaUpdate)
*/
- Uni find(EntityGraph entityGraph, Object id);
+ MutationQuery createMutationQuery(CriteriaUpdate> updateQuery);
/**
- * Asynchronously return the persistent instances of the given entity
- * class with the given identifiers, or null if there is no such
- * persistent instance.
+ * Create an instance of {@link MutationQuery} for the given delete tree.
*
- * @param entityClass The entity type
- * @param ids the identifiers
+ * @param deleteQuery the delete criteria query
*
- * @return a list of persistent instances and nulls via a {@code Uni}
+ * @return The {@link MutationQuery} instance for manipulation and execution
+ *
+ * @see org.hibernate.query.QueryProducer#createMutationQuery(CriteriaDelete)
*/
- Uni> find(Class entityClass, Object... ids);
+ MutationQuery createMutationQuery(CriteriaDelete> deleteQuery);
/**
- * Asynchronously return the persistent instance of the given entity
- * class with the given natural identifier, or null if there is no
- * such persistent instance.
+ * Create a {@link MutationQuery} from the given insert select criteria tree
*
- * @param entityClass The entity type
- * @param naturalId the natural identifier
+ * @param insert the insert select criteria query
*
- * @return a persistent instance or null via a {@code Uni}
+ * @return The {@link MutationQuery} instance for manipulation and execution
+ *
+ * @see org.hibernate.query.QueryProducer#createMutationQuery(JpaCriteriaInsert)
*/
- @Incubating
- Uni find(Class entityClass, Identifier naturalId);
+ MutationQuery createMutationQuery(JpaCriteriaInsert> insert);
/**
- * Return the persistent instance of the given entity class with the
- * given identifier, assuming that the instance exists. This method
- * never results in access to the underlying data store, and thus
- * might return a proxied instance that must be initialized explicitly
- * using {@link #fetch(Object)}.
- *