diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 2718f729f..f818b94e8 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -7,15 +7,18 @@ on:
- 'wip/**'
- '2.*'
- '3.*'
+ - '4.*'
tags:
- '2.*'
- '3.*'
+ - '4.*'
pull_request:
branches:
- 'main'
- 'wip/**'
- '2.*'
- '3.*'
+ - '4.*'
# For building snapshots
workflow_call:
inputs:
@@ -101,13 +104,13 @@ jobs:
key: gradle-examples-${{ matrix.db }}-${{ steps.get-date.outputs.yearmonth }}
- name: Set up JDK 11
if: ${{ startsWith( inputs.branch, 'wip/2' ) }}
- uses: actions/setup-java@3a4f6e1af504cf6a31855fa899c6aa5355ba6c12 # v4.7.0
+ 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@3a4f6e1af504cf6a31855fa899c6aa5355ba6c12 # v4.7.0
+ uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # v4.7.1
with:
distribution: 'temurin'
java-version: 17
@@ -150,13 +153,13 @@ jobs:
key: gradle-db-${{ matrix.db }}-${{ steps.get-date.outputs.yearmonth }}
- name: Set up JDK 11
if: ${{ startsWith( inputs.branch, 'wip/2' ) }}
- uses: actions/setup-java@3a4f6e1af504cf6a31855fa899c6aa5355ba6c12 # v4.7.0
+ 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@3a4f6e1af504cf6a31855fa899c6aa5355ba6c12 # v4.7.0
+ uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # v4.7.1
with:
distribution: 'temurin'
@@ -255,7 +258,7 @@ jobs:
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@3a4f6e1af504cf6a31855fa899c6aa5355ba6c12 # v4.7.0
+ uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # v4.7.1
with:
distribution: 'temurin'
java-version: ${{ matrix.java.java_version_numeric }}
@@ -265,14 +268,14 @@ jobs:
run: echo "::set-output name=path::${JAVA_HOME}"
- name: Set up JDK 11
if: ${{ startsWith( inputs.branch, 'wip/2' ) }}
- uses: actions/setup-java@3a4f6e1af504cf6a31855fa899c6aa5355ba6c12 # v4.7.0
+ 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@3a4f6e1af504cf6a31855fa899c6aa5355ba6c12 # v4.7.0
+ uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # v4.7.1
with:
distribution: 'temurin'
java-version: 17
diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml
index 13d87abe0..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:
@@ -27,7 +27,7 @@ jobs:
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- name: Setup Java
- uses: actions/setup-java@3a4f6e1af504cf6a31855fa899c6aa5355ba6c12 # v4.7.0
+ uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # v4.7.1
with:
distribution: temurin
java-version: 17
diff --git a/.github/workflows/scheduler.yml b/.github/workflows/scheduler.yml
index 2a25cf60a..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', 'wip/3.0' ]
+ 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/.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
index 2df00b224..bb825420f 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -16,6 +16,12 @@ All contributions are subject to the [Developer Certificate of Origin (DCO)](htt
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
diff --git a/README.md b/README.md
index c01979d65..743540d6c 100644
--- a/README.md
+++ b/README.md
@@ -38,12 +38,12 @@ Hibernate Reactive has been tested with:
- CockroachDB v24
- MS SQL Server 2022
- Oracle 23
-- [Hibernate ORM][] 7.0.0.Beta4
-- [Vert.x Reactive PostgreSQL Client](https://vertx.io/docs/vertx-pg-client/java/) 4.5.14
-- [Vert.x Reactive MySQL Client](https://vertx.io/docs/vertx-mysql-client/java/) 4.5.14
-- [Vert.x Reactive Db2 Client](https://vertx.io/docs/vertx-db2-client/java/) 4.5.14
-- [Vert.x Reactive MS SQL Server Client](https://vertx.io/docs/vertx-mssql-client/java/) 4.5.14
-- [Vert.x Reactive Oracle Client](https://vertx.io/docs/vertx-oracle-client/java/) 4.5.14
+- [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 c7ad6918c..f927371ef 100644
--- a/build.gradle
+++ b/build.gradle
@@ -22,21 +22,14 @@ ext {
// Example:
// ./gradlew build -PvertxSqlClientVersion=4.0.0-SNAPSHOT
if ( !project.hasProperty( 'vertxSqlClientVersion' ) ) {
- vertxSqlClientVersion = '4.5.14'
+ vertxSqlClientVersion = '5.0.0'
}
- testcontainersVersion = '1.20.6'
+ testcontainersVersion = '1.21.0'
logger.lifecycle "Vert.x SQL Client Version: " + project.vertxSqlClientVersion
}
-// Publishing to Sonatype (Maven Central):
-nexusPublishing {
- repositories {
- sonatype()
- }
-}
-
subprojects {
apply plugin: 'java-library'
apply plugin: 'com.diffplug.spotless'
diff --git a/ci/release/Jenkinsfile b/ci/release/Jenkinsfile
index d365436ab..8627950a1 100644
--- a/ci/release/Jenkinsfile
+++ b/ci/release/Jenkinsfile
@@ -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)
@@ -172,11 +175,10 @@ pipeline {
// 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}"
+ sh ".release/scripts/prepare-release.sh -j -b ${env.GIT_BRANCH} -v ${env.DEVELOPMENT_VERSION} ${env.PROJECT} ${env.RELEASE_VERSION}"
}
}
}
@@ -193,16 +195,22 @@ pipeline {
configFile(fileId: 'release.config.ssh.knownhosts', targetLocation: "${env.HOME}/.ssh/known_hosts")
]) {
withCredentials([
- // https://github.com/gradle-nexus/publish-plugin#publishing-to-maven-central-via-sonatype-ossrh
- usernamePassword(credentialsId: 'ossrh.sonatype.org', passwordVariable: 'ORG_GRADLE_PROJECT_sonatypePassword', usernameVariable: 'ORG_GRADLE_PROJECT_sonatypeUsername'),
- file(credentialsId: 'release.gpg.private-key', variable: 'SIGNING_GPG_PRIVATE_KEY_PATH'),
- string(credentialsId: 'release.gpg.passphrase', variable: 'SIGNING_GPG_PASSPHRASE'),
- gitUsernamePassword(credentialsId: 'username-and-token.Hibernate-CI.github.com', gitToolName: 'Default')
+ // 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: '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}"
}
}
}
@@ -217,4 +225,4 @@ pipeline {
}
}
}
-}
\ No newline at end of file
+}
diff --git a/ci/snapshot-publish.Jenkinsfile b/ci/snapshot-publish.Jenkinsfile
index 07fa844c6..fea160b23 100644
--- a/ci/snapshot-publish.Jenkinsfile
+++ b/ci/snapshot-publish.Jenkinsfile
@@ -10,6 +10,14 @@ 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 'Release'
@@ -30,13 +38,23 @@ pipeline {
}
stage('Publish') {
steps {
- withCredentials([
- // https://github.com/gradle-nexus/publish-plugin#publishing-to-maven-central-via-sonatype-ossrh
- usernamePassword(credentialsId: 'ossrh.sonatype.org', usernameVariable: 'ORG_GRADLE_PROJECT_sonatypeUsername', passwordVariable: 'ORG_GRADLE_PROJECT_sonatypePassword'),
- file(credentialsId: 'release.gpg.private-key', variable: 'SIGNING_GPG_PRIVATE_KEY_PATH'),
- string(credentialsId: 'release.gpg.passphrase', variable: 'SIGNING_GPG_PASSPHRASE')
- ]) {
- sh "./gradlew clean publish --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}"
+ }
}
}
}
@@ -48,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 4f2237edb..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
diff --git a/examples/native-sql-example/build.gradle b/examples/native-sql-example/build.gradle
index c79ec8984..3b650d34a 100644
--- a/examples/native-sql-example/build.gradle
+++ b/examples/native-sql-example/build.gradle
@@ -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/session-example/build.gradle b/examples/session-example/build.gradle
index 4da40ba69..a001112d8 100644
--- a/examples/session-example/build.gradle
+++ b/examples/session-example/build.gradle
@@ -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/gradle.properties b/gradle.properties
index 3576439d6..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 = 7.0.0.Beta5
+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 = 7.0.0.Beta4
+#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.14-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.14
-#vertxWebtClientVersion = 4.5.14
+#vertxWebVersion = 5.0.0
+#vertxWebtClientVersion = 5.0.0
diff --git a/gradle/version.properties b/gradle/version.properties
index ebfc91836..618fb2d72 100644
--- a/gradle/version.properties
+++ b/gradle/version.properties
@@ -1 +1 @@
-projectVersion=3.0.0.Beta3
\ No newline at end of file
+projectVersion=4.0.0-SNAPSHOT
\ No newline at end of file
diff --git a/hibernate-reactive-core/build.gradle b/hibernate-reactive-core/build.gradle
index fca12935f..26a4de751 100644
--- a/hibernate-reactive-core/build.gradle
+++ b/hibernate-reactive-core/build.gradle
@@ -10,22 +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.6.1.Final'
annotationProcessor 'org.jboss.logging:jboss-logging:3.6.1.Final'
- compileOnly 'org.jboss.logging:jboss-logging-annotations:3.0.3.Final'
- annotationProcessor 'org.jboss.logging:jboss-logging-annotations:3.0.3.Final'
- annotationProcessor 'org.jboss.logging:jboss-logging-processor:3.0.3.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'
//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
@@ -39,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"
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
index 3dfc8dcd0..6d87416b4 100644
--- 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
@@ -37,9 +37,9 @@
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.reactive.session.ReactiveSession;
import org.hibernate.sql.exec.spi.Callback;
import org.hibernate.sql.results.graph.entity.EntityInitializer;
import org.hibernate.sql.results.jdbc.spi.JdbcValuesSourceProcessingState;
@@ -79,8 +79,9 @@ private class NonLazyCollectionInitializer implements Consumer nonLazyCollection) {
if ( !nonLazyCollection.wasInitialized() ) {
- stage = stage.thenCompose( v -> ( (ReactiveSession) getSession() )
- .reactiveInitializeCollection( nonLazyCollection, false ) );
+ stage = stage.thenCompose( v ->
+ ( (ReactiveSharedSessionContractImplementor) getSession() )
+ .reactiveInitializeCollection( nonLazyCollection, false ) );
}
}
}
diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/context/impl/ContextualDataStorage.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/context/impl/ContextualDataStorage.java
deleted file mode 100644
index 295b92f4d..000000000
--- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/context/impl/ContextualDataStorage.java
+++ /dev/null
@@ -1,25 +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.context.impl;
-
-import java.util.concurrent.ConcurrentMap;
-
-import io.vertx.core.impl.VertxBuilder;
-import io.vertx.core.spi.VertxServiceProvider;
-import io.vertx.core.spi.context.storage.ContextLocal;
-
-/**
- * SPI Implementation for {@link ContextLocal} storage.
- */
-public class ContextualDataStorage implements VertxServiceProvider {
-
- @SuppressWarnings("rawtypes")
- static ContextLocal CONTEXTUAL_DATA_KEY = ContextLocal.registerLocal( ConcurrentMap.class );
-
- @Override
- public void init(VertxBuilder vertxBuilder) {
- }
-}
diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/context/impl/VertxContext.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/context/impl/VertxContext.java
index 937dc3b1b..02c28af5f 100644
--- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/context/impl/VertxContext.java
+++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/context/impl/VertxContext.java
@@ -6,12 +6,9 @@
package org.hibernate.reactive.context.impl;
import java.lang.invoke.MethodHandles;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentMap;
import io.vertx.core.Vertx;
-import io.vertx.core.impl.ContextInternal;
-import io.vertx.core.spi.context.storage.AccessMode;
+import io.vertx.core.internal.ContextInternal;
import org.hibernate.reactive.context.Context;
import org.hibernate.reactive.logging.impl.Log;
@@ -39,10 +36,10 @@ public void injectServices(ServiceRegistryImplementor serviceRegistry) {
@Override
public void put(Key key, T instance) {
- final ContextInternal context = ContextInternal.current();
+ final ContextInternal context = currentContext();
if ( context != null ) {
if ( trace ) LOG.tracef( "Putting key,value in context: [%1$s, %2$s]", key, instance );
- VertxContext.contextualDataMap( context ).put( key, instance );
+ context.putLocal( key, instance );
}
else {
if ( trace ) LOG.tracef( "Context is null for key,value: [%1$s, %2$s]", key, instance );
@@ -50,11 +47,15 @@ public void put(Key key, T instance) {
}
}
+ private static ContextInternal currentContext() {
+ return (ContextInternal) Vertx.currentContext();
+ }
+
@Override
public T get(Key key) {
- final ContextInternal context = ContextInternal.current();
+ final ContextInternal context = currentContext();
if ( context != null ) {
- T local = VertxContext.contextualDataMap( context ).get( key );
+ T local = context.getLocal( key );
if ( trace ) LOG.tracef( "Getting value %2$s from context for key %1$s", key, local );
return local;
}
@@ -66,9 +67,9 @@ public T get(Key key) {
@Override
public void remove(Key> key) {
- final ContextInternal context = ContextInternal.current();
+ final ContextInternal context = currentContext();
if ( context != null ) {
- boolean removed = contextualDataMap( context ).remove( key ) != null;
+ boolean removed = context.removeLocal( key );
if ( trace ) LOG.tracef( "Key %s removed from context: %s", key, removed );
}
else {
@@ -78,7 +79,7 @@ public void remove(Key> key) {
@Override
public void execute(Runnable runnable) {
- final io.vertx.core.Context currentContext = Vertx.currentContext();
+ final io.vertx.core.Context currentContext = currentContext();
if ( currentContext == null ) {
if ( trace ) LOG.tracef( "Not in a Vert.x context, checking the VertxInstance service" );
final io.vertx.core.Context newContext = vertxInstance.getVertx().getOrCreateContext();
@@ -86,6 +87,7 @@ public void execute(Runnable runnable) {
// that could lead to unintentionally share the same session with other streams.
ContextInternal newContextInternal = (ContextInternal) newContext;
final ContextInternal duplicate = newContextInternal.duplicate();
+
if ( trace ) LOG.tracef( "Using duplicated context from VertxInstance: %s", duplicate );
duplicate.runOnContext( x -> runnable.run() );
}
@@ -95,12 +97,4 @@ public void execute(Runnable runnable) {
}
}
- @SuppressWarnings({ "unchecked" })
- private static ConcurrentMap, T> contextualDataMap(ContextInternal vertxContext) {
- return vertxContext.getLocal(
- ContextualDataStorage.CONTEXTUAL_DATA_KEY,
- AccessMode.CONCURRENT,
- ConcurrentHashMap::new
- );
- }
}
diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/engine/impl/CollectionTypes.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/engine/impl/CollectionTypes.java
index 4bc488bb6..9ce6a7c5b 100644
--- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/engine/impl/CollectionTypes.java
+++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/engine/impl/CollectionTypes.java
@@ -23,7 +23,6 @@
import org.hibernate.collection.spi.PersistentCollection;
import org.hibernate.engine.spi.CollectionEntry;
import org.hibernate.engine.spi.PersistenceContext;
-import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.metamodel.mapping.PluralAttributeMapping;
import org.hibernate.persister.collection.CollectionPersister;
@@ -58,7 +57,7 @@ public static 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> originalPersistentCollection
- && result instanceof PersistentCollection> resultPersistentCollection ) {
- return preserveSnapshot(
- originalPersistentCollection, resultPersistentCollection,
- elemType, owner, copyCache, session
- ).thenApply( v -> {
- if ( !originalPersistentCollection.isDirty() ) {
- resultPersistentCollection.clearDirty();
- }
- return result;
- } );
- }
- else {
- return completedFuture( result );
- }
- } );
+ return loop( (Collection>) original,
+ o -> getReplace( elemType, o, owner, session, copyCache )
+ .thenAccept( result::add ) )
+ .thenCompose( v -> preserveSnapshotIfNecessary( original, result, owner, copyCache, session, elemType ) );
+ }
+
+ private static CompletionStage preserveSnapshotIfNecessary(
+ Object original,
+ Collection result,
+ Object owner,
+ Map copyCache,
+ SharedSessionContractImplementor session,
+ Type elemType) {
+ // if the original is a PersistentCollection, and that original
+ // was not flagged as dirty, then reset the target's dirty flag
+ // here after the copy operation.
+ //
+ // 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, ?> original,
Map target,
Object owner,
Map copyCache,
- SessionImplementor session) {
- final CollectionPersister persister = session.getFactory().getRuntimeMetamodels()
- .getMappingMetamodel().getCollectionDescriptor( type.getRole() );
- final Map result = target;
- result.clear();
-
+ SharedSessionContractImplementor session) {
+ final CollectionPersister persister =
+ session.getFactory().getRuntimeMetamodels().getMappingMetamodel()
+ .getCollectionDescriptor( type.getRole() );
+ target.clear();
return loop(
original.entrySet(), entry -> {
- final Map.Entry me = entry;
+ final Map.Entry, ?> me = entry;
return getReplace( persister.getIndexType(), me.getKey(), owner, session, copyCache )
.thenCompose( key -> getReplace(
persister.getElementType(),
@@ -301,10 +307,10 @@ private static CompletionStage replaceMapTypeElements(
owner,
session,
copyCache
- ).thenAccept( value -> result.put( key, value ) )
+ ).thenAccept( value -> target.put( key, value ) )
);
}
- ).thenApply( unused -> result );
+ ).thenApply( unused -> target);
}
private static CompletionStage replaceArrayTypeElements(
@@ -313,7 +319,7 @@ private static CompletionStage replaceArrayTypeElements(
Object target,
Object owner,
Map copyCache,
- SessionImplementor session) {
+ SharedSessionContractImplementor session) {
final Object result;
final int length = Array.getLength( original );
if ( length != Array.getLength( target ) ) {
@@ -325,8 +331,8 @@ private static CompletionStage replaceArrayTypeElements(
}
final Type elemType = type.getElementType( session.getFactory() );
- return loop(
- 0, length, i -> getReplace( elemType, Array.get( original, i ), owner, session, copyCache )
+ return loop( 0, length,
+ i -> getReplace( elemType, Array.get( original, i ), owner, session, copyCache )
.thenApply( o -> {
Array.set( result, i, o );
return result;
@@ -338,25 +344,21 @@ private static CompletionStage getReplace(
Type elemType,
Object o,
Object owner,
- SessionImplementor session,
+ SharedSessionContractImplementor session,
Map copyCache) {
return getReplace( elemType, o, null, owner, session, copyCache );
}
private static CompletionStage getReplace(
Type elemType,
- Object o,
+ Object object,
Object target,
Object owner,
- SessionImplementor session,
+ SharedSessionContractImplementor session,
Map copyCache) {
- if ( elemType instanceof EntityType ) {
- return EntityTypes.replace( (EntityType) elemType, o, target, session, owner, copyCache );
- }
- else {
- final Object replace = elemType.replace( o, target, session, owner, copyCache );
- return completedFuture( replace );
- }
+ return elemType instanceof EntityType entityType
+ ? EntityTypes.replace( entityType, object, target, session, owner, copyCache )
+ : completedFuture( elemType.replace( object, target, session, owner, copyCache) );
}
/**
@@ -368,13 +370,15 @@ private static CompletionStage preserveSnapshot(
Type elemType,
Object owner,
Map copyCache,
- SessionImplementor session) {
+ 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 ) );
}
- return voidFuture();
+ else {
+ return voidFuture();
+ }
}
/**
@@ -386,7 +390,7 @@ private static CompletionStage createSnapshot(
Type elemType,
Object owner,
Map copyCache,
- SessionImplementor session) {
+ SharedSessionContractImplementor session) {
final Serializable originalSnapshot = original.getStoredSnapshot();
if ( originalSnapshot instanceof List> list ) {
return createListSnapshot( list, elemType, owner, copyCache, session );
@@ -411,9 +415,9 @@ private static CompletionStage createArraySnapshot(
Type elemType,
Object owner,
Map copyCache,
- SessionImplementor session) {
- return loop(
- 0, array.length, i -> getReplace( elemType, array[i], owner, session, copyCache )
+ SharedSessionContractImplementor session) {
+ return loop( 0, array.length,
+ i -> getReplace( elemType, array[i], owner, session, copyCache )
.thenAccept( o -> array[i] = o )
).thenApply( unused -> array );
}
@@ -421,29 +425,26 @@ private static CompletionStage createArraySnapshot(
/**
* @see CollectionType#createMapSnapshot(Map, PersistentCollection, Type, Object, Map, SharedSessionContractImplementor)
*/
- private static CompletionStage createMapSnapshot(
- Map, ?> map,
+ private static CompletionStage createMapSnapshot(
+ Map map,
PersistentCollection> result,
Type elemType,
Object owner,
Map copyCache,
- SessionImplementor session) {
+ SharedSessionContractImplementor session) {
final Map, ?> resultSnapshot = (Map, ?>) result.getStoredSnapshot();
- final Map targetMap;
- if ( map instanceof SortedMap, ?> sortedMap ) {
- //noinspection unchecked, rawtypes
- targetMap = new TreeMap( sortedMap.comparator() );
- }
- else {
- targetMap = mapOfSize( map.size() );
- }
- return loop(
- map.entrySet(), entry ->
- getReplace( elemType, entry.getValue(), resultSnapshot, owner, session, copyCache )
- .thenAccept( newValue -> {
- final Object key = entry.getKey();
- targetMap.put( key == entry.getValue() ? newValue : key, newValue );
- } )
+ 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 );
}
@@ -455,10 +456,10 @@ private static CompletionStage createListSnapshot(
Type elemType,
Object owner,
Map copyCache,
- SessionImplementor session) {
+ SharedSessionContractImplementor session) {
final ArrayList targetList = new ArrayList<>( list.size() );
- return loop(
- list, obj -> getReplace( elemType, obj, owner, session, copyCache )
+ return loop( list,
+ obj -> getReplace( elemType, obj, owner, session, copyCache )
.thenAccept( targetList::add )
).thenApply( unused -> targetList );
}
@@ -472,9 +473,9 @@ private static Object instantiateResultIfNecessary(CollectionType type, Object o
// 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 )
+ || 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 0bb0c75ae..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,15 @@
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;
@@ -154,12 +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];
- return loop(
- 0, types.length, i -> replace( original, target, types, session, owner, copyCache, i, copied )
+ return loop( 0, types.length,
+ i -> replace( original, target, types, session, owner, copyCache, i, copied )
).thenApply( v -> copied );
}
@@ -170,13 +170,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,
final ForeignKeyDirection foreignKeyDirection) {
Object[] copied = new Object[original.length];
- return loop(
- 0, types.length,
+ return loop( 0, types.length,
i -> replace( original, target, types, session, owner, copyCache, foreignKeyDirection, i, copied )
).thenApply( v -> copied );
}
@@ -188,7 +187,7 @@ private static CompletionStage replace(
EntityType entityType,
Object original,
Object target,
- SessionImplementor session,
+ SharedSessionContractImplementor session,
Object owner,
Map copyCache,
ForeignKeyDirection foreignKeyDirection)
@@ -208,7 +207,7 @@ protected static CompletionStage replace(
EntityType entityType,
Object original,
Object target,
- SessionImplementor session,
+ SharedSessionContractImplementor session,
Object owner,
Map copyCache) {
if ( original == null ) {
@@ -254,7 +253,7 @@ protected static CompletionStage replace(
private static CompletionStage resolveIdOrUniqueKey(
EntityType entityType,
Object original,
- SessionImplementor session,
+ SharedSessionContractImplementor session,
Object owner,
Map copyCache) {
return getIdentifier( entityType, original, session )
@@ -268,7 +267,7 @@ 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 )
+ return ( (ReactiveQueryProducer) session )
.reactiveFetch( id, true )
.thenCompose( fetched -> {
Object idOrUniqueKey = entityType
@@ -289,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 );
@@ -340,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 );
@@ -357,7 +357,7 @@ 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 propertyValue;
}
@@ -372,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;
@@ -387,7 +388,7 @@ private static CompletionStage replace(
Object[] original,
Object[] target,
Type[] types,
- SessionImplementor session,
+ SharedSessionContractImplementor session,
Object owner,
Map copyCache,
int i,
@@ -433,7 +434,7 @@ private static CompletionStage replace(
Object[] original,
Object[] target,
Type[] types,
- SessionImplementor session,
+ SharedSessionContractImplementor session,
Object owner,
Map copyCache,
ForeignKeyDirection foreignKeyDirection,
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 087623e44..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
@@ -15,7 +15,6 @@
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;
@@ -48,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;
@@ -65,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;
@@ -270,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();
}
@@ -297,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
@@ -350,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();
}
@@ -387,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/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/jdbc/dialect/internal/ReactiveStandardDialectResolver.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/engine/jdbc/dialect/internal/ReactiveStandardDialectResolver.java
index 1b24e567d..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
@@ -11,24 +11,22 @@
import org.hibernate.engine.jdbc.dialect.spi.DialectResolutionInfo;
import org.hibernate.engine.jdbc.dialect.spi.DialectResolver;
-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 ) ) {
return database.createDialect( info );
}
}
-
return null;
}
}
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/impl/DefaultReactiveDeleteEventListener.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/event/impl/DefaultReactiveDeleteEventListener.java
index f490d5366..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
@@ -47,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;
@@ -198,7 +199,7 @@ 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 ) );
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/DefaultReactiveLockEventListener.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/event/impl/DefaultReactiveLockEventListener.java
index 2df247665..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
@@ -33,6 +33,7 @@
import org.hibernate.reactive.event.ReactiveLockEventListener;
import org.hibernate.reactive.logging.impl.Log;
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;
@@ -80,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 ) );
}
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/generator/values/internal/ReactiveGeneratedValuesHelper.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/generator/values/internal/ReactiveGeneratedValuesHelper.java
index 70495ccea..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;
/**
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 c820f513f..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
@@ -14,9 +14,9 @@
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 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,7 +44,7 @@ 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
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/ReactiveMultiIdEntityLoaderArrayParam.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/loader/ast/internal/ReactiveMultiIdEntityLoaderArrayParam.java
index 8239a6e15..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
@@ -18,8 +18,8 @@
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.loader.ast.internal.LoaderSelectBuilder;
import org.hibernate.loader.ast.internal.MultiIdEntityLoaderArrayParam;
import org.hibernate.loader.ast.internal.MultiKeyLoadLogging;
@@ -82,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",
@@ -90,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();
@@ -227,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",
@@ -305,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;
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 92f4e996a..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
@@ -24,7 +24,6 @@
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.internal.util.collections.CollectionHelper;
import org.hibernate.loader.ast.internal.LoaderSelectBuilder;
import org.hibernate.loader.ast.spi.MultiIdLoadOptions;
@@ -75,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() );
}
@@ -104,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 )
@@ -289,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;
@@ -312,7 +311,7 @@ protected CompletionStage> performUnorderedMultiLoad(
boolean foundAnyManagedEntities = false;
final List nonManagedIds = new ArrayList<>();
- final boolean coerce = !getSessionFactory().getJpaMetamodel().getJpaCompliance().isLoadByIdComplianceEnabled();
+ final boolean coerce = isIdCoercionEnabled();
for ( Object o : ids ) {
final Object id = coerce
? getEntityDescriptor().getIdentifierMapping().getJavaType().coerce( o, session )
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/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/logging/impl/Log.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/logging/impl/Log.java
index 75287e5be..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")
@@ -264,6 +267,9 @@ public interface Log extends BasicLogger {
@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!" )
@@ -315,4 +321,12 @@ public interface Log extends BasicLogger {
@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/mutiny/Mutiny.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/mutiny/Mutiny.java
index 59edbb875..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;
@@ -23,7 +18,6 @@
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;
@@ -43,12 +37,17 @@
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;
@@ -360,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.
@@ -517,235 +485,554 @@ 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.Session#findMultiple(Class, List, FindOption...)
+ * @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)}.
- *
- * You should not use this method to determine if an instance exists
- * (use {@link #find} instead). Use this only to retrieve an instance
- * which you safely assume exists, where non-existence would be an
- * actual error.
+ * Create an instance of {@link Query} for the given HQL/JPQL query
+ * string or HQL/JPQL update or delete statement. In the case of an
+ * update or delete, the returned {@link Query} must be executed using
+ * {@link Query#executeUpdate()} which returns an affected row count.
*
- * @param entityClass a persistent class
- * @param id a valid identifier of an existing persistent instance of the class
+ * @param queryString The HQL/JPQL query, update or delete statement
*
- * @return the persistent instance or proxy
+ * @return The {@link Query} instance for manipulation and execution
*
- * @see jakarta.persistence.EntityManager#getReference(Class, Object)
+ * @deprecated See explanation in
+ * {@link org.hibernate.query.QueryProducer#createSelectionQuery(String)}
+ *
+ * @see jakarta.persistence.EntityManager#createQuery(String)
*/
- T getReference(Class entityClass, Object id);
+ @Deprecated
+ Query createQuery(String queryString);
/**
- * Return the persistent instance with the same identity as the given
- * instance, which might be detached, assuming that the instance is
- * still persistent in the database. This method never results in
- * access to the underlying data store, and thus might return a proxy
- * that must be initialized explicitly using {@link #fetch(Object)}.
+ * Create an instance of {@link SelectionQuery} for the given HQL/JPQL
+ * query string and query result type.
*
- * @param entity a detached persistent instance
+ * @param queryString The HQL/JPQL query
+ * @param resultType the Java type returned in each row of query results
*
- * @return the persistent instance or proxy
+ * @return The {@link SelectionQuery} instance for manipulation and execution
+ *
+ * @see jakarta.persistence.EntityManager#createQuery(String, Class)
*/
- T getReference(T entity);
+ SelectionQuery createQuery(String queryString, Class resultType);
/**
- * Asynchronously persist the given transient instance, first assigning
- * a generated identifier. (Or using the current value of the identifier
- * property if the entity has assigned identifiers.)
- *
- * This operation cascades to associated instances if the association is
- * mapped with {@link jakarta.persistence.CascadeType#PERSIST}.
+ * Create an instance of {@link SelectionQuery} for the given criteria
+ * query.
*
- *
+ * @param criteriaQuery The {@link CriteriaQuery}
*
- * @param object a transient instance of a persistent class
+ * @return The {@link SelectionQuery} instance for manipulation and execution
*
- * @see jakarta.persistence.EntityManager#persist(Object)
+ * @see jakarta.persistence.EntityManager#createQuery(String)
*/
- Uni persist(Object object);
+ SelectionQuery createQuery(CriteriaQuery criteriaQuery);
/**
- * Make a transient instance persistent and mark it for later insertion in the
- * database. This operation cascades to associated instances if the association
- * is mapped with {@link jakarta.persistence.CascadeType#PERSIST}.
- *
- * For entities with a {@link jakarta.persistence.GeneratedValue generated id},
- * {@code persist()} ultimately results in generation of an identifier for the
- * given instance. But this may happen asynchronously, when the session is
- * {@linkplain #flush() flushed}, depending on the identifier generation strategy.
+ * Create an instance of {@link MutationQuery} for the given criteria update.
*
- * @param entityName the entity name
- * @param object a transient instance to be made persistent
- * @see #persist(Object)
+ * @param criteriaUpdate The {@link CriteriaUpdate}
+ *
+ * @return The {@link MutationQuery} instance for manipulation and execution
*/
- Uni persist(String entityName, Object object);
+ MutationQuery createQuery(CriteriaUpdate criteriaUpdate);
/**
- * Persist multiple transient entity instances at once.
+ * Create an instance of {@link MutationQuery} for the given criteria delete.
*
- * @see #persist(Object)
+ * @param criteriaDelete The {@link CriteriaDelete}
+ *
+ * @return The {@link MutationQuery} instance for manipulation and execution
*/
- Uni persistAll(Object... entities);
+ MutationQuery createQuery(CriteriaDelete criteriaDelete);
/**
- * Asynchronously remove a persistent instance from the datastore. The
- * argument may be an instance associated with the receiving session or
- * a transient instance with an identifier associated with existing
- * persistent state.
- *
- * This operation cascades to associated instances if the association is
- * mapped with {@link jakarta.persistence.CascadeType#REMOVE}.
+ * Create an instance of {@link Query} for the named query.
*
- *
+ * @param queryName The name of the query
*
- * @param entity the managed persistent instance to be removed
+ * @return The {@link Query} instance for manipulation and execution
*
- * @throws IllegalArgumentException if the given instance is not managed
- * @see jakarta.persistence.EntityManager#remove(Object)
+ * @see jakarta.persistence.EntityManager#createQuery(String)
*/
- Uni remove(Object entity);
+ Query createNamedQuery(String queryName);
/**
- * Remove multiple entity instances at once.
+ * Create an instance of {@link SelectionQuery} for the named query.
*
- * @see #remove(Object)
+ * @param queryName The name of the query
+ * @param resultType the Java type returned in each row of query results
+ *
+ * @return The {@link SelectionQuery} instance for manipulation and execution
+ *
+ * @see jakarta.persistence.EntityManager#createQuery(String, Class)
*/
- Uni removeAll(Object... entities);
+ SelectionQuery createNamedQuery(String queryName, Class resultType);
/**
- * Copy the state of the given object onto the persistent instance with
- * the same identifier. If there is no such persistent instance currently
- * associated with the session, it will be loaded. Return the persistent
- * instance. Or, if the given instance is transient, save a copy of it
- * and return the copy as a newly persistent instance. The given instance
- * does not become associated with the session.
- *
- * This operation cascades to associated instances if the association is
+ * Create an instance of {@link Query} for the given SQL query string,
+ * or SQL update, insert, or delete statement. In the case of an update,
+ * insert, or delete, the returned {@link Query} must be executed using
+ * {@link Query#executeUpdate()} which returns an affected row count.
+ * In the case of a query:
+ *
+ *
+ *
If the result set has a single column, the results will be returned
+ * as scalars.
+ *
Otherwise, if the result set has multiple columns, the results will
+ * be returned as elements of arrays of type {@code Object[]}.
+ *
+ *
+ * @param queryString The SQL select, update, insert, or delete statement
+ */
+ Query createNativeQuery(String queryString);
+
+ /**
+ * Create an instance of {@link Query} for the given SQL query string,
+ * or SQL update, insert, or delete statement. In the case of an update,
+ * insert, or delete, the returned {@link Query} must be executed using
+ * {@link Query#executeUpdate()} which returns an affected row count.
+ * In the case of a query:
+ *
+ *
+ *
If the result set has a single column, the results will be returned
+ * as scalars.
+ *
Otherwise, if the result set has multiple columns, the results will
+ * be returned as elements of arrays of type {@code Object[]}.
+ *
+ *
+ * Any {@link AffectedEntities affected entities} are synchronized with
+ * the database before execution of the statement.
+ *
+ * @param queryString The SQL select, update, insert, or delete statement
+ * @param affectedEntities The entities which are affected by the statement
+ */
+ Query createNativeQuery(String queryString, AffectedEntities affectedEntities);
+
+ /**
+ * Create an instance of {@link SelectionQuery} for the given SQL query
+ * string, using the given {@code resultType} to interpret the results.
+ *
+ *
+ *
If the given result type is {@link Object}, or a built-in type
+ * such as {@link String} or {@link Integer}, the result set must
+ * have a single column, which will be returned as a scalar.
+ *
If the given result type is {@code Object[]}, then the result set
+ * must have multiple columns, which will be returned in arrays.
+ *
Otherwise, the given result type must be an entity class, in which
+ * case the result set column aliases must map to the fields of the
+ * entity, and the query will return instances of the entity.
+ *
+ *
+ * @param queryString The SQL query
+ * @param resultType the Java type returned in each row of query results
+ *
+ * @return The {@link SelectionQuery} instance for manipulation and execution
+ *
+ * @see jakarta.persistence.EntityManager#createNativeQuery(String, Class)
+ */
+ SelectionQuery createNativeQuery(String queryString, Class resultType);
+
+ /**
+ * Create an instance of {@link SelectionQuery} for the given SQL query
+ * string, using the given {@code resultType} to interpret the results.
+ *
+ *
+ *
If the given result type is {@link Object}, or a built-in type
+ * such as {@link String} or {@link Integer}, the result set must
+ * have a single column, which will be returned as a scalar.
+ *
If the given result type is {@code Object[]}, then the result set
+ * must have multiple columns, which will be returned in arrays.
+ *
Otherwise, the given result type must be an entity class, in which
+ * case the result set column aliases must map to the fields of the
+ * entity, and the query will return instances of the entity.
+ *
+ *
+ * Any {@link AffectedEntities affected entities} are synchronized with
+ * the database before execution of the query.
+ *
+ * @param queryString The SQL query
+ * @param resultType the Java type returned in each row of query results
+ * @param affectedEntities The entities which are affected by the query
+ *
+ * @return The {@link Query} instance for manipulation and execution
+ *
+ * @see jakarta.persistence.EntityManager#createNativeQuery(String, Class)
+ */
+ SelectionQuery createNativeQuery(String queryString, Class resultType, AffectedEntities affectedEntities);
+
+ /**
+ * Create an instance of {@link SelectionQuery} for the given SQL query
+ * string, using the given {@link ResultSetMapping} to interpret the
+ * result set.
+ *
+ * @param queryString The SQL query
+ * @param resultSetMapping the result set mapping
+ *
+ * @return The {@link Query} instance for manipulation and execution
+ *
+ * @see #getResultSetMapping(Class, String)
+ * @see jakarta.persistence.EntityManager#createNativeQuery(String, String)
+ */
+ SelectionQuery createNativeQuery(String queryString, ResultSetMapping resultSetMapping);
+
+ /**
+ * Create an instance of {@link SelectionQuery} for the given SQL query
+ * string, using the given {@link ResultSetMapping} to interpret the
+ * result set.
+ *
+ * Any {@link AffectedEntities affected entities} are synchronized with the
+ * database before execution of the query.
+ *
+ * @param queryString The SQL query
+ * @param resultSetMapping the result set mapping
+ * @param affectedEntities The entities which are affected by the query
+ *
+ * @return The {@link SelectionQuery} instance for manipulation and execution
+ *
+ * @see #getResultSetMapping(Class, String)
+ * @see jakarta.persistence.EntityManager#createNativeQuery(String, String)
+ */
+ SelectionQuery createNativeQuery(String queryString, ResultSetMapping resultSetMapping, AffectedEntities affectedEntities);
+
+ /**
+ * Obtain a native SQL result set mapping defined via the annotation
+ * {@link jakarta.persistence.SqlResultSetMapping}.
+ */
+ ResultSetMapping getResultSetMapping(Class resultType, String mappingName);
+
+ /**
+ * Obtain a named {@link EntityGraph}
+ */
+ EntityGraph getEntityGraph(Class rootType, String graphName);
+
+ /**
+ * Create a new mutable {@link EntityGraph}
+ */
+ EntityGraph createEntityGraph(Class rootType);
+
+ /**
+ * Create a new mutable copy of a named {@link EntityGraph}
+ */
+ EntityGraph createEntityGraph(Class rootType, String graphName);
+
+ /**
+ * Convenience method to obtain the {@link CriteriaBuilder}.
+ *
+ * @since 3
+ */
+ CriteriaBuilder getCriteriaBuilder();
+ }
+
+ /**
+ * 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.
+ *
+ *
+ * @see org.hibernate.Session
+ */
+ interface Session extends QueryProducer, Closeable {
+
+ /**
+ * 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.
+ *
+ *
+ *
+ * @param entityClass The entity type
+ * @param id an identifier
+ *
+ * @return a persistent instance or null via a {@code Uni}
+ *
+ * @see jakarta.persistence.EntityManager#find(Class, Object)
+ */
+ Uni find(Class entityClass, Object id);
+
+ /**
+ * Asynchronously return the persistent instance of the given entity
+ * class with the given identifier, requesting the given {@link LockMode}.
+ *
+ * @param entityClass The entity type
+ * @param id an identifier
+ * @param lockMode the requested {@link LockMode}
+ *
+ * @return a persistent instance or null via a {@code Uni}
+ *
+ * @see #find(Class, Object)
+ * @see #lock(Object, LockMode) this discussion of lock modes
+ */
+ Uni find(Class entityClass, Object id, LockMode lockMode);
+
+ /**
+ * Asynchronously return the persistent instance of the given entity
+ * class with the given identifier, requesting the given {@link LockModeType}.
+ *
+ * @param entityClass The entity type
+ * @param id an identifier
+ * @param lockModeType the requested {@link LockModeType}
+ *
+ * @return a persistent instance or null via a {@code Uni}
+ *
+ * @see #find(Class, Object)
+ * @see #lock(Object, LockMode) this discussion of lock modes
+ */
+ default Uni find(Class entityClass, Object id, LockModeType lockModeType) {
+ return find( entityClass, id, convertToLockMode( lockModeType ) );
+ }
+
+ /**
+ * Asynchronously return the persistent instance with the given
+ * identifier of an entity class, using the given {@link EntityGraph}
+ * as a fetch plan.
+ *
+ * @param entityGraph an {@link EntityGraph} specifying the entity
+ * and associations to be fetched
+ * @param id an identifier
+ *
+ * @see #find(Class, Object)
+ */
+ Uni find(EntityGraph entityGraph, Object id);
+
+ /**
+ * Asynchronously return the persistent instances of the given entity
+ * class with the given identifiers, or null if there is no such
+ * persistent instance.
+ *
+ * @param entityClass The entity type
+ * @param ids the identifiers
+ *
+ * @return a list of persistent instances and nulls via a {@code Uni}
+ *
+ * @see org.hibernate.Session#findMultiple(Class, List, FindOption...)
+ */
+ Uni> find(Class entityClass, Object... ids);
+
+ /**
+ * Asynchronously return the persistent instance of the given entity
+ * class with the given natural identifier, or null if there is no
+ * such persistent instance.
+ *
+ * @param entityClass The entity type
+ * @param naturalId the natural identifier
+ *
+ * @return a persistent instance or null via a {@code Uni}
+ */
+ @Incubating
+ Uni find(Class entityClass, Identifier naturalId);
+
+ /**
+ * 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)}.
+ *
+ * You should not use this method to determine if an instance exists
+ * (use {@link #find} instead). Use this only to retrieve an instance
+ * which you safely assume exists, where non-existence would be an
+ * actual error.
+ *
+ * @param entityClass a persistent class
+ * @param id a valid identifier of an existing persistent instance of the class
+ *
+ * @return the persistent instance or proxy
+ *
+ * @see jakarta.persistence.EntityManager#getReference(Class, Object)
+ */
+ T getReference(Class entityClass, Object id);
+
+ /**
+ * Return the persistent instance with the same identity as the given
+ * instance, which might be detached, assuming that the instance is
+ * still persistent in the database. This method never results in
+ * access to the underlying data store, and thus might return a proxy
+ * that must be initialized explicitly using {@link #fetch(Object)}.
+ *
+ * @param entity a detached persistent instance
+ *
+ * @return the persistent instance or proxy
+ */
+ T getReference(T entity);
+
+ /**
+ * Asynchronously persist the given transient instance, first assigning
+ * a generated identifier. (Or using the current value of the identifier
+ * property if the entity has assigned identifiers.)
+ *
+ * This operation cascades to associated instances if the association is
+ * mapped with {@link jakarta.persistence.CascadeType#PERSIST}.
+ *
+ *
+ *
+ * @param object a transient instance of a persistent class
+ *
+ * @see jakarta.persistence.EntityManager#persist(Object)
+ */
+ Uni persist(Object object);
+
+ /**
+ * Make a transient instance persistent and mark it for later insertion in the
+ * database. This operation cascades to associated instances if the association
+ * is mapped with {@link jakarta.persistence.CascadeType#PERSIST}.
+ *
+ * For entities with a {@link jakarta.persistence.GeneratedValue generated id},
+ * {@code persist()} ultimately results in generation of an identifier for the
+ * given instance. But this may happen asynchronously, when the session is
+ * {@linkplain #flush() flushed}, depending on the identifier generation strategy.
+ *
+ * @param entityName the entity name
+ * @param object a transient instance to be made persistent
+ * @see #persist(Object)
+ */
+ Uni persist(String entityName, Object object);
+
+ /**
+ * Persist multiple transient entity instances at once.
+ *
+ * @see #persist(Object)
+ */
+ Uni persistAll(Object... entities);
+
+ /**
+ * Asynchronously remove a persistent instance from the datastore. The
+ * argument may be an instance associated with the receiving session or
+ * a transient instance with an identifier associated with existing
+ * persistent state.
+ *
+ * This operation cascades to associated instances if the association is
+ * mapped with {@link jakarta.persistence.CascadeType#REMOVE}.
+ *
+ *
+ *
+ * @param entity the managed persistent instance to be removed
+ *
+ * @throws IllegalArgumentException if the given instance is not managed
+ * @see jakarta.persistence.EntityManager#remove(Object)
+ */
+ Uni remove(Object entity);
+
+ /**
+ * Remove multiple entity instances at once.
+ *
+ * @see #remove(Object)
+ */
+ Uni removeAll(Object... entities);
+
+ /**
+ * Copy the state of the given object onto the persistent instance with
+ * the same identifier. If there is no such persistent instance currently
+ * associated with the session, it will be loaded. Return the persistent
+ * instance. Or, if the given instance is transient, save a copy of it
+ * and return the copy as a newly persistent instance. The given instance
+ * does not become associated with the session.
+ *
+ * This operation cascades to associated instances if the association is
* mapped with {@link jakarta.persistence.CascadeType#MERGE}.
*
* @param entity a detached instance with state to be copied
@@ -878,14 +1165,16 @@ default Uni lock(Object entity, LockModeType lockModeType) {
Uni flush();
/**
- * Asynchronously fetch an association that's configured for lazy loading.
+ * Asynchronously fetch an association configured for lazy loading.
*
- * It can also initialize proxys. For example:
+ * This operation may be even be used to initialize a reference returned by
+ * {@link #getReference(Class, Object)}.
+ *
@@ -919,295 +1208,23 @@ default Uni lock(Object entity, LockModeType lockModeType) {
* {@code session.unproxy(author.getBook()).thenAccept(book -> print(book.getTitle()));}
*
*
- * @param association a lazy-loaded association
- *
- * @return the fetched association, via a {@code Uni}
- *
- * @see org.hibernate.Hibernate#unproxy(Object)
- */
- Uni unproxy(T association);
-
- /**
- * Determine the current lock mode of the given entity.
- */
- LockMode getLockMode(Object entity);
-
- /**
- * Determine if the given instance belongs to this persistence context.
- */
- boolean contains(Object entity);
-
- /**
- * Create an instance of {@link SelectionQuery} for the given HQL/JPQL
- * query string.
- *
- * @param queryString The HQL/JPQL query
- *
- * @return The {@link SelectionQuery} instance for manipulation and execution
- *
- * @see jakarta.persistence.EntityManager#createQuery(String, Class)
- */
- SelectionQuery createSelectionQuery(String queryString, Class resultType);
-
- /**
- * Create an instance of {@link MutationQuery} for the given HQL/JPQL
- * update or delete statement.
- *
- * @param queryString The HQL/JPQL query, update or delete statement
- *
- * @return The {@link MutationQuery} instance for manipulation and execution
- *
- * @see jakarta.persistence.EntityManager#createQuery(String)
- */
- MutationQuery createMutationQuery(String queryString);
-
- /**
- * Create an instance of {@link MutationQuery} for the given update tree.
- *
- * @param updateQuery the update criteria query
- *
- * @return The {@link MutationQuery} instance for manipulation and execution
- *
- * @see org.hibernate.query.QueryProducer#createMutationQuery(CriteriaUpdate)
- */
- MutationQuery createMutationQuery(CriteriaUpdate> updateQuery);
-
- /**
- * Create an instance of {@link MutationQuery} for the given delete tree.
- *
- * @param deleteQuery the delete criteria query
- *
- * @return The {@link MutationQuery} instance for manipulation and execution
- *
- * @see org.hibernate.query.QueryProducer#createMutationQuery(CriteriaDelete)
- */
- MutationQuery createMutationQuery(CriteriaDelete> deleteQuery);
-
- /**
- * Create a {@link MutationQuery} from the given insert select criteria tree
- *
- * @param insert the insert select criteria query
- *
- * @return The {@link MutationQuery} instance for manipulation and execution
- *
- * @see org.hibernate.query.QueryProducer#createMutationQuery(JpaCriteriaInsert)
- */
- MutationQuery createMutationQuery(JpaCriteriaInsert> insert);
-
- /**
- * Create an instance of {@link Query} for the given HQL/JPQL query
- * string or HQL/JPQL update or delete statement. In the case of an
- * update or delete, the returned {@link Query} must be executed using
- * {@link Query#executeUpdate()} which returns an affected row count.
- *
- * @param queryString The HQL/JPQL query, update or delete statement
- *
- * @return The {@link Query} instance for manipulation and execution
- *
- * @deprecated See explanation in
- * {@link org.hibernate.query.QueryProducer#createSelectionQuery(String)}
- *
- * @see jakarta.persistence.EntityManager#createQuery(String)
- */
- @Deprecated
-