From 9aa2e39722e2382c4d00ec8ff6268e81ceb73e24 Mon Sep 17 00:00:00 2001 From: Davide D'Alto Date: Thu, 19 Dec 2024 11:46:17 +0100 Subject: [PATCH 001/162] [#2044] Enable GitHub workflows on different branches Include 2.* and 3.* branches and tags (before it was only the WIP ones) --- .github/workflows/build.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 6c90f0b9c..adbb93c23 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -5,12 +5,17 @@ on: branches: - 'main' - 'wip/**' + - '2.*' + - '3.*' tags: - '2.*' + - '3.*' pull_request: branches: - 'main' - 'wip/**' + - '2.*' + - '3.*' # For building snapshots workflow_call: inputs: From b14ffd21c4209a75df969b9dfee60b8f29d0a75f Mon Sep 17 00:00:00 2001 From: Davide D'Alto Date: Thu, 19 Dec 2024 09:47:14 +0100 Subject: [PATCH 002/162] [#2043] Upgrade Hibernate ORM to 6.6.4.Final --- README.md | 2 +- gradle.properties | 4 ++-- .../query/sql/spi/ReactiveNamedNativeQueryMemento.java | 5 +++++ 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index a44faa31b..d3a3431af 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ Hibernate Reactive has been tested with: - CockroachDB v24 - MS SQL Server 2022 - Oracle 23 -- [Hibernate ORM][] 6.6.3.Final +- [Hibernate ORM][] 6.6.4.Final - [Vert.x Reactive PostgreSQL Client](https://vertx.io/docs/vertx-pg-client/java/) 4.5.11 - [Vert.x Reactive MySQL Client](https://vertx.io/docs/vertx-mysql-client/java/) 4.5.11 - [Vert.x Reactive Db2 Client](https://vertx.io/docs/vertx-db2-client/java/) 4.5.11 diff --git a/gradle.properties b/gradle.properties index 55ec51fc8..e8b659047 100644 --- a/gradle.properties +++ b/gradle.properties @@ -35,12 +35,12 @@ org.gradle.java.installations.auto-download=false #enableMavenLocalRepo = true # The default Hibernate ORM version (override using `-PhibernateOrmVersion=the.version.you.want`) -hibernateOrmVersion = 6.6.3.Final +hibernateOrmVersion = 6.6.4.Final # Override default Hibernate ORM Gradle plugin version # Using the stable version because I don't know how to configure the build to download the snapshot version from # a remote repository -#hibernateOrmGradlePluginVersion = 6.6.3.Final +#hibernateOrmGradlePluginVersion = 6.6.4.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 diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/query/sql/spi/ReactiveNamedNativeQueryMemento.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/query/sql/spi/ReactiveNamedNativeQueryMemento.java index fc1493d02..9d639d099 100644 --- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/query/sql/spi/ReactiveNamedNativeQueryMemento.java +++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/query/sql/spi/ReactiveNamedNativeQueryMemento.java @@ -52,6 +52,11 @@ public Class getResultMappingClass() { return delegate.getResultMappingClass(); } + @Override + public Class getResultType() { + return delegate.getResultType(); + } + @Override public Integer getFirstResult() { return delegate.getFirstResult(); From c06e818f3ccf5aa79b1ad1314fb2e782e3c81a45 Mon Sep 17 00:00:00 2001 From: Davide D'Alto Date: Fri, 20 Dec 2024 10:51:49 +0100 Subject: [PATCH 003/162] [#2049] Update GitHub workflow cache action to v4 v2 has been deprecated for a while: https://github.blog/changelog/2024-09-16-notice-of-upcoming-deprecations-and-changes-in-github-actions-services/ --- .github/workflows/build.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index adbb93c23..c0e403d92 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -90,7 +90,7 @@ jobs: echo "::set-output name=yearmonth::$(/bin/date -u "+%Y-%m")" shell: bash - name: Cache Gradle downloads - uses: actions/cache@v2 + uses: actions/cache@v4 id: cache-gradle with: path: | @@ -132,7 +132,7 @@ jobs: echo "::set-output name=yearmonth::$(/bin/date -u "+%Y-%m")" shell: bash - name: Cache Gradle downloads - uses: actions/cache@v2 + uses: actions/cache@v4 id: cache-gradle with: path: | From bad390ee1c19de7b883da3adfb79faf2691a1c01 Mon Sep 17 00:00:00 2001 From: Steve Ebersole Date: Thu, 12 Dec 2024 09:43:53 -0600 Subject: [PATCH 004/162] [#1095] Sign the artifacts for Sonatype --- ci/release/Jenkinsfile | 6 +- ci/snapshot-publish.Jenkinsfile | 4 +- publish.gradle | 97 ++++++++++++++++++++++++++++----- 3 files changed, 89 insertions(+), 18 deletions(-) diff --git a/ci/release/Jenkinsfile b/ci/release/Jenkinsfile index bb4315fb8..5fe408354 100644 --- a/ci/release/Jenkinsfile +++ b/ci/release/Jenkinsfile @@ -168,8 +168,8 @@ pipeline { withCredentials([ usernamePassword(credentialsId: 'ossrh.sonatype.org', passwordVariable: 'OSSRH_PASSWORD', usernameVariable: 'OSSRH_USER'), usernamePassword(credentialsId: 'gradle-plugin-portal-api-key', passwordVariable: 'PLUGIN_PORTAL_PASSWORD', usernameVariable: 'PLUGIN_PORTAL_USERNAME'), - file(credentialsId: 'release.gpg.private-key', variable: 'RELEASE_GPG_PRIVATE_KEY_PATH'), - string(credentialsId: 'release.gpg.passphrase', variable: 'RELEASE_GPG_PASSPHRASE') + file(credentialsId: 'release.gpg.private-key', variable: 'SIGNING_GPG_PRIVATE_KEY_PATH'), + string(credentialsId: 'release.gpg.passphrase', variable: 'SIGNING_GPG_PASSPHRASE') ]) { sshagent(['ed25519.Hibernate-CI.github.com', 'hibernate.filemgmt.jboss.org', 'hibernate-ci.frs.sourceforge.net']) { // set release version @@ -202,7 +202,7 @@ pipeline { usernamePassword(credentialsId: 'ossrh.sonatype.org', passwordVariable: 'OSSRH_PASSWORD', usernameVariable: 'OSSRH_USER'), usernamePassword(credentialsId: 'gradle-plugin-portal-api-key', passwordVariable: 'PLUGIN_PORTAL_PASSWORD', usernameVariable: 'PLUGIN_PORTAL_USERNAME'), file(credentialsId: 'release.gpg.private-key', variable: 'RELEASE_GPG_PRIVATE_KEY_PATH'), - string(credentialsId: 'release.gpg.passphrase', variable: 'RELEASE_GPG_PASSPHRASE'), + string(credentialsId: 'release.gpg.passphrase', variable: 'RELEASE_GPG_PASSPHRASE') gitUsernamePassword(credentialsId: 'username-and-token.Hibernate-CI.github.com', gitToolName: 'Default') ]) { sshagent(['ed25519.Hibernate-CI.github.com', 'hibernate.filemgmt.jboss.org', 'hibernate-ci.frs.sourceforge.net']) { diff --git a/ci/snapshot-publish.Jenkinsfile b/ci/snapshot-publish.Jenkinsfile index c95f6663f..83fd95a4a 100644 --- a/ci/snapshot-publish.Jenkinsfile +++ b/ci/snapshot-publish.Jenkinsfile @@ -32,8 +32,8 @@ pipeline { steps { withCredentials([ usernamePassword(credentialsId: 'ossrh.sonatype.org', usernameVariable: 'hibernatePublishUsername', passwordVariable: 'hibernatePublishPassword'), - string(credentialsId: 'release.gpg.passphrase', variable: 'SIGNING_PASS'), - file(credentialsId: 'release.gpg.private-key', variable: 'SIGNING_KEYRING') + 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 \ -PhibernatePublishUsername=$hibernatePublishUsername \ diff --git a/publish.gradle b/publish.gradle index 3c48e1298..39e0e16b2 100644 --- a/publish.gradle +++ b/publish.gradle @@ -1,13 +1,14 @@ +apply plugin: 'java' apply plugin: 'maven-publish' +apply plugin: 'signing' -tasks.register( 'sourcesJar', Jar ) { - from sourceSets.main.allJava - archiveClassifier = 'sources' -} +// Java / publishing -tasks.register( 'javadocJar', Jar ) { - from javadoc - archiveClassifier = 'javadoc' +java { + // include javadoc and sources jar in the Java component + // - classes jar included by default + withJavadocJar() + withSourcesJar() } jar { @@ -35,14 +36,9 @@ javadoc { publishing { publications { - logger.lifecycle "Publishing groupId: '" + project.group + "', version: '" + project.version + "'" - publishedArtifacts(MavenPublication) { - groupId = project.group - version = project.version from components.java - artifact sourcesJar - artifact javadocJar + pom { name = project.mavenPomName description = project.description @@ -80,3 +76,78 @@ publishing { } } } + + +// signing + +var signingExtension = project.getExtensions().getByType(SigningExtension) as SigningExtension + +// create a `signPublications` "grouping" task which will execute all Sign tasks +def signPublicationsTask = tasks.register('signPublications') +tasks.named( "publishPublishedArtifactsPublicationToSonatypeRepository" ) { + dependsOn signPublicationsTask +} + +gradle.taskGraph.whenReady { TaskExecutionGraph graph -> + boolean wasSigningRequested = false + boolean wasPublishingRequested = false + List signingTasks = [] + + graph.allTasks.each {task -> + logger.lifecycle( "Checking task : $task" ) + if ( task instanceof Sign ) { + logger.lifecycle( " - Task is Sign" ) + signingTasks.add( task ) + wasSigningRequested = true + } + else if ( task instanceof PublishToMavenRepository ) { + logger.lifecycle( " - Task is PublishToMavenRepository" ) + wasPublishingRequested = true + } + } + + if ( wasPublishingRequested ) { + logger.lifecycle "Publishing groupId: '" + project.group + "', version: '" + project.version + "'" + } + + if ( wasSigningRequested || wasPublishingRequested ) { + // signing was explicitly requested and/or we are publishing to Sonatype OSSRH + // - we need the signing to happen + signingExtension.required = true + + var signingKey = resolveSigningKey() + var signingPassword = resolveSigningPassphrase() + signingExtension.useInMemoryPgpKeys( signingKey, signingPassword ) + signingExtension.sign publishing.publications.publishedArtifacts + + signPublicationsTask.get().dependsOn( signingTasks ) + } + else { + // signing was not explicitly requested and we are not publishing to OSSRH, + // - disable all Sign tasks + signingTasks.each { enabled = false } + } +} + + +static String resolveSigningKey() { + var key = System.getenv().get( "SIGNING_GPG_PRIVATE_KEY" ) + if ( key != null ) { + return key + } + + var keyFile = System.getenv().get( "SIGNING_GPG_PRIVATE_KEY_PATH" ) + if ( keyFile != null ) { + return new File( keyFile ).text + } + + throw new RuntimeException( "Cannot perform signing without GPG details." ) +} + +static String resolveSigningPassphrase() { + var passphrase = System.getenv().get( "SIGNING_GPG_PASSPHRASE" ) + if ( passphrase == null ) { + throw new RuntimeException( "Cannot perform signing without GPG details." ) + } + return passphrase +} From 8e70e3a2e5b272f389c787dbea150b3afd70e896 Mon Sep 17 00:00:00 2001 From: Steve Ebersole Date: Thu, 12 Dec 2024 11:38:34 -0600 Subject: [PATCH 005/162] [#2027] Use env-vars for passing secrets used during release --- build.gradle | 18 +-------- ci/release/Jenkinsfile | 38 ++++++++----------- ci/snapshot-publish.Jenkinsfile | 9 ++--- publish.gradle | 65 ++++++++++++++++++++++++++------- 4 files changed, 72 insertions(+), 58 deletions(-) diff --git a/build.gradle b/build.gradle index 5aee62970..ed2007312 100644 --- a/build.gradle +++ b/build.gradle @@ -12,15 +12,6 @@ group = "org.hibernate.reactive" // leverage the ProjectVersion which comes from the `local.versions` plugin version = project.projectVersion.fullName -ext { - if ( !project.hasProperty( 'hibernatePublishUsername' ) ) { - hibernatePublishUsername = null - } - if ( !project.hasProperty( 'hibernatePublishPassword' ) ) { - hibernatePublishPassword = null - } -} - // Versions which need to be aligned across modules; this also // allows overriding the build using a parameter, which can be // useful to monitor compatibility for upcoming versions on CI: @@ -39,15 +30,10 @@ ext { logger.lifecycle "Vert.x SQL Client Version: " + project.vertxSqlClientVersion } -// To release, see task ciRelease in release/build.gradle -// To publish on Sonatype (Maven Central): -// ./gradlew publishToSonatype closeAndReleaseStagingRepository -PhibernatePublishUsername="" -PhibernatePublishPassword="" +// Publishing to Sonatype (Maven Central): nexusPublishing { repositories { - sonatype { - username = project.hibernatePublishUsername - password = project.hibernatePublishPassword - } + sonatype() } } diff --git a/ci/release/Jenkinsfile b/ci/release/Jenkinsfile index 5fe408354..87e009d49 100644 --- a/ci/release/Jenkinsfile +++ b/ci/release/Jenkinsfile @@ -165,24 +165,18 @@ pipeline { configFile(fileId: 'release.config.ssh', targetLocation: "${env.HOME}/.ssh/config"), configFile(fileId: 'release.config.ssh.knownhosts', targetLocation: "${env.HOME}/.ssh/known_hosts") ]) { - withCredentials([ - usernamePassword(credentialsId: 'ossrh.sonatype.org', passwordVariable: 'OSSRH_PASSWORD', usernameVariable: 'OSSRH_USER'), - usernamePassword(credentialsId: 'gradle-plugin-portal-api-key', passwordVariable: 'PLUGIN_PORTAL_PASSWORD', usernameVariable: 'PLUGIN_PORTAL_USERNAME'), - file(credentialsId: 'release.gpg.private-key', variable: 'SIGNING_GPG_PRIVATE_KEY_PATH'), - string(credentialsId: 'release.gpg.passphrase', variable: 'SIGNING_GPG_PASSPHRASE') - ]) { - sshagent(['ed25519.Hibernate-CI.github.com', 'hibernate.filemgmt.jboss.org', 'hibernate-ci.frs.sourceforge.net']) { - // set release version - // update changelog from JIRA - // tags the version - // changes the version to the provided development version - withEnv([ - "BRANCH=${env.GIT_BRANCH}", - // Increase the amount of memory for this part since asciidoctor doc rendering consumes a lot of metaspace - "GRADLE_OPTS=-Dorg.gradle.jvmargs='-Dlog4j2.disableJmx -Xmx4g -XX:MaxMetaspaceSize=768m -XX:+HeapDumpOnOutOfMemoryError -Duser.language=en -Duser.country=US -Duser.timezone=UTC -Dfile.encoding=UTF-8'" - ]) { - sh ".release/scripts/prepare-release.sh ${env.PROJECT} ${env.RELEASE_VERSION} ${env.DEVELOPMENT_VERSION}" - } + + sshagent(['ed25519.Hibernate-CI.github.com', 'hibernate.filemgmt.jboss.org', 'hibernate-ci.frs.sourceforge.net']) { + // set release version + // update changelog from JIRA + // tags the version + // changes the version to the provided development version + withEnv([ + "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}" } } } @@ -199,10 +193,10 @@ pipeline { configFile(fileId: 'release.config.ssh.knownhosts', targetLocation: "${env.HOME}/.ssh/known_hosts") ]) { withCredentials([ - usernamePassword(credentialsId: 'ossrh.sonatype.org', passwordVariable: 'OSSRH_PASSWORD', usernameVariable: 'OSSRH_USER'), - usernamePassword(credentialsId: 'gradle-plugin-portal-api-key', passwordVariable: 'PLUGIN_PORTAL_PASSWORD', usernameVariable: 'PLUGIN_PORTAL_USERNAME'), - file(credentialsId: 'release.gpg.private-key', variable: 'RELEASE_GPG_PRIVATE_KEY_PATH'), - string(credentialsId: 'release.gpg.passphrase', variable: 'RELEASE_GPG_PASSPHRASE') + // 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') ]) { sshagent(['ed25519.Hibernate-CI.github.com', 'hibernate.filemgmt.jboss.org', 'hibernate-ci.frs.sourceforge.net']) { diff --git a/ci/snapshot-publish.Jenkinsfile b/ci/snapshot-publish.Jenkinsfile index 83fd95a4a..c2fba1d6b 100644 --- a/ci/snapshot-publish.Jenkinsfile +++ b/ci/snapshot-publish.Jenkinsfile @@ -31,15 +31,12 @@ pipeline { stage('Publish') { steps { withCredentials([ - usernamePassword(credentialsId: 'ossrh.sonatype.org', usernameVariable: 'hibernatePublishUsername', passwordVariable: 'hibernatePublishPassword'), + // 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 \ - -PhibernatePublishUsername=$hibernatePublishUsername \ - -PhibernatePublishPassword=$hibernatePublishPassword \ - --no-scan \ - ''' + sh "./gradlew clean publish --no-scan" } } } diff --git a/publish.gradle b/publish.gradle index 39e0e16b2..0271197d4 100644 --- a/publish.gradle +++ b/publish.gradle @@ -5,8 +5,8 @@ apply plugin: 'signing' // Java / publishing java { - // include javadoc and sources jar in the Java component - // - classes jar included by default + // Configure the Java "software component" to include javadoc and sources jars in addition to the classes jar. + // Ultimately, this component is what makes up the publication for this project. withJavadocJar() withSourcesJar() } @@ -36,7 +36,7 @@ javadoc { publishing { publications { - publishedArtifacts(MavenPublication) { + register( "publishedArtifacts", MavenPublication) { from components.java pom { @@ -78,35 +78,39 @@ publishing { } -// signing +// Signing var signingExtension = project.getExtensions().getByType(SigningExtension) as SigningExtension -// create a `signPublications` "grouping" task which will execute all Sign tasks -def signPublicationsTask = tasks.register('signPublications') +def signPublicationsTask = tasks.register('signPublications') { + description "Grouping task which executes all Sign tasks" + dependsOn tasks.withType( Sign ) +} + tasks.named( "publishPublishedArtifactsPublicationToSonatypeRepository" ) { + // publishing depends on signing dependsOn signPublicationsTask } gradle.taskGraph.whenReady { TaskExecutionGraph graph -> boolean wasSigningRequested = false boolean wasPublishingRequested = false - List signingTasks = [] graph.allTasks.each {task -> - logger.lifecycle( "Checking task : $task" ) if ( task instanceof Sign ) { - logger.lifecycle( " - Task is Sign" ) - signingTasks.add( task ) wasSigningRequested = true } else if ( task instanceof PublishToMavenRepository ) { - logger.lifecycle( " - Task is PublishToMavenRepository" ) wasPublishingRequested = true } } if ( wasPublishingRequested ) { + def publishUser = resolvePublishUser() + def publishPass = resolvePublishPass() + if ( publishUser == null || publishPass == null ) { + throw new RuntimeException( "Cannot perform publishing to OSSRH without credentials." ) + } logger.lifecycle "Publishing groupId: '" + project.group + "', version: '" + project.version + "'" } @@ -119,14 +123,47 @@ gradle.taskGraph.whenReady { TaskExecutionGraph graph -> var signingPassword = resolveSigningPassphrase() signingExtension.useInMemoryPgpKeys( signingKey, signingPassword ) signingExtension.sign publishing.publications.publishedArtifacts - - signPublicationsTask.get().dependsOn( signingTasks ) } else { // signing was not explicitly requested and we are not publishing to OSSRH, // - disable all Sign tasks - signingTasks.each { enabled = false } + tasks.withType( Sign ).each { enabled = false } + } +} + +String resolvePublishUser() { + var envVar = System.getenv().get( "ORG_GRADLE_PROJECT_sonatypeUsername" ) + if ( envVar != null ) { + return envVar + } + + def projectProp = projectPropOrNull( "sonatypeUsername" ) + if ( projectProp != null ) { + return projectProp + } + + return null +} + +String resolvePublishPass() { + var envVar = System.getenv().get( "ORG_GRADLE_PROJECT_sonatypePassword" ) + if ( envVar != null ) { + return envVar + } + + def projectProp = projectPropOrNull( "sonatypePassword" ) + if ( projectProp != null ) { + return projectProp + } + + return null +} + +String projectPropOrNull(String name) { + if ( project.hasProperty( name ) ) { + return project.findProperty( name ) } + return null; } From b27d9d8eede55c37e3bae47aa3b9ade792af4144 Mon Sep 17 00:00:00 2001 From: Steve Ebersole Date: Wed, 18 Dec 2024 12:01:46 -0600 Subject: [PATCH 006/162] [#1095] Sign the artifacts for Sonatype --- publish.gradle | 81 +++++++++++++++++++------------------------------- 1 file changed, 31 insertions(+), 50 deletions(-) diff --git a/publish.gradle b/publish.gradle index 0271197d4..977092d9a 100644 --- a/publish.gradle +++ b/publish.gradle @@ -82,25 +82,19 @@ publishing { var signingExtension = project.getExtensions().getByType(SigningExtension) as SigningExtension -def signPublicationsTask = tasks.register('signPublications') { - description "Grouping task which executes all Sign tasks" - dependsOn tasks.withType( Sign ) -} +var publishingExtension = project.getExtensions().getByType(PublishingExtension) as PublishingExtension +signingExtension.sign publishingExtension.publications.publishedArtifacts -tasks.named( "publishPublishedArtifactsPublicationToSonatypeRepository" ) { - // publishing depends on signing - dependsOn signPublicationsTask -} +var signingKey = resolveSigningKey() +var signingPassphrase = resolveSigningPassphrase() +signingExtension.useInMemoryPgpKeys(signingKey, signingPassphrase) gradle.taskGraph.whenReady { TaskExecutionGraph graph -> - boolean wasSigningRequested = false boolean wasPublishingRequested = false graph.allTasks.each {task -> - if ( task instanceof Sign ) { - wasSigningRequested = true - } - else if ( task instanceof PublishToMavenRepository ) { + if ( task instanceof PublishToMavenRepository ) { + logger.lifecycle( "Found PublishToMavenRepository task : {}", task.path ) wasPublishingRequested = true } } @@ -111,24 +105,34 @@ gradle.taskGraph.whenReady { TaskExecutionGraph graph -> if ( publishUser == null || publishPass == null ) { throw new RuntimeException( "Cannot perform publishing to OSSRH without credentials." ) } - logger.lifecycle "Publishing groupId: '" + project.group + "', version: '" + project.version + "'" - } - if ( wasSigningRequested || wasPublishingRequested ) { - // signing was explicitly requested and/or we are publishing to Sonatype OSSRH - // - we need the signing to happen + logger.lifecycle "Publishing {} : {} : {}", project.group, project.name, project.version + + // require signing if publishing to OSSRH signingExtension.required = true + } + else if ( signingKey == null || signingPassphrase == null ) { + tasks.withType( Sign ).each { t-> t.enabled = false } + } +} + - var signingKey = resolveSigningKey() - var signingPassword = resolveSigningPassphrase() - signingExtension.useInMemoryPgpKeys( signingKey, signingPassword ) - signingExtension.sign publishing.publications.publishedArtifacts +static String resolveSigningKey() { + var key = System.getenv().get( "SIGNING_GPG_PRIVATE_KEY" ) + if ( key != null ) { + return key } - else { - // signing was not explicitly requested and we are not publishing to OSSRH, - // - disable all Sign tasks - tasks.withType( Sign ).each { enabled = false } + + var keyFile = System.getenv().get( "SIGNING_GPG_PRIVATE_KEY_PATH" ) + if ( keyFile != null ) { + return new File( keyFile ).text } + + return null +} + +static String resolveSigningPassphrase() { + return System.getenv().get( "SIGNING_GPG_PASSPHRASE" ) } String resolvePublishUser() { @@ -164,27 +168,4 @@ String projectPropOrNull(String name) { return project.findProperty( name ) } return null; -} - - -static String resolveSigningKey() { - var key = System.getenv().get( "SIGNING_GPG_PRIVATE_KEY" ) - if ( key != null ) { - return key - } - - var keyFile = System.getenv().get( "SIGNING_GPG_PRIVATE_KEY_PATH" ) - if ( keyFile != null ) { - return new File( keyFile ).text - } - - throw new RuntimeException( "Cannot perform signing without GPG details." ) -} - -static String resolveSigningPassphrase() { - var passphrase = System.getenv().get( "SIGNING_GPG_PASSPHRASE" ) - if ( passphrase == null ) { - throw new RuntimeException( "Cannot perform signing without GPG details." ) - } - return passphrase -} +} \ No newline at end of file From c16976cd4cec1f24994995ff90371e51e65580cd Mon Sep 17 00:00:00 2001 From: Davide D'Alto Date: Fri, 20 Dec 2024 17:46:36 +0100 Subject: [PATCH 007/162] [#1095] Add missing comma to JenkinsFile --- ci/release/Jenkinsfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci/release/Jenkinsfile b/ci/release/Jenkinsfile index 87e009d49..87d2676c1 100644 --- a/ci/release/Jenkinsfile +++ b/ci/release/Jenkinsfile @@ -196,7 +196,7 @@ pipeline { // 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') + string(credentialsId: 'release.gpg.passphrase', variable: 'SIGNING_GPG_PASSPHRASE'), gitUsernamePassword(credentialsId: 'username-and-token.Hibernate-CI.github.com', gitToolName: 'Default') ]) { sshagent(['ed25519.Hibernate-CI.github.com', 'hibernate.filemgmt.jboss.org', 'hibernate-ci.frs.sourceforge.net']) { From 8db37dd4d79c1c8e40e5d63e11b5bea9d3181592 Mon Sep 17 00:00:00 2001 From: Hibernate-CI Date: Fri, 20 Dec 2024 16:49:09 +0000 Subject: [PATCH 008/162] Update project version to : `2.4.3.Final` --- gradle/version.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/version.properties b/gradle/version.properties index dd20a5fa4..7eac1a461 100644 --- a/gradle/version.properties +++ b/gradle/version.properties @@ -1 +1 @@ -projectVersion=2.4.3-SNAPSHOT \ No newline at end of file +projectVersion=2.4.3.Final \ No newline at end of file From 3c4607a9b0e61cf96a5ee5496cecd6420cb2e8e4 Mon Sep 17 00:00:00 2001 From: Hibernate-CI Date: Fri, 20 Dec 2024 16:50:08 +0000 Subject: [PATCH 009/162] Update project version to : `2.4.4-SNAPSHOT` --- gradle/version.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/version.properties b/gradle/version.properties index 7eac1a461..47693ff21 100644 --- a/gradle/version.properties +++ b/gradle/version.properties @@ -1 +1 @@ -projectVersion=2.4.3.Final \ No newline at end of file +projectVersion=2.4.4-SNAPSHOT \ No newline at end of file From 91fc13658b7d75675cdd6ece6766ea0d95c5e82c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yoann=20Rodi=C3=A8re?= Date: Tue, 14 Jan 2025 09:20:07 +0100 Subject: [PATCH 010/162] [#2063] Use specific Jenkins nodes for releases This should be safer as these nodes are only used once. --- ci/release/Jenkinsfile | 2 +- ci/snapshot-publish.Jenkinsfile | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ci/release/Jenkinsfile b/ci/release/Jenkinsfile index 87d2676c1..80b89bf9f 100644 --- a/ci/release/Jenkinsfile +++ b/ci/release/Jenkinsfile @@ -58,7 +58,7 @@ def checkoutReleaseScripts() { pipeline { agent { - label 'Worker&&Containers' + label 'Release' } tools { jdk 'OpenJDK 11 Latest' diff --git a/ci/snapshot-publish.Jenkinsfile b/ci/snapshot-publish.Jenkinsfile index c2fba1d6b..c9e19ca4c 100644 --- a/ci/snapshot-publish.Jenkinsfile +++ b/ci/snapshot-publish.Jenkinsfile @@ -12,7 +12,7 @@ if (currentBuild.getBuildCauses().toString().contains('BranchIndexingCause')) { pipeline { agent { - label 'Fedora' + label 'Release' } tools { jdk 'OpenJDK 11 Latest' From e160db5f879f4907f190c651f2483b0e191214e0 Mon Sep 17 00:00:00 2001 From: Andrea Boriero Date: Fri, 17 Jan 2025 10:31:55 +0100 Subject: [PATCH 011/162] [#2026] UnexpectedAccessToTheDatabase error when merging a detached entity with a ToMany association --- .../reactive/engine/impl/CollectionTypes.java | 516 ++++++++++++++++++ .../reactive/engine/impl/EntityTypes.java | 215 +++++--- .../hibernate/reactive/logging/impl/Log.java | 4 + 3 files changed, 661 insertions(+), 74 deletions(-) create mode 100644 hibernate-reactive-core/src/main/java/org/hibernate/reactive/engine/impl/CollectionTypes.java 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 new file mode 100644 index 000000000..ab9d02d08 --- /dev/null +++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/engine/impl/CollectionTypes.java @@ -0,0 +1,516 @@ +/* Hibernate, Relational Persistence for Idiomatic Java + * + * SPDX-License-Identifier: Apache-2.0 + * Copyright: Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.reactive.engine.impl; + +import java.io.Serializable; +import java.lang.invoke.MethodHandles; +import java.lang.reflect.Array; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.SortedMap; +import java.util.TreeMap; +import java.util.concurrent.CompletionStage; + +import org.hibernate.Hibernate; +import org.hibernate.HibernateException; +import org.hibernate.collection.spi.AbstractPersistentCollection; +import org.hibernate.collection.spi.PersistentArrayHolder; +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; +import org.hibernate.reactive.logging.impl.Log; +import org.hibernate.reactive.logging.impl.LoggerFactory; +import org.hibernate.type.ArrayType; +import org.hibernate.type.CollectionType; +import org.hibernate.type.CustomCollectionType; +import org.hibernate.type.EntityType; +import org.hibernate.type.ForeignKeyDirection; +import org.hibernate.type.MapType; +import org.hibernate.type.Type; + +import static org.hibernate.bytecode.enhance.spi.LazyPropertyInitializer.UNFETCHED_PROPERTY; +import static org.hibernate.internal.util.collections.CollectionHelper.mapOfSize; +import static org.hibernate.pretty.MessageHelper.collectionInfoString; +import static org.hibernate.reactive.util.impl.CompletionStages.completedFuture; +import static org.hibernate.reactive.util.impl.CompletionStages.loop; +import static org.hibernate.reactive.util.impl.CompletionStages.nullFuture; +import static org.hibernate.reactive.util.impl.CompletionStages.voidFuture; + +/** + * Reactive operations that really belong to {@link CollectionType} + * + */ +public class CollectionTypes { + private static final Log LOG = LoggerFactory.make( Log.class, MethodHandles.lookup() ); + + /** + * @see org.hibernate.type.AbstractType#replace(Object, Object, SharedSessionContractImplementor, Object, Map, ForeignKeyDirection) + */ + public static CompletionStage replace( + CollectionType type, + Object original, + Object target, + SessionImplementor session, + Object owner, + Map copyCache, + ForeignKeyDirection foreignKeyDirection) + throws HibernateException { + // Collection and OneToOne are the only associations that could be TO_PARENT + return type.getForeignKeyDirection() == foreignKeyDirection + ? replace( type, original, target, session, owner, copyCache ) + : completedFuture( target ); + } + + /** + * @see CollectionType#replace(Object, Object, SharedSessionContractImplementor, Object, Map) + */ + public static CompletionStage replace( + CollectionType type, + Object original, + Object target, + SessionImplementor session, + Object owner, + Map copyCache) throws HibernateException { + if ( original == null ) { + return replaceNullOriginal( target, session ); + } + else if ( !Hibernate.isInitialized( original ) ) { + return replaceUninitializedOriginal( type, original, target, session, copyCache ); + } + else { + return replaceOriginal( type, original, target, session, owner, copyCache ); + } + } + + // todo: make org.hibernate.type.CollectionType#replaceNullOriginal public ? + + /** + * @see CollectionType#replaceNullOriginal(Object, SharedSessionContractImplementor) + */ + private static CompletionStage replaceNullOriginal( + Object target, + SessionImplementor session) { + if ( target == null ) { + return nullFuture(); + } + else if ( target instanceof Collection ) { + Collection collection = (Collection) target; + collection.clear(); + return completedFuture( collection ); + } + else if ( target instanceof Map ) { + Map map = (Map) target; + map.clear(); + return completedFuture( map ); + } + else { + final PersistenceContext persistenceContext = session.getPersistenceContext(); + final PersistentCollection collectionHolder = persistenceContext.getCollectionHolder( target ); + if ( collectionHolder != null ) { + if ( collectionHolder instanceof PersistentArrayHolder ) { + PersistentArrayHolder arrayHolder = (PersistentArrayHolder) collectionHolder; + persistenceContext.removeCollectionHolder( target ); + arrayHolder.beginRead(); + final PluralAttributeMapping attributeMapping = + persistenceContext.getCollectionEntry( collectionHolder ) + .getLoadedPersister().getAttributeMapping(); + arrayHolder.injectLoadedState( attributeMapping, null ); + arrayHolder.endRead(); + arrayHolder.dirty(); + persistenceContext.addCollectionHolder( collectionHolder ); + return completedFuture( arrayHolder.getArray() ); + } + } + } + return nullFuture(); + } + + // todo: make org.hibernate.type.CollectionType#replaceUninitializedOriginal public + /** + * @see CollectionType#replaceNullOriginal(Object, SharedSessionContractImplementor) + */ + private static CompletionStage replaceUninitializedOriginal( + CollectionType type, + Object original, + Object target, + SessionImplementor session, + Map copyCache) { + final PersistentCollection persistentCollection = (PersistentCollection) original; + if ( persistentCollection.hasQueuedOperations() ) { + if ( original == target ) { + // A managed entity with an uninitialized collection is being merged, + // We need to replace any detached entities in the queued operations + // with managed copies. + final AbstractPersistentCollection pc = (AbstractPersistentCollection) original; + pc.replaceQueuedOperationValues( + session.getFactory() + .getMappingMetamodel() + .getCollectionDescriptor( type.getRole() ), copyCache + ); + } + else { + // original is a detached copy of the collection; + // it contains queued operations, which will be ignored + LOG.ignoreQueuedOperationsOnMerge( + collectionInfoString( type.getRole(), persistentCollection.getKey() ) ); + } + } + return completedFuture( target ); + } + + /** + * @see CollectionType#replaceOriginal(Object, Object, SharedSessionContractImplementor, Object, Map) + */ + private static CompletionStage replaceOriginal( + CollectionType type, + Object original, + Object target, + SessionImplementor session, + Object owner, + Map copyCache) { + + //for arrays, replaceElements() may return a different reference, since + //the array length might not match + return replaceElements( + type, + original, + instantiateResultIfNecessary( type, original, target ), + owner, + copyCache, + session + ).thenCompose( result -> { + if ( original == target ) { + // get the elements back into the target making sure to handle dirty flag + final boolean wasClean = + target instanceof PersistentCollection + && !( (PersistentCollection) target).isDirty(); + //TODO: this is a little inefficient, don't need to do a whole + // deep replaceElements() call + return replaceElements( type, result, target, owner, copyCache, session ) + .thenCompose( unused -> { + if ( wasClean ) { + ( (PersistentCollection) target ).clearDirty(); + } + return completedFuture( target ); + } ); + } + else { + return completedFuture( result ); + } + } ); + } + + /** + * @see CollectionType#replaceElements(Object, Object, Object, Map, SharedSessionContractImplementor) + */ + private static CompletionStage replaceElements( + CollectionType type, + Object original, + Object target, + Object owner, + Map copyCache, + SessionImplementor session) { + if ( type instanceof ArrayType ) { + return replaceArrayTypeElements( type, original, target, owner, copyCache, session ); + } + else if ( type instanceof CustomCollectionType ) { + return completedFuture( type.replaceElements( original, target, owner, copyCache, session ) ); + } + else if ( type instanceof MapType ) { + return replaceMapTypeElements( + type, + (Map) original, + (Map) target, + owner, + copyCache, + session + ); + } + else { + return replaceCollectionTypeElements( + type, + original, + (Collection) target, + owner, + copyCache, + session + ); + } + } + + private static CompletionStage replaceCollectionTypeElements( + CollectionType type, + Object original, + final Collection result, + Object owner, + Map copyCache, + SessionImplementor session) { + result.clear(); + + // copy elements into newly empty target collection + final Type elemType = type.getElementType( session.getFactory() ); + return loop( + (Collection) original, o -> getReplace( elemType, o, owner, session, copyCache ) + .thenAccept( result::add ) + ).thenCompose( unused -> { + // 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 + && result instanceof PersistentCollection ) { + PersistentCollection resultPersistentCollection = (PersistentCollection) result; + PersistentCollection originalPersistentCollection = (PersistentCollection) original; + return preserveSnapshot( + originalPersistentCollection, resultPersistentCollection, + elemType, owner, copyCache, session + ).thenApply( v -> { + if ( !originalPersistentCollection.isDirty() ) { + resultPersistentCollection.clearDirty(); + } + return result; + } ); + } + else { + return completedFuture( result ); + } + } ); + } + + private static CompletionStage replaceMapTypeElements( + CollectionType type, + 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(); + + return loop( + original.entrySet(), entry -> { + final Map.Entry me = entry; + return getReplace( persister.getIndexType(), me.getKey(), owner, session, copyCache ) + .thenCompose( key -> + getReplace( + persister.getElementType(), + me.getValue(), + owner, + session, + copyCache + ).thenAccept( value -> + result.put( key, value ) ) + ); + } + ).thenApply( unused -> result ); + } + + private static CompletionStage replaceArrayTypeElements( + CollectionType type, + Object original, + Object target, + Object owner, + Map copyCache, + SessionImplementor session) { + final Object result; + final int length = Array.getLength( original ); + if ( length != Array.getLength( target ) ) { + //note: this affects the return value! + result = ( (ArrayType) type ).instantiateResult( original ); + } + else { + result = target; + } + + final Type elemType = type.getElementType( session.getFactory() ); + return loop( + 0, length, i -> { + return getReplace( elemType, Array.get( original, i ), owner, session, copyCache ) + .thenApply( o -> { + Array.set( result, i, o ); + return result; + } + ); + } + ).thenApply( unused -> result ); + } + + private static CompletionStage getReplace( + Type elemType, + Object o, + Object owner, + SessionImplementor session, + Map copyCache) { + return getReplace( elemType, o, null, owner, session, copyCache ); + } + + private static CompletionStage getReplace( + Type elemType, + Object o, + Object target, + Object owner, + SessionImplementor 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 ); + } + } + + /** + * @see CollectionType#preserveSnapshot(PersistentCollection, PersistentCollection, Type, Object, Map, SharedSessionContractImplementor) + */ + private static CompletionStage preserveSnapshot( + PersistentCollection original, + PersistentCollection result, + Type elemType, + Object owner, + Map copyCache, + SessionImplementor 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(); + } + + /** + * @see CollectionType#createSnapshot(PersistentCollection, PersistentCollection, Type, Object, Map, SharedSessionContractImplementor) + */ + private static CompletionStage createSnapshot( + PersistentCollection original, + PersistentCollection result, + Type elemType, + Object owner, + Map copyCache, + SessionImplementor session) { + final Serializable originalSnapshot = original.getStoredSnapshot(); + if ( originalSnapshot instanceof List ) { + List list = (List) originalSnapshot; + return createListSnapshot( list, elemType, owner, copyCache, session ); + } + else if ( originalSnapshot instanceof Map ) { + Map map = (Map) originalSnapshot; + return createMapSnapshot( map, result, elemType, owner, copyCache, session ); + } + else if ( originalSnapshot instanceof Object[] ) { + Object[] array = (Object[]) originalSnapshot; + return createArraySnapshot( array, elemType, owner, copyCache, session ); + } + else { + // retain the same snapshot + return completedFuture( result.getStoredSnapshot() ); + } + } + + /** + * @see CollectionType#createArraySnapshot(Object[], Type, Object, Map, SharedSessionContractImplementor) + */ + private static CompletionStage createArraySnapshot( + Object[] array, + Type elemType, + Object owner, + Map copyCache, + SessionImplementor session) { + return loop( + 0, array.length, + i -> + getReplace( elemType, array[i], owner, session, copyCache ) + .thenCompose( o -> { + array[i] = o; + return voidFuture(); + } + ) + ).thenApply( unused -> array ); + } + + /** + * @see CollectionType#createMapSnapshot(Map, PersistentCollection, Type, Object, Map, SharedSessionContractImplementor) + */ + private static CompletionStage createMapSnapshot( + Map map, + PersistentCollection result, + Type elemType, + Object owner, + Map copyCache, + SessionImplementor session) { + final Map resultSnapshot = (Map) result.getStoredSnapshot(); + final Map targetMap; + if ( map instanceof SortedMap ) { + SortedMap sortedMap = (SortedMap) map; + //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 ) + .thenCompose( newValue -> { + final Object key = entry.getKey(); + targetMap.put( key == entry.getValue() ? newValue : key, newValue ); + return voidFuture(); + } ) + ).thenApply( v -> (Serializable) targetMap ); + } + + /** + * @see CollectionType#createListSnapshot(List, Type, Object, Map, SharedSessionContractImplementor) + */ + private static CompletionStage createListSnapshot( + List list, + Type elemType, + Object owner, + Map copyCache, + SessionImplementor session) { + final ArrayList targetList = new ArrayList<>( list.size() ); + return loop( + list, obj -> + getReplace( elemType, obj, owner, session, copyCache ) + .thenCompose( o -> { + targetList.add( o ); + return voidFuture(); + } ) + ).thenApply( unused -> targetList ); + } + + /** + * @see CollectionType#instantiateResultIfNecessary(Object, Object) + */ + private static Object instantiateResultIfNecessary(CollectionType type, Object original, Object target) { + // for a null target, or a target which is the same as the original, + // we need to put the merged elements in a new collection + // by default just use an unanticipated capacity since we don't + // know how to extract the capacity to use from original here... + return target == null + || target == original + || target == UNFETCHED_PROPERTY + || target instanceof PersistentCollection && ( (PersistentCollection) target).isWrapper( original ) ? + type.instantiate( -1 ) : + target; + } + + +} diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/engine/impl/EntityTypes.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/engine/impl/EntityTypes.java index 879f7ddc8..722ba4a78 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 @@ -25,6 +25,7 @@ import org.hibernate.reactive.persister.entity.impl.ReactiveEntityPersister; import org.hibernate.reactive.session.impl.ReactiveQueryExecutorLookup; import org.hibernate.reactive.session.impl.ReactiveSessionImpl; +import org.hibernate.type.CollectionType; import org.hibernate.type.EntityType; import org.hibernate.type.ForeignKeyDirection; import org.hibernate.type.OneToOneType; @@ -158,42 +159,11 @@ public static CompletionStage replace( final Object owner, final Map copyCache) { Object[] copied = new Object[original.length]; - for ( int i = 0; i < types.length; i++ ) { - if ( original[i] == UNFETCHED_PROPERTY || original[i] == UNKNOWN ) { - copied[i] = target[i]; - } - else { - if ( !( types[i] instanceof EntityType ) ) { - copied[i] = types[i].replace( - original[i], - target[i] == UNFETCHED_PROPERTY ? null : target[i], - session, - owner, - copyCache - ); - } - } - } - return loop( 0, types.length, - i -> original[i] != UNFETCHED_PROPERTY && original[i] != UNKNOWN - && types[i] instanceof EntityType, - i -> replace( - (EntityType) types[i], - original[i], - target[i] == UNFETCHED_PROPERTY ? null : target[i], - session, - owner, - copyCache - ).thenCompose( copy -> { - if ( copy instanceof CompletionStage ) { - return ( (CompletionStage) copy ) - .thenAccept( nonStageCopy -> copied[i] = nonStageCopy ); - } - else { - copied[i] = copy; - return voidFuture(); - } - } ) + return loop( + 0, types.length, + i -> + replace( original, target, types, session, owner, copyCache, i, copied ) + ).thenApply( v -> copied ); } @@ -209,43 +179,11 @@ public static CompletionStage replace( final Map copyCache, final ForeignKeyDirection foreignKeyDirection) { Object[] copied = new Object[original.length]; - for ( int i = 0; i < types.length; i++ ) { - if ( original[i] == UNFETCHED_PROPERTY || original[i] == UNKNOWN ) { - copied[i] = target[i]; - } - else { - if ( !( types[i] instanceof EntityType ) ) { - copied[i] = types[i].replace( - original[i], - target[i] == UNFETCHED_PROPERTY ? null : target[i], - session, - owner, - copyCache, - foreignKeyDirection - ); - } - } - } - return loop( 0, types.length, - i -> original[i] != UNFETCHED_PROPERTY && original[i] != UNKNOWN - && types[i] instanceof EntityType, - i -> replace( - (EntityType) types[i], - original[i], - target[i] == UNFETCHED_PROPERTY ? null : target[i], - session, - owner, - copyCache, - foreignKeyDirection - ).thenCompose( copy -> { - if ( copy instanceof CompletionStage ) { - return ( (CompletionStage) copy ).thenAccept( nonStageCopy -> copied[i] = nonStageCopy ); - } - else { - copied[i] = copy; - return voidFuture(); - } - } ) + return loop( + 0, types.length, + i -> + replace( original, target, types, session, owner, copyCache, foreignKeyDirection, i, copied ) + ).thenApply( v -> copied ); } @@ -272,7 +210,7 @@ private static CompletionStage replace( /** * @see EntityType#replace(Object, Object, SharedSessionContractImplementor, Object, Map) */ - private static CompletionStage replace( + protected static CompletionStage replace( EntityType entityType, Object original, Object target, @@ -450,4 +388,133 @@ private static CompletionStage loadHibernateProxyEntity( } } + private static CompletionStage replace( + Object[] original, + Object[] target, + Type[] types, + SessionImplementor session, + Object owner, + Map copyCache, + int i, + Object[] copied) { + if ( original[i] == UNFETCHED_PROPERTY || original[i] == UNKNOWN ) { + copied[i] = target[i]; + return voidFuture(); + } + else if ( types[i] instanceof CollectionType ) { + return CollectionTypes.replace( + (CollectionType) types[i], + original[i], + target[i] == UNFETCHED_PROPERTY ? null : target[i], + session, + owner, + copyCache + ).thenCompose( copy -> { + if ( copy instanceof CompletionStage ) { + return ( (CompletionStage) copy ).thenAccept( nonStageCopy -> copied[i] = nonStageCopy ); + } + else { + copied[i] = copy; + return voidFuture(); + } + } ); + } + else if ( types[i] instanceof EntityType ) { + return replace( + (EntityType) types[i], + original[i], + target[i] == UNFETCHED_PROPERTY ? null : target[i], + session, + owner, + copyCache + ).thenCompose( copy -> { + if ( copy instanceof CompletionStage ) { + return ( (CompletionStage) copy ) + .thenAccept( nonStageCopy -> copied[i] = nonStageCopy ); + } + else { + copied[i] = copy; + return voidFuture(); + } + } ); + } + else { + final Type type = types[i]; + copied[i] = type.replace( + original[i], + target[i] == UNFETCHED_PROPERTY ? null : target[i], + session, + owner, + copyCache + ); + return voidFuture(); + } + } + + private static CompletionStage replace( + Object[] original, + Object[] target, + Type[] types, + SessionImplementor session, + Object owner, + Map copyCache, + ForeignKeyDirection foreignKeyDirection, + int i, + Object[] copied) { + if ( original[i] == UNFETCHED_PROPERTY || original[i] == UNKNOWN ) { + copied[i] = target[i]; + return voidFuture(); + } + else if ( types[i] instanceof CollectionType ) { + return CollectionTypes.replace( + (CollectionType) types[i], + original[i], + target[i] == UNFETCHED_PROPERTY ? null : target[i], + session, + owner, + copyCache, + foreignKeyDirection + ).thenCompose( copy -> { + if ( copy instanceof CompletionStage ) { + return ( (CompletionStage) copy ).thenAccept( nonStageCopy -> copied[i] = nonStageCopy ); + } + else { + copied[i] = copy; + return voidFuture(); + } + } ); + } + else if ( types[i] instanceof EntityType ) { + return replace( + (EntityType) types[i], + original[i], + target[i] == UNFETCHED_PROPERTY ? null : target[i], + session, + owner, + copyCache, + foreignKeyDirection + ).thenCompose( copy -> { + if ( copy instanceof CompletionStage ) { + return ( (CompletionStage) copy ).thenAccept( nonStageCopy -> copied[i] = nonStageCopy ); + } + else { + copied[i] = copy; + return voidFuture(); + } + } ); + } + else { + copied[i] = types[i].replace( + original[i], + target[i] == UNFETCHED_PROPERTY ? null : target[i], + session, + owner, + copyCache, + foreignKeyDirection + ); + return voidFuture(); + } + } + + } diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/logging/impl/Log.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/logging/impl/Log.java index 72760a26b..fef169431 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 @@ -300,4 +300,8 @@ public interface Log extends BasicLogger { @LogMessage(level = WARN) @Message(id = 448, value = "Warnings creating temp table : %s") void warningsCreatingTempTable(SQLWarning warning); + + @LogMessage(level = WARN) + @Message( id= 494, value = "Attempt to merge an uninitialized collection with queued operations; queued operations will be ignored: %s") + void ignoreQueuedOperationsOnMerge(String collectionInfoString); } From 665a3405e78bbe05713b6afcd91f484d7ba2b039 Mon Sep 17 00:00:00 2001 From: Andrea Boriero Date: Mon, 20 Jan 2025 10:48:36 +0100 Subject: [PATCH 012/162] [#2026] Add test for UnexpectedAccessToTheDatabase error when merging a detached entity with a ToMany association --- .../reactive/OneToManyArrayMergeTest.java | 190 +++++++++++++++ .../reactive/OneToManyMapMergeTest.java | 199 +++++++++++++++ .../reactive/OneToManyMergeTest.java | 227 ++++++++++++++++++ 3 files changed, 616 insertions(+) create mode 100644 hibernate-reactive-core/src/test/java/org/hibernate/reactive/OneToManyArrayMergeTest.java create mode 100644 hibernate-reactive-core/src/test/java/org/hibernate/reactive/OneToManyMapMergeTest.java create mode 100644 hibernate-reactive-core/src/test/java/org/hibernate/reactive/OneToManyMergeTest.java diff --git a/hibernate-reactive-core/src/test/java/org/hibernate/reactive/OneToManyArrayMergeTest.java b/hibernate-reactive-core/src/test/java/org/hibernate/reactive/OneToManyArrayMergeTest.java new file mode 100644 index 000000000..e2eb826d9 --- /dev/null +++ b/hibernate-reactive-core/src/test/java/org/hibernate/reactive/OneToManyArrayMergeTest.java @@ -0,0 +1,190 @@ +/* Hibernate, Relational Persistence for Idiomatic Java + * + * SPDX-License-Identifier: Apache-2.0 + * Copyright: Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.reactive; + +import java.util.Collection; +import java.util.List; +import java.util.Objects; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import io.vertx.junit5.Timeout; +import io.vertx.junit5.VertxTestContext; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.Id; +import jakarta.persistence.OneToMany; +import jakarta.persistence.Table; + +import static java.util.concurrent.TimeUnit.MINUTES; +import static org.assertj.core.api.Assertions.assertThat; + +@Timeout(value = 2, timeUnit = MINUTES) +public class OneToManyArrayMergeTest extends BaseReactiveTest { + + private final static Long USER_ID = 1L; + private final static Long ADMIN_ROLE_ID = 2L; + private final static Long USER_ROLE_ID = 3L; + private final static String UPDATED_FIRSTNAME = "UPDATED FIRSTNAME"; + private final static String UPDATED_LASTNAME = "UPDATED LASTNAME"; + + @Override + protected Collection> annotatedEntities() { + return List.of( User.class, Role.class ); + } + + @BeforeEach + public void populateDb(VertxTestContext context) { + Role adminRole = new Role( ADMIN_ROLE_ID, "admin" ); + Role userRole = new Role( USER_ROLE_ID, "user" ); + User user = new User( USER_ID, "first", "last", adminRole ); + test( + context, getMutinySessionFactory() + .withTransaction( s -> s.persistAll( user, adminRole, userRole ) ) + ); + } + + @Test + public void testMerge(VertxTestContext context) { + test( + context, getMutinySessionFactory() + .withTransaction( s -> s.find( User.class, USER_ID ) ) + .chain( user -> getMutinySessionFactory() + .withTransaction( s -> s + .createQuery( "FROM Role", Role.class ) + .getResultList() ) + .map( roles -> { + user.addAll( roles ); + user.setFirstname( UPDATED_FIRSTNAME ); + user.setLastname( UPDATED_LASTNAME ); + return user; + } ) + ) + .chain( user -> { + assertThat( user.getFirstname() ).isEqualTo( UPDATED_FIRSTNAME ); + assertThat( user.getLastname() ).isEqualTo( UPDATED_LASTNAME ); + assertThat( user.getRoles() ).hasSize( 2 ); + return getMutinySessionFactory() + .withTransaction( s -> s.merge( user ) ); + } + ) + .chain( v -> getMutinySessionFactory() + .withTransaction( s -> s.find( User.class, USER_ID ) ) + ) + .invoke( user -> { + Role adminRole = new Role( ADMIN_ROLE_ID, "admin" ); + Role userRole = new Role( USER_ROLE_ID, "user" ); + assertThat( user.getFirstname() ).isEqualTo( UPDATED_FIRSTNAME ); + assertThat( user.getLastname() ).isEqualTo( UPDATED_LASTNAME ); + assertThat( user.getRoles() ).containsExactlyInAnyOrder( + adminRole, + userRole + ); + } + ) + ); + } + + @Entity(name = "User") + @Table(name = "USER_TABLE") + public static class User { + + @Id + private Long id; + + private String firstname; + + private String lastname; + + @OneToMany(fetch = FetchType.EAGER) + private Role[] roles; + + public User() { + } + + public User(Long id, String firstname, String lastname, Role... roles) { + this.id = id; + this.firstname = firstname; + this.lastname = lastname; + this.roles = new Role[roles.length]; + for ( int i = 0; i < roles.length; i++ ) { + this.roles[i] = roles[i]; + } + } + + public Long getId() { + return id; + } + + public String getFirstname() { + return firstname; + } + + public void setFirstname(String firstname) { + this.firstname = firstname; + } + + public String getLastname() { + return lastname; + } + + public void setLastname(String lastname) { + this.lastname = lastname; + } + + public Role[] getRoles() { + return roles; + } + + public void addAll(List roles) { + this.roles = new Role[roles.size()]; + for ( int i = 0; i < roles.size(); i++ ) { + this.roles[i] = roles.get( i ); + } + } + } + + @Entity(name = "Role") + @Table(name = "ROLE_TABLE") + public static class Role { + + @Id + private Long id; + private String code; + + public Role() { + } + + public Role(Long id, String code) { + this.id = id; + this.code = code; + } + + public Object getId() { + return id; + } + + @Override + public boolean equals(Object o) { + if ( o == null || getClass() != o.getClass() ) { + return false; + } + Role role = (Role) o; + return Objects.equals( id, role.id ) && Objects.equals( code, role.code ); + } + + @Override + public int hashCode() { + return Objects.hash( id, code ); + } + + @Override + public String toString() { + return "Role{" + code + '}'; + } + } +} diff --git a/hibernate-reactive-core/src/test/java/org/hibernate/reactive/OneToManyMapMergeTest.java b/hibernate-reactive-core/src/test/java/org/hibernate/reactive/OneToManyMapMergeTest.java new file mode 100644 index 000000000..7a1096d3d --- /dev/null +++ b/hibernate-reactive-core/src/test/java/org/hibernate/reactive/OneToManyMapMergeTest.java @@ -0,0 +1,199 @@ +/* Hibernate, Relational Persistence for Idiomatic Java + * + * SPDX-License-Identifier: Apache-2.0 + * Copyright: Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.reactive; + +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import io.vertx.junit5.Timeout; +import io.vertx.junit5.VertxTestContext; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.Id; +import jakarta.persistence.OneToMany; +import jakarta.persistence.Table; + +import static java.util.concurrent.TimeUnit.MINUTES; +import static org.assertj.core.api.Assertions.assertThat; + +@Timeout(value = 2, timeUnit = MINUTES) +public class OneToManyMapMergeTest extends BaseReactiveTest { + + private final static Long USER_ID = 1L; + private final static Long ADMIN_ROLE_ID = 2L; + private final static Long USER_ROLE_ID = 3L; + private final static String UPDATED_FIRSTNAME = "UPDATED FIRSTNAME"; + private final static String UPDATED_LASTNAME = "UPDATED LASTNAME"; + + @Override + protected Collection> annotatedEntities() { + return List.of( User.class, Role.class ); + } + + @BeforeEach + public void populateDb(VertxTestContext context) { + Role adminRole = new Role( ADMIN_ROLE_ID, "admin" ); + Role userRole = new Role( USER_ROLE_ID, "user" ); + User user = new User( USER_ID, "first", "last", adminRole ); + test( + context, getMutinySessionFactory() + .withTransaction( s -> s.persistAll( user, adminRole, userRole ) ) + ); + } + + @Test + public void testMerge(VertxTestContext context) { + test( + context, getMutinySessionFactory() + .withTransaction( s -> s.find( User.class, USER_ID ) ) + .chain( user -> getMutinySessionFactory() + .withTransaction( s -> s + .createQuery( "FROM Role", Role.class ) + .getResultList() ) + .map( roles -> { + user.addAll( roles ); + user.setFirstname( UPDATED_FIRSTNAME ); + user.setLastname( UPDATED_LASTNAME ); + return user; + } ) + ) + .chain( user -> { + assertThat( user.getFirstname() ).isEqualTo( UPDATED_FIRSTNAME ); + assertThat( user.getLastname() ).isEqualTo( UPDATED_LASTNAME ); + assertThat( user.getRoles() ).hasSize( 2 ); + return getMutinySessionFactory() + .withTransaction( s -> s.merge( user ) ); + } + ) + .chain( v -> getMutinySessionFactory() + .withTransaction( s -> s.find( User.class, USER_ID ) ) + ) + .invoke( user -> { + Role adminRole = new Role( ADMIN_ROLE_ID, "admin" ); + Role userRole = new Role( USER_ROLE_ID, "user" ); + assertThat( user.getFirstname() ).isEqualTo( UPDATED_FIRSTNAME ); + assertThat( user.getLastname() ).isEqualTo( UPDATED_LASTNAME ); + assertThat( user.getRoles() ).containsEntry( + adminRole.getCode(), + adminRole + ); + assertThat( user.getRoles() ).containsEntry( + userRole.getCode(), + userRole + ); + } + ) + ); + } + + @Entity(name = "User") + @Table(name = "USER_TABLE") + public static class User { + + @Id + private Long id; + + private String firstname; + + private String lastname; + + @OneToMany(fetch = FetchType.EAGER) + private Map roles = new HashMap(); + + public User() { + } + + public User(Long id, String firstname, String lastname, Role... roles) { + this.id = id; + this.firstname = firstname; + this.lastname = lastname; + for ( Role role : roles ) { + this.roles.put( role.getCode(), role ); + } + } + + public Long getId() { + return id; + } + + public String getFirstname() { + return firstname; + } + + public void setFirstname(String firstname) { + this.firstname = firstname; + } + + public String getLastname() { + return lastname; + } + + public void setLastname(String lastname) { + this.lastname = lastname; + } + + public Map getRoles() { + return roles; + } + + public void addAll(List roles) { + this.roles.clear(); + for ( Role role : roles ) { + this.roles.put( role.getCode(), role ); + } + } + } + + @Entity(name = "Role") + @Table(name = "ROLE_TABLE") + public static class Role { + + @Id + private Long id; + private String code; + + public Role() { + } + + public Role(Long id, String code) { + this.id = id; + this.code = code; + } + + public Object getId() { + return id; + } + + public String getCode() { + return code; + } + + @Override + public boolean equals(Object o) { + if ( o == null || getClass() != o.getClass() ) { + return false; + } + Role role = (Role) o; + return Objects.equals( id, role.id ) && Objects.equals( code, role.code ); + } + + @Override + public int hashCode() { + return Objects.hash( id, code ); + } + + @Override + public String toString() { + return "Role{" + code + '}'; + } + } +} diff --git a/hibernate-reactive-core/src/test/java/org/hibernate/reactive/OneToManyMergeTest.java b/hibernate-reactive-core/src/test/java/org/hibernate/reactive/OneToManyMergeTest.java new file mode 100644 index 000000000..76d7f7732 --- /dev/null +++ b/hibernate-reactive-core/src/test/java/org/hibernate/reactive/OneToManyMergeTest.java @@ -0,0 +1,227 @@ +/* Hibernate, Relational Persistence for Idiomatic Java + * + * SPDX-License-Identifier: Apache-2.0 + * Copyright: Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.reactive; + +import java.util.Collection; +import java.util.List; +import java.util.Objects; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import io.vertx.junit5.Timeout; +import io.vertx.junit5.VertxTestContext; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.Id; +import jakarta.persistence.OneToMany; +import jakarta.persistence.Table; + +import static java.util.concurrent.TimeUnit.MINUTES; +import static org.assertj.core.api.Assertions.assertThat; + +@Timeout(value = 2, timeUnit = MINUTES) +public class OneToManyMergeTest extends BaseReactiveTest { + + private final static Long USER_ID = 1L; + private final static Long ADMIN_ROLE_ID = 2L; + private final static Long USER_ROLE_ID = 3L; + private final static String UPDATED_FIRSTNAME = "UPDATED FIRSTNAME"; + private final static String UPDATED_LASTNAME = "UPDATED LASTNAME"; + + @Override + protected Collection> annotatedEntities() { + return List.of( User.class, Role.class ); + } + + @BeforeEach + public void populateDb(VertxTestContext context) { + Role adminRole = new Role( ADMIN_ROLE_ID, "admin" ); + Role userRole = new Role( USER_ROLE_ID, "user" ); + User user = new User( USER_ID, "first", "last", adminRole ); + test( + context, getMutinySessionFactory() + .withTransaction( s -> s.persistAll( user, adminRole, userRole ) ) + ); + } + + @Test + public void testMerge(VertxTestContext context) { + test( + context, getMutinySessionFactory() + .withTransaction( s -> s.find( User.class, USER_ID ) ) + .chain( user -> getMutinySessionFactory() + .withTransaction( s -> s + .createQuery( "FROM Role", Role.class ) + .getResultList() ) + .map( roles -> { + user.getRoles().clear(); + user.getRoles().addAll( roles ); + user.setFirstname( UPDATED_FIRSTNAME ); + user.setLastname( UPDATED_LASTNAME ); + return user; + } ) + ) + .chain( user -> { + assertThat( user.getFirstname() ).isEqualTo( UPDATED_FIRSTNAME ); + assertThat( user.getLastname() ).isEqualTo( UPDATED_LASTNAME ); + assertThat( user.getRoles() ).hasSize( 2 ); + return getMutinySessionFactory() + .withTransaction( s -> s.merge( user ) ); + } + ) + .chain( v -> getMutinySessionFactory() + .withTransaction( s -> s.find( User.class, USER_ID ) ) + ) + .invoke( user -> { + Role adminRole = new Role( ADMIN_ROLE_ID, "admin" ); + Role userRole = new Role( USER_ROLE_ID, "user" ); + assertThat( user.getFirstname() ).isEqualTo( UPDATED_FIRSTNAME ); + assertThat( user.getLastname() ).isEqualTo( UPDATED_LASTNAME ); + assertThat( user.getRoles() ).containsExactlyInAnyOrder( + adminRole, + userRole + ); + } + ) + ); + } + + @Test + public void testMergeRemovingCollectionElements(VertxTestContext context) { + test( + context, getMutinySessionFactory() + .withTransaction( s -> s.find( User.class, USER_ID ) ) + .chain( user -> getMutinySessionFactory() + .withTransaction( s -> s + .createQuery( "FROM Role", Role.class ) + .getResultList() ) + .map( roles -> { + user.clearRoles(); + user.setFirstname( UPDATED_FIRSTNAME ); + user.setLastname( UPDATED_LASTNAME ); + return user; + } ) + ) + .chain( user -> { + assertThat( user.getFirstname() ).isEqualTo( UPDATED_FIRSTNAME ); + assertThat( user.getLastname() ).isEqualTo( UPDATED_LASTNAME ); + assertThat( user.getRoles() ).isNull(); + return getMutinySessionFactory() + .withTransaction( s -> s.merge( user ) ); + } + ) + .chain( v -> getMutinySessionFactory() + .withTransaction( s -> s.find( User.class, USER_ID ) ) + ) + .invoke( user -> { + assertThat( user.getFirstname() ).isEqualTo( UPDATED_FIRSTNAME ); + assertThat( user.getLastname() ).isEqualTo( UPDATED_LASTNAME ); + assertThat( user.getRoles() ).isNullOrEmpty(); + } + ) + ); + } + + @Entity(name = "User") + @Table(name = "USER_TABLE") + public static class User { + + @Id + private Long id; + + private String firstname; + + private String lastname; + + @OneToMany(fetch = FetchType.EAGER) + private List roles; + + public User() { + } + + public User(Long id, String firstname, String lastname, Role... roles) { + this.id = id; + this.firstname = firstname; + this.lastname = lastname; + this.roles = List.of( roles ); + } + + public User(Long id, String firstname, String lastname) { + this.id = id; + this.firstname = firstname; + this.lastname = lastname; + } + + public Long getId() { + return id; + } + + public String getFirstname() { + return firstname; + } + + public void setFirstname(String firstname) { + this.firstname = firstname; + } + + public String getLastname() { + return lastname; + } + + public void setLastname(String lastname) { + this.lastname = lastname; + } + + public List getRoles() { + return roles; + } + + public void clearRoles() { + this.roles = null; + } + } + + @Entity(name = "Role") + @Table(name = "ROLE_TABLE") + public static class Role { + + @Id + private Long id; + private String code; + + public Role() { + } + + public Role(Long id, String code) { + this.id = id; + this.code = code; + } + + public Object getId() { + return id; + } + + @Override + public boolean equals(Object o) { + if ( o == null || getClass() != o.getClass() ) { + return false; + } + Role role = (Role) o; + return Objects.equals( id, role.id ) && Objects.equals( code, role.code ); + } + + @Override + public int hashCode() { + return Objects.hash( id, code ); + } + + @Override + public String toString() { + return "Role{" + code + '}'; + } + } +} From d2e8e8f3a0e0f2d62833421371384ce52254a6fc Mon Sep 17 00:00:00 2001 From: Davide D'Alto Date: Mon, 20 Jan 2025 11:57:06 +0100 Subject: [PATCH 013/162] [#2026] Fix EntityTypes#loadByUniqueKey It's using a `.thenApply` instead of a `.thenCompose`. --- .../reactive/engine/impl/EntityTypes.java | 47 +++---------------- 1 file changed, 7 insertions(+), 40 deletions(-) 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 722ba4a78..d5f37dba3 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 @@ -138,7 +138,7 @@ static CompletionStage loadByUniqueKey( else { return persister .reactiveLoadByUniqueKey( uniqueKeyPropertyName, key, session ) - .thenApply( ukResult -> loadHibernateProxyEntity( ukResult, session ) + .thenCompose( ukResult -> loadHibernateProxyEntity( ukResult, session ) .thenApply( targetUK -> { persistenceContext.addEntity( euk, targetUK ); return targetUK; @@ -364,9 +364,9 @@ private static CompletionStage getIdentifierFromHibernateProxy( if ( type.isEntityIdentifierMapping() ) { propertyValue = getIdentifier( (EntityType) type, propertyValue, (SessionImplementor) session ); } - return completedFuture( propertyValue ); + return propertyValue; } - return nullFuture(); + return null; } ); } @@ -409,15 +409,7 @@ else if ( types[i] instanceof CollectionType ) { session, owner, copyCache - ).thenCompose( copy -> { - if ( copy instanceof CompletionStage ) { - return ( (CompletionStage) copy ).thenAccept( nonStageCopy -> copied[i] = nonStageCopy ); - } - else { - copied[i] = copy; - return voidFuture(); - } - } ); + ).thenAccept( copy -> copied[i] = copy ); } else if ( types[i] instanceof EntityType ) { return replace( @@ -427,16 +419,7 @@ else if ( types[i] instanceof EntityType ) { session, owner, copyCache - ).thenCompose( copy -> { - if ( copy instanceof CompletionStage ) { - return ( (CompletionStage) copy ) - .thenAccept( nonStageCopy -> copied[i] = nonStageCopy ); - } - else { - copied[i] = copy; - return voidFuture(); - } - } ); + ).thenAccept( copy -> copied[i] = copy ); } else { final Type type = types[i]; @@ -474,15 +457,7 @@ else if ( types[i] instanceof CollectionType ) { owner, copyCache, foreignKeyDirection - ).thenCompose( copy -> { - if ( copy instanceof CompletionStage ) { - return ( (CompletionStage) copy ).thenAccept( nonStageCopy -> copied[i] = nonStageCopy ); - } - else { - copied[i] = copy; - return voidFuture(); - } - } ); + ).thenAccept( copy -> copied[i] = copy ); } else if ( types[i] instanceof EntityType ) { return replace( @@ -493,15 +468,7 @@ else if ( types[i] instanceof EntityType ) { owner, copyCache, foreignKeyDirection - ).thenCompose( copy -> { - if ( copy instanceof CompletionStage ) { - return ( (CompletionStage) copy ).thenAccept( nonStageCopy -> copied[i] = nonStageCopy ); - } - else { - copied[i] = copy; - return voidFuture(); - } - } ); + ).thenAccept( copy -> copied[i] = copy ); } else { copied[i] = types[i].replace( From af3d4f99828f068c4fe41d02fe6bdb51dbdff4ae Mon Sep 17 00:00:00 2001 From: Davide D'Alto Date: Mon, 20 Jan 2025 12:03:22 +0100 Subject: [PATCH 014/162] [#2026] Small refactoring and clean ups --- .../reactive/engine/impl/CollectionTypes.java | 96 +++++++------------ .../reactive/engine/impl/EntityTypes.java | 16 ++-- 2 files changed, 41 insertions(+), 71 deletions(-) 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 ab9d02d08..41dd0162b 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 @@ -42,7 +42,6 @@ import static org.hibernate.pretty.MessageHelper.collectionInfoString; import static org.hibernate.reactive.util.impl.CompletionStages.completedFuture; import static org.hibernate.reactive.util.impl.CompletionStages.loop; -import static org.hibernate.reactive.util.impl.CompletionStages.nullFuture; import static org.hibernate.reactive.util.impl.CompletionStages.voidFuture; /** @@ -81,10 +80,10 @@ public static CompletionStage replace( Object owner, Map copyCache) throws HibernateException { if ( original == null ) { - return replaceNullOriginal( target, session ); + return completedFuture( replaceNullOriginal( target, session ) ); } else if ( !Hibernate.isInitialized( original ) ) { - return replaceUninitializedOriginal( type, original, target, session, copyCache ); + return completedFuture( replaceUninitializedOriginal( type, original, target, session, copyCache ) ); } else { return replaceOriginal( type, original, target, session, owner, copyCache ); @@ -92,25 +91,24 @@ else if ( !Hibernate.isInitialized( original ) ) { } // todo: make org.hibernate.type.CollectionType#replaceNullOriginal public ? - /** * @see CollectionType#replaceNullOriginal(Object, SharedSessionContractImplementor) */ - private static CompletionStage replaceNullOriginal( + private static Object replaceNullOriginal( Object target, SessionImplementor session) { if ( target == null ) { - return nullFuture(); + return null; } else if ( target instanceof Collection ) { Collection collection = (Collection) target; collection.clear(); - return completedFuture( collection ); + return collection; } else if ( target instanceof Map ) { Map map = (Map) target; map.clear(); - return completedFuture( map ); + return map; } else { final PersistenceContext persistenceContext = session.getPersistenceContext(); @@ -127,18 +125,15 @@ else if ( target instanceof Map ) { arrayHolder.endRead(); arrayHolder.dirty(); persistenceContext.addCollectionHolder( collectionHolder ); - return completedFuture( arrayHolder.getArray() ); + return arrayHolder.getArray(); } } } - return nullFuture(); + return null; } // todo: make org.hibernate.type.CollectionType#replaceUninitializedOriginal public - /** - * @see CollectionType#replaceNullOriginal(Object, SharedSessionContractImplementor) - */ - private static CompletionStage replaceUninitializedOriginal( + private static Object replaceUninitializedOriginal( CollectionType type, Object original, Object target, @@ -164,7 +159,7 @@ private static CompletionStage replaceUninitializedOriginal( collectionInfoString( type.getRole(), persistentCollection.getKey() ) ); } } - return completedFuture( target ); + return target; } /** @@ -196,11 +191,11 @@ private static CompletionStage replaceOriginal( //TODO: this is a little inefficient, don't need to do a whole // deep replaceElements() call return replaceElements( type, result, target, owner, copyCache, session ) - .thenCompose( unused -> { + .thenApply( unused -> { if ( wasClean ) { ( (PersistentCollection) target ).clearDirty(); } - return completedFuture( target ); + return target; } ); } else { @@ -296,10 +291,8 @@ private static CompletionStage replaceMapTypeElements( Object owner, Map copyCache, SessionImplementor session) { - final CollectionPersister persister = - session.getFactory().getRuntimeMetamodels().getMappingMetamodel() - .getCollectionDescriptor( type.getRole() ); - + final CollectionPersister persister = session.getFactory().getRuntimeMetamodels() + .getMappingMetamodel().getCollectionDescriptor( type.getRole() ); final Map result = target; result.clear(); @@ -307,15 +300,13 @@ private static CompletionStage replaceMapTypeElements( original.entrySet(), entry -> { final Map.Entry me = entry; return getReplace( persister.getIndexType(), me.getKey(), owner, session, copyCache ) - .thenCompose( key -> - getReplace( - persister.getElementType(), - me.getValue(), - owner, - session, - copyCache - ).thenAccept( value -> - result.put( key, value ) ) + .thenCompose( key -> getReplace( + persister.getElementType(), + me.getValue(), + owner, + session, + copyCache + ).thenAccept( value -> result.put( key, value ) ) ); } ).thenApply( unused -> result ); @@ -340,14 +331,11 @@ private static CompletionStage replaceArrayTypeElements( final Type elemType = type.getElementType( session.getFactory() ); return loop( - 0, length, i -> { - return getReplace( elemType, Array.get( original, i ), owner, session, copyCache ) - .thenApply( o -> { - Array.set( result, i, o ); - return result; - } - ); - } + 0, length, i -> getReplace( elemType, Array.get( original, i ), owner, session, copyCache ) + .thenApply( o -> { + Array.set( result, i, o ); + return result; + } ) ).thenApply( unused -> result ); } @@ -389,8 +377,7 @@ private static CompletionStage preserveSnapshot( final CollectionEntry ce = session.getPersistenceContextInternal().getCollectionEntry( result ); if ( ce != null ) { return createSnapshot( original, result, elemType, owner, copyCache, session ) - .thenAccept( serializable -> - ce.resetStoredSnapshot( result, serializable ) ); + .thenAccept( serializable -> ce.resetStoredSnapshot( result, serializable ) ); } return voidFuture(); } @@ -434,14 +421,8 @@ private static CompletionStage createArraySnapshot( Map copyCache, SessionImplementor session) { return loop( - 0, array.length, - i -> - getReplace( elemType, array[i], owner, session, copyCache ) - .thenCompose( o -> { - array[i] = o; - return voidFuture(); - } - ) + 0, array.length, i -> getReplace( elemType, array[i], owner, session, copyCache ) + .thenAccept( o -> array[i] = o ) ).thenApply( unused -> array ); } @@ -468,10 +449,9 @@ private static CompletionStage createMapSnapshot( return loop( map.entrySet(), entry -> getReplace( elemType, entry.getValue(), resultSnapshot, owner, session, copyCache ) - .thenCompose( newValue -> { + .thenAccept( newValue -> { final Object key = entry.getKey(); targetMap.put( key == entry.getValue() ? newValue : key, newValue ); - return voidFuture(); } ) ).thenApply( v -> (Serializable) targetMap ); } @@ -487,12 +467,8 @@ private static CompletionStage createListSnapshot( SessionImplementor session) { final ArrayList targetList = new ArrayList<>( list.size() ); return loop( - list, obj -> - getReplace( elemType, obj, owner, session, copyCache ) - .thenCompose( o -> { - targetList.add( o ); - return voidFuture(); - } ) + list, obj -> getReplace( elemType, obj, owner, session, copyCache ) + .thenAccept( targetList::add ) ).thenApply( unused -> targetList ); } @@ -507,10 +483,8 @@ private static Object instantiateResultIfNecessary(CollectionType type, Object o return target == null || target == original || target == UNFETCHED_PROPERTY - || target instanceof PersistentCollection && ( (PersistentCollection) target).isWrapper( original ) ? - type.instantiate( -1 ) : - target; + || target instanceof PersistentCollection && ( (PersistentCollection) target).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 d5f37dba3..fb1c29fe4 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 @@ -160,10 +160,7 @@ public static CompletionStage replace( final Map copyCache) { Object[] copied = new Object[original.length]; return loop( - 0, types.length, - i -> - replace( original, target, types, session, owner, copyCache, i, copied ) - + 0, types.length, i -> replace( original, target, types, session, owner, copyCache, i, copied ) ).thenApply( v -> copied ); } @@ -181,9 +178,7 @@ public static CompletionStage replace( Object[] copied = new Object[original.length]; return loop( 0, types.length, - i -> - replace( original, target, types, session, owner, copyCache, foreignKeyDirection, i, copied ) - + i -> replace( original, target, types, session, owner, copyCache, foreignKeyDirection, i, copied ) ).thenApply( v -> copied ); } @@ -274,15 +269,16 @@ private static CompletionStage resolveIdOrUniqueKey( // as a ComponentType. In the case that the entity is unfetched, we need to // explicitly fetch it here before calling replace(). (Note that in Hibernate // ORM this is unnecessary due to transparent lazy fetching.) - return ( (ReactiveSessionImpl) session ).reactiveFetch( id, true ) + return ( (ReactiveSessionImpl) session ) + .reactiveFetch( id, true ) .thenCompose( fetched -> { - Object idOrUniqueKey = entityType.getIdentifierOrUniqueKeyType( session.getFactory() ) + Object idOrUniqueKey = entityType + .getIdentifierOrUniqueKeyType( session.getFactory() ) .replace( fetched, null, session, owner, copyCache ); if ( idOrUniqueKey instanceof CompletionStage ) { return ( (CompletionStage) idOrUniqueKey ) .thenCompose( key -> resolve( entityType, key, owner, session ) ); } - return resolve( entityType, idOrUniqueKey, owner, session ); } ); } ); From e82f6bcd86526c079158b7e1194f1eed14f7055d Mon Sep 17 00:00:00 2001 From: Andrea Boriero Date: Mon, 20 Jan 2025 14:08:20 +0100 Subject: [PATCH 015/162] [#2060] ClassCastException when using embeddable ids --- .../internal/ReactiveEmbeddableForeignKeyResultImpl.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/sql/results/graph/embeddable/internal/ReactiveEmbeddableForeignKeyResultImpl.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/sql/results/graph/embeddable/internal/ReactiveEmbeddableForeignKeyResultImpl.java index a708481cf..1e3433320 100644 --- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/sql/results/graph/embeddable/internal/ReactiveEmbeddableForeignKeyResultImpl.java +++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/sql/results/graph/embeddable/internal/ReactiveEmbeddableForeignKeyResultImpl.java @@ -10,7 +10,6 @@ import org.hibernate.sql.results.graph.InitializerParent; import org.hibernate.sql.results.graph.embeddable.EmbeddableInitializer; import org.hibernate.sql.results.graph.embeddable.internal.EmbeddableForeignKeyResultImpl; -import org.hibernate.sql.results.graph.embeddable.internal.EmbeddableInitializerImpl; public class ReactiveEmbeddableForeignKeyResultImpl extends EmbeddableForeignKeyResultImpl { @@ -22,6 +21,6 @@ public ReactiveEmbeddableForeignKeyResultImpl(EmbeddableForeignKeyResultImpl public EmbeddableInitializer createInitializer(InitializerParent parent, AssemblerCreationState creationState) { return getReferencedModePart() instanceof NonAggregatedIdentifierMapping ? new ReactiveNonAggregatedIdentifierMappingInitializer( this, null, creationState, true ) - : new EmbeddableInitializerImpl( this, null, null, creationState, true ); + : new ReactiveEmbeddableInitializerImpl( this, null, null, creationState, true ); } } From e9be7858133acc873ee5e349ff8adcfc0b93938c Mon Sep 17 00:00:00 2001 From: Davide D'Alto Date: Wed, 8 Jan 2025 11:54:41 +0100 Subject: [PATCH 016/162] [#2060] Add test for ClassCastException when using embeddable ids --- .../reactive/EmbeddedIdWithManyTest.java | 180 ++++++++++++++++++ 1 file changed, 180 insertions(+) create mode 100644 hibernate-reactive-core/src/test/java/org/hibernate/reactive/EmbeddedIdWithManyTest.java diff --git a/hibernate-reactive-core/src/test/java/org/hibernate/reactive/EmbeddedIdWithManyTest.java b/hibernate-reactive-core/src/test/java/org/hibernate/reactive/EmbeddedIdWithManyTest.java new file mode 100644 index 000000000..d77de6a4c --- /dev/null +++ b/hibernate-reactive-core/src/test/java/org/hibernate/reactive/EmbeddedIdWithManyTest.java @@ -0,0 +1,180 @@ +/* Hibernate, Relational Persistence for Idiomatic Java + * + * SPDX-License-Identifier: Apache-2.0 + * Copyright: Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.reactive; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import io.vertx.junit5.VertxTestContext; +import jakarta.persistence.Column; +import jakarta.persistence.Embeddable; +import jakarta.persistence.EmbeddedId; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.MappedSuperclass; +import jakarta.persistence.OneToMany; +import jakarta.persistence.Table; + +public class EmbeddedIdWithManyTest extends BaseReactiveTest { + + @Override + protected Collection> annotatedEntities() { + return List.of( Flower.class, Fruit.class ); + } + + @BeforeEach + public void populateDb(VertxTestContext context) { + Seed seed1 = new Seed( 1 ); + Flower rose = new Flower( seed1, "Rose" ); + + Fruit cherry = new Fruit( seed1, "Cherry" ); + cherry.addFriend( rose ); + + Seed seed2 = new Seed( 2 ); + Flower sunflower = new Flower( seed2, "Sunflower" ); + + Fruit apple = new Fruit( seed2, "Apple" ); + apple.addFriend( sunflower ); + + Seed seed3 = new Seed( 3 ); + Flower chrysanthemum = new Flower( seed3, "Chrysanthemum" ); + + Fruit banana = new Fruit( seed3, "Banana" ); + banana.addFriend( chrysanthemum ); + + test( + context, + getMutinySessionFactory().withTransaction( s -> s + .persistAll( cherry, rose, sunflower, apple, chrysanthemum, banana ) + ) + ); + } + + @Test + public void test(VertxTestContext context) { + test( + context, getMutinySessionFactory().withTransaction( s -> s + .createSelectionQuery( "from Flower", Flower.class ) + .getResultList() + ) + ); + } + + @Embeddable + public static class Seed { + + @Column(nullable = false, updatable = false) + private Integer id; + + public Seed() { + } + + public Seed(Integer id) { + this.id = id; + } + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + } + + @MappedSuperclass + public static abstract class Plant { + + @EmbeddedId + private Seed seed; + + @Column(length = 40, unique = true) + private String name; + + protected Plant() { + } + + protected Plant(Seed seed, String name) { + this.seed = seed; + this.name = name; + } + + public Seed getSeed() { + return seed; + } + + public void setSeed(Seed seed) { + this.seed = seed; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + } + + @Entity(name = "Fruit") + @Table(name = "known_fruits") + public static class Fruit extends Plant { + + @OneToMany(mappedBy = "friend", fetch = FetchType.LAZY) + private List friends = new ArrayList<>(); + + public Fruit() { + } + + public Fruit(Seed seed, String name) { + super( seed, name ); + } + + public void addFriend(Flower flower) { + this.friends.add( flower ); + flower.friend = this; + } + + public List getFriends() { + return friends; + } + + @Override + public String toString() { + return "Fruit{" + getSeed().getId() + "," + getName() + '}'; + } + + } + + @Entity(name = "Flower") + @Table(name = "known_flowers") + public static class Flower extends Plant { + + @ManyToOne(fetch = FetchType.LAZY, optional = false) + @JoinColumn(name = "friend", referencedColumnName = "id", nullable = false) + private Fruit friend; + + public Flower() { + } + + public Flower(Seed seed, String name) { + super( seed, name ); + } + + @Override + public String toString() { + return "Flower{" + getSeed().getId() + "," + getName() + '}'; + } + + } + +} From 2162b8bbc5db5d69bc3217888a29d93caa8404fa Mon Sep 17 00:00:00 2001 From: Davide D'Alto Date: Tue, 21 Jan 2025 07:51:13 +0100 Subject: [PATCH 017/162] [#2060] Add assertions to the test --- .../reactive/EmbeddedIdWithManyTest.java | 41 +++++++++++++++---- 1 file changed, 34 insertions(+), 7 deletions(-) diff --git a/hibernate-reactive-core/src/test/java/org/hibernate/reactive/EmbeddedIdWithManyTest.java b/hibernate-reactive-core/src/test/java/org/hibernate/reactive/EmbeddedIdWithManyTest.java index d77de6a4c..eed1e5846 100644 --- a/hibernate-reactive-core/src/test/java/org/hibernate/reactive/EmbeddedIdWithManyTest.java +++ b/hibernate-reactive-core/src/test/java/org/hibernate/reactive/EmbeddedIdWithManyTest.java @@ -24,8 +24,18 @@ import jakarta.persistence.OneToMany; import jakarta.persistence.Table; +import static org.assertj.core.api.Assertions.assertThat; + public class EmbeddedIdWithManyTest extends BaseReactiveTest { + Fruit cherry; + Fruit apple; + Fruit banana; + + Flower sunflower; + Flower chrysanthemum; + Flower rose; + @Override protected Collection> annotatedEntities() { return List.of( Flower.class, Fruit.class ); @@ -34,21 +44,21 @@ protected Collection> annotatedEntities() { @BeforeEach public void populateDb(VertxTestContext context) { Seed seed1 = new Seed( 1 ); - Flower rose = new Flower( seed1, "Rose" ); + rose = new Flower( seed1, "Rose" ); - Fruit cherry = new Fruit( seed1, "Cherry" ); + cherry = new Fruit( seed1, "Cherry" ); cherry.addFriend( rose ); Seed seed2 = new Seed( 2 ); - Flower sunflower = new Flower( seed2, "Sunflower" ); + sunflower = new Flower( seed2, "Sunflower" ); - Fruit apple = new Fruit( seed2, "Apple" ); + apple = new Fruit( seed2, "Apple" ); apple.addFriend( sunflower ); Seed seed3 = new Seed( 3 ); - Flower chrysanthemum = new Flower( seed3, "Chrysanthemum" ); + chrysanthemum = new Flower( seed3, "Chrysanthemum" ); - Fruit banana = new Fruit( seed3, "Banana" ); + banana = new Fruit( seed3, "Banana" ); banana.addFriend( chrysanthemum ); test( @@ -60,11 +70,28 @@ public void populateDb(VertxTestContext context) { } @Test - public void test(VertxTestContext context) { + public void testFindWithEmbeddedId(VertxTestContext context) { + test( + context, getMutinySessionFactory().withTransaction( s -> s + .find( Flower.class, chrysanthemum.getSeed() ) + .invoke( flower -> assertThat( flower.getName() ).isEqualTo( chrysanthemum.getName() ) ) + ) + ); + } + + @Test + public void testSelectQueryWithEmbeddedId(VertxTestContext context) { test( context, getMutinySessionFactory().withTransaction( s -> s .createSelectionQuery( "from Flower", Flower.class ) .getResultList() + .invoke( list -> assertThat( list.stream().map( Flower::getName ) ) + .containsExactlyInAnyOrder( + sunflower.getName(), + chrysanthemum.getName(), + rose.getName() + ) + ) ) ); } From 7471d527044e4b6831a139487314850591da4301 Mon Sep 17 00:00:00 2001 From: Davide D'Alto Date: Tue, 21 Jan 2025 11:47:11 +0100 Subject: [PATCH 018/162] [#2072] Upgrade Hibernate ORM to 6.6.5.Final --- README.md | 2 +- gradle.properties | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index d3a3431af..7e6234007 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ Hibernate Reactive has been tested with: - CockroachDB v24 - MS SQL Server 2022 - Oracle 23 -- [Hibernate ORM][] 6.6.4.Final +- [Hibernate ORM][] 6.6.5.Final - [Vert.x Reactive PostgreSQL Client](https://vertx.io/docs/vertx-pg-client/java/) 4.5.11 - [Vert.x Reactive MySQL Client](https://vertx.io/docs/vertx-mysql-client/java/) 4.5.11 - [Vert.x Reactive Db2 Client](https://vertx.io/docs/vertx-db2-client/java/) 4.5.11 diff --git a/gradle.properties b/gradle.properties index e8b659047..03d50309e 100644 --- a/gradle.properties +++ b/gradle.properties @@ -35,12 +35,12 @@ org.gradle.java.installations.auto-download=false #enableMavenLocalRepo = true # The default Hibernate ORM version (override using `-PhibernateOrmVersion=the.version.you.want`) -hibernateOrmVersion = 6.6.4.Final +hibernateOrmVersion = 6.6.5.Final # Override default Hibernate ORM Gradle plugin version # Using the stable version because I don't know how to configure the build to download the snapshot version from # a remote repository -#hibernateOrmGradlePluginVersion = 6.6.4.Final +#hibernateOrmGradlePluginVersion = 6.6.5.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 From a9b39f290282becfada82a086dbc3020a43cb7c9 Mon Sep 17 00:00:00 2001 From: Davide D'Alto Date: Tue, 21 Jan 2025 12:17:06 +0100 Subject: [PATCH 019/162] [#2074] Upgrade Hibernate Validator to 8.0.2.Final --- examples/native-sql-example/build.gradle | 2 +- examples/session-example/build.gradle | 2 +- integration-tests/hibernate-validator-postgres-it/build.gradle | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/native-sql-example/build.gradle b/examples/native-sql-example/build.gradle index fabdbc7fa..c79ec8984 100644 --- a/examples/native-sql-example/build.gradle +++ b/examples/native-sql-example/build.gradle @@ -27,7 +27,7 @@ dependencies { implementation project( ':hibernate-reactive-core' ) // Hibernate Validator (optional) - implementation 'org.hibernate.validator:hibernate-validator:8.0.1.Final' + implementation 'org.hibernate.validator:hibernate-validator:8.0.2.Final' runtimeOnly 'org.glassfish.expressly:expressly:5.0.0' // JPA metamodel generation for criteria queries (optional) diff --git a/examples/session-example/build.gradle b/examples/session-example/build.gradle index 7cf7fb5f6..4da40ba69 100644 --- a/examples/session-example/build.gradle +++ b/examples/session-example/build.gradle @@ -27,7 +27,7 @@ dependencies { implementation project( ':hibernate-reactive-core' ) // Hibernate Validator (optional) - implementation 'org.hibernate.validator:hibernate-validator:8.0.1.Final' + implementation 'org.hibernate.validator:hibernate-validator:8.0.2.Final' runtimeOnly 'org.glassfish.expressly:expressly:5.0.0' // JPA metamodel generation for criteria queries (optional) diff --git a/integration-tests/hibernate-validator-postgres-it/build.gradle b/integration-tests/hibernate-validator-postgres-it/build.gradle index 017a52919..8236f6509 100644 --- a/integration-tests/hibernate-validator-postgres-it/build.gradle +++ b/integration-tests/hibernate-validator-postgres-it/build.gradle @@ -22,7 +22,7 @@ ext { dependencies { implementation project(':hibernate-reactive-core') - implementation "org.hibernate.validator:hibernate-validator:8.0.1.Final" + implementation "org.hibernate.validator:hibernate-validator:8.0.2.Final" runtimeOnly 'org.glassfish.expressly:expressly:5.0.0' // JPA metamodel generation for criteria queries (optional) From 434f0ec1a54fd4237f15ed327263653c79d6c488 Mon Sep 17 00:00:00 2001 From: Hibernate-CI Date: Tue, 21 Jan 2025 14:13:24 +0000 Subject: [PATCH 020/162] Update project version to : `2.4.4.Final` --- gradle/version.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/version.properties b/gradle/version.properties index 47693ff21..ad0f4adc1 100644 --- a/gradle/version.properties +++ b/gradle/version.properties @@ -1 +1 @@ -projectVersion=2.4.4-SNAPSHOT \ No newline at end of file +projectVersion=2.4.4.Final \ No newline at end of file From 16cc0bf85e7fe865c1548807e4b87fc4d44c8362 Mon Sep 17 00:00:00 2001 From: Hibernate-CI Date: Tue, 21 Jan 2025 14:14:20 +0000 Subject: [PATCH 021/162] Update project version to : `2.4.5-SNAPSHOT` --- gradle/version.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/version.properties b/gradle/version.properties index ad0f4adc1..0b654a7ec 100644 --- a/gradle/version.properties +++ b/gradle/version.properties @@ -1 +1 @@ -projectVersion=2.4.4.Final \ No newline at end of file +projectVersion=2.4.5-SNAPSHOT \ No newline at end of file From e7c7bc0ac56d247604e84d43d4f1a9c212aa39d1 Mon Sep 17 00:00:00 2001 From: Andrea Boriero Date: Tue, 21 Jan 2025 11:13:06 +0100 Subject: [PATCH 022/162] [#1724] Attempt to fix JDBCTimeZoneZonedTest sporadic failures probably due lack of database Timestamp precision --- .../timezones/JDBCTimeZoneZonedTest.java | 35 +++++++++++++++---- 1 file changed, 28 insertions(+), 7 deletions(-) diff --git a/hibernate-reactive-core/src/test/java/org/hibernate/reactive/timezones/JDBCTimeZoneZonedTest.java b/hibernate-reactive-core/src/test/java/org/hibernate/reactive/timezones/JDBCTimeZoneZonedTest.java index 5b928c217..c86ee18bb 100644 --- a/hibernate-reactive-core/src/test/java/org/hibernate/reactive/timezones/JDBCTimeZoneZonedTest.java +++ b/hibernate-reactive-core/src/test/java/org/hibernate/reactive/timezones/JDBCTimeZoneZonedTest.java @@ -10,10 +10,15 @@ import java.time.ZoneId; import java.time.ZoneOffset; import java.time.ZonedDateTime; +import java.time.temporal.ChronoField; +import java.time.temporal.ChronoUnit; import java.util.Collection; import java.util.List; import org.hibernate.cfg.Configuration; +import org.hibernate.dialect.Dialect; +import org.hibernate.dialect.MySQLDialect; +import org.hibernate.dialect.SybaseDialect; import org.hibernate.reactive.BaseReactiveTest; import org.hibernate.reactive.annotations.DisabledFor; @@ -31,7 +36,7 @@ import static org.hibernate.cfg.AvailableSettings.TIMEZONE_DEFAULT_STORAGE; import static org.hibernate.reactive.containers.DatabaseConfiguration.DBType.DB2; import static org.hibernate.reactive.testing.ReactiveAssertions.assertWithTruncationThat; -import static org.hibernate.type.descriptor.DateTimeUtils.roundToDefaultPrecision; +import static org.hibernate.type.descriptor.DateTimeUtils.adjustToDefaultPrecision; @Timeout(value = 10, timeUnit = MINUTES) @DisabledFor(value = DB2, reason = "Exception: IllegalStateException: Needed to have 6 in buffer but only had 0") @@ -51,8 +56,24 @@ protected void setProperties(Configuration configuration) { @Test public void test(VertxTestContext context) { - ZonedDateTime nowZoned = ZonedDateTime.now().withZoneSameInstant( ZoneId.of( "CET" ) ); - OffsetDateTime nowOffset = OffsetDateTime.now().withOffsetSameInstant( ZoneOffset.ofHours( 3 ) ); + final ZonedDateTime nowZoned; + final OffsetDateTime nowOffset; + final Dialect dialect = getDialect(); + if ( dialect instanceof SybaseDialect || dialect instanceof MySQLDialect ) { + // Sybase has 1/300th sec precision + nowZoned = ZonedDateTime.now().withZoneSameInstant( ZoneId.of("CET") ) + .with( ChronoField.NANO_OF_SECOND, 0L ); + nowOffset = OffsetDateTime.now().withOffsetSameInstant( ZoneOffset.ofHours(3) ) + .with( ChronoField.NANO_OF_SECOND, 0L ); + } + else if ( dialect.getDefaultTimestampPrecision() == 6 ) { + nowZoned = ZonedDateTime.now().withZoneSameInstant( ZoneId.of("CET") ).truncatedTo( ChronoUnit.MICROS ); + nowOffset = OffsetDateTime.now().withOffsetSameInstant( ZoneOffset.ofHours(3) ).truncatedTo( ChronoUnit.MICROS ); + } + else { + nowZoned = ZonedDateTime.now().withZoneSameInstant( ZoneId.of("CET") ); + nowOffset = OffsetDateTime.now().withOffsetSameInstant( ZoneOffset.ofHours(3) ); + } test( context, getSessionFactory() .withTransaction( s -> { Zoned z = new Zoned(); @@ -63,11 +84,11 @@ public void test(VertxTestContext context) { .thenCompose( zid -> openSession() .thenCompose( s -> s.find( Zoned.class, zid ) .thenAccept( z -> { - assertWithTruncationThat( roundToDefaultPrecision( z.zonedDateTime.toInstant(), getDialect() ) ) - .isEqualTo( roundToDefaultPrecision( nowZoned.toInstant(), getDialect() ) ); + assertWithTruncationThat( adjustToDefaultPrecision( z.zonedDateTime.toInstant(), getDialect() ) ) + .isEqualTo( adjustToDefaultPrecision( nowZoned.toInstant(), getDialect() ) ); - assertWithTruncationThat( roundToDefaultPrecision( z.offsetDateTime.toInstant(), getDialect() ) ) - .isEqualTo( roundToDefaultPrecision( nowOffset.toInstant(), getDialect() ) ); + assertWithTruncationThat( adjustToDefaultPrecision( z.offsetDateTime.toInstant(), getDialect() ) ) + .isEqualTo( adjustToDefaultPrecision( nowOffset.toInstant(), getDialect() ) ); ZoneId systemZone = ZoneId.systemDefault(); ZoneOffset systemOffset = systemZone.getRules().getOffset( Instant.now() ); From f6dce68bc038304db80c4b0db24f74fb4b466921 Mon Sep 17 00:00:00 2001 From: Andrea Boriero Date: Tue, 21 Jan 2025 13:47:59 +0100 Subject: [PATCH 023/162] [#1724] Align timezones tests to changes applied to ORM corresponding tests --- .../reactive/timezones/AutoZonedTest.java | 26 ++++++++++++++----- .../reactive/timezones/ColumnZonedTest.java | 26 ++++++++++++++----- .../reactive/timezones/DefaultZonedTest.java | 26 ++++++++++++++----- .../timezones/JDBCTimeZoneZonedTest.java | 17 +++--------- .../reactive/timezones/PassThruZonedTest.java | 26 ++++++++++++++----- 5 files changed, 80 insertions(+), 41 deletions(-) diff --git a/hibernate-reactive-core/src/test/java/org/hibernate/reactive/timezones/AutoZonedTest.java b/hibernate-reactive-core/src/test/java/org/hibernate/reactive/timezones/AutoZonedTest.java index a799f5d6b..eb502bdb1 100644 --- a/hibernate-reactive-core/src/test/java/org/hibernate/reactive/timezones/AutoZonedTest.java +++ b/hibernate-reactive-core/src/test/java/org/hibernate/reactive/timezones/AutoZonedTest.java @@ -19,6 +19,7 @@ import java.time.ZoneId; import java.time.ZoneOffset; import java.time.ZonedDateTime; +import java.time.temporal.ChronoUnit; import java.util.Collection; import java.util.List; @@ -29,8 +30,11 @@ import static org.hibernate.cfg.AvailableSettings.TIMEZONE_DEFAULT_STORAGE; import static org.hibernate.reactive.containers.DatabaseConfiguration.DBType.DB2; import static org.hibernate.reactive.testing.ReactiveAssertions.assertWithTruncationThat; -import static org.hibernate.type.descriptor.DateTimeUtils.roundToDefaultPrecision; +import static org.hibernate.type.descriptor.DateTimeUtils.adjustToDefaultPrecision; +/** + * Test adapted from {@link org.hibernate.orm.test.timezones.AutoZonedTest} + */ @Timeout(value = 10, timeUnit = MINUTES) @DisabledFor(value = DB2, reason = "Exception: IllegalStateException: Needed to have 6 in buffer but only had 0") public class AutoZonedTest extends BaseReactiveTest { @@ -48,8 +52,16 @@ protected void setProperties(Configuration configuration) { @Test public void test(VertxTestContext context) { - ZonedDateTime nowZoned = ZonedDateTime.now().withZoneSameInstant( ZoneId.of( "CET" ) ); - OffsetDateTime nowOffset = OffsetDateTime.now().withOffsetSameInstant( ZoneOffset.ofHours( 3 ) ); + final ZonedDateTime nowZoned; + final OffsetDateTime nowOffset; + if ( getDialect().getDefaultTimestampPrecision() == 6 ) { + nowZoned = ZonedDateTime.now().withZoneSameInstant( ZoneId.of("CET") ).truncatedTo( ChronoUnit.MICROS ); + nowOffset = OffsetDateTime.now().withOffsetSameInstant( ZoneOffset.ofHours(3) ).truncatedTo( ChronoUnit.MICROS ); + } + else { + nowZoned = ZonedDateTime.now().withZoneSameInstant( ZoneId.of("CET") ); + nowOffset = OffsetDateTime.now().withOffsetSameInstant( ZoneOffset.ofHours(3) ); + } test( context, getSessionFactory() .withTransaction( s -> { Zoned z = new Zoned(); @@ -60,10 +72,10 @@ public void test(VertxTestContext context) { .thenCompose( zid -> openSession() .thenCompose( s -> s.find( Zoned.class, zid ) .thenAccept( z -> { - assertWithTruncationThat( roundToDefaultPrecision( z.zonedDateTime.toInstant(), getDialect() ) ) - .isEqualTo( roundToDefaultPrecision( nowZoned.toInstant(), getDialect() ) ); - assertWithTruncationThat( roundToDefaultPrecision( z.offsetDateTime.toInstant(), getDialect() ) ) - .isEqualTo( roundToDefaultPrecision( nowOffset.toInstant(), getDialect() ) ); + assertWithTruncationThat( adjustToDefaultPrecision( z.zonedDateTime.toInstant(), getDialect() ) ) + .isEqualTo( adjustToDefaultPrecision( nowZoned.toInstant(), getDialect() ) ); + assertWithTruncationThat( adjustToDefaultPrecision( z.offsetDateTime.toInstant(), getDialect() ) ) + .isEqualTo( adjustToDefaultPrecision( nowOffset.toInstant(), getDialect() ) ); assertThat( z.zonedDateTime.toOffsetDateTime().getOffset() ) .isEqualTo( nowZoned.toOffsetDateTime().getOffset() ); assertThat( z.offsetDateTime.getOffset() ) diff --git a/hibernate-reactive-core/src/test/java/org/hibernate/reactive/timezones/ColumnZonedTest.java b/hibernate-reactive-core/src/test/java/org/hibernate/reactive/timezones/ColumnZonedTest.java index f10e394e1..6e33da4f4 100644 --- a/hibernate-reactive-core/src/test/java/org/hibernate/reactive/timezones/ColumnZonedTest.java +++ b/hibernate-reactive-core/src/test/java/org/hibernate/reactive/timezones/ColumnZonedTest.java @@ -9,6 +9,7 @@ import java.time.ZoneId; import java.time.ZoneOffset; import java.time.ZonedDateTime; +import java.time.temporal.ChronoUnit; import java.util.Collection; import java.util.List; @@ -29,8 +30,11 @@ import static org.hibernate.cfg.AvailableSettings.TIMEZONE_DEFAULT_STORAGE; import static org.hibernate.reactive.containers.DatabaseConfiguration.DBType.DB2; import static org.hibernate.reactive.testing.ReactiveAssertions.assertWithTruncationThat; -import static org.hibernate.type.descriptor.DateTimeUtils.roundToDefaultPrecision; +import static org.hibernate.type.descriptor.DateTimeUtils.adjustToDefaultPrecision; +/** + * Test adapted from {@link org.hibernate.orm.test.timezones.ColumnZonedTest} + */ @Timeout(value = 10, timeUnit = MINUTES) @DisabledFor(value = DB2, reason = "java.sql.SQLException: An error occurred with a DB2 operation, SQLCODE=-180 SQLSTATE=22007") public class ColumnZonedTest extends BaseReactiveTest { @@ -48,8 +52,16 @@ protected void setProperties(Configuration configuration) { @Test public void test(VertxTestContext context) { - ZonedDateTime nowZoned = ZonedDateTime.now().withZoneSameInstant( ZoneId.of( "CET" ) ); - OffsetDateTime nowOffset = OffsetDateTime.now().withOffsetSameInstant( ZoneOffset.ofHours( 3 ) ); + final ZonedDateTime nowZoned; + final OffsetDateTime nowOffset; + if ( getDialect().getDefaultTimestampPrecision() == 6 ) { + nowZoned = ZonedDateTime.now().withZoneSameInstant( ZoneId.of("CET") ).truncatedTo( ChronoUnit.MICROS ); + nowOffset = OffsetDateTime.now().withOffsetSameInstant( ZoneOffset.ofHours(3) ).truncatedTo( ChronoUnit.MICROS ); + } + else { + nowZoned = ZonedDateTime.now().withZoneSameInstant( ZoneId.of("CET") ); + nowOffset = OffsetDateTime.now().withOffsetSameInstant( ZoneOffset.ofHours(3) ); + } test( context, getSessionFactory() .withTransaction( s -> { Zoned z = new Zoned(); @@ -60,10 +72,10 @@ public void test(VertxTestContext context) { .thenCompose( zid -> openSession() .thenCompose( s -> s.find( Zoned.class, zid ) .thenAccept( z -> { - assertWithTruncationThat( roundToDefaultPrecision( z.zonedDateTime.toInstant(), getDialect() ) ) - .isEqualTo( roundToDefaultPrecision( nowZoned.toInstant(), getDialect() ) ); - assertWithTruncationThat( roundToDefaultPrecision( z.offsetDateTime.toInstant(), getDialect() ) ) - .isEqualTo( roundToDefaultPrecision( nowOffset.toInstant(), getDialect() ) ); + assertWithTruncationThat( adjustToDefaultPrecision( z.zonedDateTime.toInstant(), getDialect() ) ) + .isEqualTo( adjustToDefaultPrecision( nowZoned.toInstant(), getDialect() ) ); + assertWithTruncationThat( adjustToDefaultPrecision( z.offsetDateTime.toInstant(), getDialect() ) ) + .isEqualTo( adjustToDefaultPrecision( nowOffset.toInstant(), getDialect() ) ); assertThat( z.zonedDateTime.toOffsetDateTime().getOffset() ) .isEqualTo( nowZoned.toOffsetDateTime().getOffset() ); assertThat( z.offsetDateTime.getOffset() ) diff --git a/hibernate-reactive-core/src/test/java/org/hibernate/reactive/timezones/DefaultZonedTest.java b/hibernate-reactive-core/src/test/java/org/hibernate/reactive/timezones/DefaultZonedTest.java index 6752b7219..4ce4dbea8 100644 --- a/hibernate-reactive-core/src/test/java/org/hibernate/reactive/timezones/DefaultZonedTest.java +++ b/hibernate-reactive-core/src/test/java/org/hibernate/reactive/timezones/DefaultZonedTest.java @@ -9,6 +9,7 @@ import java.time.ZoneId; import java.time.ZoneOffset; import java.time.ZonedDateTime; +import java.time.temporal.ChronoUnit; import java.util.Collection; import java.util.List; @@ -28,8 +29,11 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.hibernate.reactive.containers.DatabaseConfiguration.DBType.DB2; import static org.hibernate.reactive.testing.ReactiveAssertions.assertWithTruncationThat; -import static org.hibernate.type.descriptor.DateTimeUtils.roundToDefaultPrecision; +import static org.hibernate.type.descriptor.DateTimeUtils.adjustToDefaultPrecision; +/** + * Test adapted from {@link org.hibernate.orm.test.timezones.DefaultZonedTest} + */ @Timeout(value = 10, timeUnit = MINUTES) @DisabledFor(value = DB2, reason = "Exception: IllegalStateException: Needed to have 6 in buffer but only had 0") public class DefaultZonedTest extends BaseReactiveTest { @@ -41,8 +45,16 @@ protected Collection> annotatedEntities() { @Test public void test(VertxTestContext context) { - ZonedDateTime nowZoned = ZonedDateTime.now().withZoneSameInstant( ZoneId.of( "CET" ) ); - OffsetDateTime nowOffset = OffsetDateTime.now().withOffsetSameInstant( ZoneOffset.ofHours( 3 ) ); + final ZonedDateTime nowZoned; + final OffsetDateTime nowOffset; + if ( getDialect().getDefaultTimestampPrecision() == 6 ) { + nowZoned = ZonedDateTime.now().withZoneSameInstant( ZoneId.of("CET") ).truncatedTo( ChronoUnit.MICROS ); + nowOffset = OffsetDateTime.now().withOffsetSameInstant( ZoneOffset.ofHours(3) ).truncatedTo( ChronoUnit.MICROS ); + } + else { + nowZoned = ZonedDateTime.now().withZoneSameInstant( ZoneId.of("CET") ); + nowOffset = OffsetDateTime.now().withOffsetSameInstant( ZoneOffset.ofHours(3) ); + } test( context, getSessionFactory() .withTransaction( s -> { Zoned z = new Zoned(); @@ -53,10 +65,10 @@ public void test(VertxTestContext context) { .thenCompose( zid -> openSession() .thenCompose( s -> s.find( Zoned.class, zid ) .thenAccept( z -> { - assertWithTruncationThat( roundToDefaultPrecision( z.zonedDateTime.toInstant(), getDialect() ) ) - .isEqualTo( roundToDefaultPrecision( nowZoned.toInstant(), getDialect() ) ); - assertWithTruncationThat( roundToDefaultPrecision( z.offsetDateTime.toInstant(), getDialect() ) ) - .isEqualTo( roundToDefaultPrecision( nowOffset.toInstant(), getDialect() ) ); + assertWithTruncationThat( adjustToDefaultPrecision( z.zonedDateTime.toInstant(), getDialect() ) ) + .isEqualTo( adjustToDefaultPrecision( nowZoned.toInstant(), getDialect() ) ); + assertWithTruncationThat( adjustToDefaultPrecision( z.offsetDateTime.toInstant(), getDialect() ) ) + .isEqualTo( adjustToDefaultPrecision( nowOffset.toInstant(), getDialect() ) ); if ( getDialect().getTimeZoneSupport() == TimeZoneSupport.NATIVE ) { assertThat( z.zonedDateTime.toOffsetDateTime().getOffset() ) diff --git a/hibernate-reactive-core/src/test/java/org/hibernate/reactive/timezones/JDBCTimeZoneZonedTest.java b/hibernate-reactive-core/src/test/java/org/hibernate/reactive/timezones/JDBCTimeZoneZonedTest.java index c86ee18bb..71966bfc1 100644 --- a/hibernate-reactive-core/src/test/java/org/hibernate/reactive/timezones/JDBCTimeZoneZonedTest.java +++ b/hibernate-reactive-core/src/test/java/org/hibernate/reactive/timezones/JDBCTimeZoneZonedTest.java @@ -10,15 +10,11 @@ import java.time.ZoneId; import java.time.ZoneOffset; import java.time.ZonedDateTime; -import java.time.temporal.ChronoField; import java.time.temporal.ChronoUnit; import java.util.Collection; import java.util.List; import org.hibernate.cfg.Configuration; -import org.hibernate.dialect.Dialect; -import org.hibernate.dialect.MySQLDialect; -import org.hibernate.dialect.SybaseDialect; import org.hibernate.reactive.BaseReactiveTest; import org.hibernate.reactive.annotations.DisabledFor; @@ -38,6 +34,9 @@ import static org.hibernate.reactive.testing.ReactiveAssertions.assertWithTruncationThat; import static org.hibernate.type.descriptor.DateTimeUtils.adjustToDefaultPrecision; +/** + * Test adapted from {@link org.hibernate.orm.test.timezones.JDBCTimeZoneZonedTest} + */ @Timeout(value = 10, timeUnit = MINUTES) @DisabledFor(value = DB2, reason = "Exception: IllegalStateException: Needed to have 6 in buffer but only had 0") public class JDBCTimeZoneZonedTest extends BaseReactiveTest { @@ -58,15 +57,7 @@ protected void setProperties(Configuration configuration) { public void test(VertxTestContext context) { final ZonedDateTime nowZoned; final OffsetDateTime nowOffset; - final Dialect dialect = getDialect(); - if ( dialect instanceof SybaseDialect || dialect instanceof MySQLDialect ) { - // Sybase has 1/300th sec precision - nowZoned = ZonedDateTime.now().withZoneSameInstant( ZoneId.of("CET") ) - .with( ChronoField.NANO_OF_SECOND, 0L ); - nowOffset = OffsetDateTime.now().withOffsetSameInstant( ZoneOffset.ofHours(3) ) - .with( ChronoField.NANO_OF_SECOND, 0L ); - } - else if ( dialect.getDefaultTimestampPrecision() == 6 ) { + if ( getDialect().getDefaultTimestampPrecision() == 6 ) { nowZoned = ZonedDateTime.now().withZoneSameInstant( ZoneId.of("CET") ).truncatedTo( ChronoUnit.MICROS ); nowOffset = OffsetDateTime.now().withOffsetSameInstant( ZoneOffset.ofHours(3) ).truncatedTo( ChronoUnit.MICROS ); } diff --git a/hibernate-reactive-core/src/test/java/org/hibernate/reactive/timezones/PassThruZonedTest.java b/hibernate-reactive-core/src/test/java/org/hibernate/reactive/timezones/PassThruZonedTest.java index 988db4a58..3ce9f4256 100644 --- a/hibernate-reactive-core/src/test/java/org/hibernate/reactive/timezones/PassThruZonedTest.java +++ b/hibernate-reactive-core/src/test/java/org/hibernate/reactive/timezones/PassThruZonedTest.java @@ -10,6 +10,7 @@ import java.time.ZoneId; import java.time.ZoneOffset; import java.time.ZonedDateTime; +import java.time.temporal.ChronoUnit; import java.util.Collection; import java.util.List; @@ -30,8 +31,11 @@ import static org.hibernate.cfg.AvailableSettings.TIMEZONE_DEFAULT_STORAGE; import static org.hibernate.reactive.testing.ReactiveAssertions.assertWithTruncationThat; import static org.hibernate.reactive.containers.DatabaseConfiguration.DBType.DB2; -import static org.hibernate.type.descriptor.DateTimeUtils.roundToDefaultPrecision; +import static org.hibernate.type.descriptor.DateTimeUtils.adjustToDefaultPrecision; +/** + * Test adapted from {@link org.hibernate.orm.test.timezones.PassThruZonedTest} + */ @Timeout(value = 10, timeUnit = MINUTES) @DisabledFor(value = DB2, reason = "Exception: SQLException: An error occurred with a DB2 operation, SQLCODE=-180 SQLSTATE=22007") public class PassThruZonedTest extends BaseReactiveTest { @@ -49,8 +53,16 @@ protected void setProperties(Configuration configuration) { @Test public void test(VertxTestContext context) { - ZonedDateTime nowZoned = ZonedDateTime.now().withZoneSameInstant( ZoneId.of( "CET" ) ); - OffsetDateTime nowOffset = OffsetDateTime.now().withOffsetSameInstant( ZoneOffset.ofHours( 3 ) ); + final ZonedDateTime nowZoned; + final OffsetDateTime nowOffset; + if ( getDialect().getDefaultTimestampPrecision() == 6 ) { + nowZoned = ZonedDateTime.now().withZoneSameInstant( ZoneId.of("CET") ).truncatedTo( ChronoUnit.MICROS ); + nowOffset = OffsetDateTime.now().withOffsetSameInstant( ZoneOffset.ofHours(3) ).truncatedTo( ChronoUnit.MICROS ); + } + else { + nowZoned = ZonedDateTime.now().withZoneSameInstant( ZoneId.of("CET") ); + nowOffset = OffsetDateTime.now().withOffsetSameInstant( ZoneOffset.ofHours(3) ); + } test( context, getSessionFactory() .withTransaction( s -> { Zoned z = new Zoned(); @@ -61,10 +73,10 @@ public void test(VertxTestContext context) { .thenCompose( zid -> openSession() .thenCompose( s -> s.find( Zoned.class, zid ) .thenAccept( z -> { - assertWithTruncationThat( roundToDefaultPrecision( z.zonedDateTime.toInstant(), getDialect() ) ) - .isEqualTo( roundToDefaultPrecision( nowZoned.toInstant(), getDialect() ) ); - assertWithTruncationThat( roundToDefaultPrecision( z.offsetDateTime.toInstant(), getDialect() ) ) - .isEqualTo( roundToDefaultPrecision( nowOffset.toInstant(), getDialect() ) ); + assertWithTruncationThat( adjustToDefaultPrecision( z.zonedDateTime.toInstant(), getDialect() ) ) + .isEqualTo( adjustToDefaultPrecision( nowZoned.toInstant(), getDialect() ) ); + assertWithTruncationThat( adjustToDefaultPrecision( z.offsetDateTime.toInstant(), getDialect() ) ) + .isEqualTo( adjustToDefaultPrecision( nowOffset.toInstant(), getDialect() ) ); ZoneId systemZone = ZoneId.systemDefault(); ZoneOffset systemOffset = systemZone.getRules().getOffset( Instant.now() ); From a7d192e1debd2ef290eb22f651dfecb1259ddff3 Mon Sep 17 00:00:00 2001 From: Gavin King Date: Wed, 22 Jan 2025 10:43:07 +0100 Subject: [PATCH 024/162] remove unused/obsolete LOG --- .../reactive/stage/impl/StageSelectionQueryImpl.java | 4 ---- 1 file changed, 4 deletions(-) diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/stage/impl/StageSelectionQueryImpl.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/stage/impl/StageSelectionQueryImpl.java index 6a1be5d08..eaf1c9a53 100644 --- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/stage/impl/StageSelectionQueryImpl.java +++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/stage/impl/StageSelectionQueryImpl.java @@ -5,7 +5,6 @@ */ package org.hibernate.reactive.stage.impl; -import java.lang.invoke.MethodHandles; import java.util.List; import java.util.concurrent.CompletionStage; @@ -16,8 +15,6 @@ import org.hibernate.graph.spi.RootGraphImplementor; import org.hibernate.query.Order; import org.hibernate.query.Page; -import org.hibernate.reactive.logging.impl.Log; -import org.hibernate.reactive.logging.impl.LoggerFactory; import org.hibernate.reactive.query.ReactiveSelectionQuery; import org.hibernate.reactive.stage.Stage.SelectionQuery; @@ -29,7 +26,6 @@ import jakarta.persistence.Parameter; public class StageSelectionQueryImpl implements SelectionQuery { - private static final Log LOG = LoggerFactory.make( Log.class, MethodHandles.lookup() ); private final ReactiveSelectionQuery delegate; public StageSelectionQueryImpl(ReactiveSelectionQuery delegate) { From fcb48cac95a9959319c9941bae822015a2f73b00 Mon Sep 17 00:00:00 2001 From: Gavin King Date: Wed, 22 Jan 2025 10:41:57 +0100 Subject: [PATCH 025/162] fix whitespace in example persistence.xml files --- .../src/main/resources/META-INF/persistence.xml | 2 +- .../session-example/src/main/resources/META-INF/persistence.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/native-sql-example/src/main/resources/META-INF/persistence.xml b/examples/native-sql-example/src/main/resources/META-INF/persistence.xml index aaa9d3687..686442cb2 100644 --- a/examples/native-sql-example/src/main/resources/META-INF/persistence.xml +++ b/examples/native-sql-example/src/main/resources/META-INF/persistence.xml @@ -3,7 +3,7 @@ xsi:schemaLocation="https://jakarta.ee/xml/ns/persistence https://jakarta.ee/xml/ns/persistence/persistence_3_0.xsd" version="3.0"> - + org.hibernate.reactive.provider.ReactivePersistenceProvider org.hibernate.reactive.example.nativesql.Author diff --git a/examples/session-example/src/main/resources/META-INF/persistence.xml b/examples/session-example/src/main/resources/META-INF/persistence.xml index 7c2c13900..f3271f251 100644 --- a/examples/session-example/src/main/resources/META-INF/persistence.xml +++ b/examples/session-example/src/main/resources/META-INF/persistence.xml @@ -3,7 +3,7 @@ xsi:schemaLocation="https://jakarta.ee/xml/ns/persistence https://jakarta.ee/xml/ns/persistence/persistence_3_0.xsd" version="3.0"> - + org.hibernate.reactive.provider.ReactivePersistenceProvider org.hibernate.reactive.example.session.Author From f9be2a2ba827088f39a31477a7fba0cd0628b903 Mon Sep 17 00:00:00 2001 From: Andrea Boriero Date: Wed, 22 Jan 2025 11:02:30 +0100 Subject: [PATCH 026/162] [#1904] PropertyAccessException when creating a new object with a one-to-one association --- .../AbstractReactiveSaveEventListener.java | 89 ++++++++++--------- 1 file changed, 45 insertions(+), 44 deletions(-) diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/event/impl/AbstractReactiveSaveEventListener.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/event/impl/AbstractReactiveSaveEventListener.java index e9d68b00e..c0ef66b17 100644 --- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/event/impl/AbstractReactiveSaveEventListener.java +++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/event/impl/AbstractReactiveSaveEventListener.java @@ -144,55 +144,59 @@ else if ( generator instanceof Assigned ) { // the entity instance, so it will be available // to the entity in the @PrePersist callback if ( generator instanceof ReactiveIdentifierGenerator ) { - return ( (ReactiveIdentifierGenerator) generator ) - .generate( ( ReactiveConnectionSupplier ) source, entity ) - .thenApply( id -> castToIdentifierType( id, persister ) ) - .thenCompose( gid -> performSaveWithId( - entity, - context, - source, - persister, - generator, - gid, - requiresImmediateIdAccess, - false - ) ); + return generateId( entity, source, (ReactiveIdentifierGenerator) generator, persister ) + .thenCompose( gid -> { + if ( gid == SHORT_CIRCUIT_INDICATOR ) { + source.getIdentifier( entity ); + return voidFuture(); + } + persister.setIdentifier( entity, gid, source ); + return reactivePerformSave( + entity, + gid, + persister, + generatedOnExecution, + context, + source, + false + ); + } ); } generatedId = ( (BeforeExecutionGenerator) generator ).generate( source, entity, null, INSERT ); + if ( generatedId == SHORT_CIRCUIT_INDICATOR ) { + source.getIdentifier( entity ); + return voidFuture(); + } + persister.setIdentifier( entity, generatedId, source ); } final Object id = castToIdentifierType( generatedId, persister ); - return reactivePerformSave( entity, id, persister, generatedOnExecution, context, source, requiresImmediateIdAccess ); + final boolean delayIdentityInserts = !source.isTransactionInProgress() && !requiresImmediateIdAccess && generatedOnExecution; + return reactivePerformSave( entity, id, persister, generatedOnExecution, context, source, delayIdentityInserts ); } - private CompletionStage performSaveWithId( + private CompletionStage generateId( Object entity, - C context, EventSource source, - EntityPersister persister, - Generator generator, - Object generatedId, - boolean requiresImmediateIdAccess, - boolean generatedOnExecution) { - if ( generatedId == null ) { - throw new IdentifierGenerationException( "null id generated for: " + entity.getClass() ); - } - if ( generatedId == SHORT_CIRCUIT_INDICATOR ) { - source.getIdentifier( entity ); - return voidFuture(); - } - if ( LOG.isDebugEnabled() ) { - LOG.debugf( - "Generated identifier: %s, using strategy: %s", - persister.getIdentifierType().toLoggableString( generatedId, source.getFactory() ), - generator.getClass().getName() - ); - } - final boolean delayIdentityInserts = - !source.isTransactionInProgress() - && !requiresImmediateIdAccess - && generatedOnExecution; - return reactivePerformSave( entity, generatedId, persister, false, context, source, delayIdentityInserts ); + ReactiveIdentifierGenerator generator, + EntityPersister persister) { + return generator + .generate( (ReactiveConnectionSupplier) source, entity ) + .thenApply( id -> { + final Object generatedId = castToIdentifierType( id, persister ); + if ( generatedId == null ) { + throw new IdentifierGenerationException( "null id generated for: " + entity.getClass() ); + } + if ( LOG.isDebugEnabled() ) { + LOG.debugf( + "Generated identifier: %s, using strategy: %s", + persister.getIdentifierType().toLoggableString( generatedId, source.getFactory() ), + generator.getClass().getName() + ); + } + return generatedId; + } + ); } /** @@ -232,10 +236,7 @@ protected CompletionStage reactivePerformSave( if ( persister.getGenerator() instanceof Assigned ) { id = persister.getIdentifier( entity, source ); if ( id == null ) { - throw new IdentifierGenerationException( - "Identifier of entity '" + persister.getEntityName() - + "' must be manually assigned before calling 'persist()'" - ); + return failedFuture( new IdentifierGenerationException( "Identifier of entity '" + persister.getEntityName() + "' must be manually assigned before calling 'persist()'" ) ); } } From 17dfc9906a1f85389bc36c038f589e09a2a2ec93 Mon Sep 17 00:00:00 2001 From: Andrea Boriero Date: Wed, 22 Jan 2025 13:26:58 +0100 Subject: [PATCH 027/162] [#1904] Add test for PropertyAccessException when creating a new object with a one-to-one association --- .../OneToOneMapsIdAndGeneratedIdTest.java | 154 ++++++++++++++++++ 1 file changed, 154 insertions(+) create mode 100644 hibernate-reactive-core/src/test/java/org/hibernate/reactive/OneToOneMapsIdAndGeneratedIdTest.java diff --git a/hibernate-reactive-core/src/test/java/org/hibernate/reactive/OneToOneMapsIdAndGeneratedIdTest.java b/hibernate-reactive-core/src/test/java/org/hibernate/reactive/OneToOneMapsIdAndGeneratedIdTest.java new file mode 100644 index 000000000..7aca2c611 --- /dev/null +++ b/hibernate-reactive-core/src/test/java/org/hibernate/reactive/OneToOneMapsIdAndGeneratedIdTest.java @@ -0,0 +1,154 @@ +/* Hibernate, Relational Persistence for Idiomatic Java + * + * SPDX-License-Identifier: Apache-2.0 + * Copyright: Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.reactive; + +import java.util.Collection; +import java.util.List; +import java.util.Objects; + +import org.junit.jupiter.api.Test; + +import io.vertx.junit5.Timeout; +import io.vertx.junit5.VertxTestContext; +import jakarta.persistence.CascadeType; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.MapsId; +import jakarta.persistence.OneToOne; + +import static java.util.concurrent.TimeUnit.MINUTES; +import static org.assertj.core.api.Assertions.assertThat; + +@Timeout(value = 10, timeUnit = MINUTES) +public class OneToOneMapsIdAndGeneratedIdTest extends BaseReactiveTest { + + @Override + protected Collection> annotatedEntities() { + return List.of( Person.class, NaturalPerson.class ); + } + + @Test + public void testPersist(VertxTestContext context) { + NaturalPerson naturalPerson = new NaturalPerson( "natual" ); + Person person = new Person( "person", naturalPerson ); + + test( + context, getMutinySessionFactory() + .withTransaction( session -> session.persist( person ) ) + .chain( () -> getMutinySessionFactory() + .withTransaction( session -> session + .find( Person.class, person.getId() ) + .invoke( result -> { + assertThat( result ).isNotNull(); + assertThat( result.getNaturalPerson() ).isNotNull(); + assertThat( result.getNaturalPerson().getId() ).isEqualTo( result.getId() ); + } ) ) + ) + ); + + } + + @Entity + public static class Person { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + private String name; + + @OneToOne(mappedBy = "person", cascade = CascadeType.ALL) + private NaturalPerson naturalPerson; + + public Person() { + } + + public Person(String name, NaturalPerson naturalPerson) { + this.name = name; + this.naturalPerson = naturalPerson; + naturalPerson.person = this; + } + + public Long getId() { + return id; + } + + public String getName() { + return name; + } + + public NaturalPerson getNaturalPerson() { + return naturalPerson; + } + + @Override + public boolean equals(Object o) { + if ( o == null || getClass() != o.getClass() ) { + return false; + } + Person person = (Person) o; + return Objects.equals( name, person.name ); + } + + @Override + public int hashCode() { + return Objects.hashCode( name ); + } + } + + @Entity + public static class NaturalPerson { + + @Id + private Long id; + + @Column + private String name; + + @OneToOne(fetch = FetchType.LAZY) + @MapsId + private Person person; + + public NaturalPerson() { + } + + public NaturalPerson(String name) { + this.name = name; + } + + public Long getId() { + return id; + } + + public String getName() { + return name; + } + + public Person getPerson() { + return person; + } + + @Override + public boolean equals(Object o) { + if ( o == null || getClass() != o.getClass() ) { + return false; + } + NaturalPerson that = (NaturalPerson) o; + return Objects.equals( name, that.name ); + } + + @Override + public int hashCode() { + return Objects.hashCode( name ); + } + } + + +} From 92da2e61ddaffd07228f7fc8cadf0ce83f5da41c Mon Sep 17 00:00:00 2001 From: Davide D'Alto Date: Fri, 24 Jan 2025 09:29:30 +0100 Subject: [PATCH 028/162] [#2086] Upgrade Gradle Wrapper to 8.12 --- gradle/wrapper/gradle-wrapper.jar | Bin 43462 -> 43583 bytes gradle/wrapper/gradle-wrapper.properties | 2 +- gradlew | 7 +++++-- gradlew.bat | 22 ++++++++++++---------- 4 files changed, 18 insertions(+), 13 deletions(-) diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index d64cd4917707c1f8861d8cb53dd15194d4248596..a4b76b9530d66f5e68d973ea569d8e19de379189 100644 GIT binary patch delta 34592 zcmY(qRX`kF)3u#IAjsf0xCD212@LM;?(PINyAue(f;$XO2=4Cg1P$=#e%|lo zKk1`B>Q#GH)wNd-&cJog!qw7YfYndTeo)CyX{fOHsQjGa<{e=jamMNwjdatD={CN3>GNchOE9OGPIqr)3v>RcKWR3Z zF-guIMjE2UF0Wqk1)21791y#}ciBI*bAenY*BMW_)AeSuM5}vz_~`+1i!Lo?XAEq{TlK5-efNFgHr6o zD>^vB&%3ZGEWMS>`?tu!@66|uiDvS5`?bF=gIq3rkK(j<_TybyoaDHg8;Y#`;>tXI z=tXo~e9{U!*hqTe#nZjW4z0mP8A9UUv1}C#R*@yu9G3k;`Me0-BA2&Aw6f`{Ozan2 z8c8Cs#dA-7V)ZwcGKH}jW!Ja&VaUc@mu5a@CObzNot?b{f+~+212lwF;!QKI16FDS zodx>XN$sk9;t;)maB^s6sr^L32EbMV(uvW%or=|0@U6cUkE`_!<=LHLlRGJx@gQI=B(nn z-GEjDE}*8>3U$n(t^(b^C$qSTI;}6q&ypp?-2rGpqg7b}pyT zOARu2x>0HB{&D(d3sp`+}ka+Pca5glh|c=M)Ujn_$ly^X6&u z%Q4Y*LtB_>i6(YR!?{Os-(^J`(70lZ&Hp1I^?t@~SFL1!m0x6j|NM!-JTDk)%Q^R< z@e?23FD&9_W{Bgtr&CG&*Oer3Z(Bu2EbV3T9FeQ|-vo5pwzwQ%g&=zFS7b{n6T2ZQ z*!H(=z<{D9@c`KmHO&DbUIzpg`+r5207}4D=_P$ONIc5lsFgn)UB-oUE#{r+|uHc^hzv_df zV`n8&qry%jXQ33}Bjqcim~BY1?KZ}x453Oh7G@fA(}+m(f$)TY%7n=MeLi{jJ7LMB zt(mE*vFnep?YpkT_&WPV9*f>uSi#n#@STJmV&SLZnlLsWYI@y+Bs=gzcqche=&cBH2WL)dkR!a95*Ri)JH_4c*- zl4pPLl^as5_y&6RDE@@7342DNyF&GLJez#eMJjI}#pZN{Y8io{l*D+|f_Y&RQPia@ zNDL;SBERA|B#cjlNC@VU{2csOvB8$HzU$01Q?y)KEfos>W46VMh>P~oQC8k=26-Ku)@C|n^zDP!hO}Y z_tF}0@*Ds!JMt>?4y|l3?`v#5*oV-=vL7}zehMON^=s1%q+n=^^Z{^mTs7}*->#YL z)x-~SWE{e?YCarwU$=cS>VzmUh?Q&7?#Xrcce+jeZ|%0!l|H_=D_`77hBfd4Zqk&! zq-Dnt_?5*$Wsw8zGd@?woEtfYZ2|9L8b>TO6>oMh%`B7iBb)-aCefM~q|S2Cc0t9T zlu-ZXmM0wd$!gd-dTtik{bqyx32%f;`XUvbUWWJmpHfk8^PQIEsByJm+@+-aj4J#D z4#Br3pO6z1eIC>X^yKk|PeVwX_4B+IYJyJyc3B`4 zPrM#raacGIzVOexcVB;fcsxS=s1e&V;Xe$tw&KQ`YaCkHTKe*Al#velxV{3wxx}`7@isG zp6{+s)CG%HF#JBAQ_jM%zCX5X;J%-*%&jVI?6KpYyzGbq7qf;&hFprh?E5Wyo=bZ) z8YNycvMNGp1836!-?nihm6jI`^C`EeGryoNZO1AFTQhzFJOA%Q{X(sMYlzABt!&f{ zoDENSuoJQIg5Q#@BUsNJX2h>jkdx4<+ipUymWKFr;w+s>$laIIkfP6nU}r+?J9bZg zUIxz>RX$kX=C4m(zh-Eg$BsJ4OL&_J38PbHW&7JmR27%efAkqqdvf)Am)VF$+U3WR z-E#I9H6^)zHLKCs7|Zs<7Bo9VCS3@CDQ;{UTczoEprCKL3ZZW!ffmZFkcWU-V|_M2 zUA9~8tE9<5`59W-UgUmDFp11YlORl3mS3*2#ZHjv{*-1#uMV_oVTy{PY(}AqZv#wF zJVks)%N6LaHF$$<6p8S8Lqn+5&t}DmLKiC~lE{jPZ39oj{wR&fe*LX-z0m}9ZnZ{U z>3-5Bh{KKN^n5i!M79Aw5eY=`6fG#aW1_ZG;fw7JM69qk^*(rmO{|Z6rXy?l=K=#_ zE-zd*P|(sskasO(cZ5L~_{Mz&Y@@@Q)5_8l<6vB$@226O+pDvkFaK8b>%2 zfMtgJ@+cN@w>3)(_uR;s8$sGONbYvoEZ3-)zZk4!`tNzd<0lwt{RAgplo*f@Z)uO` zzd`ljSqKfHJOLxya4_}T`k5Ok1Mpo#MSqf~&ia3uIy{zyuaF}pV6 z)@$ZG5LYh8Gge*LqM_|GiT1*J*uKes=Oku_gMj&;FS`*sfpM+ygN&yOla-^WtIU#$ zuw(_-?DS?6DY7IbON7J)p^IM?N>7x^3)(7wR4PZJu(teex%l>zKAUSNL@~{czc}bR z)I{XzXqZBU3a;7UQ~PvAx8g-3q-9AEd}1JrlfS8NdPc+!=HJ6Bs( zCG!0;e0z-22(Uzw>hkEmC&xj?{0p|kc zM}MMXCF%RLLa#5jG`+}{pDL3M&|%3BlwOi?dq!)KUdv5__zR>u^o|QkYiqr(m3HxF z6J*DyN#Jpooc$ok=b7{UAVM@nwGsr6kozSddwulf5g1{B=0#2)zv!zLXQup^BZ4sv*sEsn)+MA?t zEL)}3*R?4(J~CpeSJPM!oZ~8;8s_=@6o`IA%{aEA9!GELRvOuncE`s7sH91 zmF=+T!Q6%){?lJn3`5}oW31(^Of|$r%`~gT{eimT7R~*Mg@x+tWM3KE>=Q>nkMG$U za7r>Yz2LEaA|PsMafvJ(Y>Xzha?=>#B!sYfVob4k5Orb$INFdL@U0(J8Hj&kgWUlO zPm+R07E+oq^4f4#HvEPANGWLL_!uF{nkHYE&BCH%l1FL_r(Nj@M)*VOD5S42Gk-yT z^23oAMvpA57H(fkDGMx86Z}rtQhR^L!T2iS!788E z+^${W1V}J_NwdwdxpXAW8}#6o1(Uu|vhJvubFvQIH1bDl4J4iDJ+181KuDuHwvM?` z%1@Tnq+7>p{O&p=@QT}4wT;HCb@i)&7int<0#bj8j0sfN3s6|a(l7Bj#7$hxX@~iP z1HF8RFH}irky&eCN4T94VyKqGywEGY{Gt0Xl-`|dOU&{Q;Ao;sL>C6N zXx1y^RZSaL-pG|JN;j9ADjo^XR}gce#seM4QB1?S`L*aB&QlbBIRegMnTkTCks7JU z<0(b+^Q?HN1&$M1l&I@>HMS;!&bb()a}hhJzsmB?I`poqTrSoO>m_JE5U4=?o;OV6 zBZjt;*%1P>%2{UL=;a4(aI>PRk|mr&F^=v6Fr&xMj8fRCXE5Z2qdre&;$_RNid5!S zm^XiLK25G6_j4dWkFqjtU7#s;b8h?BYFxV?OE?c~&ME`n`$ix_`mb^AWr+{M9{^^Rl;~KREplwy2q;&xe zUR0SjHzKVYzuqQ84w$NKVPGVHL_4I)Uw<$uL2-Ml#+5r2X{LLqc*p13{;w#E*Kwb*1D|v?e;(<>vl@VjnFB^^Y;;b3 z=R@(uRj6D}-h6CCOxAdqn~_SG=bN%^9(Ac?zfRkO5x2VM0+@_qk?MDXvf=@q_* z3IM@)er6-OXyE1Z4sU3{8$Y$>8NcnU-nkyWD&2ZaqX1JF_JYL8y}>@V8A5%lX#U3E zet5PJM`z79q9u5v(OE~{by|Jzlw2<0h`hKpOefhw=fgLTY9M8h+?37k@TWpzAb2Fc zQMf^aVf!yXlK?@5d-re}!fuAWu0t57ZKSSacwRGJ$0uC}ZgxCTw>cjRk*xCt%w&hh zoeiIgdz__&u~8s|_TZsGvJ7sjvBW<(C@}Y%#l_ID2&C`0;Eg2Z+pk;IK}4T@W6X5H z`s?ayU-iF+aNr5--T-^~K~p;}D(*GWOAYDV9JEw!w8ZYzS3;W6*_`#aZw&9J ziXhBKU3~zd$kKzCAP-=t&cFDeQR*_e*(excIUxKuD@;-twSlP6>wWQU)$|H3Cy+`= z-#7OW!ZlYzZxkdQpfqVDFU3V2B_-eJS)Fi{fLtRz!K{~7TR~XilNCu=Z;{GIf9KYz zf3h=Jo+1#_s>z$lc~e)l93h&RqW1VHYN;Yjwg#Qi0yzjN^M4cuL>Ew`_-_wRhi*!f zLK6vTpgo^Bz?8AsU%#n}^EGigkG3FXen3M;hm#C38P@Zs4{!QZPAU=m7ZV&xKI_HWNt90Ef zxClm)ZY?S|n**2cNYy-xBlLAVZ=~+!|7y`(fh+M$#4zl&T^gV8ZaG(RBD!`3?9xcK zp2+aD(T%QIgrLx5au&TjG1AazI;`8m{K7^!@m>uGCSR;Ut{&?t%3AsF{>0Cm(Kf)2 z?4?|J+!BUg*P~C{?mwPQ#)gDMmro20YVNsVx5oWQMkzQ? zsQ%Y>%7_wkJqnSMuZjB9lBM(o zWut|B7w48cn}4buUBbdPBW_J@H7g=szrKEpb|aE>!4rLm+sO9K%iI75y~2HkUo^iw zJ3se$8$|W>3}?JU@3h@M^HEFNmvCp|+$-0M?RQ8SMoZ@38%!tz8f8-Ptb@106heiJ z^Bx!`0=Im z1!NUhO=9ICM*+||b3a7w*Y#5*Q}K^ar+oMMtekF0JnO>hzHqZKH0&PZ^^M(j;vwf_ z@^|VMBpcw8;4E-9J{(u7sHSyZpQbS&N{VQ%ZCh{c1UA5;?R} z+52*X_tkDQ(s~#-6`z4|Y}3N#a&dgP4S_^tsV=oZr4A1 zaSoPN1czE(UIBrC_r$0HM?RyBGe#lTBL4~JW#A`P^#0wuK)C-2$B6TvMi@@%K@JAT_IB^T7Zfqc8?{wHcSVG_?{(wUG%zhCm=%qP~EqeqKI$9UivF zv+5IUOs|%@ypo6b+i=xsZ=^G1yeWe)z6IX-EC`F=(|_GCNbHbNp(CZ*lpSu5n`FRA zhnrc4w+Vh?r>her@Ba_jv0Omp#-H7avZb=j_A~B%V0&FNi#!S8cwn0(Gg-Gi_LMI{ zCg=g@m{W@u?GQ|yp^yENd;M=W2s-k7Gw2Z(tsD5fTGF{iZ%Ccgjy6O!AB4x z%&=6jB7^}pyftW2YQpOY1w@%wZy%}-l0qJlOSKZXnN2wo3|hujU+-U~blRF!^;Tan z0w;Srh0|Q~6*tXf!5-rCD)OYE(%S|^WTpa1KHtpHZ{!;KdcM^#g8Z^+LkbiBHt85m z;2xv#83lWB(kplfgqv@ZNDcHizwi4-8+WHA$U-HBNqsZ`hKcUI3zV3d1ngJP-AMRET*A{> zb2A>Fk|L|WYV;Eu4>{a6ESi2r3aZL7x}eRc?cf|~bP)6b7%BnsR{Sa>K^0obn?yiJ zCVvaZ&;d_6WEk${F1SN0{_`(#TuOOH1as&#&xN~+JDzX(D-WU_nLEI}T_VaeLA=bc zl_UZS$nu#C1yH}YV>N2^9^zye{rDrn(rS99>Fh&jtNY7PP15q%g=RGnxACdCov47= zwf^9zfJaL{y`R#~tvVL#*<`=`Qe zj_@Me$6sIK=LMFbBrJps7vdaf_HeX?eC+P^{AgSvbEn?n<}NDWiQGQG4^ZOc|GskK z$Ve2_n8gQ-KZ=s(f`_X!+vM5)4+QmOP()2Fe#IL2toZBf+)8gTVgDSTN1CkP<}!j7 z0SEl>PBg{MnPHkj4wj$mZ?m5x!1ePVEYI(L_sb0OZ*=M%yQb?L{UL(2_*CTVbRxBe z@{)COwTK1}!*CK0Vi4~AB;HF(MmQf|dsoy(eiQ>WTKcEQlnKOri5xYsqi61Y=I4kzAjn5~{IWrz_l))|Ls zvq7xgQs?Xx@`N?f7+3XKLyD~6DRJw*uj*j?yvT3}a;(j_?YOe%hUFcPGWRVBXzpMJ zM43g6DLFqS9tcTLSg=^&N-y0dXL816v&-nqC0iXdg7kV|PY+js`F8dm z2PuHw&k+8*&9SPQ6f!^5q0&AH(i+z3I7a?8O+S5`g)>}fG|BM&ZnmL;rk)|u{1!aZ zEZHpAMmK_v$GbrrWNP|^2^s*!0waLW=-h5PZa-4jWYUt(Hr@EA(m3Mc3^uDxwt-me^55FMA9^>hpp26MhqjLg#^Y7OIJ5%ZLdNx&uDgIIqc zZRZl|n6TyV)0^DDyVtw*jlWkDY&Gw4q;k!UwqSL6&sW$B*5Rc?&)dt29bDB*b6IBY z6SY6Unsf6AOQdEf=P1inu6(6hVZ0~v-<>;LAlcQ2u?wRWj5VczBT$Op#8IhppP-1t zfz5H59Aa~yh7EN;BXJsLyjkjqARS5iIhDVPj<=4AJb}m6M@n{xYj3qsR*Q8;hVxDyC4vLI;;?^eENOb5QARj#nII5l$MtBCI@5u~(ylFi$ zw6-+$$XQ}Ca>FWT>q{k)g{Ml(Yv=6aDfe?m|5|kbGtWS}fKWI+})F6`x@||0oJ^(g|+xi zqlPdy5;`g*i*C=Q(aGeDw!eQg&w>UUj^{o?PrlFI=34qAU2u@BgwrBiaM8zoDTFJ< zh7nWpv>dr?q;4ZA?}V}|7qWz4W?6#S&m>hs4IwvCBe@-C>+oohsQZ^JC*RfDRm!?y zS4$7oxcI|##ga*y5hV>J4a%HHl^t$pjY%caL%-FlRb<$A$E!ws?8hf0@(4HdgQ!@> zds{&g$ocr9W4I84TMa9-(&^_B*&R%^=@?Ntxi|Ejnh;z=!|uVj&3fiTngDPg=0=P2 zB)3#%HetD84ayj??qrxsd9nqrBem(8^_u_UY{1@R_vK-0H9N7lBX5K(^O2=0#TtUUGSz{ z%g>qU8#a$DyZ~EMa|8*@`GOhCW3%DN%xuS91T7~iXRr)SG`%=Lfu%U~Z_`1b=lSi?qpD4$vLh$?HU6t0MydaowUpb zQr{>_${AMesCEffZo`}K0^~x>RY_ZIG{(r39MP>@=aiM@C;K)jUcfQV8#?SDvq>9D zI{XeKM%$$XP5`7p3K0T}x;qn)VMo>2t}Ib(6zui;k}<<~KibAb%p)**e>ln<=qyWU zrRDy|UXFi9y~PdEFIAXejLA{K)6<)Q`?;Q5!KsuEw({!#Rl8*5_F{TP?u|5(Hijv( ztAA^I5+$A*+*e0V0R~fc{ET-RAS3suZ}TRk3r)xqj~g_hxB`qIK5z(5wxYboz%46G zq{izIz^5xW1Vq#%lhXaZL&)FJWp0VZNO%2&ADd?+J%K$fM#T_Eke1{dQsx48dUPUY zLS+DWMJeUSjYL453f@HpRGU6Dv)rw+-c6xB>(=p4U%}_p>z^I@Ow9`nkUG21?cMIh9}hN?R-d)*6%pr6d@mcb*ixr7 z)>Lo<&2F}~>WT1ybm^9UO{6P9;m+fU^06_$o9gBWL9_}EMZFD=rLJ~&e?fhDnJNBI zKM=-WR6g7HY5tHf=V~6~QIQ~rakNvcsamU8m28YE=z8+G7K=h%)l6k zmCpiDInKL6*e#)#Pt;ANmjf`8h-nEt&d}(SBZMI_A{BI#ck-_V7nx)K9_D9K-p@?Zh81#b@{wS?wCcJ%og)8RF*-0z+~)6f#T` zWqF7_CBcnn=S-1QykC*F0YTsKMVG49BuKQBH%WuDkEy%E?*x&tt%0m>>5^HCOq|ux zuvFB)JPR-W|%$24eEC^AtG3Gp4qdK%pjRijF5Sg3X}uaKEE z-L5p5aVR!NTM8T`4|2QA@hXiLXRcJveWZ%YeFfV%mO5q#($TJ`*U>hicS+CMj%Ip# zivoL;dd*araeJK9EA<(tihD50FHWbITBgF9E<33A+eMr2;cgI3Gg6<-2o|_g9|> zv5}i932( zYfTE9?4#nQhP@a|zm#9FST2 z!y+p3B;p>KkUzH!K;GkBW}bWssz)9b>Ulg^)EDca;jDl+q=243BddS$hY^fC6lbpM z(q_bo4V8~eVeA?0LFD6ZtKcmOH^75#q$Eo%a&qvE8Zsqg=$p}u^|>DSWUP5i{6)LAYF4E2DfGZuMJ zMwxxmkxQf}Q$V3&2w|$`9_SQS^2NVbTHh;atB>=A%!}k-f4*i$X8m}Ni^ppZXk5_oYF>Gq(& z0wy{LjJOu}69}~#UFPc;$7ka+=gl(FZCy4xEsk);+he>Nnl>hb5Ud-lj!CNicgd^2 z_Qgr_-&S7*#nLAI7r()P$`x~fy)+y=W~6aNh_humoZr7MWGSWJPLk}$#w_1n%(@? z3FnHf1lbxKJbQ9c&i<$(wd{tUTX6DAKs@cXIOBv~!9i{wD@*|kwfX~sjKASrNFGvN zrFc=!0Bb^OhR2f`%hrp2ibv#KUxl)Np1aixD9{^o=)*U%n%rTHX?FSWL^UGpHpY@7 z74U}KoIRwxI#>)Pn4($A`nw1%-D}`sGRZD8Z#lF$6 zOeA5)+W2qvA%m^|$WluUU-O+KtMqd;Pd58?qZj})MbxYGO<{z9U&t4D{S2G>e+J9K ztFZ?}ya>SVOLp9hpW)}G%kTrg*KXXXsLkGdgHb+R-ZXqdkdQC0_)`?6mqo8(EU#d( zy;u&aVPe6C=YgCRPV!mJ6R6kdY*`e+VGM~`VtC>{k27!9vAZT)x2~AiX5|m1Rq}_= z;A9LX^nd$l-9&2%4s~p5r6ad-siV`HtxKF}l&xGSYJmP=z!?Mlwmwef$EQq~7;#OE z)U5eS6dB~~1pkj#9(}T3j!((8Uf%!W49FfUAozijoxInUE7z`~U3Y^}xc3xp){#9D z<^Tz2xw}@o@fdUZ@hnW#dX6gDOj4R8dV}Dw`u!h@*K)-NrxT8%2`T}EvOImNF_N1S zy?uo6_ZS>Qga4Xme3j#aX+1qdFFE{NT0Wfusa$^;eL5xGE_66!5_N8!Z~jCAH2=${ z*goHjl|z|kbmIE{cl-PloSTtD+2=CDm~ZHRgXJ8~1(g4W=1c3=2eF#3tah7ho`zm4 z05P&?nyqq$nC?iJ-nK_iBo=u5l#|Ka3H7{UZ&O`~t-=triw=SE7ynzMAE{Mv-{7E_ zViZtA(0^wD{iCCcg@c{54Ro@U5p1QZq_XlEGtdBAQ9@nT?(zLO0#)q55G8_Ug~Xnu zR-^1~hp|cy&52iogG@o?-^AD8Jb^;@&Ea5jEicDlze6%>?u$-eE};bQ`T6@(bED0J zKYtdc?%9*<<$2LCBzVx9CA4YV|q-qg*-{yQ;|0=KIgI6~z0DKTtajw2Oms3L zn{C%{P`duw!(F@*P)lFy11|Z&x`E2<=$Ln38>UR~z6~za(3r;45kQK_^QTX%!s zNzoIFFH8|Y>YVrUL5#mgA-Jh>j7)n)5}iVM4%_@^GSwEIBA2g-;43* z*)i7u*xc8jo2z8&=8t7qo|B-rsGw)b8UXnu`RgE4u!(J8yIJi(5m3~aYsADcfZ!GG zzqa7p=sg`V_KjiqI*LA-=T;uiNRB;BZZ)~88 z`C%p8%hIev2rxS12@doqsrjgMg3{A&N8A?%Ui5vSHh7!iC^ltF&HqG~;=16=h0{ygy^@HxixUb1XYcR36SB}}o3nxu z_IpEmGh_CK<+sUh@2zbK9MqO!S5cao=8LSQg0Zv4?ju%ww^mvc0WU$q@!oo#2bv24 z+?c}14L2vlDn%Y0!t*z=$*a!`*|uAVu&NO!z_arim$=btpUPR5XGCG0U3YU`v>yMr z^zmTdcEa!APX zYF>^Q-TP11;{VgtMqC}7>B^2gN-3KYl33gS-p%f!X<_Hr?`rG8{jb9jmuQA9U;BeG zHj6Pk(UB5c6zwX%SNi*Py*)gk^?+729$bAN-EUd*RKN7{CM4`Q65a1qF*-QWACA&m zrT)B(M}yih{2r!Tiv5Y&O&=H_OtaHUz96Npo_k0eN|!*s2mLe!Zkuv>^E8Xa43ZwH zOI058AZznYGrRJ+`*GmZzMi6yliFmGMge6^j?|PN%ARns!Eg$ufpcLc#1Ns!1@1 zvC7N8M$mRgnixwEtX{ypBS^n`k@t2cCh#_6L6WtQb8E~*Vu+Rr)YsKZRX~hzLG*BE zaeU#LPo?RLm(Wzltk79Jd1Y$|6aWz1)wf1K1RtqS;qyQMy@H@B805vQ%wfSJB?m&&=^m4i* zYVH`zTTFbFtNFkAI`Khe4e^CdGZw;O0 zqkQe2|NG_y6D%h(|EZNf&77_!NU%0y={^E=*gKGQ=)LdKPM3zUlM@otH2X07Awv8o zY8Y7a1^&Yy%b%m{mNQ5sWNMTIq96Wtr>a(hL>Qi&F(ckgKkyvM0IH<_}v~Fv-GqDapig=3*ZMOx!%cYY)SKzo7ECyem z9Mj3C)tCYM?C9YIlt1?zTJXNOo&oVxu&uXKJs7i+j8p*Qvu2PAnY}b`KStdpi`trk ztAO}T8eOC%x)mu+4ps8sYZ=vYJp16SVWEEgQyFKSfWQ@O5id6GfL`|2<}hMXLPszS zgK>NWOoR zBRyKeUPevpqKKShD|MZ`R;~#PdNMB3LWjqFKNvH9k+;(`;-pyXM55?qaji#nl~K8m z_MifoM*W*X9CQiXAOH{cZcP0;Bn10E1)T@62Um>et2ci!J2$5-_HPy(AGif+BJpJ^ ziHWynC_%-NlrFY+(f7HyVvbDIM$5ci_i3?22ZkF>Y8RPBhgx-7k3M2>6m5R24C|~I z&RPh9xpMGzhN4bii*ryWaN^d(`0 zTOADlU)g`1p+SVMNLztd)c+;XjXox(VHQwqzu>FROvf0`s&|NEv26}(TAe;@=FpZq zaVs6mp>W0rM3Qg*6x5f_bPJd!6dQGmh?&v0rpBNfS$DW-{4L7#_~-eA@7<2BsZV=X zow){3aATmLZOQrs>uzDkXOD=IiX;Ue*B(^4RF%H zeaZ^*MWn4tBDj(wj114r(`)P96EHq4th-;tWiHhkp2rDlrklX}I@ib-nel0slFoQO zOeTc;Rh7sMIebO`1%u)=GlEj+7HU;c|Nj>2j)J-kpR)s3#+9AiB zd$hAk6;3pu9(GCR#)#>aCGPYq%r&i02$0L9=7AlIGYdlUO5%eH&M!ZWD&6^NBAj0Y9ZDcPg@r@8Y&-}e!aq0S(`}NuQ({;aigCPnq75U9cBH&Y7 ze)W0aD>muAepOKgm7uPg3Dz7G%)nEqTUm_&^^3(>+eEI;$ia`m>m0QHEkTt^=cx^JsBC68#H(3zc~Z$E9I)oSrF$3 zUClHXhMBZ|^1ikm3nL$Z@v|JRhud*IhOvx!6X<(YSX(9LG#yYuZeB{=7-MyPF;?_8 zy2i3iVKG2q!=JHN>~!#Bl{cwa6-yB@b<;8LSj}`f9pw7#x3yTD>C=>1S@H)~(n_K4 z2-yr{2?|1b#lS`qG@+823j;&UE5|2+EdU4nVw5=m>o_gj#K>>(*t=xI7{R)lJhLU{ z4IO6!x@1f$aDVIE@1a0lraN9!(j~_uGlks)!&davUFRNYHflp<|ENwAxsp~4Hun$Q z$w>@YzXp#VX~)ZP8`_b_sTg(Gt7?oXJW%^Pf0UW%YM+OGjKS}X`yO~{7WH6nX8S6Z ztl!5AnM2Lo*_}ZLvo%?iV;D2z>#qdpMx*xY2*GGlRzmHCom`VedAoR=(A1nO)Y>;5 zCK-~a;#g5yDgf7_phlkM@)C8s!xOu)N2UnQhif-v5kL$*t=X}L9EyBRq$V(sI{90> z=ghTPGswRVbTW@dS2H|)QYTY&I$ljbpNPTc_T|FEJkSW7MV!JM4I(ksRqQ8)V5>}v z2Sf^Z9_v;dKSp_orZm09jb8;C(vzFFJgoYuWRc|Tt_&3k({wPKiD|*m!+za$(l*!gNRo{xtmqjy1=kGzFkTH=Nc>EL@1Um0BiN1)wBO$i z6rG={bRcT|%A3s3xh!Bw?=L&_-X+6}L9i~xRj2}-)7fsoq0|;;PS%mcn%_#oV#kAp zGw^23c8_0~ ze}v9(p};6HM0+qF5^^>BBEI3d=2DW&O#|(;wg}?3?uO=w+{*)+^l_-gE zSw8GV=4_%U4*OU^hibDV38{Qb7P#Y8zh@BM9pEM_o2FuFc2LWrW2jRRB<+IE)G=Vx zuu?cp2-`hgqlsn|$nx@I%TC!`>bX^G00_oKboOGGXLgyLKXoo$^@L7v;GWqfUFw3< zekKMWo0LR;TaFY}Tt4!O$3MU@pqcw!0w0 zA}SnJ6Lb597|P5W8$OsEHTku2Kw9y4V=hx*K%iSn!#LW9W#~OiWf^dXEP$^2 zaok=UyGwy3GRp)bm6Gqr>8-4h@3=2`Eto2|JE6Sufh?%U6;ut1v1d@#EfcQP2chCt z+mB{Bk5~()7G>wM3KYf7Xh?LGbwg1uWLotmc_}Z_o;XOUDyfU?{9atAT$={v82^w9 z(MW$gINHt4xB3{bdbhRR%T}L?McK?!zkLK3(e>zKyei(yq%Nsijm~LV|9mll-XHavFcc$teX7v);H>=oN-+E_Q{c|! zp
    JV~-9AH}jxf6IF!PxrB9is{_9s@PYth^`pb%DkwghLdAyDREz(csf9)HcVRq z+2Vn~>{(S&_;bq_qA{v7XbU?yR7;~JrLfo;g$Lkm#ufO1P`QW_`zWW+4+7xzQZnO$ z5&GyJs4-VGb5MEDBc5=zxZh9xEVoY(|2yRv&!T7LAlIs@tw+4n?v1T8M>;hBv}2n) zcqi+>M*U@uY>4N3eDSAH2Rg@dsl!1py>kO39GMP#qOHipL~*cCac2_vH^6x@xmO|E zkWeyvl@P$2Iy*mCgVF+b{&|FY*5Ygi8237i)9YW#Fp& z?TJTQW+7U)xCE*`Nsx^yaiJ0KSW}}jc-ub)8Z8x(|K7G>`&l{Y&~W=q#^4Gf{}aJ%6kLXsmv6cr=Hi*uB`V26;dr4C$WrPnHO>g zg1@A%DvIWPDtXzll39kY6#%j;aN7grYJP9AlJgs3FnC?crv$wC7S4_Z?<_s0j;MmE z75yQGul2=bY%`l__1X3jxju2$Ws%hNv75ywfAqjgFO7wFsFDOW^)q2%VIF~WhwEW0 z45z^+r+}sJ{q+>X-w(}OiD(!*&cy4X&yM`!L0Fe+_RUfs@=J{AH#K~gArqT=#DcGE z!FwY(h&+&811rVCVoOuK)Z<-$EX zp`TzcUQC256@YWZ*GkE@P_et4D@qpM92fWA6c$MV=^qTu7&g)U?O~-fUR&xFqNiY1 zRd=|zUs_rmFZhKI|H}dcKhy%Okl(#y#QuMi81zsY56Y@757xBQqDNkd+XhLQhp2BB zBF^aJ__D676wLu|yYo6jNJNw^B+Ce;DYK!f$!dNs1*?D^97u^jKS++7S z5qE%zG#HY-SMUn^_yru=T6v`)CM%K<>_Z>tPe|js`c<|y7?qol&)C=>uLWkg5 zmzNcSAG_sL)E9or;i+O}tY^70@h7+=bG1;YDlX{<4zF_?{)K5B&?^tKZ6<$SD%@>F zY0cl2H7)%zKeDX%Eo7`ky^mzS)s;842cP{_;dzFuyd~Npb4u!bwkkhf8-^C2e3`q8>MuPhgiv0VxHxvrN9_`rJv&GX0fWz-L-Jg^B zrTsm>)-~j0F1sV=^V?UUi{L2cp%YwpvHwwLaSsCIrGI#({{QfbgDxMqR1Z0TcrO*~ z;`z(A$}o+TN+QHHSvsC2`@?YICZ>s8&hY;SmOyF0PKaZIauCMS*cOpAMn@6@g@rZ+ z+GT--(uT6#mL8^*mMf7BE`(AVj?zLY-2$aI%TjtREu}5AWdGlcWLvfz(%wn72tGczwUOgGD3RXpWs%onuMxs9!*D^698AupW z9qTDQu4`!>n|)e35b4t+d(+uOx+>VC#nXCiRex_Fq4fu1f`;C`>g;IuS%6KgEa3NK z<8dsc`?SDP0g~*EC3QU&OZH-QpPowNEUd4rJF9MGAgb@H`mjRGq;?wFRDVQY7mMpm z3yoB7eQ!#O#`XIBDXqU>Pt~tCe{Q#awQI4YOm?Q3muUO6`nZ4^zi5|(wb9R)oyarG?mI|I@A0U!+**&lW7_bYKF2biJ4BDbi~*$h?kQ`rCC(LG-oO(nPxMU zfo#Z#n8t)+3Ph87roL-y2!!U4SEWNCIM16i~-&+f55;kxC2bL$FE@jH{5p$Z8gxOiP%Y`hTTa_!v{AKQz&- ztE+dosg?pN)leO5WpNTS>IKdEEn21zMm&?r28Q52{$e2tGL44^Ys=^?m6p=kOy!gJ zWm*oFGKS@mqj~{|SONA*T2)3XC|J--en+NrnPlNhAmXMqmiXs^*154{EVE{Uc%xqF zrbcQ~sezg;wQkW;dVezGrdC0qf!0|>JG6xErVZ8_?B(25cZrr-sL&=jKwW>zKyYMY zdRn1&@Rid0oIhoRl)+X4)b&e?HUVlOtk^(xldhvgf^7r+@TXa!2`LC9AsB@wEO&eU2mN) z(2^JsyA6qfeOf%LSJx?Y8BU1m=}0P;*H3vVXSjksEcm>#5Xa`}jj5D2fEfH2Xje-M zUYHgYX}1u_p<|fIC+pI5g6KGn%JeZPZ-0!!1})tOab>y=S>3W~x@o{- z6^;@rhHTgRaoor06T(UUbrK4+@5bO?r=!vckDD+nwK+>2{{|{u4N@g}r(r z#3beB`G2`XrO(iR6q2H8yS9v;(z-=*`%fk%CVpj%l#pt?g4*)yP|xS-&NBKOeW5_5 zXkVr;A)BGS=+F;j%O|69F0Lne?{U*t=^g?1HKy7R)R*<>%xD>K zelPqrp$&BF_?^mZ&U<*tWDIuhrw3HJj~--_0)GL8jxYs2@VLev2$;`DG7X6UI9Z)P zq|z`w46OtLJ1=V3U8B%9@FSsRP+Ze)dQ@;zLq|~>(%J5G-n}dRZ6&kyH|cQ!{Vil( zBUvQvj*~0_A1JCtaGZW|?6>KdP}!4A%l>(MnVv>A%d;!|qA>*t&-9-JFU4GZhn`jG z8GrgNsQJ%JSLgNFP`5;(=b+M9GO8cg+ygIz^4i?=eR@IY>IcG?+on?I4+Y47p-DB8 zjrlar)KtoI{#kBcqL&4?ub@Df+zMt*USCD_T8O$J$~oMrC6*TP7j@H5trGV$r0P6I zV7EZ{MWH`5`DrX*wx&`d;C`jjYoc_PMSqNB290QXlRn_4*F{5hBmEE4DHBC$%EsbR zQGb7p;)4MAjY@Bd*2F3L?<8typrrUykb$JXr#}c1|BL*QF|18D{ZTYBZ_=M&Ec6IS ziv{(%>CbeR(9Aog)}hA!xSm1p@K?*ce*-6R%odqGGk?I4@6q3dmHq)4jbw+B?|%#2 zbX;ioJ_tcGO*#d0v?il&mPAi+AKQvsQnPf*?8tX6qfOPsf-ttT+RZX6Dm&RF6beP3 zdotcJDI1Kn7wkq=;Au=BIyoGfXCNVjCKTj+fxU@mxp*d*7aHec0GTUPt`xbN8x%fe zikv87g)u~0cpQaf zd<7Mi9GR0B@*S&l&9pCl-HEaNX?ZY8MoXaYHGDf}733;(88<{E%)< z^k)X#To3=_O2$lKPsc9P-MkDAhJ~{x<=xTJw2aRY5SSZIA6Gij5cFzsGk@S)4@C65 zwN^6CwOI9`5c(3?cqRrH_gSq+ox(wtSBZc-Jr5N%^t3N&WB|TT_i4!i3lxwI=*p)Y zn7fb%HlXhf8OGjhzswj!=Crh~YwQYb+p~UaV@s%YPgiH_);$|Gx3{{v5v?7s<)+cb zxlT0Bb!OwtE!K>gx6c4v^M9mL0F=It*NfQL0J0O$RCpt746=H1pPNG#AZC|Y`SZt( zG`yKMBPV_0I|S?}?$t7GU%;*_39bCGO*x3+R|<=9WNe!8jH- zw5ZJS(k@wws?6w1rejjyZ>08aizReJBo%IRb3b3|VuR6Uo&sL?L5j(isqs%CYe@@b zIID7kF*hyqmy+7D(SPa^xNVm54hVF3{;4I9+mh)F22+_YFP>ux`{F)8l;uRX>1-cH zXqPnGsFRr|UZwJtjG=1x2^l_tF-mS0@sdC38kMi$kDw8W#zceJowZuV=@agQ_#l5w znB`g+sb1mhkrXh$X4y(<-CntwmVwah5#oA_p-U<_5$ zGDc%(b6Z=!QQ%w6YZS&HWovIaN8wMw1B-9N+Vyl=>(yIgy}BrAhpc2}8YL-i*_KY7 ztV+`WKcC?{RKA@t3pu*BtqZJFSd2d)+cc07-Z#4x&7Dnd{yg6)lz@`z%=Sl-`9Z~*io zck_Lshk9JRJs=t>1jmKB~>`6+(J z@(S}J2Q{Q{a-ASTnIViecW(FIagWQ%G41y?zS)gpooM z@c<2$7TykMs4LH*UUYfts(!Ncn`?eZl}f zg)wx@0N0J(X(OJ^=$2()HLn)=Cn~=zx(_9(B@L04%{F_Zn}5!~5Ec5D4ibN6G_AD} zzxY^T_JF##qM8~B%aZ1OC}X^kQu`JDwaRaZnt!YcRrP7fq>eIihJW1UY{Xhkn>NdX zKy|<6-wD*;GtE08sLYryW<-e)?7k;;B>e$u?v!QhU9jPK6*Y$o8{Tl`N`+QvG ze}71rVC)fis9TZ<>EJ2JR`80F^2rkB7dihm$1Ta2bR?&wz>e`)w<4)1{3SfS$uKfV z3R=JT!eY+i7+IIfl3SIgiR|KvBWH*s;OEuF5tq~wLOB^xP_Dc7-BbNjpC|dHYJrZCWj-ucmv4;YS~eN!LvwER`NCd`R4Xh5%zP$V^nU>j zdOkNvbyB_117;mhiTiL_TBcy&Grvl->zO_SlCCX5dFLd`q7x-lBj*&ykj^ zR3@z`y0<8XlBHEhlCk7IV=ofWsuF|d)ECS}qnWf?I#-o~5=JFQM8u+7I!^>dg|wEb zbu4wp#rHGayeYTT>MN+(x3O`nFMpOSERQdpzQv2ui|Z5#Qd zB(+GbXda|>CW55ky@mG13K0wfXAm8yoek3MJG!Hujn$5)Q(6wWb-l4ogu?jj2Q|srw?r z-TG0$OfmDx%(qcX`Fc`D!WS{3dN*V%SZas3$vFXQy98^y3oT~8Yv>$EX0!uiRae?m z_}pvK=rBy5Z_#_!8QEmix_@_*w8E8(2{R5kf^056;GzbLOPr2uqFYaG6Fkrv($n_51%7~QN<>9$WdjE=H}>(a41KM%d2x#e@K3{W|+=-h*mR&2C01e z2sMP;YjU)9h+1kxOKJ+g*W=&D@=$q4jF%@HyRtCwOmEmpS|Rr9V_2br*NOd^ z4LN#oxd5yL=#MPWN{9Vo^X-Wo{a7IF2hvYWB%eUCkAZq+=NQ=iLI9?~@ zr+|ky4Rgm7yEDuc2dIe941~qc8V_$7;?7|XLk6+nbrh}e&Tt20EWZ@dRFDoYbwhkn zjJ$th974Z0F${3wtVLk_Ty;*J-Pi zP0IwrAT!Lj34GcoSB8g?IKPt%!iLD-$s+f_eZg@9q!2Si?`F#fUqY`!{bM0O7V^G%VB|A zyMM>SKNg|KKP}+>>?n6|5MlPK3Vto&;nxppD;yk@z4DXPm0z9hxb+U&Fv4$y&G>q= z799L0$A2&#>CfSgCuu$+9W>s<-&yq3!C{F9N!{d?I|g|+Qd9@*d;GplgY5Fk$LOV+ zoMealKns!!80PWsJ%(}L61B!7l?j1_5P#LRrVv%NBhs{R`;aufHYb&b+mF%A+DGl5 zBemAHtbLFi++KT(wv9*?;awp>ROX~P?e<4#Uf5RKIV{c3NxmUz!LYO#Cxdz*CoRQp zSvX|#NN06=q_eTU5-T!RmUJ?Ht=XQF8t)f+GnY5nY5>-}WLR1+R5pou?l@Y|F@KEX zk=jh-yq=Rn9;riE*;Slo}PfNKhXO#;FrZCf%VZ9h7W z<63YWE^s_SlAVQh6B(En9i<9%4AT|2bTQ4Ph2)pI?f2S`$j?bp`>_3(`Fz&?ig-FJ zoO7KAh@4BDOU>sBXV84Eajr9;>wlbW&OSUt&dug?oAV;`+3oBzpI18%%1wA4blzmb z-{QPYJmn_2-F$A5JI!a8+-p8Bk*^U?^f5j7uZ}jEz0E3;XbahB2iZwS&l4jj4WRS6 z3O&!w=ymQSl~7LUE99noXd2y1)9E>yK`+ouR%sTOQ@Qjt@<;lErGLk1wrw7r zV)M})+amJXs_9hQa++&vrqgU&Xr8T)=G&5Vy6vOnvt37L*nU7&ws&ZO-9`)TGA**t zpby#0X|df;etRud+s~#Y_7zlPZ=_oLg%q&wraF6s>g@;VO#2sUseO=^+3%&Z?61(- z_IKzU`+Kw;Blil&LR#qv&{rzQnG|%i(Q3zLI@gh)2FE^H;~1dx9G|AOj(e%mSwT(C z71Zp!jar*i3S|_ik_3{n0L4KavYWWZ2x3MhyU!66E$h=L+A&-s$9X_w9Q_e;+`-{ZW# z^Zn2H_I~`}!vGeFRRY^DyKK#pORBr{&?X}ut`1a(x__(dt3y_-*Np0pX~q39D{Rns z!iXBWZO~+oZu>($Mrf0rjM>$JZar!n_0_!*e@yT7n=HfVT6#jbYZ0wYEXnTgPDZ0N zVE5?$1-v94G2@1jFyj##-E1Um(naG-8WuGy@rRAg)t9Oe0$RJ3OoWV8X4DXvW+ftx zk%S(O8h?#_3B9-1NHn&@ZAXtr=PXcAATV*GzFBXK>hVb9*`iMM-zvA6RwMH#2^901uxUFh&4fT% zmP?pjNsiRIMD)<6xZyOeThl_DN_ZJ*?KUIHgnx{vz`WKxj&!7HbM8{w?{Rued(M1v zKHsK{_q=YI88@Bf0*RW@cIV@=<{eGsG21xrTrWycT7*KBd!eD2zb1R(O@H~k7>Duv zHPwp=n8;t#1>7~fuM9IaD5w%BpwLtNCe_Sq9eal4oj2DB1#<+(MGR-P&Ig%3t%=!< zS$|KxI1a~an2Q>L$s;1$9nQJal4dk)Box$YsAKgCiEGni##jr|%So6Y4J@pYBF!;~ zhXwpKhc7&QZ$=e~Sb&ABZ4o)&U~N*dSU`2G^eQh-WCe9tA}~Ae369btLlB{GjOKB@yEDH!C7Q&df^#X zi~?{rCuAE|kAjKzt+r#t6s)1h840@A<%i5(O;$Q&tD(opg0)yzgm#=ucf4CSqkqYS zaTdivk5I~#=1Z9K5M*uV6H??6s9*ynT`vzr2@%Tkr4k+Tr_ib40$fPP7$yLA$cwJ@ zF@`94=op)$x^0t+QAsNY$pi!4e7hp~gO=|yD=^8JTvTiC(HAamYEQ}t z+hR~QoKTOz%)IHEg&6iC4vP=3mw&u4wvcSwi$vNBGQE5RoSUs^l+u{A+6s~aMMkXG z+1g4wD8^Y27Oe4f``K{+tm76n(*d6BUA4;pLa26`6RD6?Rq?2K1yMXVAk`&xbks*~{+``Mhg4cQEuw+aM zaI9{}9en8DCh*S9CojIk)qh|k?#iNiCQ}rAmr&iYRJiND ztt+j*c+}Fv&6x&7U~!(Sb1eAz1N@Nf`w?YxGJdhy+seiNNZEYIG1_<^?&pm^P8W?d ze(p@$nWC`Pxqpf8d&AIGNJn#Ty)j z1NbA^Y}pNQ>OfTdiAp+WR>C6390IrFj;YZglitGH8r7(GvVRpWjZd7|r24M{u66B) zs#VS$?R*!1FT&sO-ssvW8s5jh$-O=^9=7^y z75||~QA6zLW}Lu!YOZh1J$j46m zNH|;^a$U_RKgla5h>5(igl^ek(~2nL5a_0}ipvA_Xf0k*E-ExJNld0{LZ;F^DzqAL+IZGJ7<3i1szf zxMRkQ(|@;wj9%I7h{c*{;?g%giylU}Dz{iwb(1vGK<-vlnKs!|Mb9}iTt)Rl&NZka zkkugrMiY(ng3QseY!npaOf1jo3|r35nK+eTYh*`DHabuv@IFy zG7@V!LWE0&)bvqgQ8=-L-(vt#Z-&xaOj3G@Nqw1FfbNQ`!bFEl@z)0)+#Z5e#_hQ|Rd!KrEoRn^aFz zkzYzz%hher>ixcg6fW`=rr>Nx@enQ!sQqYR{<2^|eUfw?e8;B_`T)Kxkp8${U>g?k*VhCd zp^yYLvi}<#5TDjrx@{0U$jx*tQn+mhcXsq2e46a@44^-Sd;C6S2=}sK1LQ_OUhgO` z^4yN+e9Dv9TQ64y1Bw)0i4u)98(^+@R~eUUsG!Ye84 zFa7-?x3cqUXX)$G<2MgYiGWhjq?Q-CE(|sm-68_z>h_O2vME5nX;RodIf)=No(={I z_<&3QJcPg8kAI}_Vd+OH4z{NsFMmjv3;kunMSh94VNnqD?85uOps%nq=q?kU_JT5@ zwih;eQlhxr)7d^K#-~InWlc&<*#?{A(8f^+C_WmRR{B&Yh3pxhLU9-toLz%rCPi}} zE!cw^pQlXB3aACUpacU&ZlBUl(Jo4fxpbDVwDn^m{VG||ar9B)9}@K`(SJxmAWro& z_3yzfUqLoXg`H($!I;FTudPdo6FTJm2@^S|&42H(XbSRW7!)V&=I`{;mWicu@BT7z zQs!)F9t-K|aFaMsoJ_6z-ICrzjW5#yJRs>~)bugki)ST$8T%!D4F@EBliCNSA5!fl zN;OuKbR3m0rj=rrq}5`nq<<%iHIl|euXt6QA}$hFNqV)oR?_Rm4oPnoLy|ru_DQ-= zJTDFa;zjY2p{sg zWqz0I5y>-U{xR1Rl4r{NQ?6Ge&y@N7t~Vsll=-(^?@FF2^Y6JnkbgW==09{7N}eh4 z?h`%x-LM8D}+*41ZA#EG0D9KQjc2#z59Pq zO9u!y^MeiK3jhHB6_epc9Fs0q7m}w4lLmSnf6Gb(F%*XXShZTmYQ1gTje=G?4qg`Z zf*U~;6hT37na-R}qnQiIv@S#+#J6xEf(swOhZ4_JMMMtdob%^9e?s#9@%jc}19Jk8 z4-eKFdIEVQN4T|=j2t&EtMI{9_E$cx)DHN2-1mG28IEdMq557#dRO3U?22M($g zlriC81f!!ELd`)1V?{MBFnGYPgmrGp{4)cn6%<#sg5fMU9E|fi%iTOm9KgiN)zu3o zSD!J}c*e{V&__#si_#}hO9u$51d|3zY5@QM=aUgu9h0?tFMkPm8^?8iLjVN0f)0|R zWazNhlxTrCNF5d_LAD%TwkbkKL>+-8TV4VSawTAw*fNnD^2giQT{goNRR~OwAH5%vorH%=FNNm``;VB z_N`CeB%?_hv?RK-S(>S)VQBau{&NwD>j_ zF-Hwk*KNZb#pqexc5oKPcXjOO*cH#{XIq~NkPxH{TYm*Rtv_hwbV2JZd$e=Z)-pN0 z^PH`XkLz~lpy{|;F6Sq&pjD@}vs!0PGe z6v$ZT%$%iV1Z}J(*k7K8=sNv;I#+Ovvr?~~bXs?u{hF!CQ|_-`Y?!WYn_8|j3&GBu zl|F+DcYh8nxg49<-)ESHyI0Vo;oInYTMcVX9@5;g9>>x1BRMQ@KPJc%Za)^J6|_nr zKQ#*4^Z(G>Pt6Lgrp6!zX?X+rXibm;)WBbN1WBP~{Iw45)a0toTeof%G+Oh5Wryxb zN@p5YCm&YsN!Jd$jG8^|w^_Wo-1ad{*|(#*+kcnS97j-dxV>sGIk+cCchX&K1yxY6 z`dB};!Xf&3!*LyHut$Qlnc5WEME3}4k)j3H$aVHvxg78Y3_E@b3u@5wjX7b zPLz^7h65uMRj8d}5Y1tP55ozK;r0{r?;WHL>g4laujaX3dTd*h+xuy|LOa-f%M7RA zuz#V1WlscYXGzO0Xsu-c>6UPEVQ}o>+w7v~meKw6 zfS|`8k|tL(5VDPt0$*C)(&lVYGnVeCrsb+>%XBrvR5fz~VkMmn-RV#V&X1#`XH?fx zvxb>b_48WV%}uD=X5}V20@O1vluQ2hQ-2>^k+tl+2Al20(<||vxfpIJ~|9`dJ zVH^pxv&RS97h5DqN9ZW4!UT{rMgsH>#tHOouVIW{%W|QnHohN<4ZE5RR@l7FPk$#A zI?0%8pKlXW%QH2&OfWTY{1~5fO3=QyMi3vb*?iSmEU7hC;l7%nHAo*ucA`RmedXLF zXlD(SytNYn`{9Rs;@fw21qcpYFGUH*Xmdk{4fK z0AKh-FGJC#f0Ik!{d{T7B7elr2J8>e z4=VKi^h2D=Q8&0_LHc1j$T9pQ7-FcHxZj3w-{RF}MXBm@?_X&zG?V%-Bet=g# zgEZn=6W?w3jeoQ(!&ECWHqJ zs;lJ@+Tf9MhC9~LX7*WT*0A%cJEpn#(bX;0i-*TF1j2A3zeOFlEi7~=R7B$hpH(7@ zc$q9Z%JU#Am8%BTa1gvUGZPX)hL@#()Y8UP?D?tiCHan51waKUtqypCE-ALn&``k4jkeO@}6ROkhI5oJaRd?*oW z5XmD5>YOZAT4pPd`M`dOKE|;8c#wXMeqKQ__X$u$!F<91^W0T4GtRNpyh;fxIv+8{ zOV!mig|0Jq`E}FfEGH;5uUHx|3whm^-h~cRG|loa&)cs`#D7mW5K(xZ?6+)vAgAZC zD+2J-T)KRUZh~%1{k&VASQx^y`SF+OS6KX4kyjRJJpeT){PgS47=e2L=`KjGaKL_s zUIno%SwM4WAF(xl=4hpof(h_9QEfU}Rt7%rCFq{-h?=0}Z_#HJdX0XYPezSbpFe{d z0C)YJ60>{(bbnZJLT@3P<#<0>aI5md?+Lo2+D-Fke_x?5v0p-So~;%rL+cL|`Xc=y zDo2?BXJ-XJpB{>GjhRUa08Q0fc~|Te5H?$jM>&XZG_?d?@$c3DX04&{U<}^Kj^=z zll8%>K>i=dqr$~=S9jB6O9hsxyPZc556Zw=j_nVDRZX|_LS7YaUr=}9egcpXb&Lyu z)YmbNGJh^0d;nj66%_}BAGOYHUX^~)0N68LkJ^TyJHrdKncoeHWg@5uMJ!*CaF?vi zs}inQ2`7nFmB(0lPrqn_`mS~KaI)&6rO6}?TrFA@(Ja=?UzYTXI{;CnCeCzb>5&FP zU9f&`4m+(A>lG0a8$bbgJoRdhk?tvg@Ikz#RDUy9`Bv_`)Mkhjai_S8ErG{n6Y!ZX zjPs#^rE8v{eXb(WZW}1zS0~dl)qaDzZc6#Eb{ck_GRA z#30&5L=j;Tg=w(=Im_LHt$@}KL1QA*~192~ak5Zap zUm99S=A}`1@@=9=5f6x7EHE6dJZ-x$j_M#N`oWZ#8SoMRTSbJEkaI_E1S`LPb#u`l za~4L#=6*e^6>@H+e`vvSoIfb`u^orz|9^Gmf4h-i>_^V46i#@Dxdo?h3>Vd9UB7Q1 zd*h%uq=*CJ?O?Lm(&(J#sK(r_I|5=@p*QJ8=tPJL3W(!iGFv{}j#xpF;@rMTpd4td z<_1}s1;k09u3T^?RJY`6H5?F+aq(TFbgz!+$2p?$R`cYY_JBwWirgNmvn*Q5HGe{f z-XaT1oDGR#3t6;+$vF}g;7xCzl>r&9Od6(sppYNY?IXMuZ9`V@!`mKeeSE_wM4Gd+URu(#jex(s}ep9w1GC3 z7Kw+jq#o_EXrxGYA1~6D%cM+Ge1B+?9*7ocTWaW4s-L{|jmQn!kxEX{y*KxIy1Xsk zjnC7@NQ-xSD&Z?q_a#!IA$;sPe$gu?Z@nHJio8s36Lg7G@2AP18uG-3n|dSD^zhIP z+Lua-$Q13Lqz^#~2=HF178_n9HXiZ3Ovmd`>ukdKrc^2!X-ZAeBT)7dg@2>+{JWz! z=p-xnDEg15lCRLp=uPi))DZP-pCqq%wfcyWMMo@`orpju`U#jwh%@+&z~1$+@gb_i z)6qj`VXXJU%FkkS64rkme)%TMc?)t4l%`DCsP&j<&wVcTDtWIqWv3~3;0Bqggf}`x z?`&K}p9&;=Aun6(T&k=7S$}GZhkTxv`XW6!32V~_TI%bru-U&74|$7pp-A6@^%t>z zik|j#`C5GOo6l26yv4Vpk#1d>ruU>0Sp1{7@3N40)z%`t|2VeC&_KN}@=GU4?^hP}~YUu?KOKHT)vA#ce-FMp(9pP!wPTFk%# zEwqky;$|C=p1Ezu@6K6!t$>6N_Ie-e^%}k#xcn}ovllZSv|SPDuQ-}tU^i{{+`l1; z+iYOZMxq` zyNmevH37(cCUt;!hJWefMf#0t`kVyL=P%JpzSQp?pS<i{A@amJ0F;?aT#H3gGL(m+ zMd2x(2y7PxEPwgIW>H_-O1kRG@$x~jQ_UiPlcvRrqG+t>u>Js>8_Xp<>`syJiiA&! ztVK|;R}+4AD**Ck_Nds%Xh&S}{}jiCxVtDeH;a2t6-Dft*jg0#%HQsyNF;oXVK{$( zQQY6LPpMO5t9niY*so`U_cqrfS%ttA> zMrrXr{mf-r8(+hNdUxQONMdM>QWS?n{+OpF2q5te-AZ?0^44=hA%DU`#Rc;$`A425WvPKyy?$o4V#Hc#hepIh#q zrzgc`^ts)D{=4V}+2@w~FVe?kpIh#KoUY0~x7_FGtMoP5=a&0# zq5$MRx9AIxXym?ZxgQhVvd=B|)8ZMaXDKe4fFb_31FMfwok)^Lq|q0WrRvD@ZBR=G z2pQ0I&-V@h0C*ge;YJ*jtBNjvYflqF6o%gs=t3z%xd|2&*IQdyR=^LH8WYpRgrrep z4Mx6Aw}fxhSE$jN_`x6Gk20R2MM&C)-R$h{nfE#GnVgwFe}DZ3unAM( z^yK7C>62cU)*<-~eOtHo^)=lJyq4q2*a>{Y3mU}nkX(`x@nlm*hSem0>o7{ZNZ;O< zZbWN(%QigOG8~nI>Q5dw>RYT0OXvK4;<_A&n$p-%65n=wqR{bejviAOu@}cn>s#w3 zqd~{|=TQiObS+3ii(WV`2`mPoZQ7x1xMY3^WvfM@Sq*HPLJh+LQwQ=`ny&P1^Hu$T ztXM-zVD=*VoC&`n>n>@37!?>fN*sy>#GXLvspC8GGlAj!USU^YC|}skAcN~^Xqe0( zjqx#zAj>muU<=IUs~34|v06u2ahGbSeT-uAG|Vv*Bw$#pf8#qXFt zMfw|VuC{UeT)2WpJ6&O+E6jF;;~n9>cf~Ip6j-_@&PGFD0%Vu*QJ@Ht`C7Og!xt#L> zmqlJGEh<%*ATJUmZc(FfNSB##fy_`Y-70r{Iv3jEfR|~Ii!xC44vZ(KNj#>kjsE86 zE3FB*OayD~$|}3Y&(h6^X|1 z(TcJ}8{Ua3yL1loSfg!2gTekntVO7WNyFQCfwF2ti$UvL8C6{{IPBg01XK~$ThIQx z{)~aw>(9F2L#G36*kRDPqA$P*nq=!@bbQ#RzDpVIfYc*x9=}2N^*2z1E%3epP)i30 z>M4^xlbnuWe_MAGRTTb?O*?TCw6v5$6bS)qZqo=w4J~*9i;eVx4NwO!crrOjhE8U( z&P-ZZU9$We^ubqNd73QDTJqqV55D;u{1?`JQre~$mu9WZ%=z|x?{A;q|NiAy0GH5U z*nIM2xww(4aBEe#)zoy#s-^NN%WJl5hX=Oj8cnY%e+ZYt5!@FfY;fPO8p2xj+f6?; zUE_`~@~KwcX!4d}D<7hA<#M$$MY^)MV_$1K4gr3H8yA&|Ten>yr0v!TT@%u$ScDfR zrzVR=Rjj3cjDj)fWv?wQanp7LL)Me^LS6EzBMR%1w^~9L%8&g(G;d3f4uLKFIqs5J zYKSlle?R1Fyx?%RURbI;6jq>Nh+(uYf`e8J=hO2&ZQCoTU^AKRV>_^&!W{P-3%oVM zaQqOcL1!4cYP)vuF~dMQb1#lKj_HWu4TgBXPYuJQYWv&8km~(7Mlh=5I8HE}*mJ#? zmxhx%#+9e>eorO0)eg#m6uhb7G^KSg`Cbxlf9XizZH9>B@hZcqJ*7VTp6)w1tHLB1 z1}(?)MI0$rLIUS0;Z^atECLmzzb6FE#PKdBl;L{}$M%UdWEi4$AS4ew$#8O?ZRr(G z4syuHkcGi8a#*gRz@QP|7R93=j*A$L;eA}9id+JyWjkK`Mod00;{&DlA!QJFR3&lj zf1vI*O1ec{(V=0QA?ELLVls-W``ELsu7M`3`vI4MzhVcpJ!9#^KGjq|#b-J`!F7h$ z{dUEFmBLuMbYu>nV^(S3q+UC;7s@e_qZG#+N=oo0o$G1>6Y0a{9@&9;EU2+8k|7P6 zp?HMh|8#X5UnwpxGbHw;%WXHXn_~8nedvw09V+G$(lhoq7L}=qb+OaPSD&;$TuUtG(4;py( zh)8|Nord(*d1ZH-Dmw1MqU&RKiI)26r-hE(pqnmo4uixe^`qea7(_HA_R2KjdJ4$g!)7ve&Q^b1Tf+{(Vd6vInCd>i725IomG^(Ez(D8L!4qlUAX=)EV9!3JfWLB4n1z)!ums&0UuuVLUH zP)i30*5f6tnvk?lbhL{|8I78X7|_cA3p(L9<~X5y1L3{K8Sf*xL|5gToDT;aYig?m8z^z zQ`XdEMJqC#*O|ho!7x~+MzT<5g$turF~pS;RSY&GR;6TxR)3Q+&%yG`3&ngIwR*qK&t{TERu@0|fDrKKw3=RE&t-)Xh-$i& zl5|>BSn5)z)hg3d?<~8msU=ye>CHWR!9yT;PU|$KP*qADf(V?zj^n^g~nykv^I)Uz3{78Ty81{n~ zZsS&7WH)#Ach3%UyVD1s=Ahvw9*%Wt z<42vTt%|niux3Zww13+oK)-d~G>VKHM0ov>KXKaUH(Cc)#9GFVSc4EoUbnRudxi}T z8J!VNY=4g*Y7C*Ho7#^wUVt&67&ea4^1oBw%@h^ z+YZ+eK^VI5573*KZosq?pMj(u5257?^lBu&LF9`ao`sYf9&zx;uK2iv&$;8{ z4nFUSFF5$3JHFuHORo5YgFkV{CmcNEicdQDvO7NM;484|f=_+6!)x%g1CL;L9DE%% zT=1xaKZ8v-+-@x1OZ;|0_a9J82MFd71j+6K002-1li@}jlN6Rde_awnSQ^R>8l%uQ zO&WF!6qOdxN;eu7Q-nHAUeckHnK(0P3kdECiu+2%6$MdLP?%OK@`LB_gMXCA`(~0R zX;Tm9uJ&d7>n z%9A~GP*{Z zrpyh7B^|a-)|8b<&(!>OhWQ08$LV}WQ`RD4Od8d3O-;%vhK7#W<7u;XvbxQo0JX@f zY(C0RS6^zcd>jo287k@<4tg;k3q5e5hLHE@&4ooC)S|`w7N|jm>3tns$G}U4o!(2g=!}xLHp?+qF zvj$ztd<%96=4tCKGG@ADSX{=mNZ@ho6rr?EOQ1(G2i@2;GXb&S#U3YtCuVwc*4rJc zPm$kZf2+|!X~X6%(QMj{4u)mZOi!(P(dF3hX4ra9l=RKQ$v(kJFS#;ib+z9K^#Gle z6LKa>&4oMFJ4C&NBJ7hhPSIjcOno$M6iq+l;ExpH9rF68@D3-EgCCf}JJSgVPbI1$ z?JjPPX!_88InA}KX&=#cFH#s3Ix<6LeY==wf5DK*jP`hqF%u+|sI)3HfyywfAj=0O zMNUX2pLR;T(8c+$g&}Z#q9L>(D~t~l&X^VFXp@&w92f8tq+KXMZ&o!an%$#uo^hJh z^9-RjEvqE_s%H8{qw(juo4?SC{YhO*`|H*ibxm%ZF6r=2QC)bE`d3oZ(~?;a-(mX)b!|i%p!VVP>DN6tg*Ry97gUPUJj<}OxaYL1nXE}h zxs-O{twImUw z43Eo6nJ4_RTDIQALB8H!3nq37cE6>oNG;jZZhXh!vORPsMKfzJ8_*?O7DfGmcrL8A z(_NAhSH+JE?u?`xR1|ZThDb;2Dt`9hC;UQ%94^20-MA*;<$KO0{3b&9y(ENIe@&xj z6>X23)Ftc?ax=4pL5FZ06CPOjgG%2*lbx;+sVm6EHifaku2RZ6dm2zO1s^4+O| zX?^Rl!e{47y>uJGVh+yEaNe$4U2tTYyJ3nqt9nkQP8+X`9>;yxHT1=;SB4=QU*?nq zndTZfT|OzWa_zE$8FPQtuK2+Z>H-NyCcc=wWX>wq$q7{vij#xqCQBclE;KU_SpRHh zW?)cb0G=uW2QHH@&UKOjUxp5p-v+$&z!*iIUwCrEeC5gh!qSr;%oC7--UiJO%g(@H zgQD=VC|Kd1c_uQ*S7+LyC@PW!E7G5DDhEzd%(QbXn4J;PQoYKo1+C zI4^v%{X#z$(3LimCoU9YO4kMJJG0PS25}<7q9LXMM{Esm6)13%7{fk7Wdx5wm$C1R5emYB+b4!_g{ zCYC2a7ogf;<2t!#hh+G05lGD55CT^#LlBoxIEo9C9q6 zV^AjZEfZsU6$%s=ojiXT+hlLxY4o6EhgiZ7JP-%P5cLSCVgnh(`W^-bB@{)=b3uwG zE!U6%u3dpFT>%EaE{d8bl@K+c6+w`+ju^dTU{F9&yQvzYmVNS(GoZm{D-R;bE=#wApMmV(yJpr(t7y*s2{B8_zE)_ yL|YQw3&NAZiu6_*%Ye#&V4x{Sc^DWpP)tgl235p9dFD!GE+Jk92JyL|;s5}0b2K*q delta 34555 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 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 9355b4155..cea7a793a 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.10-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.12-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/gradlew b/gradlew index 1aa94a426..f5feea6d6 100755 --- a/gradlew +++ b/gradlew @@ -15,6 +15,8 @@ # See the License for the specific language governing permissions and # limitations under the License. # +# SPDX-License-Identifier: Apache-2.0 +# ############################################################################## # @@ -55,7 +57,7 @@ # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template -# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. @@ -84,7 +86,8 @@ done # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) -APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit +APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s +' "$PWD" ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum diff --git a/gradlew.bat b/gradlew.bat index 6689b85be..9b42019c7 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -13,6 +13,8 @@ @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem +@rem SPDX-License-Identifier: Apache-2.0 +@rem @if "%DEBUG%"=="" @echo off @rem ########################################################################## @@ -43,11 +45,11 @@ set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 if %ERRORLEVEL% equ 0 goto execute -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. +echo. 1>&2 +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 goto fail @@ -57,11 +59,11 @@ set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto execute -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. +echo. 1>&2 +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 goto fail From 002dda31a62ef668aaee89529621c213fec54c2f Mon Sep 17 00:00:00 2001 From: Davide D'Alto Date: Fri, 24 Jan 2025 08:16:40 +0100 Subject: [PATCH 029/162] [#2079] Don't ignore return value of ReactiveUpdateRowsCoordinatorOneToMany#deleteRows --- ...eactiveUpdateRowsCoordinatorOneToMany.java | 20 +++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/persister/collection/mutation/ReactiveUpdateRowsCoordinatorOneToMany.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/persister/collection/mutation/ReactiveUpdateRowsCoordinatorOneToMany.java index 99bec6f5a..8b7478efa 100644 --- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/persister/collection/mutation/ReactiveUpdateRowsCoordinatorOneToMany.java +++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/persister/collection/mutation/ReactiveUpdateRowsCoordinatorOneToMany.java @@ -7,6 +7,7 @@ import java.util.Iterator; import java.util.concurrent.CompletionStage; +import java.util.function.Function; import org.hibernate.collection.spi.PersistentCollection; import org.hibernate.engine.jdbc.batch.internal.BasicBatchKey; @@ -28,9 +29,9 @@ import static java.lang.invoke.MethodHandles.lookup; import static org.hibernate.reactive.logging.impl.LoggerFactory.make; -import static org.hibernate.reactive.util.impl.CompletionStages.completedFuture; import static org.hibernate.reactive.util.impl.CompletionStages.loop; import static org.hibernate.reactive.util.impl.CompletionStages.voidFuture; +import static org.hibernate.reactive.util.impl.CompletionStages.zeroFuture; import static org.hibernate.sql.model.ModelMutationLogging.MODEL_MUTATION_LOGGER; import static org.hibernate.sql.model.MutationType.DELETE; import static org.hibernate.sql.model.MutationType.INSERT; @@ -70,15 +71,18 @@ public CompletionStage reactiveUpdateRows(Object key, PersistentCollection } private CompletionStage doReactiveUpdate(Object key, PersistentCollection collection, SharedSessionContractImplementor session) { - if ( rowMutationOperations.hasDeleteRow() ) { - deleteRows( key, collection, session ); - } + final Function> insertRowsFun = v -> { + if ( rowMutationOperations.hasInsertRow() ) { + return insertRows( key, collection, session ); + } - if ( rowMutationOperations.hasInsertRow() ) { - return insertRows( key, collection, session ); + return zeroFuture(); + }; + if ( rowMutationOperations.hasDeleteRow() ) { + return deleteRows( key, collection, session ) + .thenCompose( insertRowsFun ); } - - return completedFuture( 0 ); + return insertRowsFun.apply( null ); } private CompletionStage insertRows(Object key, PersistentCollection collection, SharedSessionContractImplementor session) { From 0cd1f8dc8ec795db150c13005d5057ff32957c93 Mon Sep 17 00:00:00 2001 From: Davide D'Alto Date: Tue, 28 Jan 2025 11:54:12 +0100 Subject: [PATCH 030/162] [#2084] Upgrade Vert.x SQL client to 4.5.12 --- README.md | 10 +++++----- build.gradle | 2 +- gradle.properties | 6 +++--- tooling/jbang/CockroachDBReactiveTest.java.qute | 4 ++-- tooling/jbang/Db2ReactiveTest.java.qute | 4 ++-- tooling/jbang/Example.java | 6 +++--- tooling/jbang/MariaDBReactiveTest.java.qute | 4 ++-- tooling/jbang/MySQLReactiveTest.java.qute | 4 ++-- tooling/jbang/PostgreSQLReactiveTest.java.qute | 4 ++-- tooling/jbang/ReactiveTest.java | 8 ++++---- 10 files changed, 26 insertions(+), 26 deletions(-) diff --git a/README.md b/README.md index 7e6234007..13352eb0e 100644 --- a/README.md +++ b/README.md @@ -38,11 +38,11 @@ Hibernate Reactive has been tested with: - MS SQL Server 2022 - Oracle 23 - [Hibernate ORM][] 6.6.5.Final -- [Vert.x Reactive PostgreSQL Client](https://vertx.io/docs/vertx-pg-client/java/) 4.5.11 -- [Vert.x Reactive MySQL Client](https://vertx.io/docs/vertx-mysql-client/java/) 4.5.11 -- [Vert.x Reactive Db2 Client](https://vertx.io/docs/vertx-db2-client/java/) 4.5.11 -- [Vert.x Reactive MS SQL Server Client](https://vertx.io/docs/vertx-mssql-client/java/) 4.5.11 -- [Vert.x Reactive Oracle Client](https://vertx.io/docs/vertx-oracle-client/java/) 4.5.11 +- [Vert.x Reactive PostgreSQL Client](https://vertx.io/docs/vertx-pg-client/java/) 4.5.12 +- [Vert.x Reactive MySQL Client](https://vertx.io/docs/vertx-mysql-client/java/) 4.5.12 +- [Vert.x Reactive Db2 Client](https://vertx.io/docs/vertx-db2-client/java/) 4.5.12 +- [Vert.x Reactive MS SQL Server Client](https://vertx.io/docs/vertx-mssql-client/java/) 4.5.12 +- [Vert.x Reactive Oracle Client](https://vertx.io/docs/vertx-oracle-client/java/) 4.5.12 - [Quarkus][Quarkus] via the Hibernate Reactive extension [PostgreSQL]: https://www.postgresql.org diff --git a/build.gradle b/build.gradle index ed2007312..e9ca27a56 100644 --- a/build.gradle +++ b/build.gradle @@ -22,7 +22,7 @@ ext { // Example: // ./gradlew build -PvertxSqlClientVersion=4.0.0-SNAPSHOT if ( !project.hasProperty( 'vertxSqlClientVersion' ) ) { - vertxSqlClientVersion = '4.5.11' + vertxSqlClientVersion = '4.5.12' } testcontainersVersion = '1.20.4' diff --git a/gradle.properties b/gradle.properties index 03d50309e..37d08384a 100644 --- a/gradle.properties +++ b/gradle.properties @@ -47,9 +47,9 @@ hibernateOrmVersion = 6.6.5.Final #skipOrmVersionParsing = true # Override default Vert.x Sql client version -#vertxSqlClientVersion = 4.5.11-SNAPSHOT +#vertxSqlClientVersion = 4.5.12-SNAPSHOT # Override default Vert.x Web client and server versions. For integration tests, both default to vertxSqlClientVersion -#vertxWebVersion = 4.5.11 -#vertxWebtClientVersion = 4.5.11 +#vertxWebVersion = 4.5.12 +#vertxWebtClientVersion = 4.5.12 diff --git a/tooling/jbang/CockroachDBReactiveTest.java.qute b/tooling/jbang/CockroachDBReactiveTest.java.qute index 17eecb479..ce9001bc3 100755 --- a/tooling/jbang/CockroachDBReactiveTest.java.qute +++ b/tooling/jbang/CockroachDBReactiveTest.java.qute @@ -5,8 +5,8 @@ * Copyright: Red Hat Inc. and Hibernate Authors */ -//DEPS io.vertx:vertx-pg-client:$\{vertx.version:4.5.11} -//DEPS io.vertx:vertx-unit:$\{vertx.version:4.5.11} +//DEPS io.vertx:vertx-pg-client:$\{vertx.version:4.5.12} +//DEPS io.vertx:vertx-unit:$\{vertx.version:4.5.12} //DEPS org.hibernate.reactive:hibernate-reactive-core:$\{hibernate-reactive.version:2.4.0.Final} //DEPS org.assertj:assertj-core:3.26.3 //DEPS junit:junit:4.13.2 diff --git a/tooling/jbang/Db2ReactiveTest.java.qute b/tooling/jbang/Db2ReactiveTest.java.qute index 2e6ae3623..72a98bbc1 100755 --- a/tooling/jbang/Db2ReactiveTest.java.qute +++ b/tooling/jbang/Db2ReactiveTest.java.qute @@ -5,8 +5,8 @@ * Copyright: Red Hat Inc. and Hibernate Authors */ -//DEPS io.vertx:vertx-db2-client:$\{vertx.version:4.5.11} -//DEPS io.vertx:vertx-unit:$\{vertx.version:4.5.11} +//DEPS io.vertx:vertx-db2-client:$\{vertx.version:4.5.12} +//DEPS io.vertx:vertx-unit:$\{vertx.version:4.5.12} //DEPS org.hibernate.reactive:hibernate-reactive-core:$\{hibernate-reactive.version:2.4.0.Final} //DEPS org.assertj:assertj-core:3.26.3 //DEPS junit:junit:4.13.2 diff --git a/tooling/jbang/Example.java b/tooling/jbang/Example.java index fe0b312e8..f272684b3 100644 --- a/tooling/jbang/Example.java +++ b/tooling/jbang/Example.java @@ -6,9 +6,9 @@ */ //DEPS com.ongres.scram:client:2.1 -//DEPS io.vertx:vertx-pg-client:${vertx.version:4.5.11} -//DEPS io.vertx:vertx-mysql-client:${vertx.version:4.5.11} -//DEPS io.vertx:vertx-db2-client:${vertx.version:4.5.11} +//DEPS io.vertx:vertx-pg-client:${vertx.version:4.5.12} +//DEPS io.vertx:vertx-mysql-client:${vertx.version:4.5.12} +//DEPS io.vertx:vertx-db2-client:${vertx.version:4.5.12} //DEPS org.hibernate.reactive:hibernate-reactive-core:${hibernate-reactive.version:2.4.0.Final} //DEPS org.slf4j:slf4j-simple:2.0.7 //DESCRIPTION Allow authentication to PostgreSQL using SCRAM: diff --git a/tooling/jbang/MariaDBReactiveTest.java.qute b/tooling/jbang/MariaDBReactiveTest.java.qute index b7592b05b..a1bfe3c56 100755 --- a/tooling/jbang/MariaDBReactiveTest.java.qute +++ b/tooling/jbang/MariaDBReactiveTest.java.qute @@ -5,8 +5,8 @@ * Copyright: Red Hat Inc. and Hibernate Authors */ -//DEPS io.vertx:vertx-mysql-client:$\{vertx.version:4.5.11} -//DEPS io.vertx:vertx-unit:$\{vertx.version:4.5.11} +//DEPS io.vertx:vertx-mysql-client:$\{vertx.version:4.5.12} +//DEPS io.vertx:vertx-unit:$\{vertx.version:4.5.12} //DEPS org.hibernate.reactive:hibernate-reactive-core:$\{hibernate-reactive.version:2.4.0.Final} //DEPS org.assertj:assertj-core:3.26.3 //DEPS junit:junit:4.13.2 diff --git a/tooling/jbang/MySQLReactiveTest.java.qute b/tooling/jbang/MySQLReactiveTest.java.qute index 7cc856c4a..13c7220c6 100755 --- a/tooling/jbang/MySQLReactiveTest.java.qute +++ b/tooling/jbang/MySQLReactiveTest.java.qute @@ -5,8 +5,8 @@ * Copyright: Red Hat Inc. and Hibernate Authors */ -//DEPS io.vertx:vertx-mysql-client:$\{vertx.version:4.5.11} -//DEPS io.vertx:vertx-unit:$\{vertx.version:4.5.11} +//DEPS io.vertx:vertx-mysql-client:$\{vertx.version:4.5.12} +//DEPS io.vertx:vertx-unit:$\{vertx.version:4.5.12} //DEPS org.hibernate.reactive:hibernate-reactive-core:$\{hibernate-reactive.version:2.4.0.Final} //DEPS org.assertj:assertj-core:3.26.3 //DEPS junit:junit:4.13.2 diff --git a/tooling/jbang/PostgreSQLReactiveTest.java.qute b/tooling/jbang/PostgreSQLReactiveTest.java.qute index 306c30476..1e2264250 100755 --- a/tooling/jbang/PostgreSQLReactiveTest.java.qute +++ b/tooling/jbang/PostgreSQLReactiveTest.java.qute @@ -5,8 +5,8 @@ * Copyright: Red Hat Inc. and Hibernate Authors */ -//DEPS io.vertx:vertx-pg-client:$\{vertx.version:4.5.11} -//DEPS io.vertx:vertx-unit:$\{vertx.version:4.5.11} +//DEPS io.vertx:vertx-pg-client:$\{vertx.version:4.5.12} +//DEPS io.vertx:vertx-unit:$\{vertx.version:4.5.12} //DEPS org.hibernate.reactive:hibernate-reactive-core:$\{hibernate-reactive.version:2.4.0.Final} //DEPS org.assertj:assertj-core:3.26.3 //DEPS junit:junit:4.13.2 diff --git a/tooling/jbang/ReactiveTest.java b/tooling/jbang/ReactiveTest.java index c79d14fe5..e642bdda8 100755 --- a/tooling/jbang/ReactiveTest.java +++ b/tooling/jbang/ReactiveTest.java @@ -5,11 +5,11 @@ */ ///usr/bin/env jbang "$0" "$@" ; exit $? -//DEPS io.vertx:vertx-pg-client:${vertx.version:4.5.11} +//DEPS io.vertx:vertx-pg-client:${vertx.version:4.5.12} //DEPS com.ongres.scram:client:2.1 -//DEPS io.vertx:vertx-db2-client:${vertx.version:4.5.11} -//DEPS io.vertx:vertx-mysql-client:${vertx.version:4.5.11} -//DEPS io.vertx:vertx-unit:${vertx.version:4.5.11} +//DEPS io.vertx:vertx-db2-client:${vertx.version:4.5.12} +//DEPS io.vertx:vertx-mysql-client:${vertx.version:4.5.12} +//DEPS io.vertx:vertx-unit:${vertx.version:4.5.12} //DEPS org.hibernate.reactive:hibernate-reactive-core:${hibernate-reactive.version:2.4.0.Final} //DEPS org.assertj:assertj-core:3.26.3 //DEPS junit:junit:4.13.2 From 5a4afb41e71fc96e4d2807972c927379d85708f4 Mon Sep 17 00:00:00 2001 From: Davide D'Alto Date: Mon, 3 Feb 2025 13:58:17 +0100 Subject: [PATCH 031/162] [#2096] Upgrade Hibernate ORM to 6.6.6.Final --- README.md | 2 +- gradle.properties | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 13352eb0e..a12487f7b 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ Hibernate Reactive has been tested with: - CockroachDB v24 - MS SQL Server 2022 - Oracle 23 -- [Hibernate ORM][] 6.6.5.Final +- [Hibernate ORM][] 6.6.6.Final - [Vert.x Reactive PostgreSQL Client](https://vertx.io/docs/vertx-pg-client/java/) 4.5.12 - [Vert.x Reactive MySQL Client](https://vertx.io/docs/vertx-mysql-client/java/) 4.5.12 - [Vert.x Reactive Db2 Client](https://vertx.io/docs/vertx-db2-client/java/) 4.5.12 diff --git a/gradle.properties b/gradle.properties index 37d08384a..443551929 100644 --- a/gradle.properties +++ b/gradle.properties @@ -35,12 +35,12 @@ org.gradle.java.installations.auto-download=false #enableMavenLocalRepo = true # The default Hibernate ORM version (override using `-PhibernateOrmVersion=the.version.you.want`) -hibernateOrmVersion = 6.6.5.Final +hibernateOrmVersion = 6.6.6.Final # Override default Hibernate ORM Gradle plugin version # Using the stable version because I don't know how to configure the build to download the snapshot version from # a remote repository -#hibernateOrmGradlePluginVersion = 6.6.5.Final +#hibernateOrmGradlePluginVersion = 6.6.6.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 From fe52c7fdcd04024d7239a4aef088c069e72bf9ee Mon Sep 17 00:00:00 2001 From: Davide D'Alto Date: Wed, 5 Feb 2025 11:35:51 +0100 Subject: [PATCH 032/162] [#2097] Use SHA instead of versions in GH actions --- .github/workflows/build.yml | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index c0e403d92..65c72d1d5 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -81,7 +81,7 @@ jobs: - 5432:5432 steps: - name: Checkout ${{ inputs.branch }} - uses: actions/checkout@v2 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: ref: ${{ inputs.branch }} - name: Get year/month for cache key @@ -90,7 +90,7 @@ jobs: echo "::set-output name=yearmonth::$(/bin/date -u "+%Y-%m")" shell: bash - name: Cache Gradle downloads - uses: actions/cache@v4 + uses: actions/cache@1bd1e32a3bdc45362d1e726936510720a7c30a57 # v4.2.0 id: cache-gradle with: path: | @@ -100,7 +100,7 @@ jobs: # refresh cache every month to avoid unlimited growth key: gradle-examples-${{ matrix.db }}-${{ steps.get-date.outputs.yearmonth }} - name: Set up JDK 11 - uses: actions/setup-java@v2.2.0 + uses: actions/setup-java@3a4f6e1af504cf6a31855fa899c6aa5355ba6c12 # v4.7.0 with: distribution: 'temurin' java-version: 11 @@ -109,7 +109,7 @@ jobs: - name: Run examples in '${{ matrix.example }}' on ${{ matrix.db }} run: ./gradlew :${{ matrix.example }}:runAllExamplesOn${{ matrix.db }} - name: Upload reports (if build failed) - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4.6.0 if: failure() with: name: reports-examples-${{ matrix.db }} @@ -123,7 +123,7 @@ jobs: db: [ 'MariaDB', 'MySQL', 'PostgreSQL', 'MSSQLServer', 'CockroachDB', 'Db2', 'Oracle' ] steps: - name: Checkout ${{ inputs.branch }} - uses: actions/checkout@v2 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: ref: ${{ inputs.branch }} - name: Get year/month for cache key @@ -132,7 +132,7 @@ jobs: echo "::set-output name=yearmonth::$(/bin/date -u "+%Y-%m")" shell: bash - name: Cache Gradle downloads - uses: actions/cache@v4 + uses: actions/cache@1bd1e32a3bdc45362d1e726936510720a7c30a57 # v4.2.0 id: cache-gradle with: path: | @@ -142,7 +142,7 @@ jobs: # refresh cache every month to avoid unlimited growth key: gradle-db-${{ matrix.db }}-${{ steps.get-date.outputs.yearmonth }} - name: Set up JDK 11 - uses: actions/setup-java@v2.2.0 + uses: actions/setup-java@3a4f6e1af504cf6a31855fa899c6aa5355ba6c12 # v4.7.0 with: distribution: 'temurin' java-version: 11 @@ -151,7 +151,7 @@ jobs: - name: Build and Test with ${{ matrix.db }} run: ./gradlew build -PshowStandardOutput -Pdocker -Pdb=${{ matrix.db }} - name: Upload reports (if build failed) - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4.6.0 if: failure() with: name: reports-db-${{ matrix.db }} @@ -182,7 +182,7 @@ jobs: - { name: "25-ea", java_version_numeric: 25, from: 'jdk.java.net', jvm_args: '--enable-preview' } steps: - name: Checkout ${{ inputs.branch }} - uses: actions/checkout@v2 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: ref: ${{ inputs.branch }} - name: Get year/month for cache key @@ -203,7 +203,7 @@ jobs: echo "buildtool-cache-key=${ROOT_CACHE_KEY}-${CURRENT_MONTH}-${CURRENT_BRANCH}-${CURRENT_DAY}" >> $GITHUB_OUTPUT - name: Cache Maven/Gradle Dependency/Dist Caches id: cache-maven - uses: actions/cache@v4 + uses: actions/cache@1bd1e32a3bdc45362d1e726936510720a7c30a57 # v4.2.0 # if it's not a pull request, we restore and save the cache if: github.event_name != 'pull_request' with: @@ -220,7 +220,7 @@ jobs: ${{ steps.cache-key.outputs.buildtool-monthly-branch-cache-key }}- ${{ steps.cache-key.outputs.buildtool-monthly-cache-key }}- - name: Restore Maven/Gradle Dependency/Dist Caches - uses: actions/cache/restore@v4 + uses: actions/cache/restore@1bd1e32a3bdc45362d1e726936510720a7c30a57 # v4.2.0 # if it's a pull request, we restore the cache, but we don't save it if: github.event_name == 'pull_request' with: @@ -236,13 +236,13 @@ jobs: - name: Set up latest JDK ${{ matrix.java.name }} from jdk.java.net if: matrix.java.from == 'jdk.java.net' - uses: oracle-actions/setup-java@v1 + uses: oracle-actions/setup-java@2e744f723b003fdd759727d0ff654c8717024845 # v1.4.0 with: website: jdk.java.net release: ${{ matrix.java.java_version_numeric }} - name: Set up latest JDK ${{ matrix.java.name }} from Adoptium if: matrix.java.from == '' || matrix.java.from == 'adoptium.net' - uses: actions/setup-java@v2.2.0 + uses: actions/setup-java@3a4f6e1af504cf6a31855fa899c6aa5355ba6c12 # v4.7.0 with: distribution: 'temurin' java-version: ${{ matrix.java.java_version_numeric }} @@ -252,7 +252,7 @@ jobs: run: echo "::set-output name=path::${JAVA_HOME}" # Always use JDK 11 to build the main code: that's what we use for releases. - name: Set up JDK 11 - uses: actions/setup-java@v2.2.0 + uses: actions/setup-java@3a4f6e1af504cf6a31855fa899c6aa5355ba6c12 # v4.7.0 with: distribution: 'temurin' java-version: 11 @@ -271,7 +271,7 @@ jobs: -Porg.gradle.java.installations.paths=${{ steps.mainjdk-exportpath.outputs.path }},${{ steps.testjdk-exportpath.outputs.path }} \ ${{ matrix.java.jvm_args && '-Ptest.jdk.launcher.args=' }}${{ matrix.java.jvm_args }} - name: Upload reports (if build failed) - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4.6.0 if: failure() with: name: reports-java${{ matrix.java.name }} From 3a996e493e42d950cd17bd49e9de8ec9002ab12f Mon Sep 17 00:00:00 2001 From: Davide D'Alto Date: Mon, 10 Feb 2025 17:24:32 +0100 Subject: [PATCH 033/162] [#2106] Upgrade Hibernate ORM to 6.6.7.Final --- README.md | 2 +- gradle.properties | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index a12487f7b..e7816a989 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ Hibernate Reactive has been tested with: - CockroachDB v24 - MS SQL Server 2022 - Oracle 23 -- [Hibernate ORM][] 6.6.6.Final +- [Hibernate ORM][] 6.6.7.Final - [Vert.x Reactive PostgreSQL Client](https://vertx.io/docs/vertx-pg-client/java/) 4.5.12 - [Vert.x Reactive MySQL Client](https://vertx.io/docs/vertx-mysql-client/java/) 4.5.12 - [Vert.x Reactive Db2 Client](https://vertx.io/docs/vertx-db2-client/java/) 4.5.12 diff --git a/gradle.properties b/gradle.properties index 443551929..f6740414b 100644 --- a/gradle.properties +++ b/gradle.properties @@ -35,12 +35,12 @@ org.gradle.java.installations.auto-download=false #enableMavenLocalRepo = true # The default Hibernate ORM version (override using `-PhibernateOrmVersion=the.version.you.want`) -hibernateOrmVersion = 6.6.6.Final +hibernateOrmVersion = 6.6.7.Final # Override default Hibernate ORM Gradle plugin version # Using the stable version because I don't know how to configure the build to download the snapshot version from # a remote repository -#hibernateOrmGradlePluginVersion = 6.6.6.Final +#hibernateOrmGradlePluginVersion = 6.6.7.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 From 6d2acaeb91065938af13dc38f507a5054d3e2e17 Mon Sep 17 00:00:00 2001 From: Hibernate-CI Date: Tue, 11 Feb 2025 08:02:10 +0000 Subject: [PATCH 034/162] Update project version to : `2.4.5.Final` --- gradle/version.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/version.properties b/gradle/version.properties index 0b654a7ec..0675a7659 100644 --- a/gradle/version.properties +++ b/gradle/version.properties @@ -1 +1 @@ -projectVersion=2.4.5-SNAPSHOT \ No newline at end of file +projectVersion=2.4.5.Final \ No newline at end of file From 85fdfa3baafa4ad7b83dd9814417ad0e9caa9fb1 Mon Sep 17 00:00:00 2001 From: Hibernate-CI Date: Tue, 11 Feb 2025 08:03:08 +0000 Subject: [PATCH 035/162] Update project version to : `2.4.6-SNAPSHOT` --- gradle/version.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/version.properties b/gradle/version.properties index 0675a7659..0d7e548df 100644 --- a/gradle/version.properties +++ b/gradle/version.properties @@ -1 +1 @@ -projectVersion=2.4.5.Final \ No newline at end of file +projectVersion=2.4.6-SNAPSHOT \ No newline at end of file From 294120c09265d7070a615de4b03d7485394e6b3f Mon Sep 17 00:00:00 2001 From: Andrea Boriero Date: Wed, 5 Feb 2025 18:21:32 +0100 Subject: [PATCH 036/162] [#2055] Setting hibernate.query.mutation_strategy.global_temporary.create_tables to false has no effect --- .../ReactiveGlobalTemporaryTableStrategy.java | 74 +++++++++---------- .../ReactivePersistentTableStrategy.java | 70 +++++++++--------- 2 files changed, 73 insertions(+), 71 deletions(-) diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/query/sqm/mutation/internal/temptable/ReactiveGlobalTemporaryTableStrategy.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/query/sqm/mutation/internal/temptable/ReactiveGlobalTemporaryTableStrategy.java index 37c3d23bc..d0204ffff 100644 --- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/query/sqm/mutation/internal/temptable/ReactiveGlobalTemporaryTableStrategy.java +++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/query/sqm/mutation/internal/temptable/ReactiveGlobalTemporaryTableStrategy.java @@ -27,8 +27,6 @@ public interface ReactiveGlobalTemporaryTableStrategy { - Log LOG = make( Log.class, lookup() ); - static String sessionIdentifier(SharedSessionContractImplementor session) { return session.getSessionIdentifier().toString(); } @@ -65,22 +63,23 @@ default void prepare(MappingModelCreationProcess mappingModelCreationProcess, Jd if ( !createIdTables ) { tableCreatedStage.complete( null ); } - - LOG.debugf( "Creating global-temp ID table : %s", getTemporaryTable().getTableExpression() ); - - connectionStage() - .thenCompose( this::createTable ) - .whenComplete( (connection, throwable) -> releaseConnection( connection ) - .thenAccept( v -> { - if ( throwable == null ) { - setDropIdTables( configService ); - tableCreatedStage.complete( null ); - } - else { - tableCreatedStage.completeExceptionally( throwable ); - } - } ) - ); + else { + make( Log.class, lookup() ).debugf( "Creating global-temp ID table : %s", getTemporaryTable().getTableExpression() ); + + connectionStage() + .thenCompose( this::createTable ) + .whenComplete( (connection, throwable) -> releaseConnection( connection ) + .thenAccept( v -> { + if ( throwable == null ) { + setDropIdTables( configService ); + tableCreatedStage.complete( null ); + } + else { + tableCreatedStage.completeExceptionally( throwable ); + } + } ) + ); + } } private CompletionStage releaseConnection(ReactiveConnection connection) { @@ -103,7 +102,7 @@ private CompletionStage releaseConnection(ReactiveConnection connection) { private static void logConnectionClosedError(Throwable t) { if ( t != null ) { - LOG.debugf( "Ignoring error closing the connection: %s", t.getMessage() ); + make( Log.class, lookup() ).debugf( "Ignoring error closing the connection: %s", t.getMessage() ); } } @@ -147,24 +146,25 @@ default void release( if ( !isDropIdTables() ) { tableDroppedStage.complete( null ); } - - setDropIdTables( false ); - - final TemporaryTable temporaryTable = getTemporaryTable(); - LOG.debugf( "Dropping global-tempk ID table : %s", temporaryTable.getTableExpression() ); - - connectionStage() - .thenCompose( this::dropTable ) - .whenComplete( (connection, throwable) -> releaseConnection( connection ) - .thenAccept( v -> { - if ( throwable == null ) { - tableDroppedStage.complete( null ); - } - else { - tableDroppedStage.completeExceptionally( throwable ); - } - } ) - ); + else { + setDropIdTables( false ); + + final TemporaryTable temporaryTable = getTemporaryTable(); + make( Log.class, lookup() ).debugf( "Dropping global-tempk ID table : %s", temporaryTable.getTableExpression() ); + + connectionStage() + .thenCompose( this::dropTable ) + .whenComplete( (connection, throwable) -> releaseConnection( connection ) + .thenAccept( v -> { + if ( throwable == null ) { + tableDroppedStage.complete( null ); + } + else { + tableDroppedStage.completeExceptionally( throwable ); + } + } ) + ); + } } private CompletionStage dropTable(ReactiveConnection connection) { diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/query/sqm/mutation/internal/temptable/ReactivePersistentTableStrategy.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/query/sqm/mutation/internal/temptable/ReactivePersistentTableStrategy.java index 472dc0ce7..ba70601ad 100644 --- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/query/sqm/mutation/internal/temptable/ReactivePersistentTableStrategy.java +++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/query/sqm/mutation/internal/temptable/ReactivePersistentTableStrategy.java @@ -68,22 +68,23 @@ default void prepare(MappingModelCreationProcess mappingModelCreationProcess, Jd if ( !createIdTables ) { tableCreatedStage.complete( null ); } - - LOG.debugf( "Creating persistent ID table : %s", getTemporaryTable().getTableExpression() ); - - connectionStage() - .thenCompose( this::createTable ) - .whenComplete( (connection, throwable) -> releaseConnection( connection ) - .thenAccept( v -> { - if ( throwable == null ) { - setDropIdTables( configService ); - tableCreatedStage.complete( null ); - } - else { - tableCreatedStage.completeExceptionally( throwable ); - } - } ) - ); + else { + LOG.debugf( "Creating persistent ID table : %s", getTemporaryTable().getTableExpression() ); + + connectionStage() + .thenCompose( this::createTable ) + .whenComplete( (connection, throwable) -> releaseConnection( connection ) + .thenAccept( v -> { + if ( throwable == null ) { + setDropIdTables( configService ); + tableCreatedStage.complete( null ); + } + else { + tableCreatedStage.completeExceptionally( throwable ); + } + } ) + ); + } } private CompletionStage releaseConnection(ReactiveConnection connection) { @@ -150,24 +151,25 @@ default void release( if ( !isDropIdTables() ) { tableDroppedStage.complete( null ); } - - setDropIdTables( false ); - - final TemporaryTable temporaryTable = getTemporaryTable(); - LOG.debugf( "Dropping persistent ID table : %s", temporaryTable.getTableExpression() ); - - connectionStage() - .thenCompose( this::dropTable ) - .whenComplete( (connection, throwable) -> releaseConnection( connection ) - .thenAccept( v -> { - if ( throwable == null ) { - tableDroppedStage.complete( null ); - } - else { - tableDroppedStage.completeExceptionally( throwable ); - } - } ) - ); + else { + setDropIdTables( false ); + + final TemporaryTable temporaryTable = getTemporaryTable(); + LOG.debugf( "Dropping persistent ID table : %s", temporaryTable.getTableExpression() ); + + connectionStage() + .thenCompose( this::dropTable ) + .whenComplete( (connection, throwable) -> releaseConnection( connection ) + .thenAccept( v -> { + if ( throwable == null ) { + tableDroppedStage.complete( null ); + } + else { + tableDroppedStage.completeExceptionally( throwable ); + } + } ) + ); + } } private CompletionStage dropTable(ReactiveConnection connection) { From f97300e3ebdd1b34482ddb0ba798980362f897f9 Mon Sep 17 00:00:00 2001 From: Andrea Boriero Date: Wed, 12 Feb 2025 10:19:51 +0100 Subject: [PATCH 037/162] [#2055] Avoid logging temporary command twice --- .../internal/temptable/ReactiveTemporaryTableHelper.java | 6 ------ 1 file changed, 6 deletions(-) diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/query/sqm/mutation/internal/temptable/ReactiveTemporaryTableHelper.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/query/sqm/mutation/internal/temptable/ReactiveTemporaryTableHelper.java index d027235a2..4eaecd04f 100644 --- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/query/sqm/mutation/internal/temptable/ReactiveTemporaryTableHelper.java +++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/query/sqm/mutation/internal/temptable/ReactiveTemporaryTableHelper.java @@ -68,11 +68,8 @@ public TemporaryTableCreationWork( @Override public CompletionStage reactiveExecute(ReactiveConnection connection) { - final JdbcServices jdbcServices = sessionFactory.getJdbcServices(); - try { final String creationCommand = exporter.getSqlCreateCommand( temporaryTable ); - logStatement( creationCommand, jdbcServices ); return connection.executeUnprepared( creationCommand ) .handle( (integer, throwable) -> { @@ -116,11 +113,8 @@ public TemporaryTableDropWork( @Override public CompletionStage reactiveExecute(ReactiveConnection connection) { - final JdbcServices jdbcServices = sessionFactory.getJdbcServices(); - try { final String dropCommand = exporter.getSqlDropCommand( temporaryTable ); - logStatement( dropCommand, jdbcServices ); return connection.update( dropCommand ) .handle( (integer, throwable) -> { From 03f9b012b939b2d622ca958f080a411766d29268 Mon Sep 17 00:00:00 2001 From: Andrea Boriero Date: Wed, 12 Feb 2025 10:37:20 +0100 Subject: [PATCH 038/162] [#2055] SessionFactoryManager.stop() should always call SessionFactory.close() PersistentTemporaryTable dropping is obtained setting PersistentTableStrategy.DROP_ID_TABLES to true --- .../hibernate/reactive/BaseReactiveTest.java | 4 +++ .../testing/SessionFactoryManager.java | 36 ++----------------- 2 files changed, 6 insertions(+), 34 deletions(-) diff --git a/hibernate-reactive-core/src/test/java/org/hibernate/reactive/BaseReactiveTest.java b/hibernate-reactive-core/src/test/java/org/hibernate/reactive/BaseReactiveTest.java index 6cd705f2b..1a5f51e3b 100644 --- a/hibernate-reactive-core/src/test/java/org/hibernate/reactive/BaseReactiveTest.java +++ b/hibernate-reactive-core/src/test/java/org/hibernate/reactive/BaseReactiveTest.java @@ -18,6 +18,8 @@ import org.hibernate.dialect.Dialect; import org.hibernate.engine.jdbc.connections.spi.ConnectionProvider; import org.hibernate.engine.spi.SessionFactoryImplementor; +import org.hibernate.query.sqm.mutation.internal.temptable.GlobalTemporaryTableStrategy; +import org.hibernate.query.sqm.mutation.internal.temptable.PersistentTableStrategy; import org.hibernate.reactive.containers.DatabaseConfiguration; import org.hibernate.reactive.containers.DatabaseConfiguration.DBType; import org.hibernate.reactive.mutiny.Mutiny; @@ -105,6 +107,8 @@ public static void setDefaultProperties(Configuration configuration) { configuration.setProperty( Settings.SHOW_SQL, System.getProperty( Settings.SHOW_SQL, "false" ) ); configuration.setProperty( Settings.FORMAT_SQL, System.getProperty( Settings.FORMAT_SQL, "false" ) ); configuration.setProperty( Settings.HIGHLIGHT_SQL, System.getProperty( Settings.HIGHLIGHT_SQL, "true" ) ); + configuration.setProperty( PersistentTableStrategy.DROP_ID_TABLES, "true" ); + configuration.setProperty( GlobalTemporaryTableStrategy.DROP_ID_TABLES, "true" ); } public static final SessionFactoryManager factoryManager = new SessionFactoryManager(); diff --git a/hibernate-reactive-core/src/test/java/org/hibernate/reactive/testing/SessionFactoryManager.java b/hibernate-reactive-core/src/test/java/org/hibernate/reactive/testing/SessionFactoryManager.java index 8262b7c22..be4362a02 100644 --- a/hibernate-reactive-core/src/test/java/org/hibernate/reactive/testing/SessionFactoryManager.java +++ b/hibernate-reactive-core/src/test/java/org/hibernate/reactive/testing/SessionFactoryManager.java @@ -5,20 +5,13 @@ */ package org.hibernate.reactive.testing; -import java.util.ArrayList; -import java.util.List; import java.util.concurrent.CompletionStage; import java.util.function.Supplier; import org.hibernate.SessionFactory; import org.hibernate.engine.spi.SessionFactoryImplementor; -import org.hibernate.metamodel.spi.MappingMetamodelImplementor; -import org.hibernate.persister.entity.EntityPersister; -import org.hibernate.query.sqm.mutation.internal.temptable.PersistentTableStrategy; import org.hibernate.reactive.pool.ReactiveConnectionPool; -import org.hibernate.reactive.query.sqm.mutation.internal.temptable.ReactivePersistentTableStrategy; -import static org.hibernate.reactive.util.impl.CompletionStages.loop; import static org.hibernate.reactive.util.impl.CompletionStages.voidFuture; /** @@ -60,24 +53,8 @@ public ReactiveConnectionPool getReactiveConnectionPool() { public CompletionStage stop() { CompletionStage releasedStage = voidFuture(); if ( sessionFactory != null && sessionFactory.isOpen() ) { - SessionFactoryImplementor sessionFactoryImplementor = sessionFactory.unwrap( SessionFactoryImplementor.class ); - MappingMetamodelImplementor mappingMetamodel = sessionFactoryImplementor - .getRuntimeMetamodels() - .getMappingMetamodel(); - final List reactiveStrategies = new ArrayList<>(); - mappingMetamodel.forEachEntityDescriptor( - entityPersister -> addPersistentTableStrategy( reactiveStrategies, entityPersister ) - ); - if ( !reactiveStrategies.isEmpty() ) { - releasedStage = loop( reactiveStrategies, strategy -> { - ( (PersistentTableStrategy) strategy ) - .release( sessionFactory.unwrap( SessionFactoryImplementor.class ), null ); - return strategy.getDropTableActionStage(); - } ); - - releasedStage = releasedStage - .whenComplete( (unused, throwable) -> sessionFactory.close() ); - } + releasedStage = releasedStage + .whenComplete( (unused, throwable) -> sessionFactory.close() ); } return releasedStage .thenCompose( unused -> { @@ -93,13 +70,4 @@ public CompletionStage stop() { return closeFuture; } ); } - - private void addPersistentTableStrategy(List reactiveStrategies, EntityPersister entityPersister) { - if ( entityPersister.getSqmMultiTableMutationStrategy() instanceof ReactivePersistentTableStrategy ) { - reactiveStrategies.add( (ReactivePersistentTableStrategy) entityPersister.getSqmMultiTableMutationStrategy() ); - } - if ( entityPersister.getSqmMultiTableInsertStrategy() instanceof ReactivePersistentTableStrategy ) { - reactiveStrategies.add( (ReactivePersistentTableStrategy) entityPersister.getSqmMultiTableInsertStrategy() ); - } - } } From d779bdfabdd3cd1763d00e848a5a39b0cc6cca43 Mon Sep 17 00:00:00 2001 From: Andrea Boriero Date: Wed, 12 Feb 2025 10:39:03 +0100 Subject: [PATCH 039/162] [#2055] Add test for temporary table strategies The test is for temporary tables created for storing ids --- .../schema/TemporaryIdTableStrategyTest.java | 235 ++++++++++++++++++ 1 file changed, 235 insertions(+) create mode 100644 hibernate-reactive-core/src/test/java/org/hibernate/reactive/schema/TemporaryIdTableStrategyTest.java diff --git a/hibernate-reactive-core/src/test/java/org/hibernate/reactive/schema/TemporaryIdTableStrategyTest.java b/hibernate-reactive-core/src/test/java/org/hibernate/reactive/schema/TemporaryIdTableStrategyTest.java new file mode 100644 index 000000000..15ed24341 --- /dev/null +++ b/hibernate-reactive-core/src/test/java/org/hibernate/reactive/schema/TemporaryIdTableStrategyTest.java @@ -0,0 +1,235 @@ +/* Hibernate, Relational Persistence for Idiomatic Java + * + * SPDX-License-Identifier: Apache-2.0 + * Copyright: Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.reactive.schema; + +import java.util.Collection; +import java.util.Set; +import java.util.concurrent.CompletionStage; +import java.util.stream.Stream; + +import org.hibernate.boot.registry.StandardServiceRegistryBuilder; +import org.hibernate.cfg.Configuration; +import org.hibernate.dialect.Dialect; +import org.hibernate.dialect.temptable.TemporaryTable; +import org.hibernate.query.sqm.mutation.internal.temptable.GlobalTemporaryTableStrategy; +import org.hibernate.query.sqm.mutation.internal.temptable.PersistentTableStrategy; +import org.hibernate.reactive.BaseReactiveTest; +import org.hibernate.reactive.annotations.EnabledFor; +import org.hibernate.reactive.provider.Settings; +import org.hibernate.reactive.testing.SqlStatementTracker; +import org.hibernate.reactive.util.impl.CompletionStages; + +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +import io.vertx.junit5.Timeout; +import io.vertx.junit5.VertxTestContext; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.Id; +import jakarta.persistence.Inheritance; +import jakarta.persistence.InheritanceType; + +import static java.util.concurrent.TimeUnit.MINUTES; +import static org.assertj.core.api.Assertions.assertThat; +import static org.hibernate.reactive.containers.DatabaseConfiguration.DBType.COCKROACHDB; +import static org.hibernate.reactive.containers.DatabaseConfiguration.DBType.ORACLE; +import static org.hibernate.reactive.util.impl.CompletionStages.voidFuture; +import static org.junit.jupiter.params.provider.Arguments.arguments; + +/** + * Test enabling and disabling of strategies for the creation of temporary tables to store ids. + * + * @see GlobalTemporaryTableStrategy + * @see PersistentTableStrategy + */ +@Timeout(value = 10, timeUnit = MINUTES) +public class TemporaryIdTableStrategyTest extends BaseReactiveTest { + private static SqlStatementTracker sqlStatementTracker; + + final static Dialect[] dialect = new Dialect[1]; + + @Override + protected Collection> annotatedEntities() { + return Set.of( Engineer.class, Doctor.class, Person.class ); + } + + public static Stream settings() { + return Stream.of( + arguments( true, 1, true, 1 ), + arguments( true, 1, false, 0 ), + // I'm assuming Hibernate won't drop the id tables if they haven't been created + arguments( false, 0, true, 0 ), + arguments( false, 0, false, 0 ) + ); + } + + @Override + protected Configuration constructConfiguration() { + Configuration configuration = super.constructConfiguration(); + configuration.setProperty( Settings.HBM2DDL_AUTO, "create" ); + // Collect all the logs, we are going to filter them later + sqlStatementTracker = new SqlStatementTracker( s -> true, configuration.getProperties() ); + return configuration; + } + + @Override + public CompletionStage deleteEntities(Class... entities) { + // Deleting entities is not necessary for this test + return voidFuture(); + } + + @Override + public void before(VertxTestContext context) { + // We need to start and close our own session factories for the test + } + + @AfterEach + @Override + public void after(VertxTestContext context) { + sqlStatementTracker.clear(); + super.after( context ); + } + + @Override + protected void addServices(StandardServiceRegistryBuilder builder) { + if ( sqlStatementTracker != null ) { + sqlStatementTracker.registerService( builder ); + } + } + + @ParameterizedTest(name = "Global Temporary tables - create: {0}, drop: {2}") + @MethodSource("settings") + @EnabledFor(value = ORACLE, reason = "It uses GlobalTemporaryTableStrategy by default") + public void testGlobalTemporaryTablesStrategy( + boolean enableCreateIdTables, + // Expected number of temporary tables created + int expectedTempTablesCreated, + boolean enableDropIdTables, + // Expected number of temporary tables dropped + int expectedTempTablesDropped, + VertxTestContext context) { + Configuration configuration = constructConfiguration(); + configuration.setProperty( GlobalTemporaryTableStrategy.CREATE_ID_TABLES, enableCreateIdTables ); + configuration.setProperty( GlobalTemporaryTableStrategy.DROP_ID_TABLES, enableDropIdTables ); + + testTemporaryIdTablesCreationAndDropping( configuration, expectedTempTablesCreated, expectedTempTablesDropped, context ); + } + + @ParameterizedTest(name = "Persistent tables - create: {0}, drop: {2}") + @MethodSource("settings") + @EnabledFor(value = COCKROACHDB, reason = "It uses PersistentTemporaryTableStrategy by default") + public void testPersistentTemporaryTablesStrategy( + boolean enableCreateIdTables, + // Expected number of temporary tables created + int expectedTempTablesCreated, + boolean enableDropIdTables, + // Expected number of temporary tables dropped + int expectedTempTablesDropped, + VertxTestContext context) { + + Configuration configuration = constructConfiguration(); + configuration.setProperty( PersistentTableStrategy.CREATE_ID_TABLES, enableCreateIdTables ); + configuration.setProperty( PersistentTableStrategy.DROP_ID_TABLES, enableDropIdTables ); + + testTemporaryIdTablesCreationAndDropping( configuration, expectedTempTablesCreated, expectedTempTablesDropped, context ); + } + + private void testTemporaryIdTablesCreationAndDropping( + Configuration configure, + int expectedTempTablesCreated, + int expectedTempTablesDropped, + VertxTestContext context) { + test( context, setupSessionFactory( configure ) + .thenAccept( v -> { + dialect[0] = getDialect(); + assertThat( commandsCount( dialect[0].getTemporaryTableCreateCommand() ) ) + .as( "Unexpected number of temporary tables for ids CREATED" ) + .isEqualTo( expectedTempTablesCreated ); + sqlStatementTracker.clear(); + } ) + // to ensure the factory is always closed even in case of exceptions + .handle( CompletionStages::handle ) + .thenCompose( this::closeFactory ) + .thenAccept( v -> assertThat( commandsCount( dialect[0].getTemporaryTableDropCommand() ) ) + .as( "Unexpected number of temporary tables for ids DROPPED" ) + .isEqualTo( expectedTempTablesDropped ) ) + ); + } + + // Always try to close the factory without losing the original error (if there was one) + private CompletionStage closeFactory(CompletionStages.CompletionStageHandler handler) { + return factoryManager.stop() + .handle( CompletionStages::handle ) + .thenCompose( factoryHandler -> handler + .getResultAsCompletionStage() + // When there's already an exception, we don't care about errors closing the factory + .thenCompose( factoryHandler::getResultAsCompletionStage ) ); + } + + private static long commandsCount(String temporaryTableCommand) { + return sqlStatementTracker.getLoggedQueries().stream() + .filter( q -> q.startsWith( temporaryTableCommand ) && q.contains( TemporaryTable.ID_TABLE_PREFIX ) ) + .count(); + } + + @Entity(name = "Person") + @Inheritance(strategy = InheritanceType.JOINED) + public static class Person { + + @Id + @GeneratedValue + private Long id; + + private String name; + + private boolean employed; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public boolean isEmployed() { + return employed; + } + + public void setEmployed(boolean employed) { + this.employed = employed; + } + } + + @Entity(name = "Doctor") + public static class Doctor extends Person { + } + + @Entity(name = "Engineer") + public static class Engineer extends Person { + + private boolean fellow; + + public boolean isFellow() { + return fellow; + } + + public void setFellow(boolean fellow) { + this.fellow = fellow; + } + } +} From 49bfe429620ca786898d1f97e09723025b2a9967 Mon Sep 17 00:00:00 2001 From: Davide D'Alto Date: Fri, 14 Feb 2025 17:21:19 +0100 Subject: [PATCH 040/162] [#2114] Upgrade Vert.x SQL client to 4.5.13 --- README.md | 10 +++++----- build.gradle | 2 +- gradle.properties | 6 +++--- tooling/jbang/CockroachDBReactiveTest.java.qute | 4 ++-- tooling/jbang/Db2ReactiveTest.java.qute | 4 ++-- tooling/jbang/Example.java | 6 +++--- tooling/jbang/MariaDBReactiveTest.java.qute | 4 ++-- tooling/jbang/MySQLReactiveTest.java.qute | 4 ++-- tooling/jbang/PostgreSQLReactiveTest.java.qute | 4 ++-- tooling/jbang/ReactiveTest.java | 8 ++++---- 10 files changed, 26 insertions(+), 26 deletions(-) diff --git a/README.md b/README.md index e7816a989..52f70595d 100644 --- a/README.md +++ b/README.md @@ -38,11 +38,11 @@ Hibernate Reactive has been tested with: - MS SQL Server 2022 - Oracle 23 - [Hibernate ORM][] 6.6.7.Final -- [Vert.x Reactive PostgreSQL Client](https://vertx.io/docs/vertx-pg-client/java/) 4.5.12 -- [Vert.x Reactive MySQL Client](https://vertx.io/docs/vertx-mysql-client/java/) 4.5.12 -- [Vert.x Reactive Db2 Client](https://vertx.io/docs/vertx-db2-client/java/) 4.5.12 -- [Vert.x Reactive MS SQL Server Client](https://vertx.io/docs/vertx-mssql-client/java/) 4.5.12 -- [Vert.x Reactive Oracle Client](https://vertx.io/docs/vertx-oracle-client/java/) 4.5.12 +- [Vert.x Reactive PostgreSQL Client](https://vertx.io/docs/vertx-pg-client/java/) 4.5.13 +- [Vert.x Reactive MySQL Client](https://vertx.io/docs/vertx-mysql-client/java/) 4.5.13 +- [Vert.x Reactive Db2 Client](https://vertx.io/docs/vertx-db2-client/java/) 4.5.13 +- [Vert.x Reactive MS SQL Server Client](https://vertx.io/docs/vertx-mssql-client/java/) 4.5.13 +- [Vert.x Reactive Oracle Client](https://vertx.io/docs/vertx-oracle-client/java/) 4.5.13 - [Quarkus][Quarkus] via the Hibernate Reactive extension [PostgreSQL]: https://www.postgresql.org diff --git a/build.gradle b/build.gradle index e9ca27a56..50ddbfa93 100644 --- a/build.gradle +++ b/build.gradle @@ -22,7 +22,7 @@ ext { // Example: // ./gradlew build -PvertxSqlClientVersion=4.0.0-SNAPSHOT if ( !project.hasProperty( 'vertxSqlClientVersion' ) ) { - vertxSqlClientVersion = '4.5.12' + vertxSqlClientVersion = '4.5.13' } testcontainersVersion = '1.20.4' diff --git a/gradle.properties b/gradle.properties index f6740414b..4d1c18f9c 100644 --- a/gradle.properties +++ b/gradle.properties @@ -47,9 +47,9 @@ hibernateOrmVersion = 6.6.7.Final #skipOrmVersionParsing = true # Override default Vert.x Sql client version -#vertxSqlClientVersion = 4.5.12-SNAPSHOT +#vertxSqlClientVersion = 4.5.13-SNAPSHOT # Override default Vert.x Web client and server versions. For integration tests, both default to vertxSqlClientVersion -#vertxWebVersion = 4.5.12 -#vertxWebtClientVersion = 4.5.12 +#vertxWebVersion = 4.5.13 +#vertxWebtClientVersion = 4.5.13 diff --git a/tooling/jbang/CockroachDBReactiveTest.java.qute b/tooling/jbang/CockroachDBReactiveTest.java.qute index ce9001bc3..a4c1e9d21 100755 --- a/tooling/jbang/CockroachDBReactiveTest.java.qute +++ b/tooling/jbang/CockroachDBReactiveTest.java.qute @@ -5,8 +5,8 @@ * Copyright: Red Hat Inc. and Hibernate Authors */ -//DEPS io.vertx:vertx-pg-client:$\{vertx.version:4.5.12} -//DEPS io.vertx:vertx-unit:$\{vertx.version:4.5.12} +//DEPS io.vertx:vertx-pg-client:$\{vertx.version:4.5.13} +//DEPS io.vertx:vertx-unit:$\{vertx.version:4.5.13} //DEPS org.hibernate.reactive:hibernate-reactive-core:$\{hibernate-reactive.version:2.4.0.Final} //DEPS org.assertj:assertj-core:3.26.3 //DEPS junit:junit:4.13.2 diff --git a/tooling/jbang/Db2ReactiveTest.java.qute b/tooling/jbang/Db2ReactiveTest.java.qute index 72a98bbc1..722ee939f 100755 --- a/tooling/jbang/Db2ReactiveTest.java.qute +++ b/tooling/jbang/Db2ReactiveTest.java.qute @@ -5,8 +5,8 @@ * Copyright: Red Hat Inc. and Hibernate Authors */ -//DEPS io.vertx:vertx-db2-client:$\{vertx.version:4.5.12} -//DEPS io.vertx:vertx-unit:$\{vertx.version:4.5.12} +//DEPS io.vertx:vertx-db2-client:$\{vertx.version:4.5.13} +//DEPS io.vertx:vertx-unit:$\{vertx.version:4.5.13} //DEPS org.hibernate.reactive:hibernate-reactive-core:$\{hibernate-reactive.version:2.4.0.Final} //DEPS org.assertj:assertj-core:3.26.3 //DEPS junit:junit:4.13.2 diff --git a/tooling/jbang/Example.java b/tooling/jbang/Example.java index f272684b3..10b482fde 100644 --- a/tooling/jbang/Example.java +++ b/tooling/jbang/Example.java @@ -6,9 +6,9 @@ */ //DEPS com.ongres.scram:client:2.1 -//DEPS io.vertx:vertx-pg-client:${vertx.version:4.5.12} -//DEPS io.vertx:vertx-mysql-client:${vertx.version:4.5.12} -//DEPS io.vertx:vertx-db2-client:${vertx.version:4.5.12} +//DEPS io.vertx:vertx-pg-client:${vertx.version:4.5.13} +//DEPS io.vertx:vertx-mysql-client:${vertx.version:4.5.13} +//DEPS io.vertx:vertx-db2-client:${vertx.version:4.5.13} //DEPS org.hibernate.reactive:hibernate-reactive-core:${hibernate-reactive.version:2.4.0.Final} //DEPS org.slf4j:slf4j-simple:2.0.7 //DESCRIPTION Allow authentication to PostgreSQL using SCRAM: diff --git a/tooling/jbang/MariaDBReactiveTest.java.qute b/tooling/jbang/MariaDBReactiveTest.java.qute index a1bfe3c56..6a44da5fc 100755 --- a/tooling/jbang/MariaDBReactiveTest.java.qute +++ b/tooling/jbang/MariaDBReactiveTest.java.qute @@ -5,8 +5,8 @@ * Copyright: Red Hat Inc. and Hibernate Authors */ -//DEPS io.vertx:vertx-mysql-client:$\{vertx.version:4.5.12} -//DEPS io.vertx:vertx-unit:$\{vertx.version:4.5.12} +//DEPS io.vertx:vertx-mysql-client:$\{vertx.version:4.5.13} +//DEPS io.vertx:vertx-unit:$\{vertx.version:4.5.13} //DEPS org.hibernate.reactive:hibernate-reactive-core:$\{hibernate-reactive.version:2.4.0.Final} //DEPS org.assertj:assertj-core:3.26.3 //DEPS junit:junit:4.13.2 diff --git a/tooling/jbang/MySQLReactiveTest.java.qute b/tooling/jbang/MySQLReactiveTest.java.qute index 13c7220c6..6a0778a30 100755 --- a/tooling/jbang/MySQLReactiveTest.java.qute +++ b/tooling/jbang/MySQLReactiveTest.java.qute @@ -5,8 +5,8 @@ * Copyright: Red Hat Inc. and Hibernate Authors */ -//DEPS io.vertx:vertx-mysql-client:$\{vertx.version:4.5.12} -//DEPS io.vertx:vertx-unit:$\{vertx.version:4.5.12} +//DEPS io.vertx:vertx-mysql-client:$\{vertx.version:4.5.13} +//DEPS io.vertx:vertx-unit:$\{vertx.version:4.5.13} //DEPS org.hibernate.reactive:hibernate-reactive-core:$\{hibernate-reactive.version:2.4.0.Final} //DEPS org.assertj:assertj-core:3.26.3 //DEPS junit:junit:4.13.2 diff --git a/tooling/jbang/PostgreSQLReactiveTest.java.qute b/tooling/jbang/PostgreSQLReactiveTest.java.qute index 1e2264250..6c41b2985 100755 --- a/tooling/jbang/PostgreSQLReactiveTest.java.qute +++ b/tooling/jbang/PostgreSQLReactiveTest.java.qute @@ -5,8 +5,8 @@ * Copyright: Red Hat Inc. and Hibernate Authors */ -//DEPS io.vertx:vertx-pg-client:$\{vertx.version:4.5.12} -//DEPS io.vertx:vertx-unit:$\{vertx.version:4.5.12} +//DEPS io.vertx:vertx-pg-client:$\{vertx.version:4.5.13} +//DEPS io.vertx:vertx-unit:$\{vertx.version:4.5.13} //DEPS org.hibernate.reactive:hibernate-reactive-core:$\{hibernate-reactive.version:2.4.0.Final} //DEPS org.assertj:assertj-core:3.26.3 //DEPS junit:junit:4.13.2 diff --git a/tooling/jbang/ReactiveTest.java b/tooling/jbang/ReactiveTest.java index e642bdda8..6ea8fc33c 100755 --- a/tooling/jbang/ReactiveTest.java +++ b/tooling/jbang/ReactiveTest.java @@ -5,11 +5,11 @@ */ ///usr/bin/env jbang "$0" "$@" ; exit $? -//DEPS io.vertx:vertx-pg-client:${vertx.version:4.5.12} +//DEPS io.vertx:vertx-pg-client:${vertx.version:4.5.13} //DEPS com.ongres.scram:client:2.1 -//DEPS io.vertx:vertx-db2-client:${vertx.version:4.5.12} -//DEPS io.vertx:vertx-mysql-client:${vertx.version:4.5.12} -//DEPS io.vertx:vertx-unit:${vertx.version:4.5.12} +//DEPS io.vertx:vertx-db2-client:${vertx.version:4.5.13} +//DEPS io.vertx:vertx-mysql-client:${vertx.version:4.5.13} +//DEPS io.vertx:vertx-unit:${vertx.version:4.5.13} //DEPS org.hibernate.reactive:hibernate-reactive-core:${hibernate-reactive.version:2.4.0.Final} //DEPS org.assertj:assertj-core:3.26.3 //DEPS junit:junit:4.13.2 From 8269ae0b664064c783c0718ea5ceaccb0d2f192f Mon Sep 17 00:00:00 2001 From: Davide D'Alto Date: Fri, 14 Mar 2025 10:50:34 +0100 Subject: [PATCH 041/162] [#2143] Upgrade Testcontainers to 1.20.6 --- build.gradle | 2 +- tooling/jbang/CockroachDBReactiveTest.java.qute | 2 +- tooling/jbang/Db2ReactiveTest.java.qute | 2 +- tooling/jbang/MariaDBReactiveTest.java.qute | 2 +- tooling/jbang/MySQLReactiveTest.java.qute | 2 +- tooling/jbang/PostgreSQLReactiveTest.java.qute | 2 +- tooling/jbang/ReactiveTest.java | 10 +++++----- 7 files changed, 11 insertions(+), 11 deletions(-) diff --git a/build.gradle b/build.gradle index 50ddbfa93..9962048b8 100644 --- a/build.gradle +++ b/build.gradle @@ -25,7 +25,7 @@ ext { vertxSqlClientVersion = '4.5.13' } - testcontainersVersion = '1.20.4' + testcontainersVersion = '1.20.6' logger.lifecycle "Vert.x SQL Client Version: " + project.vertxSqlClientVersion } diff --git a/tooling/jbang/CockroachDBReactiveTest.java.qute b/tooling/jbang/CockroachDBReactiveTest.java.qute index a4c1e9d21..39d23b73b 100755 --- a/tooling/jbang/CockroachDBReactiveTest.java.qute +++ b/tooling/jbang/CockroachDBReactiveTest.java.qute @@ -10,7 +10,7 @@ //DEPS org.hibernate.reactive:hibernate-reactive-core:$\{hibernate-reactive.version:2.4.0.Final} //DEPS org.assertj:assertj-core:3.26.3 //DEPS junit:junit:4.13.2 -//DEPS org.testcontainers:cockroachdb:1.20.4 +//DEPS org.testcontainers:cockroachdb:1.20.6 //DEPS org.slf4j:slf4j-simple:2.0.7 //// Testcontainer needs the JDBC drivers to start the container diff --git a/tooling/jbang/Db2ReactiveTest.java.qute b/tooling/jbang/Db2ReactiveTest.java.qute index 722ee939f..3a308e34d 100755 --- a/tooling/jbang/Db2ReactiveTest.java.qute +++ b/tooling/jbang/Db2ReactiveTest.java.qute @@ -10,7 +10,7 @@ //DEPS org.hibernate.reactive:hibernate-reactive-core:$\{hibernate-reactive.version:2.4.0.Final} //DEPS org.assertj:assertj-core:3.26.3 //DEPS junit:junit:4.13.2 -//DEPS org.testcontainers:db2:1.20.4 +//DEPS org.testcontainers:db2:1.20.6 //DEPS org.slf4j:slf4j-simple:2.0.7 import jakarta.persistence.Entity; diff --git a/tooling/jbang/MariaDBReactiveTest.java.qute b/tooling/jbang/MariaDBReactiveTest.java.qute index 6a44da5fc..966134e48 100755 --- a/tooling/jbang/MariaDBReactiveTest.java.qute +++ b/tooling/jbang/MariaDBReactiveTest.java.qute @@ -10,7 +10,7 @@ //DEPS org.hibernate.reactive:hibernate-reactive-core:$\{hibernate-reactive.version:2.4.0.Final} //DEPS org.assertj:assertj-core:3.26.3 //DEPS junit:junit:4.13.2 -//DEPS org.testcontainers:mariadb:1.20.4 +//DEPS org.testcontainers:mariadb:1.20.6 //DEPS org.slf4j:slf4j-simple:2.0.7 //// Testcontainer needs the JDBC drivers to start the container diff --git a/tooling/jbang/MySQLReactiveTest.java.qute b/tooling/jbang/MySQLReactiveTest.java.qute index 6a0778a30..1e06c2468 100755 --- a/tooling/jbang/MySQLReactiveTest.java.qute +++ b/tooling/jbang/MySQLReactiveTest.java.qute @@ -10,7 +10,7 @@ //DEPS org.hibernate.reactive:hibernate-reactive-core:$\{hibernate-reactive.version:2.4.0.Final} //DEPS org.assertj:assertj-core:3.26.3 //DEPS junit:junit:4.13.2 -//DEPS org.testcontainers:mysql:1.20.4 +//DEPS org.testcontainers:mysql:1.20.6 //DEPS org.slf4j:slf4j-simple:2.0.7 //// Testcontainer needs the JDBC drivers to start the container diff --git a/tooling/jbang/PostgreSQLReactiveTest.java.qute b/tooling/jbang/PostgreSQLReactiveTest.java.qute index 6c41b2985..be49feea4 100755 --- a/tooling/jbang/PostgreSQLReactiveTest.java.qute +++ b/tooling/jbang/PostgreSQLReactiveTest.java.qute @@ -10,7 +10,7 @@ //DEPS org.hibernate.reactive:hibernate-reactive-core:$\{hibernate-reactive.version:2.4.0.Final} //DEPS org.assertj:assertj-core:3.26.3 //DEPS junit:junit:4.13.2 -//DEPS org.testcontainers:postgresql:1.20.4 +//DEPS org.testcontainers:postgresql:1.20.6 //DEPS org.slf4j:slf4j-simple:2.0.7 //DESCRIPTION Allow authentication to PostgreSQL using SCRAM: //DEPS com.ongres.scram:client:2.1 diff --git a/tooling/jbang/ReactiveTest.java b/tooling/jbang/ReactiveTest.java index 6ea8fc33c..d407af2e3 100755 --- a/tooling/jbang/ReactiveTest.java +++ b/tooling/jbang/ReactiveTest.java @@ -13,11 +13,11 @@ //DEPS org.hibernate.reactive:hibernate-reactive-core:${hibernate-reactive.version:2.4.0.Final} //DEPS org.assertj:assertj-core:3.26.3 //DEPS junit:junit:4.13.2 -//DEPS org.testcontainers:postgresql:1.20.4 -//DEPS org.testcontainers:mysql:1.20.4 -//DEPS org.testcontainers:db2:1.20.4 -//DEPS org.testcontainers:mariadb:1.20.4 -//DEPS org.testcontainers:cockroachdb:1.20.4 +//DEPS org.testcontainers:postgresql:1.20.6 +//DEPS org.testcontainers:mysql:1.20.6 +//DEPS org.testcontainers:db2:1.20.6 +//DEPS org.testcontainers:mariadb:1.20.6 +//DEPS org.testcontainers:cockroachdb:1.20.6 // //// Testcontainer needs the JDBC drivers to start the containers //// Hibernate Reactive doesn't use them From bec54aee7438858f5ddd934f293443301d4347dd Mon Sep 17 00:00:00 2001 From: Davide D'Alto Date: Fri, 14 Mar 2025 10:39:02 +0100 Subject: [PATCH 042/162] [#2064] Add CONTRIBUTING.md --- CONTRIBUTING.md | 107 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 107 insertions(+) create mode 100644 CONTRIBUTING.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 000000000..3e99a1d42 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,107 @@ +# Contributing + +Contributions from the community are essential in keeping Hibernate (and any Open Source +project really) strong and successful. + +# Legal + +All original contributions to Hibernate are licensed under the +[Apache 2.0 license](https://www.apache.org/licenses/LICENSE-2.0). + +The Apache 2.0 license text is included verbatim in the [LICENSE](LICENSE) file in the root directory +of the Hibernate Reactive repository. + +All contributions are subject to the [Developer Certificate of Origin (DCO)](https://developercertificate.org/). + +The DCO text is available verbatim in the [dco.txt](dco.txt) file in the root directory +of the Hibernate Reactive repository. + +## Guidelines + +While we try to keep requirements for contributing to a minimum, there are a few guidelines +we ask that you mind. + +For code contributions, these guidelines include: +* Respect the project code style - find templates for [IntelliJ IDEA](https://hibernate.org/community/contribute/intellij-idea/) or [Eclipse](https://hibernate.org/community/contribute/eclipse-ide/) +* Have a corresponding GitHub [issue](https://github.com/hibernate/hibernate-reactive/issues) and be sure to include + the key for this issue in your commit messages. +* Have a set of appropriate tests. + For your convenience, a [set of test templates](https://github.com/hibernate/hibernate-test-case-templates/tree/main/reactive) + have been made available. + + When submitting bug reports, the tests should reproduce the initially reported bug and illustrate that your solution addresses the issue. + For features/enhancements, the tests should demonstrate that the feature works as intended. + In both cases, be sure to incorporate your tests into the project to protect against possible regressions. +* If applicable, documentation should be updated to reflect the introduced changes +* The code compiles and the tests pass (`./gradlew clean build`) + +For documentation contributions, mainly to respect the project code style, especially in regard +to the use of tabs - as mentioned above, code style templates are available for both IntelliJ IDEA and Eclipse +IDEs. Ideally, these contributions would also have a corresponding issue, although this +is less necessary for documentation contributions. + +## Getting Started + +If you are just getting started with Git, GitHub, and/or contributing to Hibernate via +GitHub there are a few pre-requisite steps to follow: + +* Make sure you have a [GitHub account](https://github.com/signup/free) +* [Fork](https://help.github.com/articles/fork-a-repo) the Hibernate Reactive repository. As discussed in +the linked page, this also includes: + * [set up your local git install](https://help.github.com/articles/set-up-git) + * clone your fork +* Instruct git to ignore certain commits when using `git blame`. From the directory of your local clone, run this: `git config blame.ignoreRevsFile .git-blame-ignore-revs` +* See the wiki pages for setting up your IDE, whether you use +[IntelliJ IDEA](https://hibernate.org/community/contribute/intellij-idea/) +or [Eclipse](https://hibernate.org/community/contribute/eclipse-ide/)(1). + + +## Create the working (topic) branch + +Create a [topic branch](https://git-scm.com/book/en/Git-Branching-Branching-Workflows#Topic-Branches) +on which you will work. The convention is to incorporate the JIRA issue key in the name of this branch, +although this is more of a mnemonic strategy than a hard-and-fast rule - but doing so helps: +* Remember what each branch is for +* Isolate the work from other contributions you may be working on + +_If there is not already a GitHub issue covering the work you want to do, create one._ + +Assuming you will be working from the `main` branch and working +on the GitHub issue #123 : `git checkout -b 123 main` + +## Code + +Do your thing! + + +## Commit + +* Make commits of logical units +* Be sure to start each commit message using the ** GitHub issue key **. For example: + ``` + [#1234] Fix some kind of problem + ``` +* Make sure you have added the necessary tests for your changes +* Run _all_ the tests to ensure nothing else was accidentally broken + +_Before committing, if you want to pull in the latest upstream changes (highly +appreciated btw), please use rebasing rather than merging. Merging creates +"merge commits" that invariably muck up the project timeline._ + +## Submit + +* Push your changes to the topic branch in your fork of the repository +* Initiate a [pull request](https://help.github.com/articles/creating-a-pull-request) +* Adding the sentence `Fix #123`, where `#123` is the issue key, will link the pull request to the corresponding issue + and close it accordingly, when the pull request gets merged. + +It is important that this topic branch of your fork: + +* Is isolated to just the work on this one issue, or multiple issues if they are + related and also fixed/implemented by this work. The main point is to not push commits for more than + one PR to a single branch - GitHub PRs are linked to a branch rather than specific commits +* remain until the PR is closed. Once the underlying branch is deleted the corresponding PR will be closed, + if not already, and the changes will be lost. + +# Notes +(1) Gradle `eclipse` plugin is no longer supported, so the recommended way to import the project in your IDE is with the proper IDE tools/plugins. Don't try to run `./gradlew clean eclipse --refresh-dependencies` from the command line as you'll get an error because `eclipse` no longer exists From d29bac6c3b2e25a3d67164a378bbc73564c8c704 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 1 Mar 2025 03:51:47 +0000 Subject: [PATCH 043/162] Bump the workflow-actions group with 2 updates Bumps the workflow-actions group with 2 updates: [actions/cache](https://github.com/actions/cache) and [actions/upload-artifact](https://github.com/actions/upload-artifact). Updates `actions/cache` from 4.2.0 to 4.2.2 - [Release notes](https://github.com/actions/cache/releases) - [Changelog](https://github.com/actions/cache/blob/main/RELEASES.md) - [Commits](https://github.com/actions/cache/compare/1bd1e32a3bdc45362d1e726936510720a7c30a57...d4323d4df104b026a6aa633fdb11d772146be0bf) Updates `actions/upload-artifact` from 4.6.0 to 4.6.1 - [Release notes](https://github.com/actions/upload-artifact/releases) - [Commits](https://github.com/actions/upload-artifact/compare/65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08...4cec3d8aa04e39d1a68397de0c4cd6fb9dce8ec1) --- updated-dependencies: - dependency-name: actions/cache dependency-type: direct:production update-type: version-update:semver-patch dependency-group: workflow-actions - dependency-name: actions/upload-artifact dependency-type: direct:production update-type: version-update:semver-patch dependency-group: workflow-actions ... Signed-off-by: dependabot[bot] --- .github/workflows/build.yml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 65c72d1d5..dbe3ecc3e 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -90,7 +90,7 @@ jobs: echo "::set-output name=yearmonth::$(/bin/date -u "+%Y-%m")" shell: bash - name: Cache Gradle downloads - uses: actions/cache@1bd1e32a3bdc45362d1e726936510720a7c30a57 # v4.2.0 + uses: actions/cache@d4323d4df104b026a6aa633fdb11d772146be0bf # v4.2.2 id: cache-gradle with: path: | @@ -109,7 +109,7 @@ jobs: - name: Run examples in '${{ matrix.example }}' on ${{ matrix.db }} run: ./gradlew :${{ matrix.example }}:runAllExamplesOn${{ matrix.db }} - name: Upload reports (if build failed) - uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4.6.0 + uses: actions/upload-artifact@4cec3d8aa04e39d1a68397de0c4cd6fb9dce8ec1 # v4.6.1 if: failure() with: name: reports-examples-${{ matrix.db }} @@ -132,7 +132,7 @@ jobs: echo "::set-output name=yearmonth::$(/bin/date -u "+%Y-%m")" shell: bash - name: Cache Gradle downloads - uses: actions/cache@1bd1e32a3bdc45362d1e726936510720a7c30a57 # v4.2.0 + uses: actions/cache@d4323d4df104b026a6aa633fdb11d772146be0bf # v4.2.2 id: cache-gradle with: path: | @@ -151,7 +151,7 @@ jobs: - name: Build and Test with ${{ matrix.db }} run: ./gradlew build -PshowStandardOutput -Pdocker -Pdb=${{ matrix.db }} - name: Upload reports (if build failed) - uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4.6.0 + uses: actions/upload-artifact@4cec3d8aa04e39d1a68397de0c4cd6fb9dce8ec1 # v4.6.1 if: failure() with: name: reports-db-${{ matrix.db }} @@ -203,7 +203,7 @@ jobs: echo "buildtool-cache-key=${ROOT_CACHE_KEY}-${CURRENT_MONTH}-${CURRENT_BRANCH}-${CURRENT_DAY}" >> $GITHUB_OUTPUT - name: Cache Maven/Gradle Dependency/Dist Caches id: cache-maven - uses: actions/cache@1bd1e32a3bdc45362d1e726936510720a7c30a57 # v4.2.0 + uses: actions/cache@d4323d4df104b026a6aa633fdb11d772146be0bf # v4.2.2 # if it's not a pull request, we restore and save the cache if: github.event_name != 'pull_request' with: @@ -220,7 +220,7 @@ jobs: ${{ steps.cache-key.outputs.buildtool-monthly-branch-cache-key }}- ${{ steps.cache-key.outputs.buildtool-monthly-cache-key }}- - name: Restore Maven/Gradle Dependency/Dist Caches - uses: actions/cache/restore@1bd1e32a3bdc45362d1e726936510720a7c30a57 # v4.2.0 + uses: actions/cache/restore@d4323d4df104b026a6aa633fdb11d772146be0bf # v4.2.2 # if it's a pull request, we restore the cache, but we don't save it if: github.event_name == 'pull_request' with: @@ -271,7 +271,7 @@ jobs: -Porg.gradle.java.installations.paths=${{ steps.mainjdk-exportpath.outputs.path }},${{ steps.testjdk-exportpath.outputs.path }} \ ${{ matrix.java.jvm_args && '-Ptest.jdk.launcher.args=' }}${{ matrix.java.jvm_args }} - name: Upload reports (if build failed) - uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4.6.0 + uses: actions/upload-artifact@4cec3d8aa04e39d1a68397de0c4cd6fb9dce8ec1 # v4.6.1 if: failure() with: name: reports-java${{ matrix.java.name }} From 12ea05aa3da275417c0f666955f3bde0360e967a Mon Sep 17 00:00:00 2001 From: Davide D'Alto Date: Tue, 25 Mar 2025 18:09:14 +0100 Subject: [PATCH 044/162] [#2159] Remove JDK 23 testing (cherry picked from commit 779a6324255acd7eba2b32f5ccbbf4e72abdb449) --- .github/workflows/build.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index dbe3ecc3e..868cbe4df 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -177,7 +177,6 @@ jobs: # and it's useful to test that. - { name: "20", java_version_numeric: 20, jvm_args: '--enable-preview' } - { name: "21", java_version_numeric: 21, jvm_args: '--enable-preview' } - - { name: "23", java_version_numeric: 23, from: 'jdk.java.net', jvm_args: '--enable-preview' } - { name: "24-ea", java_version_numeric: 24, from: 'jdk.java.net', jvm_args: '--enable-preview' } - { name: "25-ea", java_version_numeric: 25, from: 'jdk.java.net', jvm_args: '--enable-preview' } steps: From 2be0398ae65cbb7a15c7e115c483d34e2d3d18f9 Mon Sep 17 00:00:00 2001 From: Davide D'Alto Date: Tue, 25 Mar 2025 18:09:42 +0100 Subject: [PATCH 045/162] [#2159] Test with JDK 24 GA (cherry picked from commit 08e06d11ce2b79211bed8a688d8dd55891250df2) --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 868cbe4df..560d2641f 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -177,7 +177,7 @@ jobs: # and it's useful to test that. - { name: "20", java_version_numeric: 20, jvm_args: '--enable-preview' } - { name: "21", java_version_numeric: 21, jvm_args: '--enable-preview' } - - { name: "24-ea", java_version_numeric: 24, from: 'jdk.java.net', jvm_args: '--enable-preview' } + - { name: "24", java_version_numeric: 24, from: 'jdk.java.net', jvm_args: '--enable-preview' } - { name: "25-ea", java_version_numeric: 25, from: 'jdk.java.net', jvm_args: '--enable-preview' } steps: - name: Checkout ${{ inputs.branch }} From 460b2d8f11dc7ad331680431a45af12f3102934a Mon Sep 17 00:00:00 2001 From: Andrea Boriero Date: Sat, 4 Jan 2025 10:20:34 +0100 Subject: [PATCH 046/162] [#2007] NPE retrieving Entity with composite id mixing ManyToOne with basic attributes --- .../ReactiveNonAggregatedIdentifierMappingInitializer.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/sql/results/graph/embeddable/internal/ReactiveNonAggregatedIdentifierMappingInitializer.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/sql/results/graph/embeddable/internal/ReactiveNonAggregatedIdentifierMappingInitializer.java index 0096e8d0f..5228e397e 100644 --- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/sql/results/graph/embeddable/internal/ReactiveNonAggregatedIdentifierMappingInitializer.java +++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/sql/results/graph/embeddable/internal/ReactiveNonAggregatedIdentifierMappingInitializer.java @@ -62,7 +62,7 @@ public CompletionStage reactiveResolveKey(NonAggregatedIdentifierMappingIn final RowProcessingState rowProcessingState = data.getRowProcessingState(); final boolean[] dataIsMissing = {false}; return loop( getInitializers(), initializer -> { - if ( dataIsMissing[0] ) { + if ( dataIsMissing[0] || initializer == null ) { return voidFuture(); } final InitializerData subData = ( (ReactiveInitializer) initializer ) From bd6abac0a58e43cc838cc5b0ab7d6e086b1a0022 Mon Sep 17 00:00:00 2001 From: Andrea Boriero Date: Sat, 4 Jan 2025 10:20:16 +0100 Subject: [PATCH 047/162] [#2007] Add test for NPE retrieving Entity with composite id mixing ManyToOne with basic attributes --- .../reactive/ManyToOneIdClassTest.java | 141 ++++++++++++++++++ 1 file changed, 141 insertions(+) create mode 100644 hibernate-reactive-core/src/test/java/org/hibernate/reactive/ManyToOneIdClassTest.java diff --git a/hibernate-reactive-core/src/test/java/org/hibernate/reactive/ManyToOneIdClassTest.java b/hibernate-reactive-core/src/test/java/org/hibernate/reactive/ManyToOneIdClassTest.java new file mode 100644 index 000000000..a1d1d882e --- /dev/null +++ b/hibernate-reactive-core/src/test/java/org/hibernate/reactive/ManyToOneIdClassTest.java @@ -0,0 +1,141 @@ +/* Hibernate, Relational Persistence for Idiomatic Java + * + * SPDX-License-Identifier: Apache-2.0 + * Copyright: Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.reactive; + +import java.util.Collection; +import java.util.List; + +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import io.vertx.junit5.Timeout; +import io.vertx.junit5.VertxTestContext; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.Id; +import jakarta.persistence.IdClass; +import jakarta.persistence.ManyToOne; + +import static java.util.concurrent.TimeUnit.MINUTES; +import static org.assertj.core.api.Assertions.assertThat; + +@Timeout(value = 1, timeUnit = MINUTES) +public class ManyToOneIdClassTest extends BaseReactiveTest { + + private final static String USER_NAME = "user"; + private final static String SUBSYSTEM_ID = "1"; + + @Override + protected Collection> annotatedEntities() { + return List.of( SystemUser.class, Subsystem.class ); + } + + @BeforeEach + public void populateDb(VertxTestContext context) { + Subsystem subsystem = new Subsystem( SUBSYSTEM_ID, "sub 1" ); + SystemUser systemUser = new SystemUser( subsystem, USER_NAME, "system 1" ); + test( + context, getMutinySessionFactory() + .withTransaction( (s, t) -> s.persistAll( subsystem, systemUser ) ) + ); + } + + @AfterEach + public void after(VertxTestContext context) { + test( context, cleanDb() ); + } + + @Test + public void testQuery(VertxTestContext context) { + test( + context, openSession() + .thenAccept( session -> session.createQuery( "SELECT s FROM SystemUser s", SystemUser.class ) + .getResultList().thenAccept( list -> { + assertThat( list.size() ).isEqualTo( 1 ); + SystemUser systemUser = list.get( 0 ); + assertThat( systemUser.getSubsystem().getId() ).isEqualTo( SUBSYSTEM_ID ); + assertThat( systemUser.getUsername() ).isEqualTo( USER_NAME ); + } ) ) + ); + } + + @Entity(name = "SystemUser") + @IdClass(PK.class) + public static class SystemUser { + + @Id + @ManyToOne(fetch = FetchType.LAZY) + private Subsystem subsystem; + + @Id + private String username; + + private String name; + + public SystemUser() { + } + + public SystemUser(Subsystem subsystem, String username, String name) { + this.subsystem = subsystem; + this.username = username; + this.name = name; + } + + public Subsystem getSubsystem() { + return subsystem; + } + + public String getUsername() { + return username; + } + + public String getName() { + return name; + } + } + + @Entity(name = "Subsystem") + public static class Subsystem { + + @Id + private String id; + + private String description; + + public Subsystem() { + } + + public Subsystem(String id, String description) { + this.id = id; + this.description = description; + } + + public String getId() { + return id; + } + + public String getDescription() { + return description; + } + } + + public static class PK { + + private Subsystem subsystem; + + private String username; + + public PK(Subsystem subsystem, String username) { + this.subsystem = subsystem; + this.username = username; + } + + private PK() { + } + } + +} From 7db4640e49db953502d25198d95734e71c8f2d11 Mon Sep 17 00:00:00 2001 From: Davide D'Alto Date: Tue, 7 Jan 2025 14:19:40 +0100 Subject: [PATCH 048/162] [#2007] Remove obsolete code --- .../ReactiveNonAggregatedIdentifierMappingInitializer.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/sql/results/graph/embeddable/internal/ReactiveNonAggregatedIdentifierMappingInitializer.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/sql/results/graph/embeddable/internal/ReactiveNonAggregatedIdentifierMappingInitializer.java index 5228e397e..51f7d59b7 100644 --- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/sql/results/graph/embeddable/internal/ReactiveNonAggregatedIdentifierMappingInitializer.java +++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/sql/results/graph/embeddable/internal/ReactiveNonAggregatedIdentifierMappingInitializer.java @@ -60,9 +60,8 @@ public CompletionStage reactiveResolveKey(NonAggregatedIdentifierMappingIn } else { final RowProcessingState rowProcessingState = data.getRowProcessingState(); - final boolean[] dataIsMissing = {false}; return loop( getInitializers(), initializer -> { - if ( dataIsMissing[0] || initializer == null ) { + if ( initializer == null ) { return voidFuture(); } final InitializerData subData = ( (ReactiveInitializer) initializer ) @@ -72,7 +71,6 @@ public CompletionStage reactiveResolveKey(NonAggregatedIdentifierMappingIn .thenAccept( v -> { if ( subData.getState() == State.MISSING ) { data.setState( State.MISSING ); - dataIsMissing[0] = true; } } ); } ); From 0f76dbb4210fcb9df3c840ebee92480f8fd65197 Mon Sep 17 00:00:00 2001 From: Davide D'Alto Date: Tue, 7 Jan 2025 14:17:53 +0100 Subject: [PATCH 049/162] [#2007] Minor test clean up --- .../reactive/ManyToOneIdClassTest.java | 24 +++++++------------ 1 file changed, 9 insertions(+), 15 deletions(-) diff --git a/hibernate-reactive-core/src/test/java/org/hibernate/reactive/ManyToOneIdClassTest.java b/hibernate-reactive-core/src/test/java/org/hibernate/reactive/ManyToOneIdClassTest.java index a1d1d882e..73dead49a 100644 --- a/hibernate-reactive-core/src/test/java/org/hibernate/reactive/ManyToOneIdClassTest.java +++ b/hibernate-reactive-core/src/test/java/org/hibernate/reactive/ManyToOneIdClassTest.java @@ -8,7 +8,6 @@ import java.util.Collection; import java.util.List; -import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -40,26 +39,21 @@ public void populateDb(VertxTestContext context) { SystemUser systemUser = new SystemUser( subsystem, USER_NAME, "system 1" ); test( context, getMutinySessionFactory() - .withTransaction( (s, t) -> s.persistAll( subsystem, systemUser ) ) + .withTransaction( s -> s.persistAll( subsystem, systemUser ) ) ); } - @AfterEach - public void after(VertxTestContext context) { - test( context, cleanDb() ); - } - @Test public void testQuery(VertxTestContext context) { test( - context, openSession() - .thenAccept( session -> session.createQuery( "SELECT s FROM SystemUser s", SystemUser.class ) - .getResultList().thenAccept( list -> { - assertThat( list.size() ).isEqualTo( 1 ); - SystemUser systemUser = list.get( 0 ); - assertThat( systemUser.getSubsystem().getId() ).isEqualTo( SUBSYSTEM_ID ); - assertThat( systemUser.getUsername() ).isEqualTo( USER_NAME ); - } ) ) + context, openSession().thenAccept( session -> session + .createQuery( "FROM SystemUser s", SystemUser.class ) + .getResultList().thenAccept( list -> { + assertThat( list ).hasSize( 1 ); + SystemUser systemUser = list.get( 0 ); + assertThat( systemUser.getSubsystem().getId() ).isEqualTo( SUBSYSTEM_ID ); + assertThat( systemUser.getUsername() ).isEqualTo( USER_NAME ); + } ) ) ); } From 72cac022a33d5941e616cb34323c988cb5f2376d Mon Sep 17 00:00:00 2001 From: Davide D'Alto Date: Wed, 19 Mar 2025 11:32:57 +0100 Subject: [PATCH 050/162] [#2150] Avoid creation of logger at runtime Quarkus doesn't like it when running in native mode --- .../temptable/ReactiveGlobalTemporaryTableStrategy.java | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/query/sqm/mutation/internal/temptable/ReactiveGlobalTemporaryTableStrategy.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/query/sqm/mutation/internal/temptable/ReactiveGlobalTemporaryTableStrategy.java index d0204ffff..d92062e2f 100644 --- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/query/sqm/mutation/internal/temptable/ReactiveGlobalTemporaryTableStrategy.java +++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/query/sqm/mutation/internal/temptable/ReactiveGlobalTemporaryTableStrategy.java @@ -27,6 +27,8 @@ public interface ReactiveGlobalTemporaryTableStrategy { + Log LOG = make( Log.class, lookup() ); + static String sessionIdentifier(SharedSessionContractImplementor session) { return session.getSessionIdentifier().toString(); } @@ -64,7 +66,7 @@ default void prepare(MappingModelCreationProcess mappingModelCreationProcess, Jd tableCreatedStage.complete( null ); } else { - make( Log.class, lookup() ).debugf( "Creating global-temp ID table : %s", getTemporaryTable().getTableExpression() ); + LOG.debugf( "Creating global-temp ID table : %s", getTemporaryTable().getTableExpression() ); connectionStage() .thenCompose( this::createTable ) @@ -102,7 +104,7 @@ private CompletionStage releaseConnection(ReactiveConnection connection) { private static void logConnectionClosedError(Throwable t) { if ( t != null ) { - make( Log.class, lookup() ).debugf( "Ignoring error closing the connection: %s", t.getMessage() ); + LOG.debugf( "Ignoring error closing the connection: %s", t.getMessage() ); } } @@ -150,7 +152,7 @@ default void release( setDropIdTables( false ); final TemporaryTable temporaryTable = getTemporaryTable(); - make( Log.class, lookup() ).debugf( "Dropping global-tempk ID table : %s", temporaryTable.getTableExpression() ); + LOG.debugf( "Dropping global-temp ID table : %s", temporaryTable.getTableExpression() ); connectionStage() .thenCompose( this::dropTable ) From 39eeffe5503af6d14ad1b6e19748d2b7d3a2a407 Mon Sep 17 00:00:00 2001 From: marko-bekhta Date: Thu, 27 Mar 2025 21:45:44 +0100 Subject: [PATCH 051/162] [#2166] Hibernate Reactive eager fetching the wrong record for ManyToOne GHQUARKUS-305 --- .../ReactiveEmbeddableInitializerImpl.java | 10 + .../ReactiveEntitySelectFetchInitializer.java | 10 + .../reactive/EmbeddedIdWithManyEagerTest.java | 228 ++++++++++++++++++ 3 files changed, 248 insertions(+) create mode 100644 hibernate-reactive-core/src/test/java/org/hibernate/reactive/EmbeddedIdWithManyEagerTest.java diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/sql/results/graph/embeddable/internal/ReactiveEmbeddableInitializerImpl.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/sql/results/graph/embeddable/internal/ReactiveEmbeddableInitializerImpl.java index 69ae34a73..a1d4a890e 100644 --- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/sql/results/graph/embeddable/internal/ReactiveEmbeddableInitializerImpl.java +++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/sql/results/graph/embeddable/internal/ReactiveEmbeddableInitializerImpl.java @@ -33,6 +33,16 @@ public ReactiveEmbeddableInitializerData( super( initializer, rowProcessingState ); } + @Override + public void setState(State state) { + super.setState( state ); + if ( State.UNINITIALIZED == state ) { + // reset instance to null as otherwise EmbeddableInitializerImpl#prepareCompositeInstance + // will never create a new instance after the "first row with a non-null instance" gets processed + setInstance( null ); + } + } + public EmbeddableMappingType.ConcreteEmbeddableType getConcreteEmbeddableType() { return super.concreteEmbeddableType; } diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/sql/results/graph/entity/internal/ReactiveEntitySelectFetchInitializer.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/sql/results/graph/entity/internal/ReactiveEntitySelectFetchInitializer.java index b27c0cc93..8f848d01b 100644 --- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/sql/results/graph/entity/internal/ReactiveEntitySelectFetchInitializer.java +++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/sql/results/graph/entity/internal/ReactiveEntitySelectFetchInitializer.java @@ -56,6 +56,16 @@ public Object getEntityIdentifier() { public void setEntityIdentifier(Object entityIdentifier) { super.entityIdentifier = entityIdentifier; } + + @Override + public void setState(State state) { + super.setState( state ); + if ( State.UNINITIALIZED == state ) { + // reset instance to null as otherwise EmbeddableInitializerImpl#prepareCompositeInstance + // will never create a new instance after the "first row with a non-null instance" gets processed + setInstance( null ); + } + } } private static final Log LOG = LoggerFactory.make( Log.class, MethodHandles.lookup() ); diff --git a/hibernate-reactive-core/src/test/java/org/hibernate/reactive/EmbeddedIdWithManyEagerTest.java b/hibernate-reactive-core/src/test/java/org/hibernate/reactive/EmbeddedIdWithManyEagerTest.java new file mode 100644 index 000000000..0ceeaef18 --- /dev/null +++ b/hibernate-reactive-core/src/test/java/org/hibernate/reactive/EmbeddedIdWithManyEagerTest.java @@ -0,0 +1,228 @@ +/* Hibernate, Relational Persistence for Idiomatic Java + * + * SPDX-License-Identifier: Apache-2.0 + * Copyright: Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.reactive; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import io.vertx.junit5.VertxTestContext; +import jakarta.persistence.Column; +import jakarta.persistence.Embeddable; +import jakarta.persistence.EmbeddedId; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.MappedSuperclass; +import jakarta.persistence.OneToMany; +import jakarta.persistence.Table; + +public class EmbeddedIdWithManyEagerTest extends BaseReactiveTest { + + Fruit cherry; + Fruit apple; + Fruit banana; + + Flower sunflower; + Flower chrysanthemum; + Flower rose; + + @Override + protected Collection> annotatedEntities() { + return List.of( Flower.class, Fruit.class ); + } + + @BeforeEach + public void populateDb(VertxTestContext context) { + Seed seed1 = new Seed( 1 ); + rose = new Flower( seed1, "Rose" ); + + cherry = new Fruit( seed1, "Cherry" ); + cherry.addFriend( rose ); + + Seed seed2 = new Seed( 2 ); + sunflower = new Flower( seed2, "Sunflower" ); + + apple = new Fruit( seed2, "Apple" ); + apple.addFriend( sunflower ); + + Seed seed3 = new Seed( 3 ); + chrysanthemum = new Flower( seed3, "Chrysanthemum" ); + + banana = new Fruit( seed3, "Banana" ); + banana.addFriend( chrysanthemum ); + + test( + context, + getMutinySessionFactory().withTransaction( s -> s + .persistAll( cherry, rose, sunflower, apple, chrysanthemum, banana ) + ) + ); + } + + @Test + public void testFindWithEmbeddedId(VertxTestContext context) { + test( + context, getMutinySessionFactory().withTransaction( s -> s + .find( Flower.class, chrysanthemum.getSeed() ) + .invoke( flower -> assertThat( flower.getName() ).isEqualTo( chrysanthemum.getName() ) ) + ) + ); + } + + @Test + public void testSelectQueryWithEmbeddedId(VertxTestContext context) { + test( + context, getMutinySessionFactory().withTransaction( s -> s + .createSelectionQuery( "from Flower", Flower.class ) + .getResultList() + .invoke( list -> assertThat( list.stream().map( Flower::getName ) ) + .containsExactlyInAnyOrder( + sunflower.getName(), + chrysanthemum.getName(), + rose.getName() + ) + ) + ) + ); + } + + @Test + public void testSelectQueryWithEmbeddedIdAndEagerRelation(VertxTestContext context) { + test( + context, getMutinySessionFactory().withTransaction( s -> s + .createSelectionQuery( "from Flower f ", Flower.class ) + .getResultList() + .invoke( list -> assertThat( list.stream().map( Flower::getFriend ).map( Plant::getName ) ) + .containsExactlyInAnyOrder( + cherry.getName(), + apple.getName(), + banana.getName() + ) + ) + ) + ); + } + + @Embeddable + public static class Seed { + + @Column(nullable = false, updatable = false) + private Integer id; + + public Seed() { + } + + public Seed(Integer id) { + this.id = id; + } + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + } + + @MappedSuperclass + public static abstract class Plant { + + @EmbeddedId + private Seed seed; + + @Column(length = 40, unique = true) + private String name; + + protected Plant() { + } + + protected Plant(Seed seed, String name) { + this.seed = seed; + this.name = name; + } + + public Seed getSeed() { + return seed; + } + + public void setSeed(Seed seed) { + this.seed = seed; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + } + + @Entity(name = "Fruit") + @Table(name = "known_fruits") + public static class Fruit extends Plant { + + @OneToMany(mappedBy = "friend", fetch = FetchType.LAZY) + private List friends = new ArrayList<>(); + + public Fruit() { + } + + public Fruit(Seed seed, String name) { + super( seed, name ); + } + + public void addFriend(Flower flower) { + this.friends.add( flower ); + flower.friend = this; + } + + public List getFriends() { + return friends; + } + + @Override + public String toString() { + return "Fruit{" + getSeed().getId() + "," + getName() + '}'; + } + + } + + @Entity(name = "Flower") + @Table(name = "known_flowers") + public static class Flower extends Plant { + + @ManyToOne(fetch = FetchType.EAGER, optional = false) + @JoinColumn(name = "friend", referencedColumnName = "id", nullable = false) + private Fruit friend; + + public Flower() { + } + + public Flower(Seed seed, String name) { + super( seed, name ); + } + + public Fruit getFriend() { + return friend; + } + + @Override + public String toString() { + return "Flower{" + getSeed().getId() + "," + getName() + '}'; + } + + } + +} From df1a4a24c9dc5821d569654b9b5cd42c4cf9a7ad Mon Sep 17 00:00:00 2001 From: Davide D'Alto Date: Mon, 7 Apr 2025 15:39:07 +0200 Subject: [PATCH 052/162] [#2187] Use adjustToDefaultPrecision in UTCNormalizedZonedTest Replace `DateTimeUtils.roundToDefaultPrecision` with `DateTimeUtils.adjustToDefaultPrecision` This should prevent the failures we sometimes have on CI. --- .../reactive/timezones/UTCNormalizedZonedTest.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/hibernate-reactive-core/src/test/java/org/hibernate/reactive/timezones/UTCNormalizedZonedTest.java b/hibernate-reactive-core/src/test/java/org/hibernate/reactive/timezones/UTCNormalizedZonedTest.java index 9943a0f97..474f5df7b 100644 --- a/hibernate-reactive-core/src/test/java/org/hibernate/reactive/timezones/UTCNormalizedZonedTest.java +++ b/hibernate-reactive-core/src/test/java/org/hibernate/reactive/timezones/UTCNormalizedZonedTest.java @@ -29,7 +29,7 @@ import static org.hibernate.cfg.AvailableSettings.TIMEZONE_DEFAULT_STORAGE; import static org.hibernate.reactive.containers.DatabaseConfiguration.DBType.DB2; import static org.hibernate.reactive.testing.ReactiveAssertions.assertWithTruncationThat; -import static org.hibernate.type.descriptor.DateTimeUtils.roundToDefaultPrecision; +import static org.hibernate.type.descriptor.DateTimeUtils.adjustToDefaultPrecision; @Timeout(value = 10, timeUnit = MINUTES) @DisabledFor(value = DB2, reason = "Exception: IllegalStateException: Needed to have 6 in buffer but only had 0") @@ -60,10 +60,10 @@ public void test(VertxTestContext context) { .thenCompose( zid -> openSession() .thenCompose( s -> s.find( Zoned.class, zid ) .thenAccept( z -> { - assertWithTruncationThat( roundToDefaultPrecision( z.zonedDateTime.toInstant(), getDialect() ) ) - .isEqualTo( roundToDefaultPrecision( nowZoned.toInstant(), getDialect() ) ); - assertWithTruncationThat( roundToDefaultPrecision( z.offsetDateTime.toInstant(), getDialect() ) ) - .isEqualTo( roundToDefaultPrecision( nowOffset.toInstant(), getDialect() ) ); + assertWithTruncationThat( adjustToDefaultPrecision( z.zonedDateTime.toInstant(), getDialect() ) ) + .isEqualTo( adjustToDefaultPrecision( nowZoned.toInstant(), getDialect() ) ); + assertWithTruncationThat( adjustToDefaultPrecision( z.offsetDateTime.toInstant(), getDialect() ) ) + .isEqualTo( adjustToDefaultPrecision( nowOffset.toInstant(), getDialect() ) ); assertThat( z.offsetDateTime.getOffset() ).isEqualTo( ZoneId.of( "Z" ) ); assertThat( z.zonedDateTime.getZone() ).isEqualTo( ZoneOffset.ofHours( 0 ) ); } ) From aa716edd3f4b0a5d2f882400ba32c3d9d4cb4346 Mon Sep 17 00:00:00 2001 From: Davide D'Alto Date: Tue, 8 Apr 2025 14:01:41 +0200 Subject: [PATCH 053/162] [#2190] Upgrade MariaDB to 11.7.2 --- .../java/org/hibernate/reactive/containers/MariaDatabase.java | 2 +- podman.md | 2 +- tooling/jbang/MariaDBReactiveTest.java.qute | 2 +- tooling/jbang/ReactiveTest.java | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/hibernate-reactive-core/src/test/java/org/hibernate/reactive/containers/MariaDatabase.java b/hibernate-reactive-core/src/test/java/org/hibernate/reactive/containers/MariaDatabase.java index 575c5290d..6c9db8dfe 100644 --- a/hibernate-reactive-core/src/test/java/org/hibernate/reactive/containers/MariaDatabase.java +++ b/hibernate-reactive-core/src/test/java/org/hibernate/reactive/containers/MariaDatabase.java @@ -21,7 +21,7 @@ class MariaDatabase extends MySQLDatabase { * TIP: To reuse the same containers across multiple runs, set `testcontainers.reuse.enable=true` in a file located * at `$HOME/.testcontainers.properties` (create the file if it does not exist). */ - public static final MariaDBContainer maria = new MariaDBContainer<>( imageName( "mariadb", "11.4.2" ) ) + public static final MariaDBContainer maria = new MariaDBContainer<>( imageName( "mariadb", "11.7.2" ) ) .withUsername( DatabaseConfiguration.USERNAME ) .withPassword( DatabaseConfiguration.PASSWORD ) .withDatabaseName( DatabaseConfiguration.DB_NAME ) diff --git a/podman.md b/podman.md index dc81fb828..74e010be1 100644 --- a/podman.md +++ b/podman.md @@ -67,7 +67,7 @@ and schema to run the tests: ``` podman run --rm --name HibernateTestingMariaDB \ -e MYSQL_ROOT_PASSWORD=hreact -e MYSQL_DATABASE=hreact -e MYSQL_USER=hreact -e MYSQL_PASSWORD=hreact \ - -p 3306:3306 docker.io/mariadb:11.4.2 + -p 3306:3306 docker.io/mariadb:11.7.2 ``` When the database has started, you can run the tests on MariaDB with: diff --git a/tooling/jbang/MariaDBReactiveTest.java.qute b/tooling/jbang/MariaDBReactiveTest.java.qute index 966134e48..227f014a1 100755 --- a/tooling/jbang/MariaDBReactiveTest.java.qute +++ b/tooling/jbang/MariaDBReactiveTest.java.qute @@ -69,7 +69,7 @@ public class {baseName} { } @ClassRule - public final static MariaDBContainer database = new MariaDBContainer<>( imageName( "docker.io", "mariadb", "11.4.2" ) ); + public final static MariaDBContainer database = new MariaDBContainer<>( imageName( "docker.io", "mariadb", "11.7.2" ) ); private Mutiny.SessionFactory sessionFactory; diff --git a/tooling/jbang/ReactiveTest.java b/tooling/jbang/ReactiveTest.java index d407af2e3..bbec3a4b0 100755 --- a/tooling/jbang/ReactiveTest.java +++ b/tooling/jbang/ReactiveTest.java @@ -231,7 +231,7 @@ enum Database { POSTGRESQL( () -> new PostgreSQLContainer( "postgres:16.3" ) ), MYSQL( () -> new MySQLContainer( "mysql:8.4.0" ) ), DB2( () -> new Db2Container( "docker.io/icr.io/db2_community/db2:12.1.0.0" ).acceptLicense() ), - MARIADB( () -> new MariaDBContainer( "mariadb:11.4.2" ) ), + MARIADB( () -> new MariaDBContainer( "mariadb:11.7.2" ) ), COCKROACHDB( () -> new CockroachContainer( "cockroachdb/cockroach:v24.1.0" ) ); private final Supplier> containerSupplier; From d522a80325636ef6b4c92e82f70db33bab566efa Mon Sep 17 00:00:00 2001 From: Davide D'Alto Date: Tue, 8 Apr 2025 15:10:23 +0200 Subject: [PATCH 054/162] [#2190] Upgrade MySQL to 9.2.0 --- .github/workflows/build.yml | 2 +- README.md | 2 +- .../java/org/hibernate/reactive/containers/MySQLDatabase.java | 2 +- podman.md | 2 +- tooling/jbang/MySQLReactiveTest.java.qute | 2 +- tooling/jbang/ReactiveTest.java | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 560d2641f..d8787309f 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -50,7 +50,7 @@ jobs: # Label used to access the service container mysql: # Docker Hub image - image: mysql:8.4.0 + image: mysql:9.2.0 env: MYSQL_ROOT_PASSWORD: hreact MYSQL_DATABASE: hreact diff --git a/README.md b/README.md index 52f70595d..0569633d8 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,7 @@ Hibernate Reactive has been tested with: - Java 11, 17, 21, 23 - PostgreSQL 16 -- MySQL 8 +- MySQL 9 - MariaDB 11 - Db2 11 - CockroachDB v24 diff --git a/hibernate-reactive-core/src/test/java/org/hibernate/reactive/containers/MySQLDatabase.java b/hibernate-reactive-core/src/test/java/org/hibernate/reactive/containers/MySQLDatabase.java index 9b94cf8ed..72c73113d 100644 --- a/hibernate-reactive-core/src/test/java/org/hibernate/reactive/containers/MySQLDatabase.java +++ b/hibernate-reactive-core/src/test/java/org/hibernate/reactive/containers/MySQLDatabase.java @@ -87,7 +87,7 @@ class MySQLDatabase implements TestableDatabase { * TIP: To reuse the same containers across multiple runs, set `testcontainers.reuse.enable=true` in a file located * at `$HOME/.testcontainers.properties` (create the file if it does not exist). */ - public static final MySQLContainer mysql = new MySQLContainer<>( imageName( "mysql", "8.4.0") ) + public static final MySQLContainer mysql = new MySQLContainer<>( imageName( "mysql", "9.2.0") ) .withUsername( DatabaseConfiguration.USERNAME ) .withPassword( DatabaseConfiguration.PASSWORD ) .withDatabaseName( DatabaseConfiguration.DB_NAME ) diff --git a/podman.md b/podman.md index 74e010be1..711862835 100644 --- a/podman.md +++ b/podman.md @@ -94,7 +94,7 @@ and schema to run the tests: ``` podman run --rm --name HibernateTestingMySQL \ -e MYSQL_ROOT_PASSWORD=hreact -e MYSQL_DATABASE=hreact -e MYSQL_USER=hreact -e MYSQL_PASSWORD=hreact \ - -p 3306:3306 docker.io/mysql:8.4.0 + -p 3306:3306 docker.io/mysql:9.2.0 ``` When the database has started, you can run the tests on MySQL with: diff --git a/tooling/jbang/MySQLReactiveTest.java.qute b/tooling/jbang/MySQLReactiveTest.java.qute index 1e06c2468..84c7671b0 100755 --- a/tooling/jbang/MySQLReactiveTest.java.qute +++ b/tooling/jbang/MySQLReactiveTest.java.qute @@ -72,7 +72,7 @@ public class {baseName} { } @ClassRule - public final static MySQLContainer database = new MySQLContainer<>( imageName( "docker.io", "mysql", "8.4.0" ) ); + public final static MySQLContainer database = new MySQLContainer<>( imageName( "docker.io", "mysql", "9.2.0" ) ); private Mutiny.SessionFactory sessionFactory; diff --git a/tooling/jbang/ReactiveTest.java b/tooling/jbang/ReactiveTest.java index bbec3a4b0..55461c927 100755 --- a/tooling/jbang/ReactiveTest.java +++ b/tooling/jbang/ReactiveTest.java @@ -229,7 +229,7 @@ public String toString() { */ enum Database { POSTGRESQL( () -> new PostgreSQLContainer( "postgres:16.3" ) ), - MYSQL( () -> new MySQLContainer( "mysql:8.4.0" ) ), + MYSQL( () -> new MySQLContainer( "mysql:9.2.0" ) ), DB2( () -> new Db2Container( "docker.io/icr.io/db2_community/db2:12.1.0.0" ).acceptLicense() ), MARIADB( () -> new MariaDBContainer( "mariadb:11.7.2" ) ), COCKROACHDB( () -> new CockroachContainer( "cockroachdb/cockroach:v24.1.0" ) ); From e21e979743a2cfb8d04027b48698fad3c61d46a5 Mon Sep 17 00:00:00 2001 From: Davide D'Alto Date: Tue, 8 Apr 2025 15:11:10 +0200 Subject: [PATCH 055/162] [#2190] Upgrade PostgreSQL to 17.4 --- .github/workflows/build.yml | 2 +- README.md | 2 +- .../org/hibernate/reactive/containers/PostgreSQLDatabase.java | 2 +- .../src/test/java/org/hibernate/reactive/it/BaseReactiveIT.java | 2 +- .../reactive/it/quarkus/qe/database/BaseReactiveIT.java | 2 +- .../java/org/hibernate/reactive/it/verticle/VertxServer.java | 2 +- podman.md | 2 +- tooling/jbang/Example.java | 2 +- tooling/jbang/PostgreSQLReactiveTest.java.qute | 2 +- tooling/jbang/ReactiveTest.java | 2 +- 10 files changed, 10 insertions(+), 10 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index d8787309f..b99524924 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -66,7 +66,7 @@ jobs: - 3306:3306 postgres: # Docker Hub image - image: postgres:16.3 + image: postgres:17.4 env: POSTGRES_DB: hreact POSTGRES_USER: hreact diff --git a/README.md b/README.md index 0569633d8..62d0cc32b 100644 --- a/README.md +++ b/README.md @@ -30,7 +30,7 @@ Learn more at . Hibernate Reactive has been tested with: - Java 11, 17, 21, 23 -- PostgreSQL 16 +- PostgreSQL 17 - MySQL 9 - MariaDB 11 - Db2 11 diff --git a/hibernate-reactive-core/src/test/java/org/hibernate/reactive/containers/PostgreSQLDatabase.java b/hibernate-reactive-core/src/test/java/org/hibernate/reactive/containers/PostgreSQLDatabase.java index 038733e7e..0d076a93b 100644 --- a/hibernate-reactive-core/src/test/java/org/hibernate/reactive/containers/PostgreSQLDatabase.java +++ b/hibernate-reactive-core/src/test/java/org/hibernate/reactive/containers/PostgreSQLDatabase.java @@ -87,7 +87,7 @@ class PostgreSQLDatabase implements TestableDatabase { * TIP: To reuse the same containers across multiple runs, set `testcontainers.reuse.enable=true` in a file located * at `$HOME/.testcontainers.properties` (create the file if it does not exist). */ - public static final PostgreSQLContainer postgresql = new PostgreSQLContainer<>( imageName( "postgres", "16.3" ) ) + public static final PostgreSQLContainer postgresql = new PostgreSQLContainer<>( imageName( "postgres", "17.4" ) ) .withUsername( DatabaseConfiguration.USERNAME ) .withPassword( DatabaseConfiguration.PASSWORD ) .withDatabaseName( DatabaseConfiguration.DB_NAME ) diff --git a/integration-tests/bytecode-enhancements-it/src/test/java/org/hibernate/reactive/it/BaseReactiveIT.java b/integration-tests/bytecode-enhancements-it/src/test/java/org/hibernate/reactive/it/BaseReactiveIT.java index 72ad3273d..ff9f5e601 100644 --- a/integration-tests/bytecode-enhancements-it/src/test/java/org/hibernate/reactive/it/BaseReactiveIT.java +++ b/integration-tests/bytecode-enhancements-it/src/test/java/org/hibernate/reactive/it/BaseReactiveIT.java @@ -53,7 +53,7 @@ public abstract class BaseReactiveIT { public static final boolean USE_DOCKER = Boolean.getBoolean( "docker" ); public static final DockerImageName IMAGE_NAME = DockerImageName - .parse( "docker.io/postgres:16.3" ) + .parse( "docker.io/postgres:17.4" ) .asCompatibleSubstituteFor( "postgres" ); public static final String USERNAME = "hreact"; diff --git a/integration-tests/hibernate-validator-postgres-it/src/test/java/org/hibernate/reactive/it/quarkus/qe/database/BaseReactiveIT.java b/integration-tests/hibernate-validator-postgres-it/src/test/java/org/hibernate/reactive/it/quarkus/qe/database/BaseReactiveIT.java index 7272f13f2..afff092e9 100644 --- a/integration-tests/hibernate-validator-postgres-it/src/test/java/org/hibernate/reactive/it/quarkus/qe/database/BaseReactiveIT.java +++ b/integration-tests/hibernate-validator-postgres-it/src/test/java/org/hibernate/reactive/it/quarkus/qe/database/BaseReactiveIT.java @@ -53,7 +53,7 @@ public abstract class BaseReactiveIT { public static final boolean USE_DOCKER = Boolean.getBoolean( "docker" ); public static final DockerImageName IMAGE_NAME = DockerImageName - .parse( "docker.io/postgres:16.3" ) + .parse( "docker.io/postgres:17.4" ) .asCompatibleSubstituteFor( "postgres" ); public static final String USERNAME = "hreact"; diff --git a/integration-tests/verticle-postgres-it/src/main/java/org/hibernate/reactive/it/verticle/VertxServer.java b/integration-tests/verticle-postgres-it/src/main/java/org/hibernate/reactive/it/verticle/VertxServer.java index eab23a6ff..238e5278b 100644 --- a/integration-tests/verticle-postgres-it/src/main/java/org/hibernate/reactive/it/verticle/VertxServer.java +++ b/integration-tests/verticle-postgres-it/src/main/java/org/hibernate/reactive/it/verticle/VertxServer.java @@ -36,7 +36,7 @@ public class VertxServer { // These properties are in DatabaseConfiguration in core public static final boolean USE_DOCKER = Boolean.getBoolean( "docker" ); - public static final String IMAGE_NAME = "postgres:16.3"; + public static final String IMAGE_NAME = "postgres:17.4"; public static final String USERNAME = "hreact"; public static final String PASSWORD = "hreact"; public static final String DB_NAME = "hreact"; diff --git a/podman.md b/podman.md index 711862835..ea9280709 100644 --- a/podman.md +++ b/podman.md @@ -39,7 +39,7 @@ required credentials and schema to run the tests: podman run --rm --name HibernateTestingPGSQL \ -e POSTGRES_USER=hreact -e POSTGRES_PASSWORD=hreact -e POSTGRES_DB=hreact \ -e POSTGRES_INITDB_ARGS="-A password" \ - -p 5432:5432 docker.io/postgres:16.3 + -p 5432:5432 docker.io/postgres:17.4 ``` When the database has started, you can run the tests on PostgreSQL with: diff --git a/tooling/jbang/Example.java b/tooling/jbang/Example.java index 10b482fde..d453dca6a 100644 --- a/tooling/jbang/Example.java +++ b/tooling/jbang/Example.java @@ -59,7 +59,7 @@ *
      *                 podman run --rm --name HibernateTestingPGSQL \
      *                      -e POSTGRES_USER=hreact -e POSTGRES_PASSWORD=hreact -e POSTGRES_DB=hreact \
    - *                      -p 5432:5432 postgres:16.3
    + *                      -p 5432:5432 postgres:17.4
      *              
    * *
    3. Run the example with JBang
    diff --git a/tooling/jbang/PostgreSQLReactiveTest.java.qute b/tooling/jbang/PostgreSQLReactiveTest.java.qute index be49feea4..5eb85a050 100755 --- a/tooling/jbang/PostgreSQLReactiveTest.java.qute +++ b/tooling/jbang/PostgreSQLReactiveTest.java.qute @@ -67,7 +67,7 @@ public class {baseName} { } @ClassRule - public final static PostgreSQLContainer database = new PostgreSQLContainer( imageName( "docker.io", "postgres", "16.3" ) ); + public final static PostgreSQLContainer database = new PostgreSQLContainer( imageName( "docker.io", "postgres", "17.4" ) ); private Mutiny.SessionFactory sessionFactory; diff --git a/tooling/jbang/ReactiveTest.java b/tooling/jbang/ReactiveTest.java index 55461c927..8a90f763a 100755 --- a/tooling/jbang/ReactiveTest.java +++ b/tooling/jbang/ReactiveTest.java @@ -228,7 +228,7 @@ public String toString() { * It's a wrapper around the testcontainers classes. */ enum Database { - POSTGRESQL( () -> new PostgreSQLContainer( "postgres:16.3" ) ), + POSTGRESQL( () -> new PostgreSQLContainer( "postgres:17.4" ) ), MYSQL( () -> new MySQLContainer( "mysql:9.2.0" ) ), DB2( () -> new Db2Container( "docker.io/icr.io/db2_community/db2:12.1.0.0" ).acceptLicense() ), MARIADB( () -> new MariaDBContainer( "mariadb:11.7.2" ) ), From 6e201f98910fcd3e0963fa8364290db91a27879b Mon Sep 17 00:00:00 2001 From: Davide D'Alto Date: Tue, 8 Apr 2025 15:11:48 +0200 Subject: [PATCH 056/162] [#2190] Upgrade CockroachDB to 24.1.15 --- .../org/hibernate/reactive/containers/CockroachDBDatabase.java | 2 +- podman.md | 2 +- tooling/jbang/CockroachDBReactiveTest.java.qute | 2 +- tooling/jbang/ReactiveTest.java | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/hibernate-reactive-core/src/test/java/org/hibernate/reactive/containers/CockroachDBDatabase.java b/hibernate-reactive-core/src/test/java/org/hibernate/reactive/containers/CockroachDBDatabase.java index 103723127..7d9da67cc 100644 --- a/hibernate-reactive-core/src/test/java/org/hibernate/reactive/containers/CockroachDBDatabase.java +++ b/hibernate-reactive-core/src/test/java/org/hibernate/reactive/containers/CockroachDBDatabase.java @@ -25,7 +25,7 @@ class CockroachDBDatabase extends PostgreSQLDatabase { * TIP: To reuse the same containers across multiple runs, set `testcontainers.reuse.enable=true` in a file located * at `$HOME/.testcontainers.properties` (create the file if it does not exist). */ - public static final CockroachContainer cockroachDb = new CockroachContainer( imageName( "cockroachdb/cockroach", "v24.1.0" ) ) + public static final CockroachContainer cockroachDb = new CockroachContainer( imageName( "cockroachdb/cockroach", "v24.1.15" ) ) // Username, password and database are not supported by test container at the moment // Testcontainers will use a database named 'postgres' and the 'root' user .withReuse( true ); diff --git a/podman.md b/podman.md index ea9280709..733720def 100644 --- a/podman.md +++ b/podman.md @@ -121,7 +121,7 @@ configured to run the tests: ``` podman run --rm --name=HibernateTestingCockroachDB \ --hostname=roachrr1 -p 26257:26257 -p 8080:8080 \ - docker.io/cockroachdb/cockroach:v24.1.0 start-single-node --insecure + docker.io/cockroachdb/cockroach:v24.1.15 start-single-node --insecure ``` Some of tests needs temporary tables and because this is an experimental feature in diff --git a/tooling/jbang/CockroachDBReactiveTest.java.qute b/tooling/jbang/CockroachDBReactiveTest.java.qute index 39d23b73b..eabb01794 100755 --- a/tooling/jbang/CockroachDBReactiveTest.java.qute +++ b/tooling/jbang/CockroachDBReactiveTest.java.qute @@ -70,7 +70,7 @@ public class {baseName} { } @ClassRule - public final static CockroachContainer database = new CockroachContainer( imageName( "cockroachdb", "cockroach", "v24.1.0" ) ); + public final static CockroachContainer database = new CockroachContainer( imageName( "cockroachdb", "cockroach", "v24.1.15" ) ); private Mutiny.SessionFactory sessionFactory; diff --git a/tooling/jbang/ReactiveTest.java b/tooling/jbang/ReactiveTest.java index 8a90f763a..9de038cf6 100755 --- a/tooling/jbang/ReactiveTest.java +++ b/tooling/jbang/ReactiveTest.java @@ -232,7 +232,7 @@ enum Database { MYSQL( () -> new MySQLContainer( "mysql:9.2.0" ) ), DB2( () -> new Db2Container( "docker.io/icr.io/db2_community/db2:12.1.0.0" ).acceptLicense() ), MARIADB( () -> new MariaDBContainer( "mariadb:11.7.2" ) ), - COCKROACHDB( () -> new CockroachContainer( "cockroachdb/cockroach:v24.1.0" ) ); + COCKROACHDB( () -> new CockroachContainer( "cockroachdb/cockroach:v24.1.15" ) ); private final Supplier> containerSupplier; From 9947ae814108e84d76e4c13ddb703a899ad0755f Mon Sep 17 00:00:00 2001 From: Davide D'Alto Date: Tue, 8 Apr 2025 14:54:11 +0200 Subject: [PATCH 057/162] [#2190] Update Db2 version in README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 62d0cc32b..2b337596e 100644 --- a/README.md +++ b/README.md @@ -33,7 +33,7 @@ Hibernate Reactive has been tested with: - PostgreSQL 17 - MySQL 9 - MariaDB 11 -- Db2 11 +- Db2 12 - CockroachDB v24 - MS SQL Server 2022 - Oracle 23 From 66bc86eb8ba3f22a7a27d2ff0653ca4858a37165 Mon Sep 17 00:00:00 2001 From: Davide D'Alto Date: Tue, 8 Apr 2025 15:12:41 +0200 Subject: [PATCH 058/162] [#2190] Update JDKs in the README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 2b337596e..f7f9bbbf1 100644 --- a/README.md +++ b/README.md @@ -29,7 +29,7 @@ Learn more at . Hibernate Reactive has been tested with: -- Java 11, 17, 21, 23 +- Java 11, 17, 21, 24 - PostgreSQL 17 - MySQL 9 - MariaDB 11 From 922f8b38463cb659400dfbbf60ea69eaf03c0ba5 Mon Sep 17 00:00:00 2001 From: Davide D'Alto Date: Tue, 8 Apr 2025 15:25:27 +0200 Subject: [PATCH 059/162] [#2192] Upgrade Vert.x SQL client to 4.5.14 --- README.md | 10 +++++----- build.gradle | 2 +- gradle.properties | 6 +++--- tooling/jbang/CockroachDBReactiveTest.java.qute | 4 ++-- tooling/jbang/Db2ReactiveTest.java.qute | 4 ++-- tooling/jbang/Example.java | 6 +++--- tooling/jbang/MariaDBReactiveTest.java.qute | 4 ++-- tooling/jbang/MySQLReactiveTest.java.qute | 4 ++-- tooling/jbang/PostgreSQLReactiveTest.java.qute | 4 ++-- tooling/jbang/ReactiveTest.java | 8 ++++---- 10 files changed, 26 insertions(+), 26 deletions(-) diff --git a/README.md b/README.md index f7f9bbbf1..f7ef23d5b 100644 --- a/README.md +++ b/README.md @@ -38,11 +38,11 @@ Hibernate Reactive has been tested with: - MS SQL Server 2022 - Oracle 23 - [Hibernate ORM][] 6.6.7.Final -- [Vert.x Reactive PostgreSQL Client](https://vertx.io/docs/vertx-pg-client/java/) 4.5.13 -- [Vert.x Reactive MySQL Client](https://vertx.io/docs/vertx-mysql-client/java/) 4.5.13 -- [Vert.x Reactive Db2 Client](https://vertx.io/docs/vertx-db2-client/java/) 4.5.13 -- [Vert.x Reactive MS SQL Server Client](https://vertx.io/docs/vertx-mssql-client/java/) 4.5.13 -- [Vert.x Reactive Oracle Client](https://vertx.io/docs/vertx-oracle-client/java/) 4.5.13 +- [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 - [Quarkus][Quarkus] via the Hibernate Reactive extension [PostgreSQL]: https://www.postgresql.org diff --git a/build.gradle b/build.gradle index 9962048b8..1ad0a24c7 100644 --- a/build.gradle +++ b/build.gradle @@ -22,7 +22,7 @@ ext { // Example: // ./gradlew build -PvertxSqlClientVersion=4.0.0-SNAPSHOT if ( !project.hasProperty( 'vertxSqlClientVersion' ) ) { - vertxSqlClientVersion = '4.5.13' + vertxSqlClientVersion = '4.5.14' } testcontainersVersion = '1.20.6' diff --git a/gradle.properties b/gradle.properties index 4d1c18f9c..28817c734 100644 --- a/gradle.properties +++ b/gradle.properties @@ -47,9 +47,9 @@ hibernateOrmVersion = 6.6.7.Final #skipOrmVersionParsing = true # Override default Vert.x Sql client version -#vertxSqlClientVersion = 4.5.13-SNAPSHOT +#vertxSqlClientVersion = 4.5.14-SNAPSHOT # Override default Vert.x Web client and server versions. For integration tests, both default to vertxSqlClientVersion -#vertxWebVersion = 4.5.13 -#vertxWebtClientVersion = 4.5.13 +#vertxWebVersion = 4.5.14 +#vertxWebtClientVersion = 4.5.14 diff --git a/tooling/jbang/CockroachDBReactiveTest.java.qute b/tooling/jbang/CockroachDBReactiveTest.java.qute index eabb01794..22293ca9b 100755 --- a/tooling/jbang/CockroachDBReactiveTest.java.qute +++ b/tooling/jbang/CockroachDBReactiveTest.java.qute @@ -5,8 +5,8 @@ * Copyright: Red Hat Inc. and Hibernate Authors */ -//DEPS io.vertx:vertx-pg-client:$\{vertx.version:4.5.13} -//DEPS io.vertx:vertx-unit:$\{vertx.version:4.5.13} +//DEPS io.vertx:vertx-pg-client:$\{vertx.version:4.5.14} +//DEPS io.vertx:vertx-unit:$\{vertx.version:4.5.14} //DEPS org.hibernate.reactive:hibernate-reactive-core:$\{hibernate-reactive.version:2.4.0.Final} //DEPS org.assertj:assertj-core:3.26.3 //DEPS junit:junit:4.13.2 diff --git a/tooling/jbang/Db2ReactiveTest.java.qute b/tooling/jbang/Db2ReactiveTest.java.qute index 3a308e34d..f752a1a16 100755 --- a/tooling/jbang/Db2ReactiveTest.java.qute +++ b/tooling/jbang/Db2ReactiveTest.java.qute @@ -5,8 +5,8 @@ * Copyright: Red Hat Inc. and Hibernate Authors */ -//DEPS io.vertx:vertx-db2-client:$\{vertx.version:4.5.13} -//DEPS io.vertx:vertx-unit:$\{vertx.version:4.5.13} +//DEPS io.vertx:vertx-db2-client:$\{vertx.version:4.5.14} +//DEPS io.vertx:vertx-unit:$\{vertx.version:4.5.14} //DEPS org.hibernate.reactive:hibernate-reactive-core:$\{hibernate-reactive.version:2.4.0.Final} //DEPS org.assertj:assertj-core:3.26.3 //DEPS junit:junit:4.13.2 diff --git a/tooling/jbang/Example.java b/tooling/jbang/Example.java index d453dca6a..0ec38c459 100644 --- a/tooling/jbang/Example.java +++ b/tooling/jbang/Example.java @@ -6,9 +6,9 @@ */ //DEPS com.ongres.scram:client:2.1 -//DEPS io.vertx:vertx-pg-client:${vertx.version:4.5.13} -//DEPS io.vertx:vertx-mysql-client:${vertx.version:4.5.13} -//DEPS io.vertx:vertx-db2-client:${vertx.version:4.5.13} +//DEPS io.vertx:vertx-pg-client:${vertx.version:4.5.14} +//DEPS io.vertx:vertx-mysql-client:${vertx.version:4.5.14} +//DEPS io.vertx:vertx-db2-client:${vertx.version:4.5.14} //DEPS org.hibernate.reactive:hibernate-reactive-core:${hibernate-reactive.version:2.4.0.Final} //DEPS org.slf4j:slf4j-simple:2.0.7 //DESCRIPTION Allow authentication to PostgreSQL using SCRAM: diff --git a/tooling/jbang/MariaDBReactiveTest.java.qute b/tooling/jbang/MariaDBReactiveTest.java.qute index 227f014a1..f0b0a7fc6 100755 --- a/tooling/jbang/MariaDBReactiveTest.java.qute +++ b/tooling/jbang/MariaDBReactiveTest.java.qute @@ -5,8 +5,8 @@ * Copyright: Red Hat Inc. and Hibernate Authors */ -//DEPS io.vertx:vertx-mysql-client:$\{vertx.version:4.5.13} -//DEPS io.vertx:vertx-unit:$\{vertx.version:4.5.13} +//DEPS io.vertx:vertx-mysql-client:$\{vertx.version:4.5.14} +//DEPS io.vertx:vertx-unit:$\{vertx.version:4.5.14} //DEPS org.hibernate.reactive:hibernate-reactive-core:$\{hibernate-reactive.version:2.4.0.Final} //DEPS org.assertj:assertj-core:3.26.3 //DEPS junit:junit:4.13.2 diff --git a/tooling/jbang/MySQLReactiveTest.java.qute b/tooling/jbang/MySQLReactiveTest.java.qute index 84c7671b0..93d6dff11 100755 --- a/tooling/jbang/MySQLReactiveTest.java.qute +++ b/tooling/jbang/MySQLReactiveTest.java.qute @@ -5,8 +5,8 @@ * Copyright: Red Hat Inc. and Hibernate Authors */ -//DEPS io.vertx:vertx-mysql-client:$\{vertx.version:4.5.13} -//DEPS io.vertx:vertx-unit:$\{vertx.version:4.5.13} +//DEPS io.vertx:vertx-mysql-client:$\{vertx.version:4.5.14} +//DEPS io.vertx:vertx-unit:$\{vertx.version:4.5.14} //DEPS org.hibernate.reactive:hibernate-reactive-core:$\{hibernate-reactive.version:2.4.0.Final} //DEPS org.assertj:assertj-core:3.26.3 //DEPS junit:junit:4.13.2 diff --git a/tooling/jbang/PostgreSQLReactiveTest.java.qute b/tooling/jbang/PostgreSQLReactiveTest.java.qute index 5eb85a050..6178603dd 100755 --- a/tooling/jbang/PostgreSQLReactiveTest.java.qute +++ b/tooling/jbang/PostgreSQLReactiveTest.java.qute @@ -5,8 +5,8 @@ * Copyright: Red Hat Inc. and Hibernate Authors */ -//DEPS io.vertx:vertx-pg-client:$\{vertx.version:4.5.13} -//DEPS io.vertx:vertx-unit:$\{vertx.version:4.5.13} +//DEPS io.vertx:vertx-pg-client:$\{vertx.version:4.5.14} +//DEPS io.vertx:vertx-unit:$\{vertx.version:4.5.14} //DEPS org.hibernate.reactive:hibernate-reactive-core:$\{hibernate-reactive.version:2.4.0.Final} //DEPS org.assertj:assertj-core:3.26.3 //DEPS junit:junit:4.13.2 diff --git a/tooling/jbang/ReactiveTest.java b/tooling/jbang/ReactiveTest.java index 9de038cf6..73de3a9c3 100755 --- a/tooling/jbang/ReactiveTest.java +++ b/tooling/jbang/ReactiveTest.java @@ -5,11 +5,11 @@ */ ///usr/bin/env jbang "$0" "$@" ; exit $? -//DEPS io.vertx:vertx-pg-client:${vertx.version:4.5.13} +//DEPS io.vertx:vertx-pg-client:${vertx.version:4.5.14} //DEPS com.ongres.scram:client:2.1 -//DEPS io.vertx:vertx-db2-client:${vertx.version:4.5.13} -//DEPS io.vertx:vertx-mysql-client:${vertx.version:4.5.13} -//DEPS io.vertx:vertx-unit:${vertx.version:4.5.13} +//DEPS io.vertx:vertx-db2-client:${vertx.version:4.5.14} +//DEPS io.vertx:vertx-mysql-client:${vertx.version:4.5.14} +//DEPS io.vertx:vertx-unit:${vertx.version:4.5.14} //DEPS org.hibernate.reactive:hibernate-reactive-core:${hibernate-reactive.version:2.4.0.Final} //DEPS org.assertj:assertj-core:3.26.3 //DEPS junit:junit:4.13.2 From 294f7402279217e3be9cf2018cdf17dd51eab0ae Mon Sep 17 00:00:00 2001 From: Davide D'Alto Date: Tue, 8 Apr 2025 15:45:26 +0200 Subject: [PATCH 060/162] [#2196] Upgrade Hibernate ORM to 6.6.13.Final --- README.md | 2 +- gradle.properties | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index f7ef23d5b..02323747a 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ Hibernate Reactive has been tested with: - CockroachDB v24 - MS SQL Server 2022 - Oracle 23 -- [Hibernate ORM][] 6.6.7.Final +- [Hibernate ORM][] 6.6.13.Final - [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 diff --git a/gradle.properties b/gradle.properties index 28817c734..e2eca690e 100644 --- a/gradle.properties +++ b/gradle.properties @@ -35,12 +35,12 @@ org.gradle.java.installations.auto-download=false #enableMavenLocalRepo = true # The default Hibernate ORM version (override using `-PhibernateOrmVersion=the.version.you.want`) -hibernateOrmVersion = 6.6.7.Final +hibernateOrmVersion = 6.6.13.Final # Override default Hibernate ORM Gradle plugin version # Using the stable version because I don't know how to configure the build to download the snapshot version from # a remote repository -#hibernateOrmGradlePluginVersion = 6.6.7.Final +#hibernateOrmGradlePluginVersion = 6.6.13.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 From 742ab0b5f4aeda833a9463573bf5bcc6abc3eb76 Mon Sep 17 00:00:00 2001 From: Thomas Segismont Date: Wed, 2 Apr 2025 15:10:32 +0200 Subject: [PATCH 061/162] [#2174] Prepare for Vert.x 5 upgrade in Vert.x Context Closes #2174 Local context data management methods are deprecated and will be removed in Vert.x 5. This change will make it easier to upgrade to Vert.x 5 (should be just a matter of changing imports) --- .../reactive/context/impl/VertxContext.java | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) 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 4448c9b6c..fef172e66 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 @@ -36,10 +36,10 @@ public void injectServices(ServiceRegistryImplementor serviceRegistry) { @Override public void put(Key key, T instance) { - final io.vertx.core.Context context = Vertx.currentContext(); + final ContextInternal context = ContextInternal.current(); if ( context != null ) { if ( trace ) LOG.tracef( "Putting key,value in context: [%1$s, %2$s]", key, instance ); - context.putLocal( key, instance ); + context.localContextData().put( key, instance ); } else { if ( trace ) LOG.tracef( "Context is null for key,value: [%1$s, %2$s]", key, instance ); @@ -49,9 +49,10 @@ public void put(Key key, T instance) { @Override public T get(Key key) { - final io.vertx.core.Context context = Vertx.currentContext(); + final ContextInternal context = ContextInternal.current(); if ( context != null ) { - T local = context.getLocal( key ); + @SuppressWarnings("unchecked") + T local = (T) context.localContextData().get( key ); if ( trace ) LOG.tracef( "Getting value %2$s from context for key %1$s", key, local ); return local; } @@ -63,9 +64,9 @@ public T get(Key key) { @Override public void remove(Key key) { - final io.vertx.core.Context context = Vertx.currentContext(); + final ContextInternal context = ContextInternal.current(); if ( context != null ) { - boolean removed = context.removeLocal( key ); + boolean removed = context.localContextData().remove( key ) != null; if ( trace ) LOG.tracef( "Key %s removed from context: %s", key, removed ); } else { From b4ab6a4b0d09eb0f5d7dc6d750a7609088b28649 Mon Sep 17 00:00:00 2001 From: Thomas Segismont Date: Fri, 4 Apr 2025 15:38:04 +0200 Subject: [PATCH 062/162] [#2176] Create custom Vert.x contextual data storage Closes #2176 In Vert.x 5, the local context data map is deprecated. Hibernate Reactive can have its own Vert.x contextual data storage (requires creating a io.vertx.core.spi.context.storage.ContextLocal key). --- .../context/impl/ContextualDataStorage.java | 25 +++++++++++++++++++ .../reactive/context/impl/VertxContext.java | 18 ++++++++++--- .../io.vertx.core.spi.VertxServiceProvider | 1 + 3 files changed, 40 insertions(+), 4 deletions(-) create mode 100644 hibernate-reactive-core/src/main/java/org/hibernate/reactive/context/impl/ContextualDataStorage.java create mode 100644 hibernate-reactive-core/src/main/resources/META-INF/services/io.vertx.core.spi.VertxServiceProvider 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 new file mode 100644 index 000000000..295b92f4d --- /dev/null +++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/context/impl/ContextualDataStorage.java @@ -0,0 +1,25 @@ +/* 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 fef172e66..937dc3b1b 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,9 +6,12 @@ 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 org.hibernate.reactive.context.Context; import org.hibernate.reactive.logging.impl.Log; @@ -39,7 +42,7 @@ public void put(Key key, T instance) { final ContextInternal context = ContextInternal.current(); if ( context != null ) { if ( trace ) LOG.tracef( "Putting key,value in context: [%1$s, %2$s]", key, instance ); - context.localContextData().put( key, instance ); + VertxContext.contextualDataMap( context ).put( key, instance ); } else { if ( trace ) LOG.tracef( "Context is null for key,value: [%1$s, %2$s]", key, instance ); @@ -51,8 +54,7 @@ public void put(Key key, T instance) { public T get(Key key) { final ContextInternal context = ContextInternal.current(); if ( context != null ) { - @SuppressWarnings("unchecked") - T local = (T) context.localContextData().get( key ); + T local = VertxContext.contextualDataMap( context ).get( key ); if ( trace ) LOG.tracef( "Getting value %2$s from context for key %1$s", key, local ); return local; } @@ -66,7 +68,7 @@ public T get(Key key) { public void remove(Key key) { final ContextInternal context = ContextInternal.current(); if ( context != null ) { - boolean removed = context.localContextData().remove( key ) != null; + boolean removed = contextualDataMap( context ).remove( key ) != null; if ( trace ) LOG.tracef( "Key %s removed from context: %s", key, removed ); } else { @@ -93,4 +95,12 @@ 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/resources/META-INF/services/io.vertx.core.spi.VertxServiceProvider b/hibernate-reactive-core/src/main/resources/META-INF/services/io.vertx.core.spi.VertxServiceProvider new file mode 100644 index 000000000..80ffcb31c --- /dev/null +++ b/hibernate-reactive-core/src/main/resources/META-INF/services/io.vertx.core.spi.VertxServiceProvider @@ -0,0 +1 @@ +org.hibernate.reactive.context.impl.ContextualDataStorage \ No newline at end of file From 03199c5b66b3af6d72cae05fe31f77c0588d8ec0 Mon Sep 17 00:00:00 2001 From: Hibernate-CI Date: Tue, 8 Apr 2025 15:45:17 +0000 Subject: [PATCH 063/162] Update project version to : `2.4.6.Final` --- gradle/version.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/version.properties b/gradle/version.properties index 0d7e548df..3992a0cf7 100644 --- a/gradle/version.properties +++ b/gradle/version.properties @@ -1 +1 @@ -projectVersion=2.4.6-SNAPSHOT \ No newline at end of file +projectVersion=2.4.6.Final \ No newline at end of file From 1c9b52eafb42fc61dc40b83c3c2e26fb397b6ad2 Mon Sep 17 00:00:00 2001 From: Hibernate-CI Date: Tue, 8 Apr 2025 15:46:10 +0000 Subject: [PATCH 064/162] Update project version to : `2.4.7-SNAPSHOT` --- gradle/version.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/version.properties b/gradle/version.properties index 3992a0cf7..6868909df 100644 --- a/gradle/version.properties +++ b/gradle/version.properties @@ -1 +1 @@ -projectVersion=2.4.6.Final \ No newline at end of file +projectVersion=2.4.7-SNAPSHOT \ No newline at end of file From 156f7c3d97ed105e92a3bc52e6bd1daed67482f0 Mon Sep 17 00:00:00 2001 From: Thomas Segismont Date: Fri, 11 Apr 2025 13:08:14 +0200 Subject: [PATCH 065/162] Make CONTEXTUAL_DATA_KEY constant It shouldn't be allowed to change it. --- .../hibernate/reactive/context/impl/ContextualDataStorage.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 index 295b92f4d..39cb8fa10 100644 --- 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 @@ -17,7 +17,7 @@ public class ContextualDataStorage implements VertxServiceProvider { @SuppressWarnings("rawtypes") - static ContextLocal CONTEXTUAL_DATA_KEY = ContextLocal.registerLocal( ConcurrentMap.class ); + final static ContextLocal CONTEXTUAL_DATA_KEY = ContextLocal.registerLocal( ConcurrentMap.class ); @Override public void init(VertxBuilder vertxBuilder) { From 72fdc5a7687a4dadb90d3cf13c76d634266cb64f Mon Sep 17 00:00:00 2001 From: Gavin King Date: Mon, 21 Apr 2025 20:47:13 +0200 Subject: [PATCH 066/162] [#2209] fix cast to ReactiveSession that broke StatelessSession --- .../ReactiveEntitySelectFetchInitializer.java | 4 +- .../reactive/MutinyStatelessSessionTest.java | 250 ++++++++++++++++++ 2 files changed, 252 insertions(+), 2 deletions(-) create mode 100644 hibernate-reactive-core/src/test/java/org/hibernate/reactive/MutinyStatelessSessionTest.java diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/sql/results/graph/entity/internal/ReactiveEntitySelectFetchInitializer.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/sql/results/graph/entity/internal/ReactiveEntitySelectFetchInitializer.java index 8f848d01b..6d5ea5418 100644 --- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/sql/results/graph/entity/internal/ReactiveEntitySelectFetchInitializer.java +++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/sql/results/graph/entity/internal/ReactiveEntitySelectFetchInitializer.java @@ -23,7 +23,7 @@ import org.hibernate.proxy.LazyInitializer; import org.hibernate.reactive.logging.impl.Log; import org.hibernate.reactive.logging.impl.LoggerFactory; -import org.hibernate.reactive.session.ReactiveSession; +import org.hibernate.reactive.session.ReactiveQueryProducer; import org.hibernate.reactive.sql.results.graph.ReactiveInitializer; import org.hibernate.spi.NavigablePath; import org.hibernate.sql.results.graph.AssemblerCreationState; @@ -154,7 +154,7 @@ else if ( data.getInstance() == null ) { data.setState( State.INITIALIZED ); final String entityName = concreteDescriptor.getEntityName(); - return ( (ReactiveSession) session ).reactiveInternalLoad( + return ( (ReactiveQueryProducer) session ).reactiveInternalLoad( entityName, data.getEntityIdentifier(), true, diff --git a/hibernate-reactive-core/src/test/java/org/hibernate/reactive/MutinyStatelessSessionTest.java b/hibernate-reactive-core/src/test/java/org/hibernate/reactive/MutinyStatelessSessionTest.java new file mode 100644 index 000000000..5d325b5f6 --- /dev/null +++ b/hibernate-reactive-core/src/test/java/org/hibernate/reactive/MutinyStatelessSessionTest.java @@ -0,0 +1,250 @@ +/* Hibernate, Relational Persistence for Idiomatic Java + * + * SPDX-License-Identifier: Apache-2.0 + * Copyright: Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.reactive; + +import io.vertx.junit5.Timeout; +import io.vertx.junit5.VertxTestContext; +import jakarta.persistence.*; +import jakarta.persistence.criteria.*; +import org.junit.jupiter.api.Test; + +import java.util.Collection; +import java.util.List; +import java.util.Objects; + +import static java.util.concurrent.TimeUnit.MINUTES; +import static org.junit.jupiter.api.Assertions.*; + +@Timeout(value = 10, timeUnit = MINUTES) + +public class MutinyStatelessSessionTest extends BaseReactiveTest { + + @Override + protected Collection> annotatedEntities() { + return List.of( GuineaPig.class ); + } + + @Test + public void testStatelessSession(VertxTestContext context) { + GuineaPig pig = new GuineaPig( "Aloi" ); + test( context, getMutinySessionFactory().withStatelessSession( ss -> ss + .insert( pig ) + .chain( v -> ss.createSelectionQuery( "from GuineaPig where name=:n", GuineaPig.class ) + .setParameter( "n", pig.name ) + .getResultList() ) + .invoke( list -> { + assertFalse( list.isEmpty() ); + assertEquals( 1, list.size() ); + assertThatPigsAreEqual( pig, list.get( 0 ) ); + } ) + .chain( v -> ss.get( GuineaPig.class, pig.id ) ) + .chain( p -> { + assertThatPigsAreEqual( pig, p ); + p.name = "X"; + return ss.update( p ); + } ) + .chain( v -> ss.refresh( pig ) ) + .invoke( v -> assertEquals( pig.name, "X" ) ) + .chain( v -> ss.createMutationQuery( "update GuineaPig set name='Y'" ).executeUpdate() ) + .chain( v -> ss.refresh( pig ) ) + .invoke( v -> assertEquals( pig.name, "Y" ) ) + .chain( v -> ss.delete( pig ) ) + .chain( v -> ss.createSelectionQuery( "from GuineaPig", GuineaPig.class ).getResultList() ) + .invoke( list -> assertTrue( list.isEmpty() ) ) ) + ); + } + + @Test + public void testStatelessSessionWithNamed(VertxTestContext context) { + GuineaPig pig = new GuineaPig( "Aloi" ); + test( context, getMutinySessionFactory().withStatelessSession( ss -> ss + .insert( pig ) + .chain( v -> ss.createNamedQuery( "findbyname", GuineaPig.class ) + .setParameter( "n", pig.name ) + .getResultList() ) + .invoke( list -> { + assertFalse( list.isEmpty() ); + assertEquals( 1, list.size() ); + assertThatPigsAreEqual( pig, list.get( 0 ) ); + } ) + .chain( v -> ss.get( GuineaPig.class, pig.id ) ) + .chain( p -> { + assertThatPigsAreEqual( pig, p ); + p.name = "X"; + return ss.update( p ); + } ) + .chain( v -> ss.refresh( pig ) ) + .invoke( v -> assertEquals( pig.name, "X" ) ) + .chain( v -> ss.createNamedQuery( "updatebyname" ).executeUpdate() ) + .chain( v -> ss.refresh( pig ) ) + .invoke( v -> assertEquals( pig.name, "Y" ) ) + .chain( v -> ss.delete( pig ) ) + .chain( v -> ss.createNamedQuery( "findall" ).getResultList() ) + .invoke( list -> assertTrue( list.isEmpty() ) ) ) + ); + } + + @Test + public void testStatelessSessionWithNative(VertxTestContext context) { + GuineaPig pig = new GuineaPig( "Aloi" ); + test( context, getMutinySessionFactory().openStatelessSession() + .chain( ss -> ss.insert( pig ) + .chain( v -> ss + .createNativeQuery( "select * from Piggy where name=:n", GuineaPig.class ) + .setParameter( "n", pig.name ) + .getResultList() ) + .invoke( list -> { + assertFalse( list.isEmpty() ); + assertEquals( 1, list.size() ); + assertThatPigsAreEqual( pig, list.get( 0 ) ); + } ) + .chain( v -> ss.get( GuineaPig.class, pig.id ) ) + .chain( p -> { + assertThatPigsAreEqual( pig, p ); + p.name = "X"; + return ss.update( p ); + } ) + .chain( v -> ss.refresh( pig ) ) + .invoke( v -> assertEquals( pig.name, "X" ) ) + .chain( v -> ss.createNativeQuery( "update Piggy set name='Y'" ) + .executeUpdate() ) + .invoke( rows -> assertEquals( 1, rows ) ) + .chain( v -> ss.refresh( pig ) ) + .invoke( v -> assertEquals( pig.name, "Y" ) ) + .chain( v -> ss.delete( pig ) ) + .chain( v -> ss.createNativeQuery( "select id from Piggy" ).getResultList() ) + .invoke( list -> assertTrue( list.isEmpty() ) ) + .chain( v -> ss.close() ) ) + ); + } + + @Test + public void testStatelessSessionCriteria(VertxTestContext context) { + GuineaPig pig = new GuineaPig( "Aloi" ); + GuineaPig mate = new GuineaPig("Aloina"); + pig.mate = mate; + + CriteriaBuilder cb = getSessionFactory().getCriteriaBuilder(); + + CriteriaQuery query = cb.createQuery( GuineaPig.class ); + Root gp = query.from( GuineaPig.class ); + query.where( cb.equal( gp.get( "name" ), cb.parameter( String.class, "n" ) ) ); + query.orderBy( cb.asc( gp.get( "name" ) ) ); + + test( context, getMutinySessionFactory().openStatelessSession() + .chain( ss -> ss.insert(mate) + .chain( v -> ss.insert(pig) ) + .chain( v -> ss.createQuery( query ) + .setParameter( "n", pig.name ) + .getResultList() ) + .invoke( list -> { + assertFalse( list.isEmpty() ); + assertEquals( 1, list.size() ); + assertThatPigsAreEqual( pig, list.get( 0 ) ); + } ) + .chain( v -> ss.close() ) ) + ); + } + + @Test + public void testTransactionPropagation(VertxTestContext context) { + test( context, getMutinySessionFactory().withStatelessSession( + session -> session.withTransaction( transaction -> session.createSelectionQuery( "from GuineaPig", GuineaPig.class ) + .getResultList() + .chain( list -> { + assertNotNull( session.currentTransaction() ); + assertFalse( session.currentTransaction().isMarkedForRollback() ); + session.currentTransaction().markForRollback(); + assertTrue( session.currentTransaction().isMarkedForRollback() ); + assertTrue( transaction.isMarkedForRollback() ); + return session.withTransaction( t -> { + assertTrue( t.isMarkedForRollback() ); + return session.createSelectionQuery( "from GuineaPig", GuineaPig.class ).getResultList(); + } ); + } ) ) + ) ); + } + + @Test + public void testSessionPropagation(VertxTestContext context) { + test( context, getMutinySessionFactory().withStatelessSession( + session -> session.createSelectionQuery( "from GuineaPig", GuineaPig.class ).getResultList() + .chain( list -> getMutinySessionFactory().withStatelessSession( s -> { + assertEquals( session, s ); + return s.createSelectionQuery( "from GuineaPig", GuineaPig.class ).getResultList(); + } ) ) + ) ); + } + + private void assertThatPigsAreEqual( GuineaPig expected, GuineaPig actual) { + assertNotNull( actual ); + assertEquals( expected.getId(), actual.getId() ); + assertEquals( expected.getName(), actual.getName() ); + } + + @NamedQuery(name = "findbyname", query = "from GuineaPig where name=:n") + @NamedQuery(name = "updatebyname", query = "update GuineaPig set name='Y'") + @NamedQuery(name = "findall", query = "from GuineaPig") + + @Entity(name = "GuineaPig") + @Table(name = "Piggy") + public static class GuineaPig { + @Id + @GeneratedValue + private Integer id; + private String name; + @Version + private int version; + + @ManyToOne + private GuineaPig mate; + + public GuineaPig() { + } + + public GuineaPig(String name) { + this.name = name; + } + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + @Override + public String toString() { + return id + ": " + name; + } + + @Override + public boolean equals(Object o) { + if ( this == o ) { + return true; + } + if ( o == null || getClass() != o.getClass() ) { + return false; + } + GuineaPig guineaPig = (GuineaPig) o; + return Objects.equals( name, guineaPig.name ); + } + + @Override + public int hashCode() { + return Objects.hash( name ); + } + } +} From 5e26d30bc966215c79475cf7ee6cf4fdb4833cc8 Mon Sep 17 00:00:00 2001 From: Gavin King Date: Mon, 21 Apr 2025 20:53:07 +0200 Subject: [PATCH 067/162] [#2209] fix more unnecessary casts to ReactiveSession at least some of these are not actually bugs, but some others look sus --- .../event/impl/DefaultReactiveDeleteEventListener.java | 3 ++- .../reactive/event/impl/DefaultReactiveLockEventListener.java | 3 ++- .../event/impl/DefaultReactiveRefreshEventListener.java | 4 ++-- .../internal/cte/ReactiveAbstractCteMutationHandler.java | 4 ++-- .../sqm/mutation/internal/cte/ReactiveCteInsertHandler.java | 4 ++-- .../graph/entity/internal/ReactiveEntityInitializerImpl.java | 4 ++-- 6 files changed, 12 insertions(+), 10 deletions(-) diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/event/impl/DefaultReactiveDeleteEventListener.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/event/impl/DefaultReactiveDeleteEventListener.java index 66151f03b..6b2392e1e 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 @@ -48,6 +48,7 @@ import org.hibernate.reactive.event.ReactiveDeleteEventListener; import org.hibernate.reactive.logging.impl.Log; import org.hibernate.reactive.logging.impl.LoggerFactory; +import org.hibernate.reactive.session.ReactiveQueryProducer; import org.hibernate.reactive.session.ReactiveSession; import org.hibernate.type.CollectionType; import org.hibernate.type.CompositeType; @@ -199,7 +200,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/DefaultReactiveLockEventListener.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/event/impl/DefaultReactiveLockEventListener.java index 7832298e0..a75ac1194 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 @@ -35,6 +35,7 @@ import org.hibernate.reactive.logging.impl.Log; import org.hibernate.reactive.logging.impl.LoggerFactory; import org.hibernate.reactive.persister.entity.impl.ReactiveEntityPersister; +import org.hibernate.reactive.session.ReactiveQueryProducer; import org.hibernate.reactive.session.ReactiveSession; import static org.hibernate.pretty.MessageHelper.infoString; @@ -76,7 +77,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/query/sqm/mutation/internal/cte/ReactiveAbstractCteMutationHandler.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/query/sqm/mutation/internal/cte/ReactiveAbstractCteMutationHandler.java index d1ea9026f..a75872f43 100644 --- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/query/sqm/mutation/internal/cte/ReactiveAbstractCteMutationHandler.java +++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/query/sqm/mutation/internal/cte/ReactiveAbstractCteMutationHandler.java @@ -30,8 +30,8 @@ import org.hibernate.query.sqm.spi.SqmParameterMappingModelResolutionAccess; import org.hibernate.query.sqm.tree.SqmDeleteOrUpdateStatement; import org.hibernate.query.sqm.tree.expression.SqmParameter; +import org.hibernate.reactive.engine.spi.ReactiveSharedSessionContractImplementor; import org.hibernate.reactive.query.sqm.mutation.spi.ReactiveAbstractMutationHandler; -import org.hibernate.reactive.session.ReactiveSession; import org.hibernate.reactive.sql.exec.internal.StandardReactiveSelectExecutor; import org.hibernate.reactive.sql.results.spi.ReactiveListResultsConsumer; import org.hibernate.sql.ast.SqlAstTranslator; @@ -179,7 +179,7 @@ public MappingModelExpressible getResolvedMappingModelType(SqmParameter StandardReactiveSelectExecutor.INSTANCE.list( select, diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/query/sqm/mutation/internal/cte/ReactiveCteInsertHandler.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/query/sqm/mutation/internal/cte/ReactiveCteInsertHandler.java index aaf1be3e9..86f0a8bea 100644 --- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/query/sqm/mutation/internal/cte/ReactiveCteInsertHandler.java +++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/query/sqm/mutation/internal/cte/ReactiveCteInsertHandler.java @@ -43,10 +43,10 @@ import org.hibernate.query.sqm.tree.insert.SqmInsertStatement; import org.hibernate.query.sqm.tree.insert.SqmInsertValuesStatement; import org.hibernate.query.sqm.tree.insert.SqmValues; +import org.hibernate.reactive.engine.spi.ReactiveSharedSessionContractImplementor; import org.hibernate.reactive.logging.impl.Log; import org.hibernate.reactive.logging.impl.LoggerFactory; import org.hibernate.reactive.query.sqm.mutation.internal.ReactiveHandler; -import org.hibernate.reactive.session.ReactiveSession; import org.hibernate.reactive.sql.exec.internal.StandardReactiveSelectExecutor; import org.hibernate.reactive.sql.results.spi.ReactiveListResultsConsumer; import org.hibernate.spi.NavigablePath; @@ -575,7 +575,7 @@ public MappingModelExpressible getResolvedMappingModelType(SqmParameter StandardReactiveSelectExecutor.INSTANCE.list( select, diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/sql/results/graph/entity/internal/ReactiveEntityInitializerImpl.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/sql/results/graph/entity/internal/ReactiveEntityInitializerImpl.java index a00287eab..d19728fb1 100644 --- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/sql/results/graph/entity/internal/ReactiveEntityInitializerImpl.java +++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/sql/results/graph/entity/internal/ReactiveEntityInitializerImpl.java @@ -25,7 +25,7 @@ import org.hibernate.persister.entity.EntityPersister; import org.hibernate.proxy.LazyInitializer; import org.hibernate.proxy.map.MapProxy; -import org.hibernate.reactive.session.ReactiveSession; +import org.hibernate.reactive.session.ReactiveQueryProducer; import org.hibernate.reactive.sql.exec.spi.ReactiveRowProcessingState; import org.hibernate.reactive.sql.results.graph.ReactiveInitializer; import org.hibernate.sql.results.graph.AssemblerCreationState; @@ -532,7 +532,7 @@ protected CompletionStage reactiveResolveEntityInstance(ReactiveEntityIn // If this initializer owns the entity, we have to remove the entity holder, // because the subsequent loading process will claim the entity session.getPersistenceContextInternal().removeEntityHolder( data.getEntityKey() ); - return ( (ReactiveSession) session ).reactiveInternalLoad( + return ( (ReactiveQueryProducer) session ).reactiveInternalLoad( data.getConcreteDescriptor().getEntityName(), data.getEntityKey().getIdentifier(), true, From 80a9cfe70b0a54ac7591c74ac05e2f01a4744e4f Mon Sep 17 00:00:00 2001 From: Davide D'Alto Date: Thu, 24 Apr 2025 10:42:04 +0200 Subject: [PATCH 068/162] [#2207] Provide access to the contextual data map We store the session in the Vert.x local context. But, Quarkus needs a way to access the same context when using Panache. See quarkus issue: https://github.com/quarkusio/quarkus/issues/47314 --- .../context/impl/ContextualDataStorage.java | 17 ++++++++++++++++- .../reactive/context/impl/VertxContext.java | 18 ++++-------------- 2 files changed, 20 insertions(+), 15 deletions(-) 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 index 39cb8fa10..bcbfdf5f0 100644 --- 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 @@ -5,6 +5,12 @@ */ package org.hibernate.reactive.context.impl; +import org.hibernate.reactive.context.Context; + +import io.vertx.core.impl.ContextInternal; +import io.vertx.core.spi.context.storage.AccessMode; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import io.vertx.core.impl.VertxBuilder; @@ -17,9 +23,18 @@ public class ContextualDataStorage implements VertxServiceProvider { @SuppressWarnings("rawtypes") - final static ContextLocal CONTEXTUAL_DATA_KEY = ContextLocal.registerLocal( ConcurrentMap.class ); + private final static ContextLocal CONTEXTUAL_DATA_KEY = ContextLocal.registerLocal( ConcurrentMap.class ); @Override public void init(VertxBuilder vertxBuilder) { } + + @SuppressWarnings({ "unchecked" }) + public static Map, 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/context/impl/VertxContext.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/context/impl/VertxContext.java index 937dc3b1b..24975a87f 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 org.hibernate.reactive.context.Context; import org.hibernate.reactive.logging.impl.Log; @@ -20,6 +17,8 @@ import org.hibernate.service.spi.ServiceRegistryAwareService; import org.hibernate.service.spi.ServiceRegistryImplementor; +import static org.hibernate.reactive.context.impl.ContextualDataStorage.contextualDataMap; + /** * An adaptor for the Vert.x {@link io.vertx.core.Context}. * @@ -42,7 +41,7 @@ public void put(Key key, T instance) { final ContextInternal context = ContextInternal.current(); if ( context != null ) { if ( trace ) LOG.tracef( "Putting key,value in context: [%1$s, %2$s]", key, instance ); - VertxContext.contextualDataMap( context ).put( key, instance ); + ContextualDataStorage.contextualDataMap( context ).put( key, instance ); } else { if ( trace ) LOG.tracef( "Context is null for key,value: [%1$s, %2$s]", key, instance ); @@ -54,7 +53,7 @@ public void put(Key key, T instance) { public T get(Key key) { final ContextInternal context = ContextInternal.current(); if ( context != null ) { - T local = VertxContext.contextualDataMap( context ).get( key ); + T local = ContextualDataStorage.contextualDataMap( context ).get( key ); if ( trace ) LOG.tracef( "Getting value %2$s from context for key %1$s", key, local ); return local; } @@ -94,13 +93,4 @@ public void execute(Runnable runnable) { runnable.run(); } } - - @SuppressWarnings({ "unchecked" }) - private static ConcurrentMap, T> contextualDataMap(ContextInternal vertxContext) { - return vertxContext.getLocal( - ContextualDataStorage.CONTEXTUAL_DATA_KEY, - AccessMode.CONCURRENT, - ConcurrentHashMap::new - ); - } } From 415406e96b7706f1f1f4d21657831beb924b2e63 Mon Sep 17 00:00:00 2001 From: Gavin King Date: Fri, 25 Apr 2025 18:12:22 +0200 Subject: [PATCH 069/162] log the HR version --- .../hibernate/reactive/logging/impl/Log.java | 4 +-- .../reactive/logging/impl/Version.java | 32 +++++++++++++++++++ .../provider/impl/ReactiveIntegrator.java | 3 +- 3 files changed, 36 insertions(+), 3 deletions(-) create mode 100644 hibernate-reactive-core/src/main/java/org/hibernate/reactive/logging/impl/Version.java 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 fef169431..d8f77be0f 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 @@ -32,8 +32,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") 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/provider/impl/ReactiveIntegrator.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/provider/impl/ReactiveIntegrator.java index 0d1876320..cda361d5a 100644 --- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/provider/impl/ReactiveIntegrator.java +++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/provider/impl/ReactiveIntegrator.java @@ -28,6 +28,7 @@ import org.hibernate.reactive.event.impl.DefaultReactiveResolveNaturalIdEventListener; import org.hibernate.reactive.logging.impl.Log; import org.hibernate.reactive.logging.impl.LoggerFactory; +import org.hibernate.reactive.logging.impl.Version; import org.hibernate.service.ServiceRegistry; import org.hibernate.service.spi.SessionFactoryServiceRegistry; @@ -54,7 +55,7 @@ public void disintegrate(SessionFactoryImplementor sessionFactory, SessionFactor private void attachEventContextManagingListenersIfRequired(ServiceRegistry serviceRegistry) { if ( ReactiveModeCheck.isReactiveRegistry( serviceRegistry ) ) { - LOG.startHibernateReactive(); + LOG.startHibernateReactive( Version.getVersionString() ); EventListenerRegistry eventListenerRegistry = serviceRegistry.getService( EventListenerRegistry.class ); eventListenerRegistry.addDuplicationStrategy( ReplacementDuplicationStrategy.INSTANCE ); From 59205e2585c12e7efc464e6a6fd5cedf2de29773 Mon Sep 17 00:00:00 2001 From: Davide D'Alto Date: Wed, 30 Apr 2025 16:00:14 +0200 Subject: [PATCH 070/162] [#2234] Revert "[#2207] Provide access to the contextual data map" This reverts commit 80a9cfe70b0a54ac7591c74ac05e2f01a4744e4f. --- .../context/impl/ContextualDataStorage.java | 17 +---------------- .../reactive/context/impl/VertxContext.java | 18 ++++++++++++++---- 2 files changed, 15 insertions(+), 20 deletions(-) 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 index bcbfdf5f0..39cb8fa10 100644 --- 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 @@ -5,12 +5,6 @@ */ package org.hibernate.reactive.context.impl; -import org.hibernate.reactive.context.Context; - -import io.vertx.core.impl.ContextInternal; -import io.vertx.core.spi.context.storage.AccessMode; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import io.vertx.core.impl.VertxBuilder; @@ -23,18 +17,9 @@ public class ContextualDataStorage implements VertxServiceProvider { @SuppressWarnings("rawtypes") - private final static ContextLocal CONTEXTUAL_DATA_KEY = ContextLocal.registerLocal( ConcurrentMap.class ); + final static ContextLocal CONTEXTUAL_DATA_KEY = ContextLocal.registerLocal( ConcurrentMap.class ); @Override public void init(VertxBuilder vertxBuilder) { } - - @SuppressWarnings({ "unchecked" }) - public static Map, 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/context/impl/VertxContext.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/context/impl/VertxContext.java index 24975a87f..937dc3b1b 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,9 +6,12 @@ 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 org.hibernate.reactive.context.Context; import org.hibernate.reactive.logging.impl.Log; @@ -17,8 +20,6 @@ import org.hibernate.service.spi.ServiceRegistryAwareService; import org.hibernate.service.spi.ServiceRegistryImplementor; -import static org.hibernate.reactive.context.impl.ContextualDataStorage.contextualDataMap; - /** * An adaptor for the Vert.x {@link io.vertx.core.Context}. * @@ -41,7 +42,7 @@ public void put(Key key, T instance) { final ContextInternal context = ContextInternal.current(); if ( context != null ) { if ( trace ) LOG.tracef( "Putting key,value in context: [%1$s, %2$s]", key, instance ); - ContextualDataStorage.contextualDataMap( context ).put( key, instance ); + VertxContext.contextualDataMap( context ).put( key, instance ); } else { if ( trace ) LOG.tracef( "Context is null for key,value: [%1$s, %2$s]", key, instance ); @@ -53,7 +54,7 @@ public void put(Key key, T instance) { public T get(Key key) { final ContextInternal context = ContextInternal.current(); if ( context != null ) { - T local = ContextualDataStorage.contextualDataMap( context ).get( key ); + T local = VertxContext.contextualDataMap( context ).get( key ); if ( trace ) LOG.tracef( "Getting value %2$s from context for key %1$s", key, local ); return local; } @@ -93,4 +94,13 @@ public void execute(Runnable runnable) { runnable.run(); } } + + @SuppressWarnings({ "unchecked" }) + private static ConcurrentMap, T> contextualDataMap(ContextInternal vertxContext) { + return vertxContext.getLocal( + ContextualDataStorage.CONTEXTUAL_DATA_KEY, + AccessMode.CONCURRENT, + ConcurrentHashMap::new + ); + } } From ab6aa32c82aa6e9a155c285d96284817694cd7cc Mon Sep 17 00:00:00 2001 From: Davide D'Alto Date: Wed, 30 Apr 2025 16:00:44 +0200 Subject: [PATCH 071/162] [#2234] Revert "Make CONTEXTUAL_DATA_KEY constant" This reverts commit 156f7c3d97ed105e92a3bc52e6bd1daed67482f0. --- .../hibernate/reactive/context/impl/ContextualDataStorage.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 index 39cb8fa10..295b92f4d 100644 --- 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 @@ -17,7 +17,7 @@ public class ContextualDataStorage implements VertxServiceProvider { @SuppressWarnings("rawtypes") - final static ContextLocal CONTEXTUAL_DATA_KEY = ContextLocal.registerLocal( ConcurrentMap.class ); + static ContextLocal CONTEXTUAL_DATA_KEY = ContextLocal.registerLocal( ConcurrentMap.class ); @Override public void init(VertxBuilder vertxBuilder) { From 54414d141bf38c8dc426e38165aa0ced87e5ae1c Mon Sep 17 00:00:00 2001 From: Davide D'Alto Date: Wed, 30 Apr 2025 16:01:29 +0200 Subject: [PATCH 072/162] [#2234] Revert "[#2176] Create custom Vert.x contextual data storage" This reverts commit b4ab6a4b0d09eb0f5d7dc6d750a7609088b28649. --- .../context/impl/ContextualDataStorage.java | 25 ------------------- .../reactive/context/impl/VertxContext.java | 18 +++---------- .../io.vertx.core.spi.VertxServiceProvider | 1 - 3 files changed, 4 insertions(+), 40 deletions(-) delete mode 100644 hibernate-reactive-core/src/main/java/org/hibernate/reactive/context/impl/ContextualDataStorage.java delete mode 100644 hibernate-reactive-core/src/main/resources/META-INF/services/io.vertx.core.spi.VertxServiceProvider 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..fef172e66 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 org.hibernate.reactive.context.Context; import org.hibernate.reactive.logging.impl.Log; @@ -42,7 +39,7 @@ public void put(Key key, T instance) { final ContextInternal context = ContextInternal.current(); 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.localContextData().put( key, instance ); } else { if ( trace ) LOG.tracef( "Context is null for key,value: [%1$s, %2$s]", key, instance ); @@ -54,7 +51,8 @@ public void put(Key key, T instance) { public T get(Key key) { final ContextInternal context = ContextInternal.current(); if ( context != null ) { - T local = VertxContext.contextualDataMap( context ).get( key ); + @SuppressWarnings("unchecked") + T local = (T) context.localContextData().get( key ); if ( trace ) LOG.tracef( "Getting value %2$s from context for key %1$s", key, local ); return local; } @@ -68,7 +66,7 @@ public T get(Key key) { public void remove(Key key) { final ContextInternal context = ContextInternal.current(); if ( context != null ) { - boolean removed = contextualDataMap( context ).remove( key ) != null; + boolean removed = context.localContextData().remove( key ) != null; if ( trace ) LOG.tracef( "Key %s removed from context: %s", key, removed ); } else { @@ -95,12 +93,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/resources/META-INF/services/io.vertx.core.spi.VertxServiceProvider b/hibernate-reactive-core/src/main/resources/META-INF/services/io.vertx.core.spi.VertxServiceProvider deleted file mode 100644 index 80ffcb31c..000000000 --- a/hibernate-reactive-core/src/main/resources/META-INF/services/io.vertx.core.spi.VertxServiceProvider +++ /dev/null @@ -1 +0,0 @@ -org.hibernate.reactive.context.impl.ContextualDataStorage \ No newline at end of file From 02c825ab3338e4d7bf63bfa9494afbf4b1069c3b Mon Sep 17 00:00:00 2001 From: Davide D'Alto Date: Wed, 30 Apr 2025 16:01:42 +0200 Subject: [PATCH 073/162] [#2234] Revert "[#2174] Prepare for Vert.x 5 upgrade in Vert.x Context" This reverts commit 742ab0b5f4aeda833a9463573bf5bcc6abc3eb76. --- .../reactive/context/impl/VertxContext.java | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) 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 fef172e66..4448c9b6c 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 @@ -36,10 +36,10 @@ public void injectServices(ServiceRegistryImplementor serviceRegistry) { @Override public void put(Key key, T instance) { - final ContextInternal context = ContextInternal.current(); + final io.vertx.core.Context context = Vertx.currentContext(); if ( context != null ) { if ( trace ) LOG.tracef( "Putting key,value in context: [%1$s, %2$s]", key, instance ); - context.localContextData().put( key, instance ); + context.putLocal( key, instance ); } else { if ( trace ) LOG.tracef( "Context is null for key,value: [%1$s, %2$s]", key, instance ); @@ -49,10 +49,9 @@ public void put(Key key, T instance) { @Override public T get(Key key) { - final ContextInternal context = ContextInternal.current(); + final io.vertx.core.Context context = Vertx.currentContext(); if ( context != null ) { - @SuppressWarnings("unchecked") - T local = (T) context.localContextData().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; } @@ -64,9 +63,9 @@ public T get(Key key) { @Override public void remove(Key key) { - final ContextInternal context = ContextInternal.current(); + final io.vertx.core.Context context = Vertx.currentContext(); if ( context != null ) { - boolean removed = context.localContextData().remove( key ) != null; + boolean removed = context.removeLocal( key ); if ( trace ) LOG.tracef( "Key %s removed from context: %s", key, removed ); } else { From a01cb1a813b0bd7ae37ab25ef1997d5de06a16cd Mon Sep 17 00:00:00 2001 From: Gavin King Date: Wed, 30 Apr 2025 19:46:27 +0200 Subject: [PATCH 074/162] [#2238] create Delegators for use in Quarkus --- .../delegation/MutinySessionDelegator.java | 341 ++++++++++++++++++ .../MutinyStatelessSessionDelegator.java | 191 ++++++++++ .../delegation/ConcreteSessionDelegator.java | 17 + .../ConcreteStatelessSessionDelegator.java | 17 + 4 files changed, 566 insertions(+) create mode 100644 hibernate-reactive-core/src/main/java/org/hibernate/reactive/mutiny/delegation/MutinySessionDelegator.java create mode 100644 hibernate-reactive-core/src/main/java/org/hibernate/reactive/mutiny/delegation/MutinyStatelessSessionDelegator.java create mode 100644 hibernate-reactive-core/src/test/java/org/hibernate/reactive/delegation/ConcreteSessionDelegator.java create mode 100644 hibernate-reactive-core/src/test/java/org/hibernate/reactive/delegation/ConcreteStatelessSessionDelegator.java diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/mutiny/delegation/MutinySessionDelegator.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/mutiny/delegation/MutinySessionDelegator.java new file mode 100644 index 000000000..09d85913a --- /dev/null +++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/mutiny/delegation/MutinySessionDelegator.java @@ -0,0 +1,341 @@ +/* Hibernate, Relational Persistence for Idiomatic Java + * + * SPDX-License-Identifier: Apache-2.0 + * Copyright: Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.reactive.mutiny.delegation; + +import io.smallrye.mutiny.Uni; +import jakarta.persistence.CacheRetrieveMode; +import jakarta.persistence.CacheStoreMode; +import jakarta.persistence.EntityGraph; +import jakarta.persistence.FlushModeType; +import jakarta.persistence.LockModeType; +import jakarta.persistence.criteria.CriteriaDelete; +import jakarta.persistence.criteria.CriteriaQuery; +import jakarta.persistence.criteria.CriteriaUpdate; +import jakarta.persistence.metamodel.Attribute; +import org.hibernate.CacheMode; +import org.hibernate.Filter; +import org.hibernate.FlushMode; +import org.hibernate.Incubating; +import org.hibernate.LockMode; +import org.hibernate.reactive.common.AffectedEntities; +import org.hibernate.reactive.common.Identifier; +import org.hibernate.reactive.common.ResultSetMapping; +import org.hibernate.reactive.mutiny.Mutiny; + +import java.util.List; +import java.util.function.Function; + +/** + * Wraps a {@linkplain #delegate} session. + * + * @author Gavin King + */ +public abstract class MutinySessionDelegator implements Mutiny.Session { + + public abstract Mutiny.Session delegate(); + + public Uni find(Class entityClass, Object id) { + return delegate().find(entityClass, id); + } + + public Uni find(Class entityClass, Object id, LockModeType lockModeType) { + return delegate().find(entityClass, id, lockModeType); + } + + public Uni find(Class entityClass, Object id, LockMode lockMode) { + return delegate().find(entityClass, id, lockMode); + } + + public Uni find(EntityGraph entityGraph, Object id) { + return delegate().find(entityGraph, id); + } + + public Uni> find(Class entityClass, Object... ids) { + return delegate().find(entityClass, ids); + } + + public Mutiny.SelectionQuery createNamedQuery(String queryName, Class resultType) { + return delegate().createNamedQuery(queryName, resultType); + } + + public Mutiny.SelectionQuery createQuery(String queryString, Class resultType) { + return delegate().createQuery(queryString, resultType); + } + + public boolean isReadOnly(Object entityOrProxy) { + return delegate().isReadOnly(entityOrProxy); + } + + public Mutiny.SelectionQuery createNativeQuery(String queryString, Class resultType, AffectedEntities affectedEntities) { + return delegate().createNativeQuery(queryString, resultType, affectedEntities); + } + + public boolean isDefaultReadOnly() { + return delegate().isDefaultReadOnly(); + } + + public Uni unproxy(T association) { + return delegate().unproxy(association); + } + + public Mutiny.MutationQuery createMutationQuery(String queryString) { + return delegate().createMutationQuery(queryString); + } + + public Uni close() { + return delegate().close(); + } + + public Mutiny.Session disableFetchProfile(String name) { + return delegate().disableFetchProfile(name); + } + + public EntityGraph getEntityGraph(Class rootType, String graphName) { + return delegate().getEntityGraph(rootType, graphName); + } + + public Mutiny.SelectionQuery createSelectionQuery(String queryString, Class resultType) { + return delegate().createSelectionQuery(queryString, resultType); + } + + public Uni refresh(Object entity, LockModeType lockModeType) { + return delegate().refresh(entity, lockModeType); + } + + public Uni lock(Object entity, LockModeType lockModeType) { + return delegate().lock(entity, lockModeType); + } + + public Mutiny.SelectionQuery createNativeQuery(String queryString, ResultSetMapping resultSetMapping, AffectedEntities affectedEntities) { + return delegate().createNativeQuery(queryString, resultSetMapping, affectedEntities); + } + + public Uni lock(Object entity, LockMode lockMode) { + return delegate().lock(entity, lockMode); + } + + @Incubating + public Uni find(Class entityClass, Identifier naturalId) { + return delegate().find(entityClass, naturalId); + } + + public Uni withTransaction(Function> work) { + return delegate().withTransaction(work); + } + + public Mutiny.SelectionQuery createNativeQuery(String queryString, ResultSetMapping resultSetMapping) { + return delegate().createNativeQuery(queryString, resultSetMapping); + } + + public EntityGraph createEntityGraph(Class rootType, String graphName) { + return delegate().createEntityGraph(rootType, graphName); + } + + public Mutiny.Transaction currentTransaction() { + return delegate().currentTransaction(); + } + + public Mutiny.Session detach(Object entity) { + return delegate().detach(entity); + } + + public Mutiny.Session setCacheStoreMode(CacheStoreMode cacheStoreMode) { + return delegate().setCacheStoreMode(cacheStoreMode); + } + + public FlushMode getFlushMode() { + return delegate().getFlushMode(); + } + + public LockMode getLockMode(Object entity) { + return delegate().getLockMode(entity); + } + + public Mutiny.Query createNamedQuery(String queryName) { + return delegate().createNamedQuery(queryName); + } + + public Mutiny.SessionFactory getFactory() { + return delegate().getFactory(); + } + + public Mutiny.SelectionQuery createNativeQuery(String queryString, Class resultType) { + return delegate().createNativeQuery(queryString, resultType); + } + + public Mutiny.Session setSubselectFetchingEnabled(boolean enabled) { + return delegate().setSubselectFetchingEnabled(enabled); + } + + public Mutiny.Session setFlushMode(FlushMode flushMode) { + return delegate().setFlushMode(flushMode); + } + + public Uni remove(Object entity) { + return delegate().remove(entity); + } + + public Mutiny.Session setCacheMode(CacheMode cacheMode) { + return delegate().setCacheMode(cacheMode); + } + + public Filter enableFilter(String filterName) { + return delegate().enableFilter(filterName); + } + + public Mutiny.Query createNativeQuery(String queryString, AffectedEntities affectedEntities) { + return delegate().createNativeQuery(queryString, affectedEntities); + } + + public Mutiny.Session setReadOnly(Object entityOrProxy, boolean readOnly) { + return delegate().setReadOnly(entityOrProxy, readOnly); + } + + public EntityGraph createEntityGraph(Class rootType) { + return delegate().createEntityGraph(rootType); + } + + public Uni refreshAll(Object... entities) { + return delegate().refreshAll(entities); + } + + public Integer getBatchSize() { + return delegate().getBatchSize(); + } + + public Uni refresh(Object entity, LockMode lockMode) { + return delegate().refresh(entity, lockMode); + } + + public T getReference(Class entityClass, Object id) { + return delegate().getReference(entityClass, id); + } + + public T getReference(T entity) { + return delegate().getReference(entity); + } + + public Mutiny.Session setBatchSize(Integer batchSize) { + return delegate().setBatchSize(batchSize); + } + + public Uni refresh(Object entity) { + return delegate().refresh(entity); + } + + public CacheMode getCacheMode() { + return delegate().getCacheMode(); + } + + public Uni mergeAll(Object... entities) { + return delegate().mergeAll(entities); + } + + public Uni persist(Object object) { + return delegate().persist(object); + } + + public boolean contains(Object entity) { + return delegate().contains(entity); + } + + public int getFetchBatchSize() { + return delegate().getFetchBatchSize(); + } + + public Mutiny.Session setDefaultReadOnly(boolean readOnly) { + return delegate().setDefaultReadOnly(readOnly); + } + + public Mutiny.Session clear() { + return delegate().clear(); + } + + public Uni fetch(E entity, Attribute field) { + return delegate().fetch(entity, field); + } + + public Mutiny.SelectionQuery createQuery(CriteriaQuery criteriaQuery) { + return delegate().createQuery(criteriaQuery); + } + + public Mutiny.Session setCacheRetrieveMode(CacheRetrieveMode cacheRetrieveMode) { + return delegate().setCacheRetrieveMode(cacheRetrieveMode); + } + + public Uni removeAll(Object... entities) { + return delegate().removeAll(entities); + } + + public Filter getEnabledFilter(String filterName) { + return delegate().getEnabledFilter(filterName); + } + + public void disableFilter(String filterName) { + delegate().disableFilter(filterName); + } + + public Mutiny.MutationQuery createQuery(CriteriaDelete criteriaDelete) { + return delegate().createQuery(criteriaDelete); + } + + public Mutiny.Session enableFetchProfile(String name) { + return delegate().enableFetchProfile(name); + } + + public ResultSetMapping getResultSetMapping(Class resultType, String mappingName) { + return delegate().getResultSetMapping(resultType, mappingName); + } + + public Uni flush() { + return delegate().flush(); + } + + public Mutiny.Query createNativeQuery(String queryString) { + return delegate().createNativeQuery(queryString); + } + + public boolean isFetchProfileEnabled(String name) { + return delegate().isFetchProfileEnabled(name); + } + + public Uni merge(T entity) { + return delegate().merge(entity); + } + + public boolean isSubselectFetchingEnabled() { + return delegate().isSubselectFetchingEnabled(); + } + + public Mutiny.MutationQuery createQuery(CriteriaUpdate criteriaUpdate) { + return delegate().createQuery(criteriaUpdate); + } + + public Mutiny.Session setFetchBatchSize(int batchSize) { + return delegate().setFetchBatchSize(batchSize); + } + + public Uni fetch(T association) { + return delegate().fetch(association); + } + + public Uni persistAll(Object... entities) { + return delegate().persistAll(entities); + } + + @Deprecated + public Mutiny.Query createQuery(String queryString) { + return delegate().createQuery(queryString); + } + + public Mutiny.Session setFlushMode(FlushModeType flushModeType) { + return delegate().setFlushMode(flushModeType); + } + + public boolean isOpen() { + return delegate().isOpen(); + } +} diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/mutiny/delegation/MutinyStatelessSessionDelegator.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/mutiny/delegation/MutinyStatelessSessionDelegator.java new file mode 100644 index 000000000..152140006 --- /dev/null +++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/mutiny/delegation/MutinyStatelessSessionDelegator.java @@ -0,0 +1,191 @@ +/* Hibernate, Relational Persistence for Idiomatic Java + * + * SPDX-License-Identifier: Apache-2.0 + * Copyright: Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.reactive.mutiny.delegation; + +import io.smallrye.mutiny.Uni; +import jakarta.persistence.EntityGraph; +import jakarta.persistence.LockModeType; +import jakarta.persistence.criteria.CriteriaQuery; +import org.hibernate.Incubating; +import org.hibernate.LockMode; +import org.hibernate.reactive.common.ResultSetMapping; +import org.hibernate.reactive.mutiny.Mutiny; + +import java.util.function.Function; + +/** + * Wraps a {@linkplain #delegate} stateless session. + * + * @author Gavin King + */ +public abstract class MutinyStatelessSessionDelegator implements Mutiny.StatelessSession { + + public abstract Mutiny.StatelessSession delegate(); + + public Uni get(Class entityClass, Object id) { + return delegate().get(entityClass, id); + } + + @Deprecated + public Mutiny.Query createQuery(String queryString) { + return delegate().createQuery(queryString); + } + + public Uni get(EntityGraph entityGraph, Object id) { + return delegate().get(entityGraph, id); + } + + public Mutiny.SelectionQuery createNativeQuery(String queryString, ResultSetMapping resultSetMapping) { + return delegate().createNativeQuery(queryString, resultSetMapping); + } + + public Uni get(Class entityClass, Object id, LockMode lockMode) { + return delegate().get(entityClass, id, lockMode); + } + + public boolean isOpen() { + return delegate().isOpen(); + } + + public Uni insertAll(Object... entities) { + return delegate().insertAll(entities); + } + + public Uni updateAll(int batchSize, Object... entities) { + return delegate().updateAll(batchSize, entities); + } + + public EntityGraph createEntityGraph(Class rootType, String graphName) { + return delegate().createEntityGraph(rootType, graphName); + } + + public EntityGraph getEntityGraph(Class rootType, String graphName) { + return delegate().getEntityGraph(rootType, graphName); + } + + public Uni get(Class entityClass, Object id, LockModeType lockModeType) { + return delegate().get(entityClass, id, lockModeType); + } + + public Uni update(Object entity) { + return delegate().update(entity); + } + + public Uni refreshAll(int batchSize, Object... entities) { + return delegate().refreshAll(batchSize, entities); + } + + public Mutiny.SelectionQuery createQuery(String queryString, Class resultType) { + return delegate().createQuery(queryString, resultType); + } + + public Uni delete(Object entity) { + return delegate().delete(entity); + } + + public Uni refresh(Object entity, LockModeType lockModeType) { + return delegate().refresh(entity, lockModeType); + } + + public Mutiny.SessionFactory getFactory() { + return delegate().getFactory(); + } + + public Mutiny.SelectionQuery createNativeQuery(String queryString, Class resultType) { + return delegate().createNativeQuery(queryString, resultType); + } + + public Uni deleteAll(Object... entities) { + return delegate().deleteAll(entities); + } + + public Mutiny.SelectionQuery createSelectionQuery(String queryString, Class resultType) { + return delegate().createSelectionQuery(queryString, resultType); + } + + @Incubating + public Uni upsert(Object entity) { + return delegate().upsert(entity); + } + + public Mutiny.MutationQuery createMutationQuery(String queryString) { + return delegate().createMutationQuery(queryString); + } + + public Uni refresh(Object entity) { + return delegate().refresh(entity); + } + + public ResultSetMapping getResultSetMapping(Class resultType, String mappingName) { + return delegate().getResultSetMapping(resultType, mappingName); + } + + public Uni insertAll(int batchSize, Object... entities) { + return delegate().insertAll(batchSize, entities); + } + + public Mutiny.Query createNativeQuery(String queryString) { + return delegate().createNativeQuery(queryString); + } + + public Mutiny.Query createNamedQuery(String queryName) { + return delegate().createNamedQuery(queryName); + } + + public Mutiny.SelectionQuery createNamedQuery(String queryName, Class resultType) { + return delegate().createNamedQuery(queryName, resultType); + } + + public Uni refreshAll(Object... entities) { + return delegate().refreshAll(entities); + } + + public Uni close() { + return delegate().close(); + } + + public Uni updateAll(Object... entities) { + return delegate().updateAll(entities); + } + + public Mutiny.SelectionQuery createQuery(CriteriaQuery criteriaQuery) { + return delegate().createQuery(criteriaQuery); + } + + public Uni withTransaction(Function> work) { + return delegate().withTransaction(work); + } + + public Uni fetch(T association) { + return delegate().fetch(association); + } + + @Incubating + public Uni upsert(String entityName, Object entity) { + return delegate().upsert(entityName, entity); + } + + @Incubating + public Mutiny.Transaction currentTransaction() { + return delegate().currentTransaction(); + } + + public EntityGraph createEntityGraph(Class rootType) { + return delegate().createEntityGraph(rootType); + } + + public Uni insert(Object entity) { + return delegate().insert(entity); + } + + public Uni refresh(Object entity, LockMode lockMode) { + return delegate().refresh(entity, lockMode); + } + + public Uni deleteAll(int batchSize, Object... entities) { + return delegate().deleteAll(batchSize, entities); + } +} diff --git a/hibernate-reactive-core/src/test/java/org/hibernate/reactive/delegation/ConcreteSessionDelegator.java b/hibernate-reactive-core/src/test/java/org/hibernate/reactive/delegation/ConcreteSessionDelegator.java new file mode 100644 index 000000000..2c93d9226 --- /dev/null +++ b/hibernate-reactive-core/src/test/java/org/hibernate/reactive/delegation/ConcreteSessionDelegator.java @@ -0,0 +1,17 @@ +/* Hibernate, Relational Persistence for Idiomatic Java + * + * SPDX-License-Identifier: Apache-2.0 + * Copyright: Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.reactive.delegation; + +import org.hibernate.reactive.mutiny.Mutiny; +import org.hibernate.reactive.mutiny.delegation.MutinySessionDelegator; + +@SuppressWarnings("unused") +class ConcreteSessionDelegator extends MutinySessionDelegator { + @Override + public Mutiny.Session delegate() { + throw new UnsupportedOperationException(); + } +} diff --git a/hibernate-reactive-core/src/test/java/org/hibernate/reactive/delegation/ConcreteStatelessSessionDelegator.java b/hibernate-reactive-core/src/test/java/org/hibernate/reactive/delegation/ConcreteStatelessSessionDelegator.java new file mode 100644 index 000000000..e275d0180 --- /dev/null +++ b/hibernate-reactive-core/src/test/java/org/hibernate/reactive/delegation/ConcreteStatelessSessionDelegator.java @@ -0,0 +1,17 @@ +/* Hibernate, Relational Persistence for Idiomatic Java + * + * SPDX-License-Identifier: Apache-2.0 + * Copyright: Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.reactive.delegation; + +import org.hibernate.reactive.mutiny.Mutiny; +import org.hibernate.reactive.mutiny.delegation.MutinyStatelessSessionDelegator; + +@SuppressWarnings("unused") +class ConcreteStatelessSessionDelegator extends MutinyStatelessSessionDelegator { + @Override + public Mutiny.StatelessSession delegate() { + throw new UnsupportedOperationException(); + } +} From ae30a682bd04444a74778c147a16506f64c8f4cf Mon Sep 17 00:00:00 2001 From: Gavin King Date: Wed, 30 Apr 2025 11:44:50 +0200 Subject: [PATCH 075/162] [#1780] add operations for obtaining the current sessions from the context this will make it easier to implement the necessary Quarkus integration --- .../org/hibernate/reactive/mutiny/Mutiny.java | 25 +++++++++++++++++++ .../mutiny/impl/MutinySessionFactoryImpl.java | 10 ++++++++ .../org/hibernate/reactive/stage/Stage.java | 25 +++++++++++++++++++ .../stage/impl/StageSessionFactoryImpl.java | 10 ++++++++ 4 files changed, 70 insertions(+) diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/mutiny/Mutiny.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/mutiny/Mutiny.java index 65b0ad906..90972f9c5 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 @@ -2279,6 +2279,31 @@ default Uni withStatelessTransaction(Function> w */ Statistics getStatistics(); + /** + * Return the current instance of {@link Session}, if any. + * A current session exists only when this method is called + * from within an invocation of {@link #withSession(Function)} + * or {@link #withTransaction(Function)}. + * + * @return the current instance, if any, or {@code null} + * + * @since 2.4.7 + */ + Session getCurrentSession(); + + /** + * Return the current instance of {@link Session}, if any. + * A current session exists only when this method is called + * from within an invocation of + * {@link #withStatelessSession(Function)} or + * {@link #withStatelessTransaction(Function)}. + * + * @return the current instance, if any, or {@code null} + * + * @since 2.4.7 + */ + StatelessSession getCurrentStatelessSession(); + /** * Destroy the session factory and clean up its connection pool. */ diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/mutiny/impl/MutinySessionFactoryImpl.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/mutiny/impl/MutinySessionFactoryImpl.java index aecc99e37..23feaba57 100644 --- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/mutiny/impl/MutinySessionFactoryImpl.java +++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/mutiny/impl/MutinySessionFactoryImpl.java @@ -148,6 +148,16 @@ private CompletionStage connection(String tenantId) { : connectionPool.getConnection( tenantId ); } + @Override + public Mutiny.Session getCurrentSession() { + return context.get( contextKeyForSession ); + } + + @Override + public Mutiny.StatelessSession getCurrentStatelessSession() { + return context.get( contextKeyForStatelessSession ); + } + @Override public Uni withSession(Function> work) { Objects.requireNonNull( work, "parameter 'work' is required" ); diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/stage/Stage.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/stage/Stage.java index 47da9f6cf..3a6164a39 100644 --- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/stage/Stage.java +++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/stage/Stage.java @@ -2314,6 +2314,31 @@ default CompletionStage withStatelessTransaction(Function connection(String tenantId) { : connectionPool.getConnection( tenantId ); } + @Override + public Stage.Session getCurrentSession() { + return context.get( contextKeyForSession ); + } + + @Override + public Stage.StatelessSession getCurrentStatelessSession() { + return context.get( contextKeyForStatelessSession ); + } + @Override public CompletionStage withSession(Function> work) { Objects.requireNonNull( work, "parameter 'work' is required" ); From a7bd6ea9a6664bf91ef9a1acec1f01aecc67ea0f Mon Sep 17 00:00:00 2001 From: marko-bekhta Date: Fri, 25 Apr 2025 16:45:33 +0200 Subject: [PATCH 076/162] [#2222] Add a simple JReleaser configuration --- .gitignore | 3 -- .release/.gitignore | 3 ++ build.gradle | 7 --- ci/release/Jenkinsfile | 28 ++++++---- ci/snapshot-publish.Jenkinsfile | 38 ++++++++++--- jreleaser.yml | 59 ++++++++++++++++++++ publish.gradle | 96 ++------------------------------- release/build.gradle | 1 - 8 files changed, 114 insertions(+), 121 deletions(-) create mode 100644 .release/.gitignore create mode 100644 jreleaser.yml 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/build.gradle b/build.gradle index 1ad0a24c7..33e79e8fd 100644 --- a/build.gradle +++ b/build.gradle @@ -30,13 +30,6 @@ ext { 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 80b89bf9f..74a2ada51 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 = true // 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 -b ${env.GIT_BRANCH} -d ${env.DEVELOPMENT_VERSION} ${env.PROJECT} ${env.RELEASE_VERSION}" } } } @@ -193,11 +195,17 @@ 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 @@ -217,4 +225,4 @@ pipeline { } } } -} \ No newline at end of file +} diff --git a/ci/snapshot-publish.Jenkinsfile b/ci/snapshot-publish.Jenkinsfile index c9e19ca4c..b0c4dc48c 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,27 @@ 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 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'), + string(credentialsId: 'Hibernate-CI.github.com', variable: 'JRELEASER_GITHUB_TOKEN') + ]) { + checkoutReleaseScripts() + def version = sh( + script: ".release/scripts/determine-current-version.sh orm", + returnStdout: true + ).trim() + echo "Current version: '${version}'" + sh "bash -xe .release/scripts/snapshot-deploy.sh reactive ${version}" + } } } } @@ -48,4 +70,4 @@ pipeline { } } } -} \ No newline at end of file +} diff --git a/jreleaser.yml b/jreleaser.yml new file mode 100644 index 000000000..c3eeec649 --- /dev/null +++ b/jreleaser.yml @@ -0,0 +1,59 @@ +project: + languages: + java: + groupId: org.hibernate.reactive + +release: + github: + skipTag: true + skipRelease: true + tagName: '{{projectVersion}}' + +# File signing is always active +signing: + mode: COMMAND + active: RELEASE + armored: true + +deploy: + maven: + # TODO: Remove the entire nexus2 section when switching to maven central publishing (see below): + nexus2: + maven-central: + active: RELEASE + url: https://oss.sonatype.org/service/local + snapshotUrl: https://oss.sonatype.org/content/repositories/snapshots/ + closeRepository: true + releaseRepository: false + stagingRepositories: + - build/staging-deploy/maven + maven-central-snapshot: + active: SNAPSHOT + url: https://oss.sonatype.org/service/local + snapshotUrl: https://oss.sonatype.org/content/repositories/snapshots/ + closeRepository: true + releaseRepository: true + javadocJar: false + sign: false + stagingRepositories: + - build/staging-deploy/maven + mavenCentral: + maven-central: + # TODO: Change to RELEASE once switching to Maven-Central: + # Note, this is an untested configuration, hence might need further adjustments + active: NEVER + url: https://central.sonatype.com/api/v1/publisher + snapshotSupported: false + applyMavenCentralRules: true + stagingRepositories: + - build/staging-deploy/maven + maven-central-snapshot: + # TODO: Change to SNAPSHOT once switching to Maven-Central: + active: NEVER + url: https://central.sonatype.com/api/v1/publisher + snapshotSupported: true + applyMavenCentralRules: true + javadocJar: false + sign: false + stagingRepositories: + - build/staging-deploy/maven diff --git a/publish.gradle b/publish.gradle index 977092d9a..201b67a8a 100644 --- a/publish.gradle +++ b/publish.gradle @@ -1,6 +1,5 @@ apply plugin: 'java' apply plugin: 'maven-publish' -apply plugin: 'signing' // Java / publishing @@ -75,97 +74,10 @@ publishing { } } } -} - - -// Signing - -var signingExtension = project.getExtensions().getByType(SigningExtension) as SigningExtension - -var publishingExtension = project.getExtensions().getByType(PublishingExtension) as PublishingExtension -signingExtension.sign publishingExtension.publications.publishedArtifacts - -var signingKey = resolveSigningKey() -var signingPassphrase = resolveSigningPassphrase() -signingExtension.useInMemoryPgpKeys(signingKey, signingPassphrase) - -gradle.taskGraph.whenReady { TaskExecutionGraph graph -> - boolean wasPublishingRequested = false - - graph.allTasks.each {task -> - if ( task instanceof PublishToMavenRepository ) { - logger.lifecycle( "Found PublishToMavenRepository task : {}", task.path ) - wasPublishingRequested = true + repositories { + maven { + name = "staging" + url = rootProject.layout.buildDirectory.dir("staging-deploy${File.separator}maven") } } - - if ( wasPublishingRequested ) { - def publishUser = resolvePublishUser() - def publishPass = resolvePublishPass() - if ( publishUser == null || publishPass == null ) { - throw new RuntimeException( "Cannot perform publishing to OSSRH without credentials." ) - } - - logger.lifecycle "Publishing {} : {} : {}", project.group, project.name, project.version - - // require signing if publishing to OSSRH - signingExtension.required = true - } - else if ( signingKey == null || signingPassphrase == null ) { - tasks.withType( Sign ).each { t-> t.enabled = false } - } } - - -static String resolveSigningKey() { - var key = System.getenv().get( "SIGNING_GPG_PRIVATE_KEY" ) - if ( key != null ) { - return key - } - - var keyFile = System.getenv().get( "SIGNING_GPG_PRIVATE_KEY_PATH" ) - if ( keyFile != null ) { - return new File( keyFile ).text - } - - return null -} - -static String resolveSigningPassphrase() { - return System.getenv().get( "SIGNING_GPG_PASSPHRASE" ) -} - -String resolvePublishUser() { - var envVar = System.getenv().get( "ORG_GRADLE_PROJECT_sonatypeUsername" ) - if ( envVar != null ) { - return envVar - } - - def projectProp = projectPropOrNull( "sonatypeUsername" ) - if ( projectProp != null ) { - return projectProp - } - - return null -} - -String resolvePublishPass() { - var envVar = System.getenv().get( "ORG_GRADLE_PROJECT_sonatypePassword" ) - if ( envVar != null ) { - return envVar - } - - def projectProp = projectPropOrNull( "sonatypePassword" ) - if ( projectProp != null ) { - return projectProp - } - - return null -} - -String projectPropOrNull(String name) { - if ( project.hasProperty( name ) ) { - return project.findProperty( name ) - } - return null; -} \ No newline at end of file diff --git a/release/build.gradle b/release/build.gradle index 2b507a9a2..690534750 100644 --- a/release/build.gradle +++ b/release/build.gradle @@ -236,7 +236,6 @@ void updateVersionFile(var version) { def publishReleaseArtifactsTask = tasks.register( 'publishReleaseArtifacts' ) { dependsOn uploadDocumentationTask - dependsOn ":hibernate-reactive-core:publishToSonatype" mustRunAfter gitPreparationForReleaseTask } From dd6644199ced030cea703c2e94978de4335f4567 Mon Sep 17 00:00:00 2001 From: marko-bekhta Date: Mon, 5 May 2025 11:50:46 +0200 Subject: [PATCH 077/162] [#2222] Adjust snapshot publishing to use the publish plugin instead of JReleaser --- ci/snapshot-publish.Jenkinsfile | 12 ++++-------- jreleaser.yml | 20 -------------------- publish.gradle | 7 +++++++ 3 files changed, 11 insertions(+), 28 deletions(-) diff --git a/ci/snapshot-publish.Jenkinsfile b/ci/snapshot-publish.Jenkinsfile index b0c4dc48c..de6a030f2 100644 --- a/ci/snapshot-publish.Jenkinsfile +++ b/ci/snapshot-publish.Jenkinsfile @@ -41,19 +41,15 @@ pipeline { 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 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'), + // 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 orm", + script: ".release/scripts/determine-current-version.sh reactive", returnStdout: true ).trim() echo "Current version: '${version}'" diff --git a/jreleaser.yml b/jreleaser.yml index c3eeec649..f9428278e 100644 --- a/jreleaser.yml +++ b/jreleaser.yml @@ -27,16 +27,6 @@ deploy: releaseRepository: false stagingRepositories: - build/staging-deploy/maven - maven-central-snapshot: - active: SNAPSHOT - url: https://oss.sonatype.org/service/local - snapshotUrl: https://oss.sonatype.org/content/repositories/snapshots/ - closeRepository: true - releaseRepository: true - javadocJar: false - sign: false - stagingRepositories: - - build/staging-deploy/maven mavenCentral: maven-central: # TODO: Change to RELEASE once switching to Maven-Central: @@ -47,13 +37,3 @@ deploy: applyMavenCentralRules: true stagingRepositories: - build/staging-deploy/maven - maven-central-snapshot: - # TODO: Change to SNAPSHOT once switching to Maven-Central: - active: NEVER - url: https://central.sonatype.com/api/v1/publisher - snapshotSupported: true - applyMavenCentralRules: true - javadocJar: false - sign: false - stagingRepositories: - - build/staging-deploy/maven diff --git a/publish.gradle b/publish.gradle index 201b67a8a..f77b26959 100644 --- a/publish.gradle +++ b/publish.gradle @@ -79,5 +79,12 @@ publishing { name = "staging" url = rootProject.layout.buildDirectory.dir("staging-deploy${File.separator}maven") } + maven { + name = 'snapshots' + url = "https://oss.sonatype.org/content/repositories/snapshots/" + // So that Gradle uses the `ORG_GRADLE_PROJECT_snapshotsPassword` / `ORG_GRADLE_PROJECT_snapshotsUsername` + // env variables to read the username/password for the `snapshots` repository publishing: + credentials(PasswordCredentials) + } } } From e0e67189e629c0ebd82aedcba5e0a91b6961f0b5 Mon Sep 17 00:00:00 2001 From: marko-bekhta Date: Mon, 5 May 2025 15:39:06 +0200 Subject: [PATCH 078/162] [#2222] Set the dry run option from the parameters rather than keeping it always set to `true` --- ci/release/Jenkinsfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci/release/Jenkinsfile b/ci/release/Jenkinsfile index 74a2ada51..f4c001431 100644 --- a/ci/release/Jenkinsfile +++ b/ci/release/Jenkinsfile @@ -151,7 +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 = true + 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) From 3d1a30d18fbb0bb00c3a3b3ea328333dabed017a Mon Sep 17 00:00:00 2001 From: marko-bekhta Date: Mon, 5 May 2025 15:43:59 +0200 Subject: [PATCH 079/162] [#2222] Set the dry run option from the parameters rather than keeping it always set to `true` also release the staging repository automatically --- jreleaser.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jreleaser.yml b/jreleaser.yml index f9428278e..e39594d95 100644 --- a/jreleaser.yml +++ b/jreleaser.yml @@ -24,7 +24,7 @@ deploy: url: https://oss.sonatype.org/service/local snapshotUrl: https://oss.sonatype.org/content/repositories/snapshots/ closeRepository: true - releaseRepository: false + releaseRepository: true stagingRepositories: - build/staging-deploy/maven mavenCentral: From 5dfa251e8248d494144ebbfabbd2c3c3955269c2 Mon Sep 17 00:00:00 2001 From: Hibernate-CI Date: Mon, 5 May 2025 14:16:26 +0000 Subject: [PATCH 080/162] Update project version to : `2.4.7.Final` --- gradle/version.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/version.properties b/gradle/version.properties index 6868909df..c96d0ad0c 100644 --- a/gradle/version.properties +++ b/gradle/version.properties @@ -1 +1 @@ -projectVersion=2.4.7-SNAPSHOT \ No newline at end of file +projectVersion=2.4.7.Final \ No newline at end of file From 30da17f6c5093a34658767714c5f8ae7cf41d582 Mon Sep 17 00:00:00 2001 From: Hibernate-CI Date: Mon, 5 May 2025 14:17:21 +0000 Subject: [PATCH 081/162] Update project version to : `2.4.8-SNAPSHOT` --- gradle/version.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/version.properties b/gradle/version.properties index c96d0ad0c..bbcfe69a7 100644 --- a/gradle/version.properties +++ b/gradle/version.properties @@ -1 +1 @@ -projectVersion=2.4.7.Final \ No newline at end of file +projectVersion=2.4.8-SNAPSHOT \ No newline at end of file From 23394e923c77c0e2312b3696245ddfb46e25abf6 Mon Sep 17 00:00:00 2001 From: Andrea Boriero Date: Tue, 6 May 2025 16:59:00 +0200 Subject: [PATCH 082/162] Remove JReleaser config from the sources as it will be now located inside the release scripts (cherry picked from commit 88283527105e5de8acfdc52ff6b6ec50bb1dbe9c) --- ci/release/Jenkinsfile | 4 ++-- jreleaser.yml | 39 --------------------------------------- 2 files changed, 2 insertions(+), 41 deletions(-) delete mode 100644 jreleaser.yml diff --git a/ci/release/Jenkinsfile b/ci/release/Jenkinsfile index f4c001431..915aa211e 100644 --- a/ci/release/Jenkinsfile +++ b/ci/release/Jenkinsfile @@ -178,7 +178,7 @@ pipeline { // 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 -b ${env.GIT_BRANCH} -d ${env.DEVELOPMENT_VERSION} ${env.PROJECT} ${env.RELEASE_VERSION}" + sh ".release/scripts/prepare-release.sh -j -b ${env.GIT_BRANCH} -v ${env.DEVELOPMENT_VERSION} ${env.PROJECT} ${env.RELEASE_VERSION}" } } } @@ -210,7 +210,7 @@ pipeline { 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}" } } } diff --git a/jreleaser.yml b/jreleaser.yml deleted file mode 100644 index e39594d95..000000000 --- a/jreleaser.yml +++ /dev/null @@ -1,39 +0,0 @@ -project: - languages: - java: - groupId: org.hibernate.reactive - -release: - github: - skipTag: true - skipRelease: true - tagName: '{{projectVersion}}' - -# File signing is always active -signing: - mode: COMMAND - active: RELEASE - armored: true - -deploy: - maven: - # TODO: Remove the entire nexus2 section when switching to maven central publishing (see below): - nexus2: - maven-central: - active: RELEASE - url: https://oss.sonatype.org/service/local - snapshotUrl: https://oss.sonatype.org/content/repositories/snapshots/ - closeRepository: true - releaseRepository: true - stagingRepositories: - - build/staging-deploy/maven - mavenCentral: - maven-central: - # TODO: Change to RELEASE once switching to Maven-Central: - # Note, this is an untested configuration, hence might need further adjustments - active: NEVER - url: https://central.sonatype.com/api/v1/publisher - snapshotSupported: false - applyMavenCentralRules: true - stagingRepositories: - - build/staging-deploy/maven From 1218fbce05c85ee01b8e9fe649b15ab4dcc0bd1d Mon Sep 17 00:00:00 2001 From: Davide D'Alto Date: Wed, 14 May 2025 11:16:51 +0200 Subject: [PATCH 083/162] Upgrade Hibernate ORM to 6.6.15.Final It doesn't require any changes, but it's needed to fix #2138 --- README.md | 2 +- gradle.properties | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 02323747a..c39228e47 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ Hibernate Reactive has been tested with: - CockroachDB v24 - MS SQL Server 2022 - Oracle 23 -- [Hibernate ORM][] 6.6.13.Final +- [Hibernate ORM][] 6.6.15.Final - [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 diff --git a/gradle.properties b/gradle.properties index e2eca690e..1de1027bc 100644 --- a/gradle.properties +++ b/gradle.properties @@ -35,12 +35,12 @@ org.gradle.java.installations.auto-download=false #enableMavenLocalRepo = true # The default Hibernate ORM version (override using `-PhibernateOrmVersion=the.version.you.want`) -hibernateOrmVersion = 6.6.13.Final +hibernateOrmVersion = 6.6.15.Final # Override default Hibernate ORM Gradle plugin version # Using the stable version because I don't know how to configure the build to download the snapshot version from # a remote repository -#hibernateOrmGradlePluginVersion = 6.6.13.Final +#hibernateOrmGradlePluginVersion = 6.6.15.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 From 36e1ee9e9e5fcd08f268c37c852009001a913068 Mon Sep 17 00:00:00 2001 From: marko-bekhta Date: Mon, 31 Mar 2025 21:56:30 +0200 Subject: [PATCH 084/162] [#2138] Use UPDATE event type for generator where applicable --- .../ReactiveUpdateCoordinatorStandard.java | 4 +- .../org/hibernate/reactive/TimestampTest.java | 69 ++++++++++++++++++- 2 files changed, 69 insertions(+), 4 deletions(-) diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/persister/entity/mutation/ReactiveUpdateCoordinatorStandard.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/persister/entity/mutation/ReactiveUpdateCoordinatorStandard.java index d3237cf72..f0aa8bdc9 100644 --- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/persister/entity/mutation/ReactiveUpdateCoordinatorStandard.java +++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/persister/entity/mutation/ReactiveUpdateCoordinatorStandard.java @@ -31,7 +31,7 @@ import org.hibernate.tuple.entity.EntityMetamodel; import static org.hibernate.engine.jdbc.mutation.internal.ModelMutationHelper.identifiedResultsCheck; -import static org.hibernate.generator.EventType.INSERT; +import static org.hibernate.generator.EventType.UPDATE; import static org.hibernate.internal.util.collections.ArrayHelper.EMPTY_INT_ARRAY; import static org.hibernate.internal.util.collections.ArrayHelper.trim; import static org.hibernate.reactive.persister.entity.mutation.GeneratorValueUtil.generateValue; @@ -194,7 +194,7 @@ private CompletionStage reactivePreUpdateInMemoryValueGeneration( && generator.generatesOnUpdate() ) { final Object currentValue = currentValues[i]; final BeforeExecutionGenerator beforeGenerator = (BeforeExecutionGenerator) generator; - result = result.thenCompose( v -> generateValue( session, entity, currentValue, beforeGenerator, INSERT ) + result = result.thenCompose( v -> generateValue( session, entity, currentValue, beforeGenerator, UPDATE ) .thenAccept( generatedValue -> { currentValues[index] = generatedValue; entityPersister().setValue( entity, index, generatedValue ); diff --git a/hibernate-reactive-core/src/test/java/org/hibernate/reactive/TimestampTest.java b/hibernate-reactive-core/src/test/java/org/hibernate/reactive/TimestampTest.java index 8a6f631fc..7841216c7 100644 --- a/hibernate-reactive-core/src/test/java/org/hibernate/reactive/TimestampTest.java +++ b/hibernate-reactive-core/src/test/java/org/hibernate/reactive/TimestampTest.java @@ -6,6 +6,7 @@ package org.hibernate.reactive; import java.time.Instant; +import java.time.LocalDateTime; import java.time.temporal.ChronoUnit; import java.util.Collection; import java.util.List; @@ -18,6 +19,9 @@ import io.vertx.junit5.Timeout; import io.vertx.junit5.VertxTestContext; import jakarta.persistence.Basic; +import jakarta.persistence.Column; +import jakarta.persistence.Embeddable; +import jakarta.persistence.Embedded; import jakarta.persistence.Entity; import jakarta.persistence.GeneratedValue; import jakarta.persistence.Id; @@ -28,12 +32,11 @@ import static org.junit.jupiter.api.Assertions.assertTrue; @Timeout(value = 10, timeUnit = MINUTES) - public class TimestampTest extends BaseReactiveTest { @Override protected Collection> annotatedEntities() { - return List.of( Record.class ); + return List.of( Record.class, Event.class ); } @Test @@ -56,6 +59,30 @@ public void test(VertxTestContext context) { ); } + @Test + public void testEmbedded(VertxTestContext context) { + Event event = new Event(); + History history = new History(); + event.name = "Concert"; + test( context, getMutinySessionFactory() + .withSession( session -> session.persist( event ) + .chain( session::flush ) + .invoke( () -> { + history.created = event.history.created; + history.updated = event.history.updated; + assertEquals( + event.history.created.truncatedTo( ChronoUnit.HOURS ), + event.history.updated.truncatedTo( ChronoUnit.HOURS ) + ); }) + .invoke( () -> event.name = "Conference" ) + .chain( session::flush ) + .invoke( () -> assertInstants( event, history ) ) ) + .chain( () -> getMutinySessionFactory().withSession( session -> session + .find( Record.class, event.id ) ) ) + .invoke( r -> assertInstants( event, history ) ) + ); + } + private static void assertInstants(Record r) { assertNotNull( r.created ); assertNotNull( r.updated ); @@ -66,6 +93,18 @@ private static void assertInstants(Record r) { ); } + private static void assertInstants(Event e, History h) { + assertNotNull( e.history.created ); + assertNotNull( e.history.updated ); + // Sometimes, when the test suite is fast enough, they might be the same + assertTrue( + !e.history.updated.isBefore( e.history.created ), + "Updated instant is before created. Updated[" + e.history.updated + "], Created[" + e.history.created + "]" + ); + assertEquals( h.created, e.history.created ); + + } + @Entity(name = "Record") static class Record { @GeneratedValue @@ -78,4 +117,30 @@ static class Record { @UpdateTimestamp Instant updated; } + + @Entity(name = "Event") + static class Event { + + @Id + @GeneratedValue + public Long id; + + public String name; + + @Embedded + public History history; + + } + + @Embeddable + static class History { + @Column + @CreationTimestamp + public LocalDateTime created; + + @Column + @UpdateTimestamp + public LocalDateTime updated; + + } } From ce9cb988dd3085dcba7e467d0fb7888728a30c7d Mon Sep 17 00:00:00 2001 From: Hibernate-CI Date: Wed, 14 May 2025 09:39:07 +0000 Subject: [PATCH 085/162] Update project version to : `2.4.8.Final` --- gradle/version.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/version.properties b/gradle/version.properties index bbcfe69a7..47a2dada0 100644 --- a/gradle/version.properties +++ b/gradle/version.properties @@ -1 +1 @@ -projectVersion=2.4.8-SNAPSHOT \ No newline at end of file +projectVersion=2.4.8.Final \ No newline at end of file From 6e8a38b28ac4cc2584203b8b39a2616a36ec0dac Mon Sep 17 00:00:00 2001 From: Hibernate-CI Date: Wed, 14 May 2025 09:40:04 +0000 Subject: [PATCH 086/162] Update project version to : `2.4.9-SNAPSHOT` --- gradle/version.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/version.properties b/gradle/version.properties index 47a2dada0..85fe62918 100644 --- a/gradle/version.properties +++ b/gradle/version.properties @@ -1 +1 @@ -projectVersion=2.4.8.Final \ No newline at end of file +projectVersion=2.4.9-SNAPSHOT \ No newline at end of file From 4a6d0e77556137cc67403cff09afc0ba10489b81 Mon Sep 17 00:00:00 2001 From: Davide D'Alto Date: Wed, 21 May 2025 09:39:45 +0200 Subject: [PATCH 087/162] test: Upgrade PostgreSQL to 17.5 --- .../hibernate/reactive/containers/PostgreSQLDatabase.java | 2 +- .../test/java/org/hibernate/reactive/it/BaseReactiveIT.java | 2 +- .../reactive/it/quarkus/qe/database/BaseReactiveIT.java | 2 +- .../org/hibernate/reactive/it/verticle/VertxServer.java | 2 +- podman.md | 6 +++--- tooling/jbang/Example.java | 2 +- tooling/jbang/PostgreSQLReactiveTest.java.qute | 2 +- tooling/jbang/ReactiveTest.java | 2 +- 8 files changed, 10 insertions(+), 10 deletions(-) diff --git a/hibernate-reactive-core/src/test/java/org/hibernate/reactive/containers/PostgreSQLDatabase.java b/hibernate-reactive-core/src/test/java/org/hibernate/reactive/containers/PostgreSQLDatabase.java index 0d076a93b..c19d1c06a 100644 --- a/hibernate-reactive-core/src/test/java/org/hibernate/reactive/containers/PostgreSQLDatabase.java +++ b/hibernate-reactive-core/src/test/java/org/hibernate/reactive/containers/PostgreSQLDatabase.java @@ -87,7 +87,7 @@ class PostgreSQLDatabase implements TestableDatabase { * TIP: To reuse the same containers across multiple runs, set `testcontainers.reuse.enable=true` in a file located * at `$HOME/.testcontainers.properties` (create the file if it does not exist). */ - public static final PostgreSQLContainer postgresql = new PostgreSQLContainer<>( imageName( "postgres", "17.4" ) ) + public static final PostgreSQLContainer postgresql = new PostgreSQLContainer<>( imageName( "postgres", "17.5" ) ) .withUsername( DatabaseConfiguration.USERNAME ) .withPassword( DatabaseConfiguration.PASSWORD ) .withDatabaseName( DatabaseConfiguration.DB_NAME ) diff --git a/integration-tests/bytecode-enhancements-it/src/test/java/org/hibernate/reactive/it/BaseReactiveIT.java b/integration-tests/bytecode-enhancements-it/src/test/java/org/hibernate/reactive/it/BaseReactiveIT.java index ff9f5e601..2388cb421 100644 --- a/integration-tests/bytecode-enhancements-it/src/test/java/org/hibernate/reactive/it/BaseReactiveIT.java +++ b/integration-tests/bytecode-enhancements-it/src/test/java/org/hibernate/reactive/it/BaseReactiveIT.java @@ -53,7 +53,7 @@ public abstract class BaseReactiveIT { public static final boolean USE_DOCKER = Boolean.getBoolean( "docker" ); public static final DockerImageName IMAGE_NAME = DockerImageName - .parse( "docker.io/postgres:17.4" ) + .parse( "docker.io/postgres:17.5" ) .asCompatibleSubstituteFor( "postgres" ); public static final String USERNAME = "hreact"; diff --git a/integration-tests/hibernate-validator-postgres-it/src/test/java/org/hibernate/reactive/it/quarkus/qe/database/BaseReactiveIT.java b/integration-tests/hibernate-validator-postgres-it/src/test/java/org/hibernate/reactive/it/quarkus/qe/database/BaseReactiveIT.java index afff092e9..7debdbb2c 100644 --- a/integration-tests/hibernate-validator-postgres-it/src/test/java/org/hibernate/reactive/it/quarkus/qe/database/BaseReactiveIT.java +++ b/integration-tests/hibernate-validator-postgres-it/src/test/java/org/hibernate/reactive/it/quarkus/qe/database/BaseReactiveIT.java @@ -53,7 +53,7 @@ public abstract class BaseReactiveIT { public static final boolean USE_DOCKER = Boolean.getBoolean( "docker" ); public static final DockerImageName IMAGE_NAME = DockerImageName - .parse( "docker.io/postgres:17.4" ) + .parse( "docker.io/postgres:17.5" ) .asCompatibleSubstituteFor( "postgres" ); public static final String USERNAME = "hreact"; diff --git a/integration-tests/verticle-postgres-it/src/main/java/org/hibernate/reactive/it/verticle/VertxServer.java b/integration-tests/verticle-postgres-it/src/main/java/org/hibernate/reactive/it/verticle/VertxServer.java index 238e5278b..990fef754 100644 --- a/integration-tests/verticle-postgres-it/src/main/java/org/hibernate/reactive/it/verticle/VertxServer.java +++ b/integration-tests/verticle-postgres-it/src/main/java/org/hibernate/reactive/it/verticle/VertxServer.java @@ -36,7 +36,7 @@ public class VertxServer { // These properties are in DatabaseConfiguration in core public static final boolean USE_DOCKER = Boolean.getBoolean( "docker" ); - public static final String IMAGE_NAME = "postgres:17.4"; + public static final String IMAGE_NAME = "postgres:17.5"; public static final String USERNAME = "hreact"; public static final String PASSWORD = "hreact"; public static final String DB_NAME = "hreact"; diff --git a/podman.md b/podman.md index 733720def..7d651353e 100644 --- a/podman.md +++ b/podman.md @@ -14,13 +14,13 @@ If you replace `podman` with `sudo docker`, they will also work with [Docker][do Example: ``` -podman run --rm --name HibernateTestingPGSQL postgres:14.0 +podman run --rm --name HibernateTestingPGSQL postgres:17.5 ``` becomes for Docker: ``` -sudo docker run --rm --name HibernateTestingPGSQL postgres:14.0 +sudo docker run --rm --name HibernateTestingPGSQL postgres:17.5 ``` --- @@ -39,7 +39,7 @@ required credentials and schema to run the tests: podman run --rm --name HibernateTestingPGSQL \ -e POSTGRES_USER=hreact -e POSTGRES_PASSWORD=hreact -e POSTGRES_DB=hreact \ -e POSTGRES_INITDB_ARGS="-A password" \ - -p 5432:5432 docker.io/postgres:17.4 + -p 5432:5432 docker.io/postgres:17.5 ``` When the database has started, you can run the tests on PostgreSQL with: diff --git a/tooling/jbang/Example.java b/tooling/jbang/Example.java index 0ec38c459..10ae59842 100644 --- a/tooling/jbang/Example.java +++ b/tooling/jbang/Example.java @@ -59,7 +59,7 @@ *
      *                 podman run --rm --name HibernateTestingPGSQL \
      *                      -e POSTGRES_USER=hreact -e POSTGRES_PASSWORD=hreact -e POSTGRES_DB=hreact \
    - *                      -p 5432:5432 postgres:17.4
    + *                      -p 5432:5432 postgres:17.5
      *              
    * *
    3. Run the example with JBang
    diff --git a/tooling/jbang/PostgreSQLReactiveTest.java.qute b/tooling/jbang/PostgreSQLReactiveTest.java.qute index 6178603dd..f404f4d1e 100755 --- a/tooling/jbang/PostgreSQLReactiveTest.java.qute +++ b/tooling/jbang/PostgreSQLReactiveTest.java.qute @@ -67,7 +67,7 @@ public class {baseName} { } @ClassRule - public final static PostgreSQLContainer database = new PostgreSQLContainer( imageName( "docker.io", "postgres", "17.4" ) ); + public final static PostgreSQLContainer database = new PostgreSQLContainer( imageName( "docker.io", "postgres", "17.5" ) ); private Mutiny.SessionFactory sessionFactory; diff --git a/tooling/jbang/ReactiveTest.java b/tooling/jbang/ReactiveTest.java index 73de3a9c3..071b4cfd7 100755 --- a/tooling/jbang/ReactiveTest.java +++ b/tooling/jbang/ReactiveTest.java @@ -228,7 +228,7 @@ public String toString() { * It's a wrapper around the testcontainers classes. */ enum Database { - POSTGRESQL( () -> new PostgreSQLContainer( "postgres:17.4" ) ), + POSTGRESQL( () -> new PostgreSQLContainer( "postgres:17.5" ) ), MYSQL( () -> new MySQLContainer( "mysql:9.2.0" ) ), DB2( () -> new Db2Container( "docker.io/icr.io/db2_community/db2:12.1.0.0" ).acceptLicense() ), MARIADB( () -> new MariaDBContainer( "mariadb:11.7.2" ) ), From bc98e8fa9d1cbd4c870cb79ce032f1ac86561205 Mon Sep 17 00:00:00 2001 From: Davide D'Alto Date: Wed, 21 May 2025 09:45:38 +0200 Subject: [PATCH 088/162] test: Upgrade CockroachDB to v24.3.13 --- .../org/hibernate/reactive/containers/CockroachDBDatabase.java | 2 +- podman.md | 2 +- tooling/jbang/CockroachDBReactiveTest.java.qute | 2 +- tooling/jbang/ReactiveTest.java | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/hibernate-reactive-core/src/test/java/org/hibernate/reactive/containers/CockroachDBDatabase.java b/hibernate-reactive-core/src/test/java/org/hibernate/reactive/containers/CockroachDBDatabase.java index 7d9da67cc..92cb42e6e 100644 --- a/hibernate-reactive-core/src/test/java/org/hibernate/reactive/containers/CockroachDBDatabase.java +++ b/hibernate-reactive-core/src/test/java/org/hibernate/reactive/containers/CockroachDBDatabase.java @@ -25,7 +25,7 @@ class CockroachDBDatabase extends PostgreSQLDatabase { * TIP: To reuse the same containers across multiple runs, set `testcontainers.reuse.enable=true` in a file located * at `$HOME/.testcontainers.properties` (create the file if it does not exist). */ - public static final CockroachContainer cockroachDb = new CockroachContainer( imageName( "cockroachdb/cockroach", "v24.1.15" ) ) + public static final CockroachContainer cockroachDb = new CockroachContainer( imageName( "cockroachdb/cockroach", "v24.3.13" ) ) // Username, password and database are not supported by test container at the moment // Testcontainers will use a database named 'postgres' and the 'root' user .withReuse( true ); diff --git a/podman.md b/podman.md index 7d651353e..bc4d96ba7 100644 --- a/podman.md +++ b/podman.md @@ -121,7 +121,7 @@ configured to run the tests: ``` podman run --rm --name=HibernateTestingCockroachDB \ --hostname=roachrr1 -p 26257:26257 -p 8080:8080 \ - docker.io/cockroachdb/cockroach:v24.1.15 start-single-node --insecure + docker.io/cockroachdb/cockroach:v24.3.13 start-single-node --insecure ``` Some of tests needs temporary tables and because this is an experimental feature in diff --git a/tooling/jbang/CockroachDBReactiveTest.java.qute b/tooling/jbang/CockroachDBReactiveTest.java.qute index 22293ca9b..71695f45b 100755 --- a/tooling/jbang/CockroachDBReactiveTest.java.qute +++ b/tooling/jbang/CockroachDBReactiveTest.java.qute @@ -70,7 +70,7 @@ public class {baseName} { } @ClassRule - public final static CockroachContainer database = new CockroachContainer( imageName( "cockroachdb", "cockroach", "v24.1.15" ) ); + public final static CockroachContainer database = new CockroachContainer( imageName( "cockroachdb", "cockroach", "v24.3.13" ) ); private Mutiny.SessionFactory sessionFactory; diff --git a/tooling/jbang/ReactiveTest.java b/tooling/jbang/ReactiveTest.java index 071b4cfd7..08d872619 100755 --- a/tooling/jbang/ReactiveTest.java +++ b/tooling/jbang/ReactiveTest.java @@ -232,7 +232,7 @@ enum Database { MYSQL( () -> new MySQLContainer( "mysql:9.2.0" ) ), DB2( () -> new Db2Container( "docker.io/icr.io/db2_community/db2:12.1.0.0" ).acceptLicense() ), MARIADB( () -> new MariaDBContainer( "mariadb:11.7.2" ) ), - COCKROACHDB( () -> new CockroachContainer( "cockroachdb/cockroach:v24.1.15" ) ); + COCKROACHDB( () -> new CockroachContainer( "cockroachdb/cockroach:v24.3.13" ) ); private final Supplier> containerSupplier; From cf98d8e750087dc50acdc237cf438109d228c3a6 Mon Sep 17 00:00:00 2001 From: Andrea Boriero Date: Wed, 28 May 2025 16:26:09 +0200 Subject: [PATCH 089/162] [#1793] Test HQL 'new' construct with many-to-one Test case showing the issue has been resolved --- .../org/hibernate/reactive/HQLQueryTest.java | 152 +++++++++++++++++- 1 file changed, 149 insertions(+), 3 deletions(-) diff --git a/hibernate-reactive-core/src/test/java/org/hibernate/reactive/HQLQueryTest.java b/hibernate-reactive-core/src/test/java/org/hibernate/reactive/HQLQueryTest.java index e48d3ec69..00e541285 100644 --- a/hibernate-reactive-core/src/test/java/org/hibernate/reactive/HQLQueryTest.java +++ b/hibernate-reactive-core/src/test/java/org/hibernate/reactive/HQLQueryTest.java @@ -5,6 +5,10 @@ */ package org.hibernate.reactive; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.OneToMany; +import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.Objects; @@ -20,6 +24,8 @@ import jakarta.persistence.Id; import jakarta.persistence.Table; +import static jakarta.persistence.CascadeType.PERSIST; +import static jakarta.persistence.FetchType.LAZY; import static java.util.concurrent.TimeUnit.MINUTES; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -34,15 +40,22 @@ public class HQLQueryTest extends BaseReactiveTest { Flour rye = new Flour( 2, "Rye", "Used to bake the traditional sourdough breads of Germany.", "Wheat flour" ); Flour almond = new Flour( 3, "Almond", "made from ground almonds.", "Gluten free" ); + Author miller = new Author( "Madeline Miller"); + Author camilleri = new Author( "Andrea Camilleri"); + Book circe = new Book( "9780316556347", "Circe", miller ); + Book shapeOfWater = new Book( "0-330-49286-1 ", "The Shape of Water", camilleri ); + Book spider = new Book( "978-0-14-311203-7", "The Patience of the Spider", camilleri ); + @Override protected Collection> annotatedEntities() { - return List.of( Flour.class ); + return List.of( Flour.class, Book.class, Author.class ); } @BeforeEach public void populateDb(VertxTestContext context) { - test( context, getMutinySessionFactory() - .withTransaction( (session, transaction) -> session.persistAll( spelt, rye, almond ) ) ); + test( context, getMutinySessionFactory().withTransaction( session -> session + .persistAll( spelt, rye, almond, miller, camilleri, circe, shapeOfWater, spider ) ) + ); } @Test @@ -129,6 +142,21 @@ public void testFromQuery(VertxTestContext context) { ); } + @Test + public void testSelectNewConstructor(VertxTestContext context) { + test( context, getMutinySessionFactory() + .withTransaction( session -> session + .createQuery( "SELECT NEW Book(b.title, b.author) FROM Book b ORDER BY b.title DESC", Book.class ) + .getResultList() + ) + .invoke( books -> assertThat( books ).containsExactly( + new Book( shapeOfWater.title, camilleri ), + new Book( spider.title, camilleri ), + new Book( circe.title, miller ) + ) ) + ); + } + @Entity(name = "Flour") @Table(name = "Flour") public static class Flour { @@ -204,4 +232,122 @@ public int hashCode() { return Objects.hash( name, description, type ); } } + + @Entity(name = "Book") + @Table(name = "Book_HQL") + public static class Book { + @Id + @GeneratedValue + private Integer id; + + private String isbn; + + private String title; + + @ManyToOne(fetch = LAZY) + private Author author; + + public Book() { + } + + public Book(String title, Author author) { + this.title = title; + this.author = author; + } + + public Book(String isbn, String title, Author author) { + this.isbn = isbn; + this.title = title; + this.author = author; + author.books.add( this ); + } + + public Integer getId() { + return id; + } + + public String getIsbn() { + return isbn; + } + + public String getTitle() { + return title; + } + + public Author getAuthor() { + return author; + } + + @Override + public boolean equals(Object o) { + if ( o == null || getClass() != o.getClass() ) { + return false; + } + Book book = (Book) o; + return Objects.equals( isbn, book.isbn ) && Objects.equals( + title, + book.title + ) && Objects.equals( author, book.author ); + } + + @Override + public int hashCode() { + return Objects.hash( isbn, title, author ); + } + + @Override + public String toString() { + return id + ":" + isbn + ":" + title + ":" + author; + } + } + + @Entity(name = "Author") + @Table(name = "Author_HQL") + public static class Author { + @Id @GeneratedValue + private Integer id; + + private String name; + + @OneToMany(mappedBy = "author", cascade = PERSIST) + private List books = new ArrayList<>(); + + public Author() { + } + + public Author(String name) { + this.name = name; + } + + public Integer getId() { + return id; + } + + public String getName() { + return name; + } + + public List getBooks() { + return books; + } + + @Override + public boolean equals(Object o) { + if ( o == null || getClass() != o.getClass() ) { + return false; + } + Author author = (Author) o; + return Objects.equals( name, author.name ); + } + + @Override + public int hashCode() { + return Objects.hashCode( name ); + } + + @Override + public String toString() { + return id + ":" + name; + } + } } From 9640cd5b8a31138de2f06bf5b116d9ab6066a20d Mon Sep 17 00:00:00 2001 From: Davide D'Alto Date: Fri, 30 May 2025 10:36:08 +0200 Subject: [PATCH 090/162] chore: clean up HQLQueryTest class * Code formattation * Replace Jupiter assertions with AssertJ ones --- .../org/hibernate/reactive/HQLQueryTest.java | 38 +++++++++---------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/hibernate-reactive-core/src/test/java/org/hibernate/reactive/HQLQueryTest.java b/hibernate-reactive-core/src/test/java/org/hibernate/reactive/HQLQueryTest.java index 00e541285..77331fe2b 100644 --- a/hibernate-reactive-core/src/test/java/org/hibernate/reactive/HQLQueryTest.java +++ b/hibernate-reactive-core/src/test/java/org/hibernate/reactive/HQLQueryTest.java @@ -5,9 +5,6 @@ */ package org.hibernate.reactive; -import jakarta.persistence.GeneratedValue; -import jakarta.persistence.ManyToOne; -import jakarta.persistence.OneToMany; import java.util.ArrayList; import java.util.Collection; import java.util.List; @@ -21,7 +18,10 @@ import io.vertx.junit5.Timeout; import io.vertx.junit5.VertxTestContext; import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; import jakarta.persistence.Id; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.OneToMany; import jakarta.persistence.Table; import static jakarta.persistence.CascadeType.PERSIST; @@ -29,11 +29,8 @@ import static java.util.concurrent.TimeUnit.MINUTES; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertTrue; @Timeout(value = 10, timeUnit = MINUTES) - public class HQLQueryTest extends BaseReactiveTest { Flour spelt = new Flour( 1, "Spelt", "An ancient grain, is a hexaploid species of wheat.", "Wheat flour" ); @@ -82,7 +79,7 @@ public void testAutoFlushOnResultList(VertxTestContext context) { public void testSelectScalarString(VertxTestContext context) { test( context, getSessionFactory().withSession( s -> { Stage.SelectionQuery qr = s.createSelectionQuery( "SELECT 'Prova' FROM Flour WHERE id = " + rye.getId(), String.class ); - assertNotNull( qr ); + assertThat( qr ).isNotNull(); return qr.getSingleResult(); } ).thenAccept( found -> assertEquals( "Prova", found ) ) ); } @@ -91,7 +88,7 @@ public void testSelectScalarString(VertxTestContext context) { public void testSelectScalarCount(VertxTestContext context) { test( context, getSessionFactory().withSession( s -> { Stage.SelectionQuery qr = s.createSelectionQuery( "SELECT count(*) FROM Flour", Long.class ); - assertNotNull( qr ); + assertThat( qr ).isNotNull(); return qr.getSingleResult(); } ).thenAccept( found -> assertEquals( 3L, found ) ) ); } @@ -99,14 +96,17 @@ public void testSelectScalarCount(VertxTestContext context) { @Test public void testSelectWithMultipleScalarValues(VertxTestContext context) { test( context, getSessionFactory().withSession( s -> { - Stage.SelectionQuery qr = s.createSelectionQuery( "SELECT 'Prova', f.id FROM Flour f WHERE f.id = " + rye.getId(), Object[].class ); - assertNotNull( qr ); - return qr.getSingleResult(); - } ).thenAccept( found -> { - assertTrue( found instanceof Object[] ); - assertEquals( "Prova", ( (Object[]) found )[0] ); - assertEquals( rye.getId(), ( (Object[]) found )[1] ); - } ) + Stage.SelectionQuery qr = s.createSelectionQuery( + "SELECT 'Prova', f.id FROM Flour f WHERE f.id = " + rye.getId(), + Object[].class + ); + assertThat( qr ).isNotNull(); + return qr.getSingleResult(); + } ).thenAccept( found -> { + assertThat( found ).isInstanceOf( Object[].class ); + assertEquals( "Prova", ( (Object[]) found )[0] ); + assertEquals( rye.getId(), ( (Object[]) found )[1] ); + } ) ); } @@ -114,7 +114,7 @@ public void testSelectWithMultipleScalarValues(VertxTestContext context) { public void testSingleResultQueryOnId(VertxTestContext context) { test( context, getSessionFactory().withSession( s -> { Stage.SelectionQuery qr = s.createSelectionQuery( "FROM Flour WHERE id = 1", Flour.class ); - assertNotNull( qr ); + assertThat( qr ).isNotNull(); return qr.getSingleResult(); } ).thenAccept( flour -> assertEquals( spelt, flour ) ) ); @@ -124,7 +124,7 @@ public void testSingleResultQueryOnId(VertxTestContext context) { public void testSingleResultQueryOnName(VertxTestContext context) { test( context, getSessionFactory().withSession( s -> { Stage.SelectionQuery qr = s.createSelectionQuery( "FROM Flour WHERE name = 'Almond'", Flour.class ); - assertNotNull( qr ); + assertThat( qr ).isNotNull(); return qr.getSingleResult(); } ).thenAccept( flour -> assertEquals( almond, flour ) ) ); @@ -135,7 +135,7 @@ public void testFromQuery(VertxTestContext context) { test( context, getSessionFactory() .withSession( s -> { Stage.SelectionQuery qr = s.createSelectionQuery( "FROM Flour ORDER BY name", Flour.class ); - assertNotNull( qr ); + assertThat( qr ).isNotNull(); return qr.getResultList(); } ) .thenAccept( results -> assertThat( results ).containsExactly( almond, rye, spelt ) ) From a0f068920c1163549b8cada66d32cea53d3f9f67 Mon Sep 17 00:00:00 2001 From: Andrea Boriero Date: Tue, 27 May 2025 12:26:30 +0200 Subject: [PATCH 091/162] [#2230] ClassCastException when with @EmebedddedId and @OneToOne relationship --- ...ReactiveEmbeddedIdentifierMappingImpl.java | 11 ++ .../internal/ReactiveEmbeddableAssembler.java | 42 ++++++ .../internal/ReactiveEmbeddableFetchImpl.java | 21 +++ .../ReactiveEmbeddableInitializerImpl.java | 140 +++++++++++++++++- .../ReactiveEntityInitializerImpl.java | 107 ++++++++----- 5 files changed, 283 insertions(+), 38 deletions(-) create mode 100644 hibernate-reactive-core/src/main/java/org/hibernate/reactive/sql/results/graph/embeddable/internal/ReactiveEmbeddableAssembler.java 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/sql/results/graph/embeddable/internal/ReactiveEmbeddableAssembler.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/sql/results/graph/embeddable/internal/ReactiveEmbeddableAssembler.java new file mode 100644 index 000000000..db8222838 --- /dev/null +++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/sql/results/graph/embeddable/internal/ReactiveEmbeddableAssembler.java @@ -0,0 +1,42 @@ +/* Hibernate, Relational Persistence for Idiomatic Java + * + * SPDX-License-Identifier: Apache-2.0 + * Copyright: Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.reactive.sql.results.graph.embeddable.internal; + +import org.hibernate.reactive.sql.exec.spi.ReactiveRowProcessingState; +import org.hibernate.reactive.sql.results.graph.ReactiveDomainResultsAssembler; +import org.hibernate.reactive.sql.results.graph.ReactiveInitializer; +import org.hibernate.sql.results.graph.Initializer; +import org.hibernate.sql.results.graph.InitializerData; +import org.hibernate.sql.results.graph.embeddable.EmbeddableInitializer; +import org.hibernate.sql.results.graph.embeddable.internal.EmbeddableAssembler; +import org.hibernate.sql.results.jdbc.spi.JdbcValuesSourceProcessingOptions; + +import java.util.concurrent.CompletionStage; + +import static org.hibernate.reactive.util.impl.CompletionStages.completedFuture; + +/** + * @see org.hibernate.sql.results.graph.embeddable.internal.EmbeddableAssembler + */ +public class ReactiveEmbeddableAssembler extends EmbeddableAssembler implements ReactiveDomainResultsAssembler { + + public ReactiveEmbeddableAssembler(EmbeddableInitializer initializer) { + super( initializer ); + } + + @Override + public CompletionStage reactiveAssemble(ReactiveRowProcessingState rowProcessingState, JdbcValuesSourceProcessingOptions options) { + final ReactiveInitializer reactiveInitializer = (ReactiveInitializer) getInitializer(); + final InitializerData data = reactiveInitializer.getData( rowProcessingState ); + final Initializer.State state = data.getState(); + if ( state == Initializer.State.KEY_RESOLVED ) { + return reactiveInitializer + .reactiveResolveInstance( data ) + .thenApply( v -> reactiveInitializer.getResolvedInstance( data ) ); + } + return completedFuture( reactiveInitializer.getResolvedInstance( data ) ); + } +} diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/sql/results/graph/embeddable/internal/ReactiveEmbeddableFetchImpl.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/sql/results/graph/embeddable/internal/ReactiveEmbeddableFetchImpl.java index 50034533b..8a5ec18f9 100644 --- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/sql/results/graph/embeddable/internal/ReactiveEmbeddableFetchImpl.java +++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/sql/results/graph/embeddable/internal/ReactiveEmbeddableFetchImpl.java @@ -6,14 +6,20 @@ package org.hibernate.reactive.sql.results.graph.embeddable.internal; import org.hibernate.engine.FetchTiming; +import org.hibernate.reactive.sql.results.graph.entity.internal.ReactiveEntityFetchSelectImpl; import org.hibernate.spi.NavigablePath; import org.hibernate.sql.results.graph.AssemblerCreationState; +import org.hibernate.sql.results.graph.DomainResultAssembler; 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; +import org.hibernate.sql.results.graph.Initializer; import org.hibernate.sql.results.graph.InitializerParent; import org.hibernate.sql.results.graph.embeddable.EmbeddableInitializer; import org.hibernate.sql.results.graph.embeddable.EmbeddableValuedFetchable; import org.hibernate.sql.results.graph.embeddable.internal.EmbeddableFetchImpl; +import org.hibernate.sql.results.graph.entity.internal.EntityFetchSelectImpl; public class ReactiveEmbeddableFetchImpl extends EmbeddableFetchImpl { @@ -37,4 +43,19 @@ public EmbeddableInitializer createInitializer( AssemblerCreationState creationState) { return new ReactiveEmbeddableInitializerImpl( this, getDiscriminatorFetch(), parent, creationState, true ); } + + @Override + public DomainResultAssembler createAssembler(InitializerParent parent, AssemblerCreationState creationState) { + Initializer initializer = creationState.resolveInitializer( this, parent, this ); + EmbeddableInitializer embeddableInitializer = initializer.asEmbeddableInitializer(); + return new ReactiveEmbeddableAssembler( embeddableInitializer ); + } + + @Override + public Fetch findFetch(Fetchable fetchable) { + Fetch fetch = super.findFetch( fetchable ); + return fetch instanceof EntityFetchSelectImpl + ? new ReactiveEntityFetchSelectImpl( (EntityFetchSelectImpl) fetch ) + : fetch; + } } diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/sql/results/graph/embeddable/internal/ReactiveEmbeddableInitializerImpl.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/sql/results/graph/embeddable/internal/ReactiveEmbeddableInitializerImpl.java index a1d4a890e..b7d21216b 100644 --- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/sql/results/graph/embeddable/internal/ReactiveEmbeddableInitializerImpl.java +++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/sql/results/graph/embeddable/internal/ReactiveEmbeddableInitializerImpl.java @@ -5,12 +5,19 @@ */ package org.hibernate.reactive.sql.results.graph.embeddable.internal; + import java.util.concurrent.CompletionStage; import java.util.function.BiFunction; +import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.metamodel.mapping.EmbeddableMappingType; +import org.hibernate.metamodel.mapping.VirtualModelPart; +import org.hibernate.metamodel.spi.EmbeddableInstantiator; +import org.hibernate.reactive.sql.exec.spi.ReactiveRowProcessingState; +import org.hibernate.reactive.sql.results.graph.ReactiveDomainResultsAssembler; import org.hibernate.reactive.sql.results.graph.ReactiveInitializer; import org.hibernate.sql.results.graph.AssemblerCreationState; +import org.hibernate.sql.results.graph.DomainResultAssembler; import org.hibernate.sql.results.graph.Initializer; import org.hibernate.sql.results.graph.InitializerData; import org.hibernate.sql.results.graph.InitializerParent; @@ -19,12 +26,19 @@ import org.hibernate.sql.results.graph.embeddable.internal.EmbeddableInitializerImpl; import org.hibernate.sql.results.jdbc.spi.RowProcessingState; +import static org.hibernate.reactive.util.impl.CompletionStages.completedFuture; import static org.hibernate.reactive.util.impl.CompletionStages.loop; +import static org.hibernate.reactive.util.impl.CompletionStages.nullFuture; import static org.hibernate.reactive.util.impl.CompletionStages.voidFuture; +import static org.hibernate.reactive.util.impl.CompletionStages.whileLoop; +import static org.hibernate.sql.results.graph.embeddable.EmbeddableLoadingLogger.EMBEDDED_LOAD_LOGGER; +import static org.hibernate.sql.results.graph.entity.internal.BatchEntityInsideEmbeddableSelectFetchInitializer.BATCH_PROPERTY; public class ReactiveEmbeddableInitializerImpl extends EmbeddableInitializerImpl implements ReactiveInitializer { + private final SessionFactoryImplementor sessionFactory; + private static class ReactiveEmbeddableInitializerData extends EmbeddableInitializerData { public ReactiveEmbeddableInitializerData( @@ -33,6 +47,10 @@ public ReactiveEmbeddableInitializerData( super( initializer, rowProcessingState ); } + public Object[] getRowState(){ + return rowState; + } + @Override public void setState(State state) { super.setState( state ); @@ -55,6 +73,7 @@ public ReactiveEmbeddableInitializerImpl( AssemblerCreationState creationState, boolean isResultInitializer) { super( resultDescriptor, discriminatorFetch, parent, creationState, isResultInitializer ); + sessionFactory = creationState.getSqlAstCreationContext().getSessionFactory(); } @Override @@ -64,10 +83,129 @@ protected InitializerData createInitializerData(RowProcessingState rowProcessing @Override public CompletionStage reactiveResolveInstance(EmbeddableInitializerData data) { - super.resolveInstance( data ); + if ( data.getState() != State.KEY_RESOLVED ) { + return voidFuture(); + } + + data.setState( State.RESOLVED ); + return extractRowState( (ReactiveEmbeddableInitializerData) data ) + .thenAccept( unused -> prepareCompositeInstance( (ReactiveEmbeddableInitializerData) data ) ); + } + + private CompletionStage extractRowState(ReactiveEmbeddableInitializerData data) { + final DomainResultAssembler[] subAssemblers = assemblers[data.getSubclassId()]; + final RowProcessingState rowProcessingState = data.getRowProcessingState(); + final Object[] rowState = data.getRowState(); + final boolean[] stateAllNull = {true}; + final int[] index = {0}; + final boolean[] forceExit = { false }; + return whileLoop( + () -> index[0] < subAssemblers.length && !forceExit[0], + () -> { + final int i = index[0]++; + final DomainResultAssembler assembler = subAssemblers[i]; + if ( assembler instanceof ReactiveDomainResultsAssembler ) { + return ( (ReactiveDomainResultsAssembler) assembler ) + .reactiveAssemble( (ReactiveRowProcessingState) rowProcessingState ) + .thenAccept( contributorValue -> setContributorValue( + contributorValue, + i, + rowState, + stateAllNull, + forceExit + ) ); + } + else { + setContributorValue( + assembler == null ? null : assembler.assemble( rowProcessingState ), + i, + rowState, + stateAllNull, + forceExit + ); + return voidFuture(); + } + }) + .whenComplete( + (unused, throwable) -> { + if ( stateAllNull[0] ) { + data.setState( State.MISSING ); + } + } + ); + } + + private void setContributorValue( + Object contributorValue, + int index, + Object[] rowState, + boolean[] stateAllNull, + boolean[] forceExit) { + if ( contributorValue == BATCH_PROPERTY ) { + rowState[index] = null; + } + else { + rowState[index] = contributorValue; + } + if ( contributorValue != null ) { + stateAllNull[0] = false; + } + else if ( isPartOfKey() ) { + // If this is a foreign key and there is a null part, the whole thing has to be turned into null + stateAllNull[0] = true; + forceExit[0] = true; + } + } + + private CompletionStage prepareCompositeInstance(ReactiveEmbeddableInitializerData data) { + // Virtual model parts use the owning entity as container which the fetch parent access provides. + // For an identifier or foreign key this is called during the resolveKey phase of the fetch parent, + // so we can't use the fetch parent access in that case. + final ReactiveInitializer parent = (ReactiveInitializer) getParent(); + if ( parent != null && getInitializedPart() instanceof VirtualModelPart && !isPartOfKey() && data.getState() != State.MISSING ) { + final ReactiveEmbeddableInitializerData subData = parent.getData( data.getRowProcessingState() ); + return parent + .reactiveResolveInstance( subData ) + .thenCompose( + unused -> { + data.setInstance( parent.getResolvedInstance( subData ) ); + if ( data.getState() == State.INITIALIZED ) { + return voidFuture(); + } + return doCreateCompositeInstance( data ) + .thenAccept( v -> EMBEDDED_LOAD_LOGGER.debugf( + "Created composite instance [%s]", + getNavigablePath() + ) ); + } ); + } + + return doCreateCompositeInstance( data ) + .thenAccept( v -> EMBEDDED_LOAD_LOGGER.debugf( "Created composite instance [%s]", getNavigablePath() ) ); + + } + + private CompletionStage doCreateCompositeInstance(ReactiveEmbeddableInitializerData data) { + if ( data.getInstance() == null ) { + return createCompositeInstance( data ) + .thenAccept( data::setInstance ); + } return voidFuture(); } + private CompletionStage createCompositeInstance(ReactiveEmbeddableInitializerData data) { + if ( data.getState() == State.MISSING ) { + return nullFuture(); + } + + final EmbeddableInstantiator instantiator = data.getConcreteEmbeddableType() == null + ? getInitializedPart().getEmbeddableTypeDescriptor().getRepresentationStrategy().getInstantiator() + : data.getConcreteEmbeddableType().getInstantiator(); + final Object instance = instantiator.instantiate( data, sessionFactory ); + data.setState( State.RESOLVED ); + return completedFuture( instance ); + } + @Override public CompletionStage reactiveInitializeInstance(EmbeddableInitializerData data) { super.initializeInstance( data ); diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/sql/results/graph/entity/internal/ReactiveEntityInitializerImpl.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/sql/results/graph/entity/internal/ReactiveEntityInitializerImpl.java index d19728fb1..8e94f006e 100644 --- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/sql/results/graph/entity/internal/ReactiveEntityInitializerImpl.java +++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/sql/results/graph/entity/internal/ReactiveEntityInitializerImpl.java @@ -27,6 +27,7 @@ import org.hibernate.proxy.map.MapProxy; import org.hibernate.reactive.session.ReactiveQueryProducer; import org.hibernate.reactive.sql.exec.spi.ReactiveRowProcessingState; +import org.hibernate.reactive.sql.results.graph.ReactiveDomainResultsAssembler; import org.hibernate.reactive.sql.results.graph.ReactiveInitializer; import org.hibernate.sql.results.graph.AssemblerCreationState; import org.hibernate.sql.results.graph.DomainResult; @@ -253,47 +254,79 @@ public CompletionStage reactiveResolveInstance(EntityInitializerData origi } final RowProcessingState rowProcessingState = data.getRowProcessingState(); data.setState( State.RESOLVED ); + return assembleId( data, rowProcessingState ) + .thenCompose( unused -> { + if ( data.getState() == State.MISSING ) { + return voidFuture(); + } + else { + final PersistenceContext persistenceContext = rowProcessingState + .getSession().getPersistenceContextInternal(); + data.setEntityHolder( persistenceContext.claimEntityHolderIfPossible( + data.getEntityKey(), + null, + rowProcessingState.getJdbcValuesSourceProcessingState(), + this + ) ); + + if ( useEmbeddedIdentifierInstanceAsEntity( data ) ) { + data.setEntityInstanceForNotify( rowProcessingState.getEntityId() ); + data.setInstance( data.getEntityInstanceForNotify() ); + } + else { + return reactiveResolveEntityInstance1( data ) + .thenAccept( v -> { + if ( data.getUniqueKeyAttributePath() != null ) { + final SharedSessionContractImplementor session = rowProcessingState.getSession(); + final EntityPersister concreteDescriptor = getConcreteDescriptor( data ); + final EntityUniqueKey euk = new EntityUniqueKey( + concreteDescriptor.getEntityName(), + data.getUniqueKeyAttributePath(), + rowProcessingState.getEntityUniqueKey(), + data.getUniqueKeyPropertyTypes()[concreteDescriptor.getSubclassId()], + session.getFactory() + ); + session.getPersistenceContextInternal().addEntity( + euk, + data.getInstance() + ); + } + postResolveInstance( data ); + } ); + } + postResolveInstance( data ); + return voidFuture(); + } + } ); + } + + private CompletionStage assembleId( + ReactiveEntityInitializerData data, + RowProcessingState rowProcessingState) { if ( data.getEntityKey() == null ) { - assert getIdentifierAssembler() != null; - final Object id = getIdentifierAssembler().assemble( rowProcessingState ); - if ( id == null ) { - setMissing( data ); + DomainResultAssembler identifierAssembler = getIdentifierAssembler(); + assert identifierAssembler != null; + if ( identifierAssembler instanceof ReactiveDomainResultsAssembler ) { + return ( (ReactiveDomainResultsAssembler) identifierAssembler ) + .reactiveAssemble( (ReactiveRowProcessingState) rowProcessingState ) + .thenAccept( id -> { + if ( id == null ) { + setMissing( data ); + return ; + } + resolveEntityKey( data, id ); + } ); + } + else { + final Object id = identifierAssembler.assemble( rowProcessingState ); + if ( id == null ) { + setMissing( data ); + return voidFuture(); + } + resolveEntityKey( data, id ); return voidFuture(); } - resolveEntityKey( data, id ); - } - final PersistenceContext persistenceContext = rowProcessingState.getSession() - .getPersistenceContextInternal(); - data.setEntityHolder( persistenceContext.claimEntityHolderIfPossible( - data.getEntityKey(), - null, - rowProcessingState.getJdbcValuesSourceProcessingState(), - this - ) ); - - if ( useEmbeddedIdentifierInstanceAsEntity( data ) ) { - data.setEntityInstanceForNotify( rowProcessingState.getEntityId() ); - data.setInstance( data.getEntityInstanceForNotify() ); - } - else { - return reactiveResolveEntityInstance1( data ) - .thenAccept( v -> { - if ( data.getUniqueKeyAttributePath() != null ) { - final SharedSessionContractImplementor session = rowProcessingState.getSession(); - final EntityPersister concreteDescriptor = getConcreteDescriptor( data ); - final EntityUniqueKey euk = new EntityUniqueKey( - concreteDescriptor.getEntityName(), - data.getUniqueKeyAttributePath(), - rowProcessingState.getEntityUniqueKey(), - data.getUniqueKeyPropertyTypes()[concreteDescriptor.getSubclassId()], - session.getFactory() - ); - session.getPersistenceContextInternal().addEntity( euk, data.getInstance() ); - } - postResolveInstance( data ); - } ); } - postResolveInstance( data ); return voidFuture(); } From 6d3d151e6a2ecda46fdd4f617b6d7badbf708bd5 Mon Sep 17 00:00:00 2001 From: Davide D'Alto Date: Tue, 29 Apr 2025 15:57:45 +0200 Subject: [PATCH 092/162] [#2230] Test embedded id with one-to-one --- .../reactive/EmbeddedIdWithOneToOneTest.java | 131 ++++++++++++++++++ 1 file changed, 131 insertions(+) create mode 100644 hibernate-reactive-core/src/test/java/org/hibernate/reactive/EmbeddedIdWithOneToOneTest.java diff --git a/hibernate-reactive-core/src/test/java/org/hibernate/reactive/EmbeddedIdWithOneToOneTest.java b/hibernate-reactive-core/src/test/java/org/hibernate/reactive/EmbeddedIdWithOneToOneTest.java new file mode 100644 index 000000000..f5cbf5fd9 --- /dev/null +++ b/hibernate-reactive-core/src/test/java/org/hibernate/reactive/EmbeddedIdWithOneToOneTest.java @@ -0,0 +1,131 @@ +/* Hibernate, Relational Persistence for Idiomatic Java + * + * SPDX-License-Identifier: Apache-2.0 + * Copyright: Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.reactive; + +import org.junit.jupiter.api.Test; + +import io.vertx.junit5.VertxTestContext; +import jakarta.persistence.Embeddable; +import jakarta.persistence.EmbeddedId; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.OneToOne; +import java.util.Collection; +import java.util.List; +import java.util.Objects; + +import static org.assertj.core.api.Assertions.assertThat; + +public class EmbeddedIdWithOneToOneTest extends BaseReactiveTest { + + @Override + protected Collection> annotatedEntities() { + return List.of( FooEntity.class, BarEntity.class ); + } + + @Test + public void test(VertxTestContext context) { + BarEntity barEntity = new BarEntity( "1" ); + FooId fooId = new FooId( barEntity ); + FooEntity entity = new FooEntity( fooId ); + + test( + context, getMutinySessionFactory() + .withTransaction( s -> s.persistAll( barEntity, entity ) ) + .chain( () -> getMutinySessionFactory() + .withTransaction( s -> s.find( FooEntity.class, fooId ) ) + ) + .invoke( result -> { + assertThat( result.getId() ).isEqualTo( fooId ); + assertThat( result.getId().getIdEntity() ).isEqualTo( fooId.getIdEntity() ); + assertThat( result.getId().getIdEntity().getId() ).isEqualTo( fooId.getIdEntity().getId() ); + } ) + ); + } + + @Entity(name = "bar") + public static class BarEntity { + + @Id + private String id; + + public BarEntity() { + } + + public BarEntity(String id) { + this.id = id; + } + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + } + + @Entity(name = "foo") + public static class FooEntity { + + @EmbeddedId + private FooId id; + + public FooEntity() { + } + + public FooEntity(FooId id) { + this.id = id; + } + + public FooId getId() { + return id; + } + + public void setId(FooId id) { + this.id = id; + } + } + + @Embeddable + public static class FooId { + + @OneToOne(fetch = FetchType.EAGER) + @JoinColumn(name = "id", nullable = false) + private BarEntity barEntity; + + public FooId() { + } + + public FooId(BarEntity barEntity) { + this.barEntity = barEntity; + } + + public BarEntity getIdEntity() { + return barEntity; + } + + public void setIdEntity(BarEntity barEntity) { + this.barEntity = barEntity; + } + + @Override + public boolean equals(Object o) { + if ( o == null || getClass() != o.getClass() ) { + return false; + } + FooId fooId = (FooId) o; + return Objects.equals( barEntity, fooId.barEntity ); + } + + @Override + public int hashCode() { + return Objects.hashCode( barEntity ); + } + } +} From 2aba8d66d242b6b247c4905bcacc48bb258c89c4 Mon Sep 17 00:00:00 2001 From: Davide D'Alto Date: Wed, 4 Jun 2025 10:53:49 +0200 Subject: [PATCH 093/162] [#2230] Small refactoring Make the structure of the code more similar to the one in Hibernate ORM (See EntityInitializerImpl) --- .../ReactiveEntityInitializerImpl.java | 121 ++++++++---------- 1 file changed, 52 insertions(+), 69 deletions(-) diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/sql/results/graph/entity/internal/ReactiveEntityInitializerImpl.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/sql/results/graph/entity/internal/ReactiveEntityInitializerImpl.java index 8e94f006e..70d8335ac 100644 --- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/sql/results/graph/entity/internal/ReactiveEntityInitializerImpl.java +++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/sql/results/graph/entity/internal/ReactiveEntityInitializerImpl.java @@ -254,82 +254,65 @@ public CompletionStage reactiveResolveInstance(EntityInitializerData origi } final RowProcessingState rowProcessingState = data.getRowProcessingState(); data.setState( State.RESOLVED ); - return assembleId( data, rowProcessingState ) - .thenCompose( unused -> { - if ( data.getState() == State.MISSING ) { - return voidFuture(); - } - else { - final PersistenceContext persistenceContext = rowProcessingState - .getSession().getPersistenceContextInternal(); - data.setEntityHolder( persistenceContext.claimEntityHolderIfPossible( - data.getEntityKey(), - null, - rowProcessingState.getJdbcValuesSourceProcessingState(), - this - ) ); - - if ( useEmbeddedIdentifierInstanceAsEntity( data ) ) { - data.setEntityInstanceForNotify( rowProcessingState.getEntityId() ); - data.setInstance( data.getEntityInstanceForNotify() ); - } - else { - return reactiveResolveEntityInstance1( data ) - .thenAccept( v -> { - if ( data.getUniqueKeyAttributePath() != null ) { - final SharedSessionContractImplementor session = rowProcessingState.getSession(); - final EntityPersister concreteDescriptor = getConcreteDescriptor( data ); - final EntityUniqueKey euk = new EntityUniqueKey( - concreteDescriptor.getEntityName(), - data.getUniqueKeyAttributePath(), - rowProcessingState.getEntityUniqueKey(), - data.getUniqueKeyPropertyTypes()[concreteDescriptor.getSubclassId()], - session.getFactory() - ); - session.getPersistenceContextInternal().addEntity( - euk, - data.getInstance() - ); - } - postResolveInstance( data ); - } ); + if ( data.getEntityKey() == null ) { + return assembleId( rowProcessingState ) + .thenCompose( id -> { + if ( id == null ) { + setMissing( data ); + return voidFuture(); } - postResolveInstance( data ); - return voidFuture(); + resolveEntityKey( data, id ); + return postAssembleId( rowProcessingState, data ); + } ); + } + return postAssembleId( rowProcessingState, data ); + } + + private CompletionStage postAssembleId(RowProcessingState rowProcessingState, ReactiveEntityInitializerData data) { + final PersistenceContext persistenceContext = rowProcessingState.getSession().getPersistenceContextInternal(); + data.setEntityHolder( persistenceContext.claimEntityHolderIfPossible( + data.getEntityKey(), + null, + rowProcessingState.getJdbcValuesSourceProcessingState(), + this + ) ); + + if ( useEmbeddedIdentifierInstanceAsEntity( data ) ) { + data.setEntityInstanceForNotify( rowProcessingState.getEntityId() ); + data.setInstance( data.getEntityInstanceForNotify() ); + postResolveInstance( data ); + return voidFuture(); + } + + return reactiveResolveEntityInstance1( data ) + .thenAccept( v -> { + if ( data.getUniqueKeyAttributePath() != null ) { + final SharedSessionContractImplementor session = rowProcessingState.getSession(); + final EntityPersister concreteDescriptor = getConcreteDescriptor( data ); + final EntityUniqueKey euk = new EntityUniqueKey( + concreteDescriptor.getEntityName(), + data.getUniqueKeyAttributePath(), + rowProcessingState.getEntityUniqueKey(), + data.getUniqueKeyPropertyTypes()[concreteDescriptor.getSubclassId()], + session.getFactory() + ); + session.getPersistenceContextInternal().addEntity( euk, data.getInstance() ); } - } ); + postResolveInstance( data ); + } ); } - private CompletionStage assembleId( - ReactiveEntityInitializerData data, - RowProcessingState rowProcessingState) { - if ( data.getEntityKey() == null ) { - DomainResultAssembler identifierAssembler = getIdentifierAssembler(); - assert identifierAssembler != null; - if ( identifierAssembler instanceof ReactiveDomainResultsAssembler ) { - return ( (ReactiveDomainResultsAssembler) identifierAssembler ) - .reactiveAssemble( (ReactiveRowProcessingState) rowProcessingState ) - .thenAccept( id -> { - if ( id == null ) { - setMissing( data ); - return ; - } - resolveEntityKey( data, id ); - } ); - } - else { - final Object id = identifierAssembler.assemble( rowProcessingState ); - if ( id == null ) { - setMissing( data ); - return voidFuture(); - } - resolveEntityKey( data, id ); - return voidFuture(); - } + private CompletionStage assembleId(RowProcessingState rowProcessingState) { + final DomainResultAssembler identifierAssembler = getIdentifierAssembler(); + assert identifierAssembler != null; + if ( identifierAssembler instanceof ReactiveDomainResultsAssembler ) { + return ( (ReactiveDomainResultsAssembler) identifierAssembler ) + .reactiveAssemble( (ReactiveRowProcessingState) rowProcessingState ); } - return voidFuture(); + return completedFuture( identifierAssembler.assemble( rowProcessingState ) ); } + // We could move this method in ORM private void postResolveInstance(ReactiveEntityInitializerData data) { if ( data.getInstance() != null ) { upgradeLockMode( data ); From dfb9eea41df6b4e095fd8d751ebd8420d774881c Mon Sep 17 00:00:00 2001 From: Davide D'Alto Date: Fri, 6 Jun 2025 11:55:47 +0200 Subject: [PATCH 094/162] [#2186] Improve error message when asking for a JDBC connection --- .../main/java/org/hibernate/reactive/logging/impl/Log.java | 4 ++++ .../provider/service/NoJdbcConnectionProvider.java | 7 ++++++- 2 files changed, 10 insertions(+), 1 deletion(-) 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 d8f77be0f..7e19c58f3 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,6 +7,7 @@ +import java.sql.SQLException; import java.sql.SQLWarning; import jakarta.persistence.PersistenceException; @@ -258,6 +259,9 @@ public interface Log extends BasicLogger { @Message(id = 80, value = "No results were returned by the query (you can try running it with '.executeUpdate()'): %1$s") HibernateException noResultException(String sql); + @Message(id = 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!" ) diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/provider/service/NoJdbcConnectionProvider.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/provider/service/NoJdbcConnectionProvider.java index 5c3380f65..a02c3e152 100644 --- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/provider/service/NoJdbcConnectionProvider.java +++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/provider/service/NoJdbcConnectionProvider.java @@ -6,10 +6,14 @@ package org.hibernate.reactive.provider.service; import org.hibernate.engine.jdbc.connections.spi.ConnectionProvider; +import org.hibernate.reactive.logging.impl.Log; import java.sql.Connection; import java.sql.SQLException; +import static java.lang.invoke.MethodHandles.lookup; +import static org.hibernate.reactive.logging.impl.LoggerFactory.make; + /** * A dummy Hibernate {@link ConnectionProvider} throws an * exception if a JDBC connection is requested. @@ -17,12 +21,13 @@ * @author Gavin King */ public class NoJdbcConnectionProvider implements ConnectionProvider { + private static final Log LOG = make( Log.class, lookup() ); public static final NoJdbcConnectionProvider INSTANCE = new NoJdbcConnectionProvider(); @Override public Connection getConnection() throws SQLException { - throw new SQLException( "Not using JDBC" ); + throw LOG.notUsingJdbc(); } @Override From b3623b41e72e56f052122622b4976689ee1c5d03 Mon Sep 17 00:00:00 2001 From: marko-bekhta Date: Fri, 13 Jun 2025 23:45:33 +0200 Subject: [PATCH 095/162] [#2305] Switch to Maven Central publishing --- ci/release/Jenkinsfile | 8 +------- ci/snapshot-publish.Jenkinsfile | 2 +- publish.gradle | 6 +++--- 3 files changed, 5 insertions(+), 11 deletions(-) diff --git a/ci/release/Jenkinsfile b/ci/release/Jenkinsfile index 915aa211e..1815b77ac 100644 --- a/ci/release/Jenkinsfile +++ b/ci/release/Jenkinsfile @@ -195,13 +195,7 @@ pipeline { configFile(fileId: 'release.config.ssh.knownhosts', targetLocation: "${env.HOME}/.ssh/known_hosts") ]) { withCredentials([ - // 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'), + usernamePassword(credentialsId: 'central.sonatype.com', passwordVariable: 'JRELEASER_MAVENCENTRAL_TOKEN', usernameVariable: 'JRELEASER_MAVENCENTRAL_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'), diff --git a/ci/snapshot-publish.Jenkinsfile b/ci/snapshot-publish.Jenkinsfile index de6a030f2..9a9ecd707 100644 --- a/ci/snapshot-publish.Jenkinsfile +++ b/ci/snapshot-publish.Jenkinsfile @@ -43,7 +43,7 @@ pipeline { // 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'), + usernamePassword(credentialsId: 'central.sonatype.com', 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') ]) { diff --git a/publish.gradle b/publish.gradle index f77b26959..6d05724fa 100644 --- a/publish.gradle +++ b/publish.gradle @@ -21,7 +21,7 @@ jar { 'Implementation-Version': project.version, 'Implementation-Vendor': 'Hibernate.org', 'Implementation-Vendor-Id': 'org.hibernate', - 'Implementation-Url': 'http://hibernate.org/reactive', + 'Implementation-Url': 'https://hibernate.org/reactive', ) } } @@ -50,7 +50,7 @@ publishing { license { name = 'Apache License Version 2.0' url = 'https://opensource.org/licenses/Apache-2.0' - comments = 'See discussion at http://hibernate.org/community/license/ for more details.' + comments = 'See discussion at https://hibernate.org/community/license/ for more details.' distribution = 'repo' } } @@ -81,7 +81,7 @@ publishing { } maven { name = 'snapshots' - url = "https://oss.sonatype.org/content/repositories/snapshots/" + url = "https://central.sonatype.com/repository/maven-snapshots/" // So that Gradle uses the `ORG_GRADLE_PROJECT_snapshotsPassword` / `ORG_GRADLE_PROJECT_snapshotsUsername` // env variables to read the username/password for the `snapshots` repository publishing: credentials(PasswordCredentials) From df72562a6f7eeecc160de0b3f32f555a22ff1699 Mon Sep 17 00:00:00 2001 From: Davide D'Alto Date: Tue, 17 Jun 2025 10:49:58 +0200 Subject: [PATCH 096/162] [#2309] Add JDK 26-ea to the build --- .github/workflows/build.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index b99524924..07b9bfc3b 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -179,6 +179,7 @@ jobs: - { name: "21", java_version_numeric: 21, jvm_args: '--enable-preview' } - { name: "24", java_version_numeric: 24, from: 'jdk.java.net', jvm_args: '--enable-preview' } - { name: "25-ea", java_version_numeric: 25, from: 'jdk.java.net', jvm_args: '--enable-preview' } + - { name: "26-ea", java_version_numeric: 26, from: 'jdk.java.net', jvm_args: '--enable-preview' } steps: - name: Checkout ${{ inputs.branch }} uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 From f102f787f118132390caeb4f09c3acdbc4f7dfca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yoann=20Rodi=C3=A8re?= Date: Fri, 20 Jun 2025 16:44:59 +0200 Subject: [PATCH 097/162] [#2314] Test setMaxResults() on native queries --- .../org/hibernate/reactive/QueryTest.java | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/hibernate-reactive-core/src/test/java/org/hibernate/reactive/QueryTest.java b/hibernate-reactive-core/src/test/java/org/hibernate/reactive/QueryTest.java index d6146b2e5..44c822718 100644 --- a/hibernate-reactive-core/src/test/java/org/hibernate/reactive/QueryTest.java +++ b/hibernate-reactive-core/src/test/java/org/hibernate/reactive/QueryTest.java @@ -43,6 +43,7 @@ import static jakarta.persistence.FetchType.LAZY; import static java.util.concurrent.TimeUnit.MINUTES; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.groups.Tuple.tuple; import static org.hibernate.reactive.QueryTest.Author.AUTHOR_TABLE; import static org.hibernate.reactive.QueryTest.Author.HQL_NAMED_QUERY; import static org.hibernate.reactive.QueryTest.Author.SQL_NAMED_QUERY; @@ -395,6 +396,42 @@ public void testNativeEntityQueryWithParam(VertxTestContext context) { ); } + // https://github.com/hibernate/hibernate-reactive/issues/2314 + @Test + public void testNativeEntityQueryWithLimit(VertxTestContext context) { + Author author1 = new Author( "Iain M. Banks" ); + Author author2 = new Author( "Neal Stephenson" ); + Book book1 = new Book( "1-85723-235-6", "Feersum Endjinn", author1 ); + Book book2 = new Book( "0-380-97346-4", "Cryptonomicon", author2 ); + Book book3 = new Book( "0-553-08853-X", "Snow Crash", author2 ); + author1.books.add( book1 ); + author2.books.add( book2 ); + author2.books.add( book3 ); + + test( + context, + openSession() + .thenCompose( session -> session.persist( author1, author2 ) + .thenCompose( v -> session.flush() ) + ) + .thenCompose( v -> openSession() ) + .thenCompose( session -> session.createNativeQuery( + "select * from " + BOOK_TABLE + " order by isbn", + Book.class + ) + .setMaxResults( 2 ) + .getResultList() ) + .thenAccept( books -> { + assertThat( books ) + .extracting( b -> b.id, b -> b.title, b -> b.isbn ) + .containsExactly( + tuple( book2.id, book2.title, book2.isbn ), + tuple( book3.id, book3.title, book3.isbn ) + ); + } ) + ); + } + @Test public void testNativeEntityQueryWithNamedParam(VertxTestContext context) { Author author1 = new Author( "Iain M. Banks" ); From f056c3bc4b707b500a5769bddde7cd28bb043a3d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yoann=20Rodi=C3=A8re?= Date: Fri, 20 Jun 2025 17:25:25 +0200 Subject: [PATCH 098/162] [#2314] Fix '?' parameters in limit/offset not being replaced with native equivalent when using PostgreSQL/MSSQL Reverts some changes introduced in e257189f643346799703eab7805de6c4b74a8b33, probably assuming this was more efficient and didn't break anything (understandably, considering tests did pass). --- .../results/internal/ReactiveDeferredResultSetAccess.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/sql/results/internal/ReactiveDeferredResultSetAccess.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/sql/results/internal/ReactiveDeferredResultSetAccess.java index da94cc329..3b185152a 100644 --- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/sql/results/internal/ReactiveDeferredResultSetAccess.java +++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/sql/results/internal/ReactiveDeferredResultSetAccess.java @@ -149,9 +149,10 @@ private CompletionStage executeQuery() { return completedFuture( logicalConnection ) .thenCompose( lg -> { LOG.tracef( "Executing query to retrieve ResultSet : %s", getFinalSql() ); - Dialect dialect = DialectDelegateWrapper.extractRealDialect( executionContext.getSession().getJdbcServices().getDialect() ); - // I'm not sure calling Parameters here is necessary, the query should already have the right parameters + + // This must happen at the very last minute in order to process parameters + // added in org.hibernate.dialect.pagination.OffsetFetchLimitHandler.processSql final String sql = Parameters.instance( dialect ).process( getFinalSql() ); Object[] parameters = PreparedStatementAdaptor.bind( super::bindParameters ); From 748dac48bd48de81ad3d97c40f32f384b89d0f79 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yoann=20Rodi=C3=A8re?= Date: Mon, 23 Jun 2025 12:51:04 +0200 Subject: [PATCH 099/162] Release job: minor aligmnent on ORM's job --- ci/release/Jenkinsfile | 47 ++++++++++++++++++++++-------------------- 1 file changed, 25 insertions(+), 22 deletions(-) diff --git a/ci/release/Jenkinsfile b/ci/release/Jenkinsfile index 1815b77ac..5fcacce73 100644 --- a/ci/release/Jenkinsfile +++ b/ci/release/Jenkinsfile @@ -1,9 +1,7 @@ #! /usr/bin/groovy /* - * Hibernate, Relational Persistence for Idiomatic Java - * - * License: GNU Lesser General Public License (LGPL), version 2.1 or later. - * See the lgpl.txt file in the root directory or . + * SPDX-License-Identifier: Apache-2.0 + * Copyright Red Hat Inc. and Hibernate Authors */ /* @@ -89,9 +87,13 @@ pipeline { ) } stages { - stage('Release check') { + stage('Check') { steps { script { + print "INFO: params.RELEASE_VERSION = ${params.RELEASE_VERSION}" + print "INFO: params.DEVELOPMENT_VERSION = ${params.DEVELOPMENT_VERSION}" + print "INFO: params.RELEASE_DRY_RUN? = ${params.RELEASE_DRY_RUN}" + checkoutReleaseScripts() def currentVersion = Version.parseDevelopmentVersion( sh( @@ -107,7 +109,9 @@ pipeline { echo "Release was requested manually" if ( !params.RELEASE_VERSION ) { - throw new IllegalArgumentException( 'Missing value for parameter RELEASE_VERSION. This parameter must be set explicitly to prevent mistakes.' ) + throw new IllegalArgumentException( + 'Missing value for parameter RELEASE_VERSION. This parameter must be set explicitly to prevent mistakes.' + ) } releaseVersion = Version.parseReleaseVersion( params.RELEASE_VERSION ) @@ -149,17 +153,12 @@ pipeline { env.RELEASE_VERSION = releaseVersion.toString() env.DEVELOPMENT_VERSION = developmentVersion.toString() - // Dry run is not supported at the moment - env.SCRIPT_OPTIONS = params.RELEASE_DRY_RUN ? "-d" : "" + 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) - // sh ".release/scripts/determine-jira-version-id.sh ${env.JIRA_KEY} ${releaseVersion.withoutFinalQualifier}" } } } - stage('Release prepare') { + stage('Prepare') { steps { script { checkoutReleaseScripts() @@ -168,13 +167,13 @@ pipeline { configFile(fileId: 'release.config.ssh', targetLocation: "${env.HOME}/.ssh/config"), configFile(fileId: 'release.config.ssh.knownhosts', targetLocation: "${env.HOME}/.ssh/known_hosts") ]) { - - sshagent(['ed25519.Hibernate-CI.github.com', 'hibernate.filemgmt.jboss.org', 'hibernate-ci.frs.sourceforge.net']) { + sshagent(['ed25519.Hibernate-CI.github.com', 'hibernate.filemgmt.jboss.org', 'hibernate-ci.frs.sourceforge.net']) { // set release version // update changelog from JIRA // tags the version // changes the version to the provided development version withEnv([ + "DISABLE_REMOTE_GRADLE_CACHE=true", // 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'" ]) { @@ -185,7 +184,7 @@ pipeline { } } } - stage('Publish release') { + stage('Publish') { steps { script { checkoutReleaseScripts() @@ -195,16 +194,20 @@ pipeline { configFile(fileId: 'release.config.ssh.knownhosts', targetLocation: "${env.HOME}/.ssh/known_hosts") ]) { withCredentials([ - usernamePassword(credentialsId: 'central.sonatype.com', passwordVariable: 'JRELEASER_MAVENCENTRAL_TOKEN', usernameVariable: 'JRELEASER_MAVENCENTRAL_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') + usernamePassword(credentialsId: 'central.sonatype.com', passwordVariable: 'JRELEASER_MAVENCENTRAL_TOKEN', usernameVariable: 'JRELEASER_MAVENCENTRAL_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 -j ${env.SCRIPT_OPTIONS} ${env.PROJECT} ${env.RELEASE_VERSION} ${env.DEVELOPMENT_VERSION} ${env.GIT_BRANCH}" + withEnv([ + "DISABLE_REMOTE_GRADLE_CACHE=true" + ]) { + sh ".release/scripts/publish.sh -j ${env.SCRIPT_OPTIONS} ${env.PROJECT} ${env.RELEASE_VERSION} ${env.DEVELOPMENT_VERSION} ${env.GIT_BRANCH}" + } } } } From 19700a09ab6a95527a23538e9f280fab795a2626 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yoann=20Rodi=C3=A8re?= Date: Mon, 23 Jun 2025 12:52:52 +0200 Subject: [PATCH 100/162] Release job: Avoid auto-release when there are no "releasable" commits The determination of "releasable" is in the release scripts, but currently it boils down to having an issue key in the commit message. --- ci/release/Jenkinsfile | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/ci/release/Jenkinsfile b/ci/release/Jenkinsfile index 5fcacce73..3e9a0b902 100644 --- a/ci/release/Jenkinsfile +++ b/ci/release/Jenkinsfile @@ -122,14 +122,15 @@ pipeline { else { 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).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' + // Avoid doing an automatic release if there are no "releasable" commits since the last release (see release scripts for determination) + def releasableCommitCount = sh( + script: ".release/scripts/count-releasable-commits.sh ${env.PROJECT}", + returnStdout: true + ).trim().toInteger() + if ( releasableCommitCount <= 0 ) { + print "INFO: Automatic release skipped because no releasable commits were pushed since the previous release" + currentBuild.getRawBuild().getExecutor().interrupt(Result.NOT_BUILT) + sleep(1) // Interrupt is not blocking and does not take effect immediately. return } From b44c0eaf5c68b700691a11b1f1cad3797585b302 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yoann=20Rodi=C3=A8re?= Date: Mon, 23 Jun 2025 12:54:34 +0200 Subject: [PATCH 101/162] Release job: update the hibernate.org website automatically for micros --- ci/release/Jenkinsfile | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/ci/release/Jenkinsfile b/ci/release/Jenkinsfile index 3e9a0b902..9f832efe2 100644 --- a/ci/release/Jenkinsfile +++ b/ci/release/Jenkinsfile @@ -215,6 +215,33 @@ pipeline { } } } + stage('Update website') { + steps { + script { + checkoutReleaseScripts() + + configFileProvider([ + configFile(fileId: 'release.config.ssh', targetLocation: "${env.HOME}/.ssh/config"), + configFile(fileId: 'release.config.ssh.knownhosts', targetLocation: "${env.HOME}/.ssh/known_hosts") + ]) { + withCredentials([ + gitUsernamePassword(credentialsId: 'username-and-token.Hibernate-CI.github.com', gitToolName: 'Default') + ]) { + sshagent( ['ed25519.Hibernate-CI.github.com', 'hibernate.filemgmt.jboss.org', 'hibernate-ci.frs.sourceforge.net'] ) { + dir( '.release/hibernate.org' ) { + checkout scmGit( + branches: [[name: '*/production']], + extensions: [], + userRemoteConfigs: [[credentialsId: 'ed25519.Hibernate-CI.github.com', url: 'https://github.com/hibernate/hibernate.org.git']] + ) + sh "../scripts/website-release.sh ${env.SCRIPT_OPTIONS} ${env.PROJECT} ${env.RELEASE_VERSION}" + } + } + } + } + } + } + } } post { always { From 4b32a389ba824f7b5c78e24b580e9aacd15bf4a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yoann=20Rodi=C3=A8re?= Date: Mon, 23 Jun 2025 13:02:00 +0200 Subject: [PATCH 102/162] Release job: code for weekly release (disabled for now) --- ci/release/Jenkinsfile | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/ci/release/Jenkinsfile b/ci/release/Jenkinsfile index 9f832efe2..dbfec2ba5 100644 --- a/ci/release/Jenkinsfile +++ b/ci/release/Jenkinsfile @@ -15,11 +15,10 @@ import org.hibernate.jenkins.pipeline.helpers.version.Version // Global build configuration env.PROJECT = "reactive" env.JIRA_KEY = "HREACT" -def RELEASE_ON_PUSH = false // Set to `true` *only* on branches where you want a release on each push. +def RELEASE_ON_SCHEDULE = false // Set to `true` *only* on branches where you want a scheduled release. print "INFO: env.PROJECT = ${env.PROJECT}" print "INFO: env.JIRA_KEY = ${env.JIRA_KEY}" -print "INFO: RELEASE_ON_PUSH = ${RELEASE_ON_PUSH}" // -------------------------------------------- // Build conditions @@ -32,10 +31,17 @@ if (currentBuild.getBuildCauses().toString().contains('BranchIndexingCause')) { } def manualRelease = currentBuild.getBuildCauses().toString().contains( 'UserIdCause' ) +def cronRelease = currentBuild.getBuildCauses().toString().contains( 'TimerTriggerCause' ) // Only do automatic release on branches where we opted in -if ( !manualRelease && !RELEASE_ON_PUSH ) { - print "INFO: Build skipped because automated releases are disabled on this branch. See constant RELEASE_ON_PUSH in ci/release/Jenkinsfile" +if ( !manualRelease && !cronRelease ) { + print "INFO: Build skipped because automated releases on push are disabled on this branch." + currentBuild.result = 'NOT_BUILT' + return +} + +if ( !manualRelease && cronRelease && !RELEASE_ON_SCHEDULE ) { + print "INFO: Build skipped because automated releases are disabled on this branch. See constant RELEASE_ON_SCHEDULE in ci/release/Jenkinsfile" currentBuild.result = 'NOT_BUILT' return } @@ -51,6 +57,7 @@ def checkoutReleaseScripts() { } } + // -------------------------------------------- // Pipeline @@ -58,12 +65,15 @@ pipeline { agent { label 'Release' } + triggers { + // Run every week Sunday 1 AM + cron('0 1 * * 0') + } tools { jdk 'OpenJDK 11 Latest' } options { buildDiscarder logRotator(daysToKeepStr: '30', numToKeepStr: '10') - rateLimitBuilds(throttle: [count: 1, durationName: 'day', userBoost: true]) disableConcurrentBuilds(abortPrevious: false) preserveStashes() } From b57c3e1ce4c1f8ef682ae7fa133abafd5898e931 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yoann=20Rodi=C3=A8re?= Date: Mon, 23 Jun 2025 13:05:21 +0200 Subject: [PATCH 103/162] Release job: enable auto release on weekends --- ci/release/Jenkinsfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci/release/Jenkinsfile b/ci/release/Jenkinsfile index dbfec2ba5..70a7401df 100644 --- a/ci/release/Jenkinsfile +++ b/ci/release/Jenkinsfile @@ -15,7 +15,7 @@ import org.hibernate.jenkins.pipeline.helpers.version.Version // Global build configuration env.PROJECT = "reactive" env.JIRA_KEY = "HREACT" -def RELEASE_ON_SCHEDULE = false // Set to `true` *only* on branches where you want a scheduled release. +def RELEASE_ON_SCHEDULE = true // Set to `true` *only* on branches where you want a scheduled release. print "INFO: env.PROJECT = ${env.PROJECT}" print "INFO: env.JIRA_KEY = ${env.JIRA_KEY}" From 4825ea587f130e7cf4c8364f1784666d1ad5bb8a Mon Sep 17 00:00:00 2001 From: marko-bekhta Date: Thu, 19 Jun 2025 15:10:49 +0200 Subject: [PATCH 104/162] [#2305] Update optional snapshot repositories to point to central snapshots instead of ossrh ones since now our snapshots are published to central. --- build.gradle | 6 +++--- examples/native-sql-example/build.gradle | 6 +++--- examples/session-example/build.gradle | 6 +++--- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/build.gradle b/build.gradle index 33e79e8fd..93e94504e 100644 --- a/build.gradle +++ b/build.gradle @@ -56,9 +56,9 @@ subprojects { // Useful for local development, it should be disabled otherwise mavenLocal() } - // Example: ./gradlew build -PenableSonatypeOpenSourceSnapshotsRep - if ( project.hasProperty('enableSonatypeOpenSourceSnapshotsRep') ) { - maven { url 'https://oss.sonatype.org/content/repositories/snapshots/' } + // Example: ./gradlew build -PenableCentralSonatypeSnapshotsRep + if ( project.hasProperty('enableCentralSonatypeSnapshotsRep') ) { + maven { url 'https://central.sonatype.com/repository/maven-snapshots/' } } mavenCentral() diff --git a/examples/native-sql-example/build.gradle b/examples/native-sql-example/build.gradle index c79ec8984..2cfd95a16 100644 --- a/examples/native-sql-example/build.gradle +++ b/examples/native-sql-example/build.gradle @@ -8,9 +8,9 @@ buildscript { mavenLocal() } // Optional: Enables snapshots repository - // Example: ./gradlew build -PenableSonatypeOpenSourceSnapshotsRep - if ( project.hasProperty('enableSonatypeOpenSourceSnapshotsRep') ) { - maven { url 'https://oss.sonatype.org/content/repositories/snapshots/' } + // Example: ./gradlew build -PenableCentralSonatypeSnapshotsRep + if ( project.hasProperty('enableCentralSonatypeSnapshotsRep') ) { + maven { url 'https://central.sonatype.com/repository/maven-snapshots/' } } mavenCentral() } diff --git a/examples/session-example/build.gradle b/examples/session-example/build.gradle index 4da40ba69..35fa10dcc 100644 --- a/examples/session-example/build.gradle +++ b/examples/session-example/build.gradle @@ -8,9 +8,9 @@ buildscript { mavenLocal() } // Optional: Enables snapshots repository - // Example: ./gradlew build -PenableSonatypeOpenSourceSnapshotsRep - if ( project.hasProperty('enableSonatypeOpenSourceSnapshotsRep') ) { - maven { url 'https://oss.sonatype.org/content/repositories/snapshots/' } + // Example: ./gradlew build -PenableCentralSonatypeSnapshotsRep + if ( project.hasProperty('enableCentralSonatypeSnapshotsRep') ) { + maven { url 'https://central.sonatype.com/repository/maven-snapshots/' } } mavenCentral() } From 4103eebcd2f4b1ede083f73acd5621d5877088f6 Mon Sep 17 00:00:00 2001 From: Davide D'Alto Date: Fri, 27 Jun 2025 15:25:58 +0200 Subject: [PATCH 105/162] [#2324] Upgrade Vert.x SQL client to 4.5.16 --- README.md | 10 +++++----- build.gradle | 2 +- gradle.properties | 6 +++--- tooling/jbang/CockroachDBReactiveTest.java.qute | 4 ++-- tooling/jbang/Db2ReactiveTest.java.qute | 4 ++-- tooling/jbang/Example.java | 6 +++--- tooling/jbang/MariaDBReactiveTest.java.qute | 4 ++-- tooling/jbang/MySQLReactiveTest.java.qute | 4 ++-- tooling/jbang/PostgreSQLReactiveTest.java.qute | 4 ++-- tooling/jbang/ReactiveTest.java | 8 ++++---- 10 files changed, 26 insertions(+), 26 deletions(-) diff --git a/README.md b/README.md index c39228e47..55dc68c76 100644 --- a/README.md +++ b/README.md @@ -38,11 +38,11 @@ Hibernate Reactive has been tested with: - MS SQL Server 2022 - Oracle 23 - [Hibernate ORM][] 6.6.15.Final -- [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 +- [Vert.x Reactive PostgreSQL Client](https://vertx.io/docs/vertx-pg-client/java/) 4.5.16 +- [Vert.x Reactive MySQL Client](https://vertx.io/docs/vertx-mysql-client/java/) 4.5.16 +- [Vert.x Reactive Db2 Client](https://vertx.io/docs/vertx-db2-client/java/) 4.5.16 +- [Vert.x Reactive MS SQL Server Client](https://vertx.io/docs/vertx-mssql-client/java/) 4.5.16 +- [Vert.x Reactive Oracle Client](https://vertx.io/docs/vertx-oracle-client/java/) 4.5.16 - [Quarkus][Quarkus] via the Hibernate Reactive extension [PostgreSQL]: https://www.postgresql.org diff --git a/build.gradle b/build.gradle index 93e94504e..0e650f224 100644 --- a/build.gradle +++ b/build.gradle @@ -22,7 +22,7 @@ ext { // Example: // ./gradlew build -PvertxSqlClientVersion=4.0.0-SNAPSHOT if ( !project.hasProperty( 'vertxSqlClientVersion' ) ) { - vertxSqlClientVersion = '4.5.14' + vertxSqlClientVersion = '4.5.16' } testcontainersVersion = '1.20.6' diff --git a/gradle.properties b/gradle.properties index 1de1027bc..5db7442ce 100644 --- a/gradle.properties +++ b/gradle.properties @@ -47,9 +47,9 @@ hibernateOrmVersion = 6.6.15.Final #skipOrmVersionParsing = true # Override default Vert.x Sql client version -#vertxSqlClientVersion = 4.5.14-SNAPSHOT +#vertxSqlClientVersion = 4.5.16-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 = 4.5.16 +#vertxWebtClientVersion = 4.5.16 diff --git a/tooling/jbang/CockroachDBReactiveTest.java.qute b/tooling/jbang/CockroachDBReactiveTest.java.qute index 71695f45b..584d8e1db 100755 --- a/tooling/jbang/CockroachDBReactiveTest.java.qute +++ b/tooling/jbang/CockroachDBReactiveTest.java.qute @@ -5,8 +5,8 @@ * Copyright: Red Hat Inc. and Hibernate Authors */ -//DEPS io.vertx:vertx-pg-client:$\{vertx.version:4.5.14} -//DEPS io.vertx:vertx-unit:$\{vertx.version:4.5.14} +//DEPS io.vertx:vertx-pg-client:$\{vertx.version:4.5.16} +//DEPS io.vertx:vertx-unit:$\{vertx.version:4.5.16} //DEPS org.hibernate.reactive:hibernate-reactive-core:$\{hibernate-reactive.version:2.4.0.Final} //DEPS org.assertj:assertj-core:3.26.3 //DEPS junit:junit:4.13.2 diff --git a/tooling/jbang/Db2ReactiveTest.java.qute b/tooling/jbang/Db2ReactiveTest.java.qute index f752a1a16..2b34f8a5d 100755 --- a/tooling/jbang/Db2ReactiveTest.java.qute +++ b/tooling/jbang/Db2ReactiveTest.java.qute @@ -5,8 +5,8 @@ * Copyright: Red Hat Inc. and Hibernate Authors */ -//DEPS io.vertx:vertx-db2-client:$\{vertx.version:4.5.14} -//DEPS io.vertx:vertx-unit:$\{vertx.version:4.5.14} +//DEPS io.vertx:vertx-db2-client:$\{vertx.version:4.5.16} +//DEPS io.vertx:vertx-unit:$\{vertx.version:4.5.16} //DEPS org.hibernate.reactive:hibernate-reactive-core:$\{hibernate-reactive.version:2.4.0.Final} //DEPS org.assertj:assertj-core:3.26.3 //DEPS junit:junit:4.13.2 diff --git a/tooling/jbang/Example.java b/tooling/jbang/Example.java index 10ae59842..8e8ec3091 100644 --- a/tooling/jbang/Example.java +++ b/tooling/jbang/Example.java @@ -6,9 +6,9 @@ */ //DEPS com.ongres.scram:client:2.1 -//DEPS io.vertx:vertx-pg-client:${vertx.version:4.5.14} -//DEPS io.vertx:vertx-mysql-client:${vertx.version:4.5.14} -//DEPS io.vertx:vertx-db2-client:${vertx.version:4.5.14} +//DEPS io.vertx:vertx-pg-client:${vertx.version:4.5.16} +//DEPS io.vertx:vertx-mysql-client:${vertx.version:4.5.16} +//DEPS io.vertx:vertx-db2-client:${vertx.version:4.5.16} //DEPS org.hibernate.reactive:hibernate-reactive-core:${hibernate-reactive.version:2.4.0.Final} //DEPS org.slf4j:slf4j-simple:2.0.7 //DESCRIPTION Allow authentication to PostgreSQL using SCRAM: diff --git a/tooling/jbang/MariaDBReactiveTest.java.qute b/tooling/jbang/MariaDBReactiveTest.java.qute index f0b0a7fc6..f89f2129e 100755 --- a/tooling/jbang/MariaDBReactiveTest.java.qute +++ b/tooling/jbang/MariaDBReactiveTest.java.qute @@ -5,8 +5,8 @@ * Copyright: Red Hat Inc. and Hibernate Authors */ -//DEPS io.vertx:vertx-mysql-client:$\{vertx.version:4.5.14} -//DEPS io.vertx:vertx-unit:$\{vertx.version:4.5.14} +//DEPS io.vertx:vertx-mysql-client:$\{vertx.version:4.5.16} +//DEPS io.vertx:vertx-unit:$\{vertx.version:4.5.16} //DEPS org.hibernate.reactive:hibernate-reactive-core:$\{hibernate-reactive.version:2.4.0.Final} //DEPS org.assertj:assertj-core:3.26.3 //DEPS junit:junit:4.13.2 diff --git a/tooling/jbang/MySQLReactiveTest.java.qute b/tooling/jbang/MySQLReactiveTest.java.qute index 93d6dff11..1c78cc704 100755 --- a/tooling/jbang/MySQLReactiveTest.java.qute +++ b/tooling/jbang/MySQLReactiveTest.java.qute @@ -5,8 +5,8 @@ * Copyright: Red Hat Inc. and Hibernate Authors */ -//DEPS io.vertx:vertx-mysql-client:$\{vertx.version:4.5.14} -//DEPS io.vertx:vertx-unit:$\{vertx.version:4.5.14} +//DEPS io.vertx:vertx-mysql-client:$\{vertx.version:4.5.16} +//DEPS io.vertx:vertx-unit:$\{vertx.version:4.5.16} //DEPS org.hibernate.reactive:hibernate-reactive-core:$\{hibernate-reactive.version:2.4.0.Final} //DEPS org.assertj:assertj-core:3.26.3 //DEPS junit:junit:4.13.2 diff --git a/tooling/jbang/PostgreSQLReactiveTest.java.qute b/tooling/jbang/PostgreSQLReactiveTest.java.qute index f404f4d1e..f5a922b4f 100755 --- a/tooling/jbang/PostgreSQLReactiveTest.java.qute +++ b/tooling/jbang/PostgreSQLReactiveTest.java.qute @@ -5,8 +5,8 @@ * Copyright: Red Hat Inc. and Hibernate Authors */ -//DEPS io.vertx:vertx-pg-client:$\{vertx.version:4.5.14} -//DEPS io.vertx:vertx-unit:$\{vertx.version:4.5.14} +//DEPS io.vertx:vertx-pg-client:$\{vertx.version:4.5.16} +//DEPS io.vertx:vertx-unit:$\{vertx.version:4.5.16} //DEPS org.hibernate.reactive:hibernate-reactive-core:$\{hibernate-reactive.version:2.4.0.Final} //DEPS org.assertj:assertj-core:3.26.3 //DEPS junit:junit:4.13.2 diff --git a/tooling/jbang/ReactiveTest.java b/tooling/jbang/ReactiveTest.java index 08d872619..9abcda9d9 100755 --- a/tooling/jbang/ReactiveTest.java +++ b/tooling/jbang/ReactiveTest.java @@ -5,11 +5,11 @@ */ ///usr/bin/env jbang "$0" "$@" ; exit $? -//DEPS io.vertx:vertx-pg-client:${vertx.version:4.5.14} +//DEPS io.vertx:vertx-pg-client:${vertx.version:4.5.16} //DEPS com.ongres.scram:client:2.1 -//DEPS io.vertx:vertx-db2-client:${vertx.version:4.5.14} -//DEPS io.vertx:vertx-mysql-client:${vertx.version:4.5.14} -//DEPS io.vertx:vertx-unit:${vertx.version:4.5.14} +//DEPS io.vertx:vertx-db2-client:${vertx.version:4.5.16} +//DEPS io.vertx:vertx-mysql-client:${vertx.version:4.5.16} +//DEPS io.vertx:vertx-unit:${vertx.version:4.5.16} //DEPS org.hibernate.reactive:hibernate-reactive-core:${hibernate-reactive.version:2.4.0.Final} //DEPS org.assertj:assertj-core:3.26.3 //DEPS junit:junit:4.13.2 From afb9c97ca590a36fe0b63ddb4d01a51434cbf844 Mon Sep 17 00:00:00 2001 From: Davide D'Alto Date: Mon, 7 Jul 2025 17:23:23 +0200 Subject: [PATCH 106/162] [#2333] Rename property for enabling the snapshot repository From `enableSonatypeOpenSourceSnapshotsRep` to `enableCentralSonatypeSnapshotsRep` (in [gradle.properties](https://github.com/hibernate/hibernate-reactive/blob/main/gradle.properties)). It was changed in commit c254ebb as part of the move to Maven Central (#2305). --- gradle.properties | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gradle.properties b/gradle.properties index 5db7442ce..3f55c40eb 100644 --- a/gradle.properties +++ b/gradle.properties @@ -28,8 +28,8 @@ org.gradle.java.installations.auto-download=false # Db2, MySql, PostgreSQL, CockroachDB, SqlServer, Oracle #db = MSSQL -# Enable the SonatypeOS maven repository (mainly for Vert.x snapshots) when present (value ignored) -#enableSonatypeOpenSourceSnapshotsRep = true +# Enable the maven Central Snapshot repository, when set to any value (the value is ignored) +#enableCentralSonatypeSnapshotsRep = true # Enable the maven local repository (for local development when needed) when present (value ignored) #enableMavenLocalRepo = true From 1d036069574a2ac3237db324cf28fd92686328c5 Mon Sep 17 00:00:00 2001 From: Davide D'Alto Date: Tue, 8 Jul 2025 09:49:03 +0200 Subject: [PATCH 107/162] [#2333] Print the resolved Hibernate ORM and Vert.x version This is important to check what verison is actually resolved on the `wip/*` branches, where we test the snapshots, because we use a versions range. --- examples/native-sql-example/build.gradle | 33 ++++++++++++++++++++++++ examples/session-example/build.gradle | 32 +++++++++++++++++++++++ hibernate-reactive-core/build.gradle | 32 +++++++++++++++++++++++ 3 files changed, 97 insertions(+) diff --git a/examples/native-sql-example/build.gradle b/examples/native-sql-example/build.gradle index 2cfd95a16..8695f9df7 100644 --- a/examples/native-sql-example/build.gradle +++ b/examples/native-sql-example/build.gradle @@ -75,3 +75,36 @@ tasks.register( "runAllExamples" ) { dependsOn = ["runAllExamplesOnPostgreSQL"] description = "Run all examples on ${dbs}" } + +// Optional: Task to print the resolved versions of Hibernate ORM and Vert.x +tasks.register( "printResolvedVersions" ) { + description = "Print the resolved hibernate-orm-core and vert.x versions" + doLast { + def hibernateCoreVersion = "n/a" + def vertxVersion = "n/a" + + // Resolve Hibernate Core and Vert.x versions from compile classpath + configurations.compileClasspath.resolvedConfiguration.resolvedArtifacts.each { artifact -> + if (artifact.moduleVersion.id.name == 'hibernate-core') { + hibernateCoreVersion = artifact.moduleVersion.id.version + } + if (artifact.moduleVersion.id.group == 'io.vertx' && artifact.moduleVersion.id.name == 'vertx-sql-client') { + vertxVersion = artifact.moduleVersion.id.version + } + } + + // Print the resolved versions + println "Resolved Hibernate ORM Core Version: ${hibernateCoreVersion}" + println "Resolved Vert.x SQL client Version: ${vertxVersion}" + } +} + +// Make the version printing task run before tests and JavaExec tasks +tasks.withType( Test ).configureEach { + dependsOn printResolvedVersions +} + +tasks.withType( JavaExec ).configureEach { + dependsOn printResolvedVersions +} + diff --git a/examples/session-example/build.gradle b/examples/session-example/build.gradle index 35fa10dcc..f436ccd27 100644 --- a/examples/session-example/build.gradle +++ b/examples/session-example/build.gradle @@ -81,3 +81,35 @@ tasks.register( "runAllExamples" ) { dependsOn = ["runAllExamplesOnPostgreSQL", "runAllExamplesOnMySQL"] description = "Run all examples on ${dbs}" } + +// Optional: Task to print the resolved versions of Hibernate ORM and Vert.x +tasks.register( "printResolvedVersions" ) { + description = "Print the resolved hibernate-orm-core and vert.x versions" + doLast { + def hibernateCoreVersion = "n/a" + def vertxVersion = "n/a" + + // Resolve Hibernate Core and Vert.x versions from compile classpath + configurations.compileClasspath.resolvedConfiguration.resolvedArtifacts.each { artifact -> + if (artifact.moduleVersion.id.name == 'hibernate-core') { + hibernateCoreVersion = artifact.moduleVersion.id.version + } + if (artifact.moduleVersion.id.group == 'io.vertx' && artifact.moduleVersion.id.name == 'vertx-sql-client') { + vertxVersion = artifact.moduleVersion.id.version + } + } + + // Print the resolved versions + println "Resolved Hibernate ORM Core Version: ${hibernateCoreVersion}" + println "Resolved Vert.x SQL client Version: ${vertxVersion}" + } +} + +// Make the version printing task run before tests and JavaExec tasks +tasks.withType( Test ).configureEach { + dependsOn printResolvedVersions +} + +tasks.withType( JavaExec ).configureEach { + dependsOn printResolvedVersions +} diff --git a/hibernate-reactive-core/build.gradle b/hibernate-reactive-core/build.gradle index bbcbc9e6c..860d6dc7c 100644 --- a/hibernate-reactive-core/build.gradle +++ b/hibernate-reactive-core/build.gradle @@ -157,3 +157,35 @@ tasks.register( "testAll", Test ) { description = "Run tests for ${dbs}" dependsOn = dbs.collect( [] as HashSet ) { db -> "testDb${db}" } } + +// Task to print the resolved versions of Hibernate ORM and Vert.x +tasks.register( "printResolvedVersions" ) { + description = "Print the resolved hibernate-orm-core and vert.x versions" + doLast { + def hibernateCoreVersion = "n/a" + def vertxVersion = "n/a" + + // Resolve Hibernate Core and Vert.x versions from compile classpath + configurations.compileClasspath.resolvedConfiguration.resolvedArtifacts.each { artifact -> + if (artifact.moduleVersion.id.name == 'hibernate-core') { + hibernateCoreVersion = artifact.moduleVersion.id.version + } + if (artifact.moduleVersion.id.group == 'io.vertx' && artifact.moduleVersion.id.name == 'vertx-sql-client') { + vertxVersion = artifact.moduleVersion.id.version + } + } + + // Print the resolved versions + println "Resolved Hibernate ORM Core Version: ${hibernateCoreVersion}" + println "Resolved Vert.x SQL client Version: ${vertxVersion}" + } +} + +// Make the version printing task run before tests and JavaExec tasks +tasks.withType( Test ).configureEach { + dependsOn printResolvedVersions +} + +tasks.withType( JavaExec ).configureEach { + dependsOn printResolvedVersions +} From f58054c6de235e8b528d1637a4a9e215c044c346 Mon Sep 17 00:00:00 2001 From: exoego Date: Thu, 3 Jul 2025 18:10:19 +0900 Subject: [PATCH 108/162] [#1989] Migrate to Gradle version catalogs Plus, some test dependencies upgrade (for alignment with main): * AssertJ from 3.26.7 to 3.27.7 * Testcontainers from 1.20.6 to 1.21.0 * PostgreSQL from 42.7.4 to 42.7.5 * MariaDB JDBC Driver from 3.5.1 to 3.5.3 * MSSQL JDBC Driver from 12.8.1.jre11 to 12.10.0.jre11 * MySQL JDBC Driver from 9.1.0 to 9.3.0 --- build.gradle | 31 +++------ documentation/build.gradle | 2 +- examples/native-sql-example/build.gradle | 14 ++-- examples/session-example/build.gradle | 16 ++--- gradle.properties | 12 ++-- gradle/libs.versions.toml | 59 ++++++++++++++++ hibernate-reactive-core/build.gradle | 68 +++++++++---------- .../bytecode-enhancements-it/build.gradle | 23 +++---- .../build.gradle | 27 +++----- .../techempower-postgres-it/build.gradle | 30 +++----- .../verticle-postgres-it/build.gradle | 30 +++----- .../reactive/env/VersionsPlugin.java | 27 ++++++-- .../reactive/env/VersionsTomlParser.java | 68 +++++++++++++++++++ settings.gradle | 38 +++++++++++ 14 files changed, 292 insertions(+), 153 deletions(-) create mode 100644 gradle/libs.versions.toml create mode 100644 local-build-plugins/src/main/java/org/hibernate/reactive/env/VersionsTomlParser.java diff --git a/build.gradle b/build.gradle index 0e650f224..7400020fe 100644 --- a/build.gradle +++ b/build.gradle @@ -3,33 +3,15 @@ plugins { id 'java-library' id 'maven-publish' - id 'com.diffplug.spotless' version '6.25.0' - id 'org.asciidoctor.jvm.convert' version '4.0.2' apply false - id 'io.github.gradle-nexus.publish-plugin' version '1.3.0' + alias(libs.plugins.com.diffplug.spotless) + alias(libs.plugins.org.asciidoctor.jvm.convert) apply false + alias(libs.plugins.io.github.gradle.nexus.publish.plugin) } group = "org.hibernate.reactive" // leverage the ProjectVersion which comes from the `local.versions` plugin version = project.projectVersion.fullName -// Versions which need to be aligned across modules; this also -// allows overriding the build using a parameter, which can be -// useful to monitor compatibility for upcoming versions on CI: -// -// ./gradlew clean build -PhibernateOrmVersion=5.6.15-SNAPSHOT -ext { - // Mainly, to allow CI to test the latest versions of Vert.X - // Example: - // ./gradlew build -PvertxSqlClientVersion=4.0.0-SNAPSHOT - if ( !project.hasProperty( 'vertxSqlClientVersion' ) ) { - vertxSqlClientVersion = '4.5.16' - } - - testcontainersVersion = '1.20.6' - - logger.lifecycle "Vert.x SQL Client Version: " + project.vertxSqlClientVersion -} - subprojects { apply plugin: 'java-library' apply plugin: 'com.diffplug.spotless' @@ -135,3 +117,10 @@ subprojects { } } +rootProject.afterEvaluate { + // Workaround since "libs.versions.NAME" notation cannot be used here + def libs = project.extensions.getByType(VersionCatalogsExtension).named('libs') + logger.lifecycle "ORM version: ${libs.findVersion('hibernateOrmVersion').get().requiredVersion}" + logger.lifecycle "ORM Gradle plugin version: ${libs.findVersion('hibernateOrmGradlePluginVersion').get().requiredVersion}" + logger.lifecycle "Vert.x SQL Client version: ${libs.findVersion('vertxSqlClientVersion').get().requiredVersion}" +} diff --git a/documentation/build.gradle b/documentation/build.gradle index aa6a27622..95c3dcb2b 100644 --- a/documentation/build.gradle +++ b/documentation/build.gradle @@ -52,7 +52,7 @@ def aggregateJavadocsTask = tasks.register( 'aggregateJavadocs', Javadoc ) { use = true options.encoding = 'UTF-8' - def matcher = hibernateOrmVersion =~ /\d+\.\d+/ + def matcher = libs.versions.hibernateOrmVersion =~ /\d+\.\d+/ def ormMinorVersion = matcher.find() ? matcher.group() : "5.6"; links = [ diff --git a/examples/native-sql-example/build.gradle b/examples/native-sql-example/build.gradle index 8695f9df7..50c5a4117 100644 --- a/examples/native-sql-example/build.gradle +++ b/examples/native-sql-example/build.gradle @@ -18,7 +18,7 @@ buildscript { plugins { // Optional: Hibernate Gradle plugin to enable bytecode enhancements - id "org.hibernate.orm" version "${hibernateOrmGradlePluginVersion}" + alias(libs.plugins.org.hibernate.orm) } description = 'Hibernate Reactive native SQL Example' @@ -27,20 +27,20 @@ dependencies { implementation project( ':hibernate-reactive-core' ) // Hibernate Validator (optional) - implementation 'org.hibernate.validator:hibernate-validator:8.0.2.Final' - runtimeOnly 'org.glassfish.expressly:expressly:5.0.0' + implementation(libs.org.hibernate.validator.hibernate.validator) + runtimeOnly(libs.org.glassfish.expressly.expressly) // JPA metamodel generation for criteria queries (optional) - annotationProcessor "org.hibernate.orm:hibernate-jpamodelgen:${hibernateOrmVersion}" + annotationProcessor(libs.org.hibernate.orm.hibernate.jpamodelgen) // database driver for PostgreSQL - runtimeOnly "io.vertx:vertx-pg-client:${vertxSqlClientVersion}" + runtimeOnly(libs.io.vertx.vertx.pg.client) // logging (optional) - runtimeOnly "org.apache.logging.log4j:log4j-core:2.20.0" + runtimeOnly(libs.org.apache.logging.log4j.log4j.core) // Allow authentication to PostgreSQL using SCRAM: - runtimeOnly 'com.ongres.scram:client:2.1' + runtimeOnly(libs.com.ongres.scram.client) } // Optional: enable the bytecode enhancements diff --git a/examples/session-example/build.gradle b/examples/session-example/build.gradle index f436ccd27..41f9135a5 100644 --- a/examples/session-example/build.gradle +++ b/examples/session-example/build.gradle @@ -18,7 +18,7 @@ buildscript { plugins { // Optional: Hibernate Gradle plugin to enable bytecode enhancements - id "org.hibernate.orm" version "${hibernateOrmGradlePluginVersion}" + alias(libs.plugins.org.hibernate.orm) } description = 'Hibernate Reactive Session Examples' @@ -27,21 +27,21 @@ dependencies { implementation project( ':hibernate-reactive-core' ) // Hibernate Validator (optional) - implementation 'org.hibernate.validator:hibernate-validator:8.0.2.Final' - runtimeOnly 'org.glassfish.expressly:expressly:5.0.0' + implementation(libs.org.hibernate.validator.hibernate.validator) + runtimeOnly(libs.org.glassfish.expressly.expressly) // JPA metamodel generation for criteria queries (optional) - annotationProcessor "org.hibernate.orm:hibernate-jpamodelgen:${hibernateOrmVersion}" + annotationProcessor(libs.org.hibernate.orm.hibernate.jpamodelgen) // database drivers for PostgreSQL and MySQL - runtimeOnly "io.vertx:vertx-pg-client:${vertxSqlClientVersion}" - runtimeOnly "io.vertx:vertx-mysql-client:${vertxSqlClientVersion}" + runtimeOnly(libs.io.vertx.vertx.pg.client) + runtimeOnly(libs.io.vertx.vertx.mysql.client) // logging (optional) - runtimeOnly "org.apache.logging.log4j:log4j-core:2.20.0" + runtimeOnly(libs.org.apache.logging.log4j.log4j.core) // Allow authentication to PostgreSQL using SCRAM: - runtimeOnly 'com.ongres.scram:client:2.1' + runtimeOnly(libs.com.ongres.scram.client) } // Optional: enable the bytecode enhancements diff --git a/gradle.properties b/gradle.properties index 3f55c40eb..346e9fa42 100644 --- a/gradle.properties +++ b/gradle.properties @@ -18,7 +18,9 @@ org.gradle.java.installations.auto-download=false ######################################################################### # Additional custom gradle build properties. -# Please, leave these properties commented upstream +# Please, leave these properties commented upstream. +# They are meant to be used for local builds or WIP branches. +# The same properties can be set from the command line. ########################################################################## # Enable Testcontainers + Docker when present (value ignored) @@ -34,13 +36,13 @@ org.gradle.java.installations.auto-download=false # Enable the maven local repository (for local development when needed) when present (value ignored) #enableMavenLocalRepo = true +### Settings the following properties will override the version defined in gradle/libs.versions.toml + # The default Hibernate ORM version (override using `-PhibernateOrmVersion=the.version.you.want`) -hibernateOrmVersion = 6.6.15.Final +#hibernateOrmVersion = 7.0.2.Final # Override default Hibernate ORM Gradle plugin version -# Using the stable version because I don't know how to configure the build to download the snapshot version from -# a remote repository -#hibernateOrmGradlePluginVersion = 6.6.15.Final +#hibernateOrmGradlePluginVersion = 7.0.2.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 diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml new file mode 100644 index 000000000..ec7271281 --- /dev/null +++ b/gradle/libs.versions.toml @@ -0,0 +1,59 @@ +[versions] +assertjVersion = "3.27.3" +hibernateOrmVersion = "6.6.15.Final" +hibernateOrmGradlePluginVersion = "6.6.15.Final" +jacksonDatabindVersion = "2.15.2" +jbossLoggingAnnotationVersion = "2.2.1.Final" +jbossLoggingVersion = "3.5.0.Final" +junitVersion = "5.11.3" +log4jVersion = "2.20.0" +testcontainersVersion = "1.21.0" +vertxSqlClientVersion = "4.5.16" +vertxWebVersion= "4.5.16" +vertxWebClientVersion = "4.5.16" + +[libraries] +com-fasterxml-jackson-core-jackson-databind = { group = "com.fasterxml.jackson.core", name = "jackson-databind", version.ref = "jacksonDatabindVersion" } +com-ibm-db2-jcc = { group = "com.ibm.db2", name = "jcc", version = "12.1.0.0" } +com-microsoft-sqlserver-mssql-jdbc = { group = "com.microsoft.sqlserver", name = "mssql-jdbc", version = "12.10.0.jre11" } +com-mysql-mysql-connector-j = { group = "com.mysql", name = "mysql-connector-j", version = "9.3.0" } +com-ongres-scram-client = { group = "com.ongres.scram", name = "client", version = "2.1" } +io-smallrye-reactive-mutiny = { group = "io.smallrye.reactive", name = "mutiny", version = "2.7.0" } +io-vertx-vertx-db2-client = { group = "io.vertx", name = "vertx-db2-client", version.ref = "vertxSqlClientVersion" } +io-vertx-vertx-junit5 = { group = "io.vertx", name = "vertx-junit5", version.ref = "vertxSqlClientVersion" } +io-vertx-vertx-micrometer-metrics = { group = "io.vertx", name = "vertx-micrometer-metrics", version.ref = "vertxSqlClientVersion" } +io-vertx-vertx-mssql-client = { group = "io.vertx", name = "vertx-mssql-client", version.ref = "vertxSqlClientVersion" } +io-vertx-vertx-mysql-client = { group = "io.vertx", name = "vertx-mysql-client", version.ref = "vertxSqlClientVersion" } +io-vertx-vertx-oracle-client = { group = "io.vertx", name = "vertx-oracle-client", version.ref = "vertxSqlClientVersion" } +io-vertx-vertx-pg-client = { group = "io.vertx", name = "vertx-pg-client", version.ref = "vertxSqlClientVersion" } +io-vertx-vertx-sql-client = { group = "io.vertx", name = "vertx-sql-client", version.ref = "vertxSqlClientVersion" } +io-vertx-vertx-web = { group = "io.vertx", name = "vertx-web", version.ref = "vertxWebVersion" } +io-vertx-vertx-web-client = { group = "io.vertx", name = "vertx-web-client", version.ref = "vertxWebClientVersion" } +org-apache-logging-log4j-log4j-core = { group = "org.apache.logging.log4j", name = "log4j-core", version.ref = "log4jVersion" } +org-assertj-assertj-core = { group = "org.assertj", name = "assertj-core", version.ref = "assertjVersion" } +org-ehcache-ehcache = { group = "org.ehcache", name = "ehcache", version = "3.10.8" } +org-glassfish-expressly-expressly = { group = "org.glassfish.expressly", name = "expressly", version = "5.0.0" } +org-hibernate-orm-hibernate-core = { group = "org.hibernate.orm", name = "hibernate-core", version.ref = "hibernateOrmVersion" } +org-hibernate-orm-hibernate-jcache = { group = "org.hibernate.orm", name = "hibernate-jcache", version.ref = "hibernateOrmVersion" } +org-hibernate-orm-hibernate-jpamodelgen = { group = "org.hibernate.orm", name = "hibernate-jpamodelgen", version.ref = "hibernateOrmVersion" } +org-hibernate-validator-hibernate-validator = { group = "org.hibernate.validator", name = "hibernate-validator", version = "8.0.2.Final" } +org-jboss-logging-jboss-logging = { group = "org.jboss.logging", name = "jboss-logging", version.ref = "jbossLoggingVersion" } +org-jboss-logging-jboss-logging-annotations = { group = "org.jboss.logging", name = "jboss-logging-annotations", version.ref = "jbossLoggingAnnotationVersion" } +org-jboss-logging-jboss-logging-processor = { group = "org.jboss.logging", name = "jboss-logging-processor", version.ref = "jbossLoggingAnnotationVersion" } +org-junit-jupiter-junit-jupiter-api = { group = "org.junit.jupiter", name = "junit-jupiter-api", version.ref = "junitVersion" } +org-junit-jupiter-junit-jupiter-engine = { group = "org.junit.jupiter", name = "junit-jupiter-engine", version.ref = "junitVersion" } +org-mariadb-jdbc-mariadb-java-client = { group = "org.mariadb.jdbc", name = "mariadb-java-client", version = "3.5.3" } +org-postgresql-postgresql = { group = "org.postgresql", name = "postgresql", version = "42.7.5" } +org-testcontainers-cockroachdb = { group = "org.testcontainers", name = "cockroachdb", version.ref = "testcontainersVersion" } +org-testcontainers-db2 = { group = "org.testcontainers", name = "db2", version.ref = "testcontainersVersion" } +org-testcontainers-mariadb = { group = "org.testcontainers", name = "mariadb", version.ref = "testcontainersVersion" } +org-testcontainers-mssqlserver = { group = "org.testcontainers", name = "mssqlserver", version.ref = "testcontainersVersion" } +org-testcontainers-mysql = { group = "org.testcontainers", name = "mysql", version.ref = "testcontainersVersion" } +org-testcontainers-oracle-xe = { group = "org.testcontainers", name = "oracle-xe", version.ref = "testcontainersVersion" } +org-testcontainers-postgresql = { group = "org.testcontainers", name = "postgresql", version.ref = "testcontainersVersion" } + +[plugins] +com-diffplug-spotless = { id = "com.diffplug.spotless", version = "6.25.0" } +io-github-gradle-nexus-publish-plugin = { id = "io.github.gradle-nexus.publish-plugin", version = "1.3.0" } +org-asciidoctor-jvm-convert = { id = "org.asciidoctor.jvm.convert", version = "4.0.2" } +org-hibernate-orm = { id = "org.hibernate.orm", version.ref = "hibernateOrmGradlePluginVersion" } diff --git a/hibernate-reactive-core/build.gradle b/hibernate-reactive-core/build.gradle index 860d6dc7c..69f1dc5b8 100644 --- a/hibernate-reactive-core/build.gradle +++ b/hibernate-reactive-core/build.gradle @@ -8,76 +8,76 @@ apply from: publishScript dependencies { - api "org.hibernate.orm:hibernate-core:${hibernateOrmVersion}" + api(libs.org.hibernate.orm.hibernate.core) - api 'io.smallrye.reactive:mutiny:2.7.0' + api(libs.io.smallrye.reactive.mutiny) //Logging - implementation 'org.jboss.logging:jboss-logging:3.5.0.Final' - compileOnly 'org.jboss.logging:jboss-logging-annotations:2.2.1.Final' + implementation(libs.org.jboss.logging.jboss.logging) + compileOnly(libs.org.jboss.logging.jboss.logging.annotations) - annotationProcessor 'org.jboss.logging:jboss-logging:3.5.0.Final' - annotationProcessor 'org.jboss.logging:jboss-logging-annotations:2.2.1.Final' - annotationProcessor 'org.jboss.logging:jboss-logging-processor:2.2.1.Final' + annotationProcessor(libs.org.jboss.logging.jboss.logging) + annotationProcessor(libs.org.jboss.logging.jboss.logging.annotations) + annotationProcessor(libs.org.jboss.logging.jboss.logging.processor) //Specific implementation details of Hibernate Reactive: - implementation "io.vertx:vertx-sql-client:${vertxSqlClientVersion}" + implementation(libs.io.vertx.vertx.sql.client) // Testing - testImplementation 'org.assertj:assertj-core:3.26.3' - testImplementation "io.vertx:vertx-junit5:${vertxSqlClientVersion}" + testImplementation(libs.org.assertj.assertj.core) + testImplementation(libs.io.vertx.vertx.junit5) // Drivers - testImplementation "io.vertx:vertx-pg-client:${vertxSqlClientVersion}" - testImplementation "io.vertx:vertx-mysql-client:${vertxSqlClientVersion}" - testImplementation "io.vertx:vertx-db2-client:${vertxSqlClientVersion}" - testImplementation "io.vertx:vertx-mssql-client:${vertxSqlClientVersion}" - testImplementation "io.vertx:vertx-oracle-client:${vertxSqlClientVersion}" + testImplementation(libs.io.vertx.vertx.pg.client) + testImplementation(libs.io.vertx.vertx.mysql.client) + testImplementation(libs.io.vertx.vertx.db2.client) + testImplementation(libs.io.vertx.vertx.mssql.client) + testImplementation(libs.io.vertx.vertx.oracle.client) // Metrics - testImplementation "io.vertx:vertx-micrometer-metrics:${vertxSqlClientVersion}" + testImplementation(libs.io.vertx.vertx.micrometer.metrics) // Optional dependency of vertx-pg-client, essential when connecting via SASL SCRAM - testImplementation 'com.ongres.scram:client:2.1' + testImplementation(libs.com.ongres.scram.client) // JUnit Jupiter - testImplementation 'org.junit.jupiter:junit-jupiter-api:5.11.3' - testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.11.3' + testImplementation(libs.org.junit.jupiter.junit.jupiter.api) + testRuntimeOnly(libs.org.junit.jupiter.junit.jupiter.engine) // JDBC driver to test with ORM and PostgreSQL - testRuntimeOnly "org.postgresql:postgresql:42.7.4" + testRuntimeOnly(libs.org.postgresql.postgresql) // JDBC driver for Testcontainers with MS SQL Server - testRuntimeOnly "com.microsoft.sqlserver:mssql-jdbc:12.8.1.jre11" + testRuntimeOnly(libs.com.microsoft.sqlserver.mssql.jdbc) // JDBC driver for Testcontainers with MariaDB Server - testRuntimeOnly "org.mariadb.jdbc:mariadb-java-client:3.5.1" + testRuntimeOnly(libs.org.mariadb.jdbc.mariadb.java.client) // JDBC driver for Testcontainers with MYSQL Server - testRuntimeOnly "com.mysql:mysql-connector-j:9.1.0" + testRuntimeOnly(libs.com.mysql.mysql.connector.j) // JDBC driver for Db2 server, for testing - testRuntimeOnly "com.ibm.db2:jcc:12.1.0.0" + testRuntimeOnly(libs.com.ibm.db2.jcc) // EHCache - testRuntimeOnly ("org.ehcache:ehcache:3.10.8") { + testRuntimeOnly(libs.org.ehcache.ehcache) { capabilities { requireCapability 'org.ehcache.modules:ehcache-xml-jakarta' } } - testRuntimeOnly ("org.hibernate.orm:hibernate-jcache:${hibernateOrmVersion}") + testRuntimeOnly(libs.org.hibernate.orm.hibernate.jcache) // log4j - testRuntimeOnly 'org.apache.logging.log4j:log4j-core:2.20.0' + testRuntimeOnly(libs.org.apache.logging.log4j.log4j.core) // Testcontainers - testImplementation "org.testcontainers:postgresql:${testcontainersVersion}" - testImplementation "org.testcontainers:mysql:${testcontainersVersion}" - testImplementation "org.testcontainers:mariadb:${testcontainersVersion}" - testImplementation "org.testcontainers:db2:${testcontainersVersion}" - testImplementation "org.testcontainers:cockroachdb:${testcontainersVersion}" - testImplementation "org.testcontainers:mssqlserver:${testcontainersVersion}" - testImplementation "org.testcontainers:oracle-xe:${testcontainersVersion}" + testImplementation(libs.org.testcontainers.postgresql) + testImplementation(libs.org.testcontainers.mysql) + testImplementation(libs.org.testcontainers.mariadb) + testImplementation(libs.org.testcontainers.db2) + testImplementation(libs.org.testcontainers.cockroachdb) + testImplementation(libs.org.testcontainers.mssqlserver) + testImplementation(libs.org.testcontainers.oracle.xe) } // Print a summary of the results of the tests (number of failures, successes and skipped) diff --git a/integration-tests/bytecode-enhancements-it/build.gradle b/integration-tests/bytecode-enhancements-it/build.gradle index 177deae9c..cd9a23e52 100644 --- a/integration-tests/bytecode-enhancements-it/build.gradle +++ b/integration-tests/bytecode-enhancements-it/build.gradle @@ -10,37 +10,32 @@ buildscript { } plugins { - id "org.hibernate.orm" version "${hibernateOrmGradlePluginVersion}" + alias(libs.plugins.org.hibernate.orm) } description = 'Bytecode enhancements integration tests' -ext { - log4jVersion = '2.20.0' - assertjVersion = '3.26.3' -} - dependencies { implementation project(':hibernate-reactive-core') // JPA metamodel generation for criteria queries (optional) - annotationProcessor "org.hibernate.orm:hibernate-jpamodelgen:${hibernateOrmVersion}" + annotationProcessor(libs.org.hibernate.orm.hibernate.jpamodelgen) // Testing on one database should be enough - runtimeOnly "io.vertx:vertx-pg-client:${vertxSqlClientVersion}" + runtimeOnly(libs.io.vertx.vertx.pg.client) // Allow authentication to PostgreSQL using SCRAM: - runtimeOnly 'com.ongres.scram:client:2.1' + runtimeOnly(libs.com.ongres.scram.client) // logging - runtimeOnly "org.apache.logging.log4j:log4j-core:${log4jVersion}" + runtimeOnly(libs.org.apache.logging.log4j.log4j.core) // Testcontainers - testImplementation "org.testcontainers:postgresql:${testcontainersVersion}" + testImplementation(libs.org.testcontainers.postgresql) // Testing - testImplementation "org.assertj:assertj-core:${assertjVersion}" - testImplementation "io.vertx:vertx-junit5:${vertxSqlClientVersion}" + testImplementation(libs.org.assertj.assertj.core) + testImplementation(libs.io.vertx.vertx.junit5) } // Optional: enable the bytecode enhancements @@ -113,4 +108,4 @@ tasks.addRule( "Pattern testDb" ) { String taskName -> } } -} \ No newline at end of file +} diff --git a/integration-tests/hibernate-validator-postgres-it/build.gradle b/integration-tests/hibernate-validator-postgres-it/build.gradle index 8236f6509..61500ef81 100644 --- a/integration-tests/hibernate-validator-postgres-it/build.gradle +++ b/integration-tests/hibernate-validator-postgres-it/build.gradle @@ -10,39 +10,34 @@ buildscript { } plugins { - id "org.hibernate.orm" version "${hibernateOrmGradlePluginVersion}" + alias(libs.plugins.org.hibernate.orm) } description = 'Quarkus QE integration tests' -ext { - log4jVersion = '2.20.0' - assertjVersion = '3.26.3' -} - dependencies { implementation project(':hibernate-reactive-core') - implementation "org.hibernate.validator:hibernate-validator:8.0.2.Final" - runtimeOnly 'org.glassfish.expressly:expressly:5.0.0' + implementation(libs.org.hibernate.validator.hibernate.validator) + runtimeOnly(libs.org.glassfish.expressly.expressly) // JPA metamodel generation for criteria queries (optional) - annotationProcessor "org.hibernate.orm:hibernate-jpamodelgen:${hibernateOrmVersion}" + annotationProcessor(libs.org.hibernate.orm.hibernate.jpamodelgen) // Testing on one database should be enough - runtimeOnly "io.vertx:vertx-pg-client:${vertxSqlClientVersion}" + runtimeOnly(libs.io.vertx.vertx.pg.client) // Allow authentication to PostgreSQL using SCRAM: - runtimeOnly 'com.ongres.scram:client:2.1' + runtimeOnly(libs.com.ongres.scram.client) // logging - runtimeOnly "org.apache.logging.log4j:log4j-core:${log4jVersion}" + runtimeOnly(libs.org.apache.logging.log4j.log4j.core) // Testcontainers - testImplementation "org.testcontainers:postgresql:${testcontainersVersion}" + testImplementation(libs.org.testcontainers.postgresql) // Testing - testImplementation "org.assertj:assertj-core:${assertjVersion}" - testImplementation "io.vertx:vertx-junit5:${vertxSqlClientVersion}" + testImplementation(libs.org.assertj.assertj.core) + testImplementation(libs.io.vertx.vertx.junit5) } // Optional: enable the bytecode enhancements @@ -116,4 +111,4 @@ tasks.addRule( "Pattern testDb" ) { String taskName -> } } -} \ No newline at end of file +} diff --git a/integration-tests/techempower-postgres-it/build.gradle b/integration-tests/techempower-postgres-it/build.gradle index 925aedfd8..edfc4ae4d 100644 --- a/integration-tests/techempower-postgres-it/build.gradle +++ b/integration-tests/techempower-postgres-it/build.gradle @@ -11,37 +11,25 @@ buildscript { description = 'TechEmpower integration tests' -ext { - jacksonDatabindVersion = '2.15.2' - jbossLoggingVersion = '3.5.0.Final' - assertjVersion = '3.26.3' - vertxWebVersion = project.hasProperty( 'vertxWebVersion' ) - ? project.property( 'vertxWebVersion' ) - : vertxSqlClientVersion - vertxWebClientVersion = project.hasProperty( 'vertxWebClientVersion' ) - ? project.property( 'vertxWebClientVersion' ) - : vertxSqlClientVersion -} - dependencies { implementation project( ':hibernate-reactive-core' ) - implementation "io.vertx:vertx-web:${vertxWebVersion}" - implementation "io.vertx:vertx-web-client:${vertxWebClientVersion}" + implementation(libs.io.vertx.vertx.web) + implementation(libs.io.vertx.vertx.web.client) - runtimeOnly "io.vertx:vertx-pg-client:${vertxSqlClientVersion}" + runtimeOnly(libs.io.vertx.vertx.pg.client) // The Pg client requires this dependency - runtimeOnly "com.ongres.scram:client:2.1" - runtimeOnly "com.fasterxml.jackson.core:jackson-databind:${jacksonDatabindVersion}" + runtimeOnly(libs.com.ongres.scram.client) + runtimeOnly(libs.com.fasterxml.jackson.core.jackson.databind) // logging - implementation "org.jboss.logging:jboss-logging:${jbossLoggingVersion}" + implementation(libs.org.jboss.logging.jboss.logging) // Testcontainers - implementation "org.testcontainers:postgresql:${testcontainersVersion}" + implementation(libs.org.testcontainers.postgresql) // Testing - testImplementation "org.assertj:assertj-core:${assertjVersion}" - testImplementation "io.vertx:vertx-junit5:${vertxSqlClientVersion}" + testImplementation(libs.org.assertj.assertj.core) + testImplementation(libs.io.vertx.vertx.junit5) } // Configuration for the tests diff --git a/integration-tests/verticle-postgres-it/build.gradle b/integration-tests/verticle-postgres-it/build.gradle index 4b48e87aa..2cd6edfec 100644 --- a/integration-tests/verticle-postgres-it/build.gradle +++ b/integration-tests/verticle-postgres-it/build.gradle @@ -11,37 +11,25 @@ buildscript { description = 'Bytecode enhancements integration tests' -ext { - jacksonDatabindVersion = '2.15.2' - jbossLoggingVersion = '3.5.0.Final' - assertjVersion = '3.26.3' - vertxWebVersion = project.hasProperty( 'vertxWebVersion' ) - ? project.property( 'vertxWebVersion' ) - : vertxSqlClientVersion - vertxWebClientVersion = project.hasProperty( 'vertxWebClientVersion' ) - ? project.property( 'vertxWebClientVersion' ) - : vertxSqlClientVersion -} - dependencies { implementation project(':hibernate-reactive-core') - implementation "io.vertx:vertx-web:${vertxWebVersion}" - implementation "io.vertx:vertx-web-client:${vertxWebClientVersion}" + implementation(libs.io.vertx.vertx.web) + implementation(libs.io.vertx.vertx.web.client) - runtimeOnly "io.vertx:vertx-pg-client:${vertxSqlClientVersion}" + runtimeOnly(libs.io.vertx.vertx.pg.client) // The Pg client requires this dependency - runtimeOnly "com.ongres.scram:client:2.1" - runtimeOnly "com.fasterxml.jackson.core:jackson-databind:${jacksonDatabindVersion}" + runtimeOnly(libs.com.ongres.scram.client) + runtimeOnly(libs.com.fasterxml.jackson.core.jackson.databind) // logging - implementation "org.jboss.logging:jboss-logging:${jbossLoggingVersion}" + implementation(libs.org.jboss.logging.jboss.logging) // Testcontainers - implementation "org.testcontainers:postgresql:${testcontainersVersion}" + implementation(libs.org.testcontainers.postgresql) // Testing - testImplementation "org.assertj:assertj-core:${assertjVersion}" - testImplementation "io.vertx:vertx-junit5:${vertxSqlClientVersion}" + testImplementation(libs.org.assertj.assertj.core) + testImplementation(libs.io.vertx.vertx.junit5) } // Configuration for the tests diff --git a/local-build-plugins/src/main/java/org/hibernate/reactive/env/VersionsPlugin.java b/local-build-plugins/src/main/java/org/hibernate/reactive/env/VersionsPlugin.java index 36b5ae10a..c34a4b479 100644 --- a/local-build-plugins/src/main/java/org/hibernate/reactive/env/VersionsPlugin.java +++ b/local-build-plugins/src/main/java/org/hibernate/reactive/env/VersionsPlugin.java @@ -28,6 +28,7 @@ public class VersionsPlugin implements Plugin { public static final String SKIP_ORM_VERSION_PARSING = "skipOrmVersionParsing"; public static final String RELATIVE_FILE = "gradle/version.properties"; + public static final String RELATIVE_CATALOG = "gradle/libs.versions.toml"; @Override public void apply(Project project) { @@ -57,12 +58,13 @@ public void apply(Project project) { project.getLogger().lifecycle( "Development version: n/a" ); } - final String ormVersionString = determineOrmVersion( project ); + final VersionsTomlParser tomlParser = new VersionsTomlParser( RELATIVE_CATALOG ); + final String ormVersionString = determineOrmVersion( project, tomlParser ); final Object ormVersion = resolveOrmVersion( ormVersionString, project ); project.getLogger().lifecycle( "ORM version: {}", ormVersion ); project.getExtensions().add( ORM_VERSION, ormVersion ); - final Object ormPluginVersion = determineOrmPluginVersion( ormVersion, project ); + final Object ormPluginVersion = determineOrmPluginVersion( ormVersion, project, tomlParser ); project.getLogger().lifecycle( "ORM Gradle plugin version: {}", ormPluginVersion ); project.getExtensions().add( ORM_PLUGIN_VERSION, ormPluginVersion ); } @@ -123,10 +125,17 @@ private static void withInputStream(File file, Consumer action) { } } - private String determineOrmVersion(Project project) { + private String determineOrmVersion(Project project, VersionsTomlParser parser) { + // Check if it has been set in the project if ( project.hasProperty( ORM_VERSION ) ) { return (String) project.property( ORM_VERSION ); } + + // Check in the catalog + final String version = parser.read( ORM_VERSION ); + if ( version != null ) { + return version; + } throw new IllegalStateException( "Hibernate ORM version not specified on project" ); } @@ -138,10 +147,18 @@ private Object resolveOrmVersion(String stringForm, Project project) { return new ProjectVersion( stringForm ); } - private Object determineOrmPluginVersion(Object ormVersion, Project project) { + private Object determineOrmPluginVersion(Object ormVersion, Project project, VersionsTomlParser parser) { + // Check if it has been set in the project if ( project.hasProperty( ORM_PLUGIN_VERSION ) ) { return project.property( ORM_PLUGIN_VERSION ); } - return ormVersion; + + // Check in the catalog + final String version = parser.read( ORM_PLUGIN_VERSION ); + if ( version != null ) { + return version; + } + + throw new IllegalStateException( "Hibernate ORM Gradle plugin version not specified on project" ); } } diff --git a/local-build-plugins/src/main/java/org/hibernate/reactive/env/VersionsTomlParser.java b/local-build-plugins/src/main/java/org/hibernate/reactive/env/VersionsTomlParser.java new file mode 100644 index 000000000..b0adafd6d --- /dev/null +++ b/local-build-plugins/src/main/java/org/hibernate/reactive/env/VersionsTomlParser.java @@ -0,0 +1,68 @@ +package org.hibernate.reactive.env; + +import java.io.BufferedReader; +import java.io.FileReader; +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +/** + * Read the versions section of the library catalog + */ +public class VersionsTomlParser { + + private final Map data = new HashMap<>(); + + public VersionsTomlParser(String filePath) { + parse( filePath ); + } + + private void parse(String filePath) { + try ( BufferedReader reader = new BufferedReader( new FileReader( filePath ) ) ) { + String line; + String currentSection = null; + while ( ( line = reader.readLine() ) != null ) { + line = line.trim(); + + // Skip comments and blank lines + if ( line.isEmpty() || line.startsWith( "#" ) ) { + continue; + } + + // Handle [section] + if ( line.startsWith( "[" ) && line.endsWith( "]" ) ) { + currentSection = line.substring( 1, line.length() - 1 ).trim(); + continue; + } + + if ( "versions".equalsIgnoreCase( currentSection ) ) { + // Handle key = value + int equalsIndex = line.indexOf( '=' ); + if ( equalsIndex == -1 ) { + continue; + } + + String key = line.substring( 0, equalsIndex ).trim(); + String value = line.substring( equalsIndex + 1 ).trim(); + + // Remove optional quotes around string values + if ( value.startsWith( "\"" ) && value.endsWith( "\"" ) ) { + value = value.substring( 1, value.length() - 1 ); + } + + data.put( key, value ); + } + } + } + catch (IOException e) { + throw new RuntimeException( e ); + } + } + + /** + * Read the value of the property in the versions section of a toml file + */ + public String read(String property) { + return data.get( property ); + } +} diff --git a/settings.gradle b/settings.gradle index af4c707eb..b894dfc9a 100644 --- a/settings.gradle +++ b/settings.gradle @@ -19,6 +19,44 @@ gradle.ext.baselineJavaVersion = JavaLanguageVersion.of( 11 ) // You can't use bytecode higher than what Gradle supports, even with toolchains. def GRADLE_MAX_SUPPORTED_BYTECODE_VERSION = 23 +// This overrides the default version catalog in gradle/libs.versions.toml, which can be +// useful to monitor compatibility for upcoming versions on CI: +dependencyResolutionManagement { + versionCatalogs { + create("libs") { + // ./gradlew build -PhibernateOrmVersion=7.0.2.Final + def hibernateOrmVersion = settings.ext.find("hibernateOrmVersion") ?: "" + if ( hibernateOrmVersion != "" ) { + version("hibernateOrmVersion", hibernateOrmVersion) + } + + // ./gradlew build -PhibernateOrmGradlePluginVersion=7.0.2.Final + def hibernateOrmGradlePluginVersion = settings.ext.find("hibernateOrmGradlePluginVersion") ?: "" + if ( hibernateOrmGradlePluginVersion ) { + version("hibernateOrmGradlePluginVersion", hibernateOrmGradlePluginVersion) + } + + // ./gradlew build -PvertxSqlClientVersion=4.0.0-SNAPSHOT + def vertxSqlClientVersion = settings.ext.find("vertxSqlClientVersion") ?: "" + if ( vertxSqlClientVersion ) { + version("vertxSqlClientVersion", vertxSqlClientVersion) + } + + // ./gradlew build -PvertxWebVersion=4.0.0-SNAPSHOT + def vertxWebVersion = settings.ext.find("vertxWebVersion") ?: vertxSqlClientVersion + if ( vertxWebVersion ) { + version("vertxWebVersion", vertxWebVersion) + } + + // ./gradlew build -PvertxWebClientVersion=4.0.0-SNAPSHOT + def vertxWebClientVersion = settings.ext.find("vertxWebClientVersion") ?: vertxSqlClientVersion + if ( vertxWebClientVersion ) { + version("vertxWebClientVersion", vertxWebClientVersion) + } + } + } +} + // If either 'main.jdk.version' or 'test.jdk.version' is set, enable the toolchain and use the selected jdk. // If only one property is set, the other defaults to the baseline Java version (8). // Note that when toolchain is enabled, you also need to specify From de846b2440bcc5a0290b7158dbd73a9becdaec2f Mon Sep 17 00:00:00 2001 From: Davide D'Alto Date: Wed, 9 Jul 2025 15:10:08 +0200 Subject: [PATCH 109/162] [#2269] chore: Upgrade Testcontainers to 1.21.3 --- gradle/libs.versions.toml | 2 +- tooling/jbang/CockroachDBReactiveTest.java.qute | 2 +- tooling/jbang/Db2ReactiveTest.java.qute | 2 +- tooling/jbang/MariaDBReactiveTest.java.qute | 2 +- tooling/jbang/MySQLReactiveTest.java.qute | 2 +- tooling/jbang/PostgreSQLReactiveTest.java.qute | 2 +- tooling/jbang/ReactiveTest.java | 10 +++++----- 7 files changed, 11 insertions(+), 11 deletions(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index ec7271281..8542b3fc6 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -7,7 +7,7 @@ jbossLoggingAnnotationVersion = "2.2.1.Final" jbossLoggingVersion = "3.5.0.Final" junitVersion = "5.11.3" log4jVersion = "2.20.0" -testcontainersVersion = "1.21.0" +testcontainersVersion = "1.21.3" vertxSqlClientVersion = "4.5.16" vertxWebVersion= "4.5.16" vertxWebClientVersion = "4.5.16" diff --git a/tooling/jbang/CockroachDBReactiveTest.java.qute b/tooling/jbang/CockroachDBReactiveTest.java.qute index 584d8e1db..8b87070b8 100755 --- a/tooling/jbang/CockroachDBReactiveTest.java.qute +++ b/tooling/jbang/CockroachDBReactiveTest.java.qute @@ -10,7 +10,7 @@ //DEPS org.hibernate.reactive:hibernate-reactive-core:$\{hibernate-reactive.version:2.4.0.Final} //DEPS org.assertj:assertj-core:3.26.3 //DEPS junit:junit:4.13.2 -//DEPS org.testcontainers:cockroachdb:1.20.6 +//DEPS org.testcontainers:cockroachdb:1.21.3 //DEPS org.slf4j:slf4j-simple:2.0.7 //// Testcontainer needs the JDBC drivers to start the container diff --git a/tooling/jbang/Db2ReactiveTest.java.qute b/tooling/jbang/Db2ReactiveTest.java.qute index 2b34f8a5d..8e8c6554c 100755 --- a/tooling/jbang/Db2ReactiveTest.java.qute +++ b/tooling/jbang/Db2ReactiveTest.java.qute @@ -10,7 +10,7 @@ //DEPS org.hibernate.reactive:hibernate-reactive-core:$\{hibernate-reactive.version:2.4.0.Final} //DEPS org.assertj:assertj-core:3.26.3 //DEPS junit:junit:4.13.2 -//DEPS org.testcontainers:db2:1.20.6 +//DEPS org.testcontainers:db2:1.21.3 //DEPS org.slf4j:slf4j-simple:2.0.7 import jakarta.persistence.Entity; diff --git a/tooling/jbang/MariaDBReactiveTest.java.qute b/tooling/jbang/MariaDBReactiveTest.java.qute index f89f2129e..444e0421d 100755 --- a/tooling/jbang/MariaDBReactiveTest.java.qute +++ b/tooling/jbang/MariaDBReactiveTest.java.qute @@ -10,7 +10,7 @@ //DEPS org.hibernate.reactive:hibernate-reactive-core:$\{hibernate-reactive.version:2.4.0.Final} //DEPS org.assertj:assertj-core:3.26.3 //DEPS junit:junit:4.13.2 -//DEPS org.testcontainers:mariadb:1.20.6 +//DEPS org.testcontainers:mariadb:1.21.3 //DEPS org.slf4j:slf4j-simple:2.0.7 //// Testcontainer needs the JDBC drivers to start the container diff --git a/tooling/jbang/MySQLReactiveTest.java.qute b/tooling/jbang/MySQLReactiveTest.java.qute index 1c78cc704..4e1b68993 100755 --- a/tooling/jbang/MySQLReactiveTest.java.qute +++ b/tooling/jbang/MySQLReactiveTest.java.qute @@ -10,7 +10,7 @@ //DEPS org.hibernate.reactive:hibernate-reactive-core:$\{hibernate-reactive.version:2.4.0.Final} //DEPS org.assertj:assertj-core:3.26.3 //DEPS junit:junit:4.13.2 -//DEPS org.testcontainers:mysql:1.20.6 +//DEPS org.testcontainers:mysql:1.21.3 //DEPS org.slf4j:slf4j-simple:2.0.7 //// Testcontainer needs the JDBC drivers to start the container diff --git a/tooling/jbang/PostgreSQLReactiveTest.java.qute b/tooling/jbang/PostgreSQLReactiveTest.java.qute index f5a922b4f..2c32c08c9 100755 --- a/tooling/jbang/PostgreSQLReactiveTest.java.qute +++ b/tooling/jbang/PostgreSQLReactiveTest.java.qute @@ -10,7 +10,7 @@ //DEPS org.hibernate.reactive:hibernate-reactive-core:$\{hibernate-reactive.version:2.4.0.Final} //DEPS org.assertj:assertj-core:3.26.3 //DEPS junit:junit:4.13.2 -//DEPS org.testcontainers:postgresql:1.20.6 +//DEPS org.testcontainers:postgresql:1.21.3 //DEPS org.slf4j:slf4j-simple:2.0.7 //DESCRIPTION Allow authentication to PostgreSQL using SCRAM: //DEPS com.ongres.scram:client:2.1 diff --git a/tooling/jbang/ReactiveTest.java b/tooling/jbang/ReactiveTest.java index 9abcda9d9..8162a9ea7 100755 --- a/tooling/jbang/ReactiveTest.java +++ b/tooling/jbang/ReactiveTest.java @@ -13,11 +13,11 @@ //DEPS org.hibernate.reactive:hibernate-reactive-core:${hibernate-reactive.version:2.4.0.Final} //DEPS org.assertj:assertj-core:3.26.3 //DEPS junit:junit:4.13.2 -//DEPS org.testcontainers:postgresql:1.20.6 -//DEPS org.testcontainers:mysql:1.20.6 -//DEPS org.testcontainers:db2:1.20.6 -//DEPS org.testcontainers:mariadb:1.20.6 -//DEPS org.testcontainers:cockroachdb:1.20.6 +//DEPS org.testcontainers:postgresql:1.21.3 +//DEPS org.testcontainers:mysql:1.21.3 +//DEPS org.testcontainers:db2:1.21.3 +//DEPS org.testcontainers:mariadb:1.21.3 +//DEPS org.testcontainers:cockroachdb:1.21.3 // //// Testcontainer needs the JDBC drivers to start the containers //// Hibernate Reactive doesn't use them From 0bcbeed38931b890e28b75210b3a013cf46b4039 Mon Sep 17 00:00:00 2001 From: Davide D'Alto Date: Thu, 10 Jul 2025 17:00:11 +0200 Subject: [PATCH 110/162] [#2269] Keep containers image and version in docker files We are trying to achieve two things: * Make it possible for dependabot to upgrade the containers automatically * Collect the image and version of the containers we use for testing in one place Note that the test suite will still create and start the containers programmatically, but it will read the first FROM line in each Dockerfile to extract the image and version to use. It will ignore everything else. My initial plan was to configure each container using the Dockerfile directly, but I prefer to reuse the exsisting Testcontainers classes for each database (for example, PostgreSQLContainer) because they contain out-of-the-box configuration that I would need to copy somewhere else. In any case, this is a good starting point and we can improve it later. --- build.gradle | 6 + .../containers/CockroachDBDatabase.java | 4 +- .../reactive/containers/DB2Database.java | 4 +- .../reactive/containers/DockerImage.java | 103 ++++++++++++++- .../containers/MSSQLServerDatabase.java | 4 +- .../reactive/containers/MariaDatabase.java | 6 +- .../reactive/containers/MySQLDatabase.java | 4 +- .../reactive/containers/OracleDatabase.java | 6 +- .../containers/PostgreSQLDatabase.java | 8 +- .../hibernate/reactive/it/BaseReactiveIT.java | 4 +- .../hibernate/reactive/it/DockerImage.java | 125 ++++++++++++++++++ .../quarkus/qe/database/BaseReactiveIT.java | 4 +- .../it/quarkus/qe/database/DockerImage.java | 125 ++++++++++++++++++ .../reactive/it/verticle/DockerImage.java | 125 ++++++++++++++++++ .../reactive/it/verticle/VertxServer.java | 4 +- tooling/docker/README.md | 6 + tooling/docker/cockroachdb.Dockerfile | 3 + tooling/docker/db2.Dockerfile | 3 + tooling/docker/maria.Dockerfile | 3 + tooling/docker/mysql.Dockerfile | 3 + tooling/docker/oracle.Dockerfile | 3 + tooling/docker/postgresql.Dockerfile | 3 + tooling/docker/sqlserver.Dockerfile | 3 + 23 files changed, 529 insertions(+), 30 deletions(-) create mode 100644 integration-tests/bytecode-enhancements-it/src/test/java/org/hibernate/reactive/it/DockerImage.java create mode 100644 integration-tests/hibernate-validator-postgres-it/src/test/java/org/hibernate/reactive/it/quarkus/qe/database/DockerImage.java create mode 100644 integration-tests/verticle-postgres-it/src/main/java/org/hibernate/reactive/it/verticle/DockerImage.java create mode 100644 tooling/docker/README.md create mode 100644 tooling/docker/cockroachdb.Dockerfile create mode 100644 tooling/docker/db2.Dockerfile create mode 100644 tooling/docker/maria.Dockerfile create mode 100644 tooling/docker/mysql.Dockerfile create mode 100644 tooling/docker/oracle.Dockerfile create mode 100644 tooling/docker/postgresql.Dockerfile create mode 100644 tooling/docker/sqlserver.Dockerfile diff --git a/build.gradle b/build.gradle index 7400020fe..f9172203e 100644 --- a/build.gradle +++ b/build.gradle @@ -52,6 +52,12 @@ subprojects { options.encoding = 'UTF-8' } + // Configure test tasks for all subprojects + tasks.withType( Test ).configureEach { + // Set the project root for finding Docker files - available to all modules + systemProperty 'hibernate.reactive.project.root', rootProject.projectDir.absolutePath + } + if ( !gradle.ext.javaToolchainEnabled ) { sourceCompatibility = JavaVersion.toVersion( gradle.ext.baselineJavaVersion ) targetCompatibility = JavaVersion.toVersion( gradle.ext.baselineJavaVersion ) diff --git a/hibernate-reactive-core/src/test/java/org/hibernate/reactive/containers/CockroachDBDatabase.java b/hibernate-reactive-core/src/test/java/org/hibernate/reactive/containers/CockroachDBDatabase.java index 92cb42e6e..d8bedf9ac 100644 --- a/hibernate-reactive-core/src/test/java/org/hibernate/reactive/containers/CockroachDBDatabase.java +++ b/hibernate-reactive-core/src/test/java/org/hibernate/reactive/containers/CockroachDBDatabase.java @@ -12,7 +12,7 @@ import org.testcontainers.containers.CockroachContainer; import org.testcontainers.containers.Container; -import static org.hibernate.reactive.containers.DockerImage.imageName; +import static org.hibernate.reactive.containers.DockerImage.fromDockerfile; class CockroachDBDatabase extends PostgreSQLDatabase { @@ -25,7 +25,7 @@ class CockroachDBDatabase extends PostgreSQLDatabase { * TIP: To reuse the same containers across multiple runs, set `testcontainers.reuse.enable=true` in a file located * at `$HOME/.testcontainers.properties` (create the file if it does not exist). */ - public static final CockroachContainer cockroachDb = new CockroachContainer( imageName( "cockroachdb/cockroach", "v24.3.13" ) ) + public static final CockroachContainer cockroachDb = new CockroachContainer( fromDockerfile( "cockroachdb" ) ) // Username, password and database are not supported by test container at the moment // Testcontainers will use a database named 'postgres' and the 'root' user .withReuse( true ); diff --git a/hibernate-reactive-core/src/test/java/org/hibernate/reactive/containers/DB2Database.java b/hibernate-reactive-core/src/test/java/org/hibernate/reactive/containers/DB2Database.java index b7ac63e4d..29154b2bf 100644 --- a/hibernate-reactive-core/src/test/java/org/hibernate/reactive/containers/DB2Database.java +++ b/hibernate-reactive-core/src/test/java/org/hibernate/reactive/containers/DB2Database.java @@ -28,7 +28,7 @@ import org.testcontainers.containers.Db2Container; -import static org.hibernate.reactive.containers.DockerImage.imageName; +import static org.hibernate.reactive.containers.DockerImage.fromDockerfile; class DB2Database implements TestableDatabase { @@ -87,7 +87,7 @@ class DB2Database implements TestableDatabase { * TIP: To reuse the same containers across multiple runs, set `testcontainers.reuse.enable=true` in a file located * at `$HOME/.testcontainers.properties` (create the file if it does not exist). */ - static final Db2Container db2 = new Db2Container( imageName( "icr.io", "db2_community/db2", "12.1.0.0" ) ) + static final Db2Container db2 = new Db2Container( fromDockerfile( "db2" ) ) .withUsername( DatabaseConfiguration.USERNAME ) .withPassword( DatabaseConfiguration.PASSWORD ) .withDatabaseName( DatabaseConfiguration.DB_NAME ) diff --git a/hibernate-reactive-core/src/test/java/org/hibernate/reactive/containers/DockerImage.java b/hibernate-reactive-core/src/test/java/org/hibernate/reactive/containers/DockerImage.java index 1b2f3f6a7..e8f40f34d 100644 --- a/hibernate-reactive-core/src/test/java/org/hibernate/reactive/containers/DockerImage.java +++ b/hibernate-reactive-core/src/test/java/org/hibernate/reactive/containers/DockerImage.java @@ -5,10 +5,17 @@ */ package org.hibernate.reactive.containers; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.List; + import org.testcontainers.utility.DockerImageName; + /** - * A utility class with methods to generate {@link DockerImageName} for testcontainers. + * A utility class with methods to generate a {@link DockerImageName} for Testcontainers. *

    * Testcontainers might not work if the image required is available in multiple different registries (for example when * using podman instead of docker). @@ -17,10 +24,28 @@ */ public final class DockerImage { - public static final String DEFAULT_REGISTRY = "docker.io"; + /** + * The absolute path of the project root that we have set in Gradle. + */ + private static final String PROJECT_ROOT = System.getProperty( "hibernate.reactive.project.root" ); + + /** + * The path to the directory containing all the Dockerfile files + */ + private static final Path DOCKERFILE_DIR_PATH = Path.of( PROJECT_ROOT ).resolve( "tooling" ).resolve( "docker" ); - public static DockerImageName imageName(String image, String version) { - return imageName( DEFAULT_REGISTRY, image, version ); + /** + * Extract the image name and version from the first FROM instruction in the Dockerfile. + * Note that everything else is ignored. + */ + public static DockerImageName fromDockerfile(String databaseName) { + try { + final ImageInformation imageInformation = readFromInstruction( databaseName.toLowerCase() ); + return imageName( imageInformation.getRegistry(), imageInformation.getImage(), imageInformation.getVersion() ); + } + catch (IOException e) { + throw new RuntimeException( e ); + } } public static DockerImageName imageName(String registry, String image, String version) { @@ -28,4 +53,74 @@ public static DockerImageName imageName(String registry, String image, String ve .parse( registry + "/" + image + ":" + version ) .asCompatibleSubstituteFor( image ); } + + private static class ImageInformation { + private final String registry; + private final String image; + private final String version; + + public ImageInformation(String fullImageInfo) { + // FullImageInfo pattern: /: + // For example: "docker.io/cockroachdb/cockroach:v24.3.13" becomes registry = "docker.io", image = "cockroachdb/cockroach", version = "v24.3.13" + final int registryEndPos = fullImageInfo.indexOf( '/' ); + final int imageEndPos = fullImageInfo.lastIndexOf( ':' ); + this.registry = fullImageInfo.substring( 0, registryEndPos ); + this.image = fullImageInfo.substring( registryEndPos + 1, imageEndPos ); + this.version = fullImageInfo.substring( imageEndPos + 1 ); + } + + public String getRegistry() { + return registry; + } + + public String getImage() { + return image; + } + + public String getVersion() { + return version; + } + + @Override + public String toString() { + return registry + "/" + image + ":" + version; + } + } + + private static Path dockerFilePath(String database) { + // Get project root from system property set by Gradle, with fallback + return DOCKERFILE_DIR_PATH.resolve( database.toLowerCase() + ".Dockerfile" ); + } + + private static ImageInformation readFromInstruction(String database) throws IOException { + return readFromInstruction( dockerFilePath( database ) ); + } + + /** + * Read a Dockerfile and extract the first FROM instruction. + * + * @param dockerfilePath path to the Dockerfile + * @return the first FROM instruction found, or empty if none found + * @throws IOException if the file cannot be read + */ + private static ImageInformation readFromInstruction(Path dockerfilePath) throws IOException { + if ( !Files.exists( dockerfilePath ) ) { + throw new FileNotFoundException( "Dockerfile not found: " + dockerfilePath ); + } + + List lines = Files.readAllLines( dockerfilePath ); + for ( String line : lines ) { + // Skip comments and empty lines + String trimmedLine = line.trim(); + if ( trimmedLine.isEmpty() || trimmedLine.startsWith( "#" ) ) { + continue; + } + + if ( trimmedLine.startsWith( "FROM " ) ) { + return new ImageInformation( trimmedLine.substring( "FROM ".length() ) ); + } + } + + throw new IOException( " Missing FROM instruction in " + dockerfilePath ); + } } diff --git a/hibernate-reactive-core/src/test/java/org/hibernate/reactive/containers/MSSQLServerDatabase.java b/hibernate-reactive-core/src/test/java/org/hibernate/reactive/containers/MSSQLServerDatabase.java index 8078d1b7e..d0219f34d 100644 --- a/hibernate-reactive-core/src/test/java/org/hibernate/reactive/containers/MSSQLServerDatabase.java +++ b/hibernate-reactive-core/src/test/java/org/hibernate/reactive/containers/MSSQLServerDatabase.java @@ -28,7 +28,7 @@ import org.testcontainers.containers.MSSQLServerContainer; -import static org.hibernate.reactive.containers.DockerImage.imageName; +import static org.hibernate.reactive.containers.DockerImage.fromDockerfile; /** * The JDBC driver syntax is: @@ -96,7 +96,7 @@ class MSSQLServerDatabase implements TestableDatabase { * TIP: To reuse the same containers across multiple runs, set `testcontainers.reuse.enable=true` in a file located * at `$HOME/.testcontainers.properties` (create the file if it does not exist). */ - public static final MSSQLServerContainer mssqlserver = new MSSQLServerContainer<>( imageName( "mcr.microsoft.com", "mssql/server", "2022-latest" ) ) + public static final MSSQLServerContainer mssqlserver = new MSSQLServerContainer<>( fromDockerfile( "sqlserver" ) ) .acceptLicense() .withPassword( PASSWORD ) .withReuse( true ); diff --git a/hibernate-reactive-core/src/test/java/org/hibernate/reactive/containers/MariaDatabase.java b/hibernate-reactive-core/src/test/java/org/hibernate/reactive/containers/MariaDatabase.java index 6c9db8dfe..e704df38c 100644 --- a/hibernate-reactive-core/src/test/java/org/hibernate/reactive/containers/MariaDatabase.java +++ b/hibernate-reactive-core/src/test/java/org/hibernate/reactive/containers/MariaDatabase.java @@ -6,10 +6,10 @@ package org.hibernate.reactive.containers; -import static org.hibernate.reactive.containers.DockerImage.imageName; - import org.testcontainers.containers.MariaDBContainer; +import static org.hibernate.reactive.containers.DockerImage.fromDockerfile; + class MariaDatabase extends MySQLDatabase { static MariaDatabase INSTANCE = new MariaDatabase(); @@ -21,7 +21,7 @@ class MariaDatabase extends MySQLDatabase { * TIP: To reuse the same containers across multiple runs, set `testcontainers.reuse.enable=true` in a file located * at `$HOME/.testcontainers.properties` (create the file if it does not exist). */ - public static final MariaDBContainer maria = new MariaDBContainer<>( imageName( "mariadb", "11.7.2" ) ) + public static final MariaDBContainer maria = new MariaDBContainer<>( fromDockerfile( "maria" ) ) .withUsername( DatabaseConfiguration.USERNAME ) .withPassword( DatabaseConfiguration.PASSWORD ) .withDatabaseName( DatabaseConfiguration.DB_NAME ) diff --git a/hibernate-reactive-core/src/test/java/org/hibernate/reactive/containers/MySQLDatabase.java b/hibernate-reactive-core/src/test/java/org/hibernate/reactive/containers/MySQLDatabase.java index 72c73113d..142a88c5a 100644 --- a/hibernate-reactive-core/src/test/java/org/hibernate/reactive/containers/MySQLDatabase.java +++ b/hibernate-reactive-core/src/test/java/org/hibernate/reactive/containers/MySQLDatabase.java @@ -5,7 +5,7 @@ */ package org.hibernate.reactive.containers; -import static org.hibernate.reactive.containers.DockerImage.imageName; +import static org.hibernate.reactive.containers.DockerImage.fromDockerfile; import java.io.Serializable; import java.math.BigDecimal; @@ -87,7 +87,7 @@ class MySQLDatabase implements TestableDatabase { * TIP: To reuse the same containers across multiple runs, set `testcontainers.reuse.enable=true` in a file located * at `$HOME/.testcontainers.properties` (create the file if it does not exist). */ - public static final MySQLContainer mysql = new MySQLContainer<>( imageName( "mysql", "9.2.0") ) + public static final MySQLContainer mysql = new MySQLContainer<>( fromDockerfile( "mysql" ) ) .withUsername( DatabaseConfiguration.USERNAME ) .withPassword( DatabaseConfiguration.PASSWORD ) .withDatabaseName( DatabaseConfiguration.DB_NAME ) diff --git a/hibernate-reactive-core/src/test/java/org/hibernate/reactive/containers/OracleDatabase.java b/hibernate-reactive-core/src/test/java/org/hibernate/reactive/containers/OracleDatabase.java index 9ad2f8136..594ccf462 100644 --- a/hibernate-reactive-core/src/test/java/org/hibernate/reactive/containers/OracleDatabase.java +++ b/hibernate-reactive-core/src/test/java/org/hibernate/reactive/containers/OracleDatabase.java @@ -29,7 +29,7 @@ import org.testcontainers.containers.OracleContainer; -import static org.hibernate.reactive.containers.DockerImage.imageName; +import static org.hibernate.reactive.containers.DockerImage.fromDockerfile; /** * Connection string for Oracle thin should be something like: @@ -88,9 +88,7 @@ class OracleDatabase implements TestableDatabase { } } - public static final OracleContainer oracle = new OracleContainer( - imageName( "gvenzl/oracle-free", "23-slim-faststart" ) - .asCompatibleSubstituteFor( "gvenzl/oracle-xe" ) ) + public static final OracleContainer oracle = new OracleContainer( fromDockerfile( "oracle" ).asCompatibleSubstituteFor( "gvenzl/oracle-xe" ) ) .withUsername( DatabaseConfiguration.USERNAME ) .withPassword( DatabaseConfiguration.PASSWORD ) .withDatabaseName( DatabaseConfiguration.DB_NAME ) diff --git a/hibernate-reactive-core/src/test/java/org/hibernate/reactive/containers/PostgreSQLDatabase.java b/hibernate-reactive-core/src/test/java/org/hibernate/reactive/containers/PostgreSQLDatabase.java index c19d1c06a..4f31ea47b 100644 --- a/hibernate-reactive-core/src/test/java/org/hibernate/reactive/containers/PostgreSQLDatabase.java +++ b/hibernate-reactive-core/src/test/java/org/hibernate/reactive/containers/PostgreSQLDatabase.java @@ -5,8 +5,6 @@ */ package org.hibernate.reactive.containers; -import static org.hibernate.reactive.containers.DockerImage.imageName; - import java.io.Serializable; import java.math.BigDecimal; import java.math.BigInteger; @@ -30,9 +28,11 @@ import org.testcontainers.containers.PostgreSQLContainer; +import static org.hibernate.reactive.containers.DockerImage.fromDockerfile; + class PostgreSQLDatabase implements TestableDatabase { - public static PostgreSQLDatabase INSTANCE = new PostgreSQLDatabase(); + public static final PostgreSQLDatabase INSTANCE = new PostgreSQLDatabase(); private static Map, String> expectedDBTypeForClass = new HashMap<>(); @@ -87,7 +87,7 @@ class PostgreSQLDatabase implements TestableDatabase { * TIP: To reuse the same containers across multiple runs, set `testcontainers.reuse.enable=true` in a file located * at `$HOME/.testcontainers.properties` (create the file if it does not exist). */ - public static final PostgreSQLContainer postgresql = new PostgreSQLContainer<>( imageName( "postgres", "17.5" ) ) + public static final PostgreSQLContainer postgresql = new PostgreSQLContainer<>( fromDockerfile( "postgresql" ) ) .withUsername( DatabaseConfiguration.USERNAME ) .withPassword( DatabaseConfiguration.PASSWORD ) .withDatabaseName( DatabaseConfiguration.DB_NAME ) diff --git a/integration-tests/bytecode-enhancements-it/src/test/java/org/hibernate/reactive/it/BaseReactiveIT.java b/integration-tests/bytecode-enhancements-it/src/test/java/org/hibernate/reactive/it/BaseReactiveIT.java index 2388cb421..8f6081a8a 100644 --- a/integration-tests/bytecode-enhancements-it/src/test/java/org/hibernate/reactive/it/BaseReactiveIT.java +++ b/integration-tests/bytecode-enhancements-it/src/test/java/org/hibernate/reactive/it/BaseReactiveIT.java @@ -52,9 +52,7 @@ public abstract class BaseReactiveIT { // These properties are in DatabaseConfiguration in core public static final boolean USE_DOCKER = Boolean.getBoolean( "docker" ); - public static final DockerImageName IMAGE_NAME = DockerImageName - .parse( "docker.io/postgres:17.5" ) - .asCompatibleSubstituteFor( "postgres" ); + public static final DockerImageName IMAGE_NAME = DockerImage.fromDockerfile( "postgresql" ); public static final String USERNAME = "hreact"; public static final String PASSWORD = "hreact"; diff --git a/integration-tests/bytecode-enhancements-it/src/test/java/org/hibernate/reactive/it/DockerImage.java b/integration-tests/bytecode-enhancements-it/src/test/java/org/hibernate/reactive/it/DockerImage.java new file mode 100644 index 000000000..b5621249d --- /dev/null +++ b/integration-tests/bytecode-enhancements-it/src/test/java/org/hibernate/reactive/it/DockerImage.java @@ -0,0 +1,125 @@ +/* Hibernate, Relational Persistence for Idiomatic Java + * + * SPDX-License-Identifier: Apache-2.0 + * Copyright: Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.reactive.it; + +import java.io.FileNotFoundException; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.List; + +import org.testcontainers.utility.DockerImageName; + +/** + * A utility class with methods to generate a {@link DockerImageName} for Testcontainers. + *

    + * Testcontainers might not work if the image required is available in multiple different registries (for example when + * using podman instead of docker). + * These methods make sure to pick a registry as default. + *

    + */ +public final class DockerImage { + + /** + * The absolute path of the project root that we have set in Gradle. + */ + private static final String PROJECT_ROOT = System.getProperty( "hibernate.reactive.project.root" ); + + /** + * The path to the directory containing all the Dockerfile files + */ + private static final Path DOCKERFILE_DIR_PATH = Path.of( PROJECT_ROOT ).resolve( "tooling" ).resolve( "docker" ); + + /** + * Extract the image name and version from the first FROM instruction in the Dockerfile. + * Note that everything else is ignored. + */ + public static DockerImageName fromDockerfile(String databaseName) { + try { + final ImageInformation imageInformation = readFromInstruction( databaseName.toLowerCase() ); + return imageName( imageInformation.getRegistry(), imageInformation.getImage(), imageInformation.getVersion() ); + } + catch (IOException e) { + throw new RuntimeException( e ); + } + } + + public static DockerImageName imageName(String registry, String image, String version) { + return DockerImageName + .parse( registry + "/" + image + ":" + version ) + .asCompatibleSubstituteFor( image ); + } + + private static class ImageInformation { + private final String registry; + private final String image; + private final String version; + + public ImageInformation(String fullImageInfo) { + // FullImageInfo pattern: /: + // For example: "docker.io/cockroachdb/cockroach:v24.3.13" becomes registry = "docker.io", image = "cockroachdb/cockroach", version = "v24.3.13" + final int registryEndPos = fullImageInfo.indexOf( '/' ); + final int imageEndPos = fullImageInfo.lastIndexOf( ':' ); + this.registry = fullImageInfo.substring( 0, registryEndPos ); + this.image = fullImageInfo.substring( registryEndPos + 1, imageEndPos ); + this.version = fullImageInfo.substring( imageEndPos + 1 ); + } + + public String getRegistry() { + return registry; + } + + public String getImage() { + return image; + } + + public String getVersion() { + return version; + } + + @Override + public String toString() { + return registry + "/" + image + ":" + version; + } + } + + private static Path dockerFilePath(String database) { + // Get project root from system property set by Gradle, with fallback + return DOCKERFILE_DIR_PATH.resolve( database.toLowerCase() + ".Dockerfile" ); + } + + private static ImageInformation readFromInstruction(String database) throws IOException { + return readFromInstruction( dockerFilePath( database ) ); + } + + /** + * Read a Dockerfile and extract the first FROM instruction. + * + * @param dockerfilePath path to the Dockerfile + * @return the first FROM instruction found, or empty if none found + * @throws IOException if the file cannot be read + */ + private static ImageInformation readFromInstruction(Path dockerfilePath) throws IOException { + if ( !Files.exists( dockerfilePath ) ) { + throw new FileNotFoundException( "Dockerfile not found: " + dockerfilePath ); + } + + List lines = Files.readAllLines( dockerfilePath ); + for ( String line : lines ) { + // Skip comments and empty lines + String trimmedLine = line.trim(); + if ( trimmedLine.isEmpty() || trimmedLine.startsWith( "#" ) ) { + continue; + } + + if ( trimmedLine.startsWith( "FROM " ) ) { + return new ImageInformation( trimmedLine.substring( "FROM ".length() ) ); + } + } + + throw new IOException( " Missing FROM instruction in " + dockerfilePath ); + } +} diff --git a/integration-tests/hibernate-validator-postgres-it/src/test/java/org/hibernate/reactive/it/quarkus/qe/database/BaseReactiveIT.java b/integration-tests/hibernate-validator-postgres-it/src/test/java/org/hibernate/reactive/it/quarkus/qe/database/BaseReactiveIT.java index 7debdbb2c..fcefdaa84 100644 --- a/integration-tests/hibernate-validator-postgres-it/src/test/java/org/hibernate/reactive/it/quarkus/qe/database/BaseReactiveIT.java +++ b/integration-tests/hibernate-validator-postgres-it/src/test/java/org/hibernate/reactive/it/quarkus/qe/database/BaseReactiveIT.java @@ -52,9 +52,7 @@ public abstract class BaseReactiveIT { // These properties are in DatabaseConfiguration in core public static final boolean USE_DOCKER = Boolean.getBoolean( "docker" ); - public static final DockerImageName IMAGE_NAME = DockerImageName - .parse( "docker.io/postgres:17.5" ) - .asCompatibleSubstituteFor( "postgres" ); + public static final DockerImageName IMAGE_NAME = DockerImage.fromDockerfile( "postgresql" ); public static final String USERNAME = "hreact"; public static final String PASSWORD = "hreact"; diff --git a/integration-tests/hibernate-validator-postgres-it/src/test/java/org/hibernate/reactive/it/quarkus/qe/database/DockerImage.java b/integration-tests/hibernate-validator-postgres-it/src/test/java/org/hibernate/reactive/it/quarkus/qe/database/DockerImage.java new file mode 100644 index 000000000..7770da76c --- /dev/null +++ b/integration-tests/hibernate-validator-postgres-it/src/test/java/org/hibernate/reactive/it/quarkus/qe/database/DockerImage.java @@ -0,0 +1,125 @@ +/* Hibernate, Relational Persistence for Idiomatic Java + * + * SPDX-License-Identifier: Apache-2.0 + * Copyright: Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.reactive.it.quarkus.qe.database; + +import java.io.FileNotFoundException; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.List; + +import org.testcontainers.utility.DockerImageName; + +/** + * A utility class with methods to generate a {@link DockerImageName} for Testcontainers. + *

    + * Testcontainers might not work if the image required is available in multiple different registries (for example when + * using podman instead of docker). + * These methods make sure to pick a registry as default. + *

    + */ +public final class DockerImage { + + /** + * The absolute path of the project root that we have set in Gradle. + */ + private static final String PROJECT_ROOT = System.getProperty( "hibernate.reactive.project.root" ); + + /** + * The path to the directory containing all the Dockerfile files + */ + private static final Path DOCKERFILE_DIR_PATH = Path.of( PROJECT_ROOT ).resolve( "tooling" ).resolve( "docker" ); + + /** + * Extract the image name and version from the first FROM instruction in the Dockerfile. + * Note that everything else is ignored. + */ + public static DockerImageName fromDockerfile(String databaseName) { + try { + final ImageInformation imageInformation = readFromInstruction( databaseName.toLowerCase() ); + return imageName( imageInformation.getRegistry(), imageInformation.getImage(), imageInformation.getVersion() ); + } + catch (IOException e) { + throw new RuntimeException( e ); + } + } + + public static DockerImageName imageName(String registry, String image, String version) { + return DockerImageName + .parse( registry + "/" + image + ":" + version ) + .asCompatibleSubstituteFor( image ); + } + + private static class ImageInformation { + private final String registry; + private final String image; + private final String version; + + public ImageInformation(String fullImageInfo) { + // FullImageInfo pattern: /: + // For example: "docker.io/cockroachdb/cockroach:v24.3.13" becomes registry = "docker.io", image = "cockroachdb/cockroach", version = "v24.3.13" + final int registryEndPos = fullImageInfo.indexOf( '/' ); + final int imageEndPos = fullImageInfo.lastIndexOf( ':' ); + this.registry = fullImageInfo.substring( 0, registryEndPos ); + this.image = fullImageInfo.substring( registryEndPos + 1, imageEndPos ); + this.version = fullImageInfo.substring( imageEndPos + 1 ); + } + + public String getRegistry() { + return registry; + } + + public String getImage() { + return image; + } + + public String getVersion() { + return version; + } + + @Override + public String toString() { + return registry + "/" + image + ":" + version; + } + } + + private static Path dockerFilePath(String database) { + // Get project root from system property set by Gradle, with fallback + return DOCKERFILE_DIR_PATH.resolve( database.toLowerCase() + ".Dockerfile" ); + } + + private static ImageInformation readFromInstruction(String database) throws IOException { + return readFromInstruction( dockerFilePath( database ) ); + } + + /** + * Read a Dockerfile and extract the first FROM instruction. + * + * @param dockerfilePath path to the Dockerfile + * @return the first FROM instruction found, or empty if none found + * @throws IOException if the file cannot be read + */ + private static ImageInformation readFromInstruction(Path dockerfilePath) throws IOException { + if ( !Files.exists( dockerfilePath ) ) { + throw new FileNotFoundException( "Dockerfile not found: " + dockerfilePath ); + } + + List lines = Files.readAllLines( dockerfilePath ); + for ( String line : lines ) { + // Skip comments and empty lines + String trimmedLine = line.trim(); + if ( trimmedLine.isEmpty() || trimmedLine.startsWith( "#" ) ) { + continue; + } + + if ( trimmedLine.startsWith( "FROM " ) ) { + return new ImageInformation( trimmedLine.substring( "FROM ".length() ) ); + } + } + + throw new IOException( " Missing FROM instruction in " + dockerfilePath ); + } +} diff --git a/integration-tests/verticle-postgres-it/src/main/java/org/hibernate/reactive/it/verticle/DockerImage.java b/integration-tests/verticle-postgres-it/src/main/java/org/hibernate/reactive/it/verticle/DockerImage.java new file mode 100644 index 000000000..10026d020 --- /dev/null +++ b/integration-tests/verticle-postgres-it/src/main/java/org/hibernate/reactive/it/verticle/DockerImage.java @@ -0,0 +1,125 @@ +/* Hibernate, Relational Persistence for Idiomatic Java + * + * SPDX-License-Identifier: Apache-2.0 + * Copyright: Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.reactive.it.verticle; + +import java.io.FileNotFoundException; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.List; + +import org.testcontainers.utility.DockerImageName; + +/** + * A utility class with methods to generate a {@link DockerImageName} for Testcontainers. + *

    + * Testcontainers might not work if the image required is available in multiple different registries (for example when + * using podman instead of docker). + * These methods make sure to pick a registry as default. + *

    + */ +public final class DockerImage { + + /** + * The absolute path of the project root that we have set in Gradle. + */ + private static final String PROJECT_ROOT = System.getProperty( "hibernate.reactive.project.root" ); + + /** + * The path to the directory containing all the Dockerfile files + */ + private static final Path DOCKERFILE_DIR_PATH = Path.of( PROJECT_ROOT ).resolve( "tooling" ).resolve( "docker" ); + + /** + * Extract the image name and version from the first FROM instruction in the Dockerfile. + * Note that everything else is ignored. + */ + public static DockerImageName fromDockerfile(String databaseName) { + try { + final ImageInformation imageInformation = readFromInstruction( databaseName.toLowerCase() ); + return imageName( imageInformation.getRegistry(), imageInformation.getImage(), imageInformation.getVersion() ); + } + catch (IOException e) { + throw new RuntimeException( e ); + } + } + + public static DockerImageName imageName(String registry, String image, String version) { + return DockerImageName + .parse( registry + "/" + image + ":" + version ) + .asCompatibleSubstituteFor( image ); + } + + private static class ImageInformation { + private final String registry; + private final String image; + private final String version; + + public ImageInformation(String fullImageInfo) { + // FullImageInfo pattern: /: + // For example: "docker.io/cockroachdb/cockroach:v24.3.13" becomes registry = "docker.io", image = "cockroachdb/cockroach", version = "v24.3.13" + final int registryEndPos = fullImageInfo.indexOf( '/' ); + final int imageEndPos = fullImageInfo.lastIndexOf( ':' ); + this.registry = fullImageInfo.substring( 0, registryEndPos ); + this.image = fullImageInfo.substring( registryEndPos + 1, imageEndPos ); + this.version = fullImageInfo.substring( imageEndPos + 1 ); + } + + public String getRegistry() { + return registry; + } + + public String getImage() { + return image; + } + + public String getVersion() { + return version; + } + + @Override + public String toString() { + return registry + "/" + image + ":" + version; + } + } + + private static Path dockerFilePath(String database) { + // Get project root from system property set by Gradle, with fallback + return DOCKERFILE_DIR_PATH.resolve( database.toLowerCase() + ".Dockerfile" ); + } + + private static ImageInformation readFromInstruction(String database) throws IOException { + return readFromInstruction( dockerFilePath( database ) ); + } + + /** + * Read a Dockerfile and extract the first FROM instruction. + * + * @param dockerfilePath path to the Dockerfile + * @return the first FROM instruction found, or empty if none found + * @throws IOException if the file cannot be read + */ + private static ImageInformation readFromInstruction(Path dockerfilePath) throws IOException { + if ( !Files.exists( dockerfilePath ) ) { + throw new FileNotFoundException( "Dockerfile not found: " + dockerfilePath ); + } + + List lines = Files.readAllLines( dockerfilePath ); + for ( String line : lines ) { + // Skip comments and empty lines + String trimmedLine = line.trim(); + if ( trimmedLine.isEmpty() || trimmedLine.startsWith( "#" ) ) { + continue; + } + + if ( trimmedLine.startsWith( "FROM " ) ) { + return new ImageInformation( trimmedLine.substring( "FROM ".length() ) ); + } + } + + throw new IOException( " Missing FROM instruction in " + dockerfilePath ); + } +} diff --git a/integration-tests/verticle-postgres-it/src/main/java/org/hibernate/reactive/it/verticle/VertxServer.java b/integration-tests/verticle-postgres-it/src/main/java/org/hibernate/reactive/it/verticle/VertxServer.java index 990fef754..f11254c6d 100644 --- a/integration-tests/verticle-postgres-it/src/main/java/org/hibernate/reactive/it/verticle/VertxServer.java +++ b/integration-tests/verticle-postgres-it/src/main/java/org/hibernate/reactive/it/verticle/VertxServer.java @@ -21,6 +21,7 @@ import io.vertx.core.Vertx; import io.vertx.core.VertxOptions; import org.testcontainers.containers.PostgreSQLContainer; +import org.testcontainers.utility.DockerImageName; import static java.lang.invoke.MethodHandles.lookup; import static org.hibernate.reactive.logging.impl.LoggerFactory.make; @@ -36,7 +37,8 @@ public class VertxServer { // These properties are in DatabaseConfiguration in core public static final boolean USE_DOCKER = Boolean.getBoolean( "docker" ); - public static final String IMAGE_NAME = "postgres:17.5"; + public static final DockerImageName IMAGE_NAME = DockerImage.fromDockerfile( "postgresql" ); + public static final String USERNAME = "hreact"; public static final String PASSWORD = "hreact"; public static final String DB_NAME = "hreact"; diff --git a/tooling/docker/README.md b/tooling/docker/README.md new file mode 100644 index 000000000..4de2451e0 --- /dev/null +++ b/tooling/docker/README.md @@ -0,0 +1,6 @@ +Our test suite will only read the first FROM instruction from each Dockerfile to extract the base image and the version +of the container to run. It will ignore everything else. + +The reason we have these files is that we want to automate the upgrade of the containers using dependabot. + +See the class `DockerImage`. diff --git a/tooling/docker/cockroachdb.Dockerfile b/tooling/docker/cockroachdb.Dockerfile new file mode 100644 index 000000000..a4710ad5b --- /dev/null +++ b/tooling/docker/cockroachdb.Dockerfile @@ -0,0 +1,3 @@ +# CockroachDB +# See https://hub.docker.com/r/cockroachdb/cockroach +FROM docker.io/cockroachdb/cockroach:v24.3.13 diff --git a/tooling/docker/db2.Dockerfile b/tooling/docker/db2.Dockerfile new file mode 100644 index 000000000..1ccb34906 --- /dev/null +++ b/tooling/docker/db2.Dockerfile @@ -0,0 +1,3 @@ +# IBM DB2 +# See https://hub.docker.com/r/ibmcom/db2 +FROM icr.io/db2_community/db2:12.1.0.0 diff --git a/tooling/docker/maria.Dockerfile b/tooling/docker/maria.Dockerfile new file mode 100644 index 000000000..4ccb397c8 --- /dev/null +++ b/tooling/docker/maria.Dockerfile @@ -0,0 +1,3 @@ +# MariaDB +# See https://hub.docker.com/_/mariadb +FROM docker.io/mariadb:11.7.2 diff --git a/tooling/docker/mysql.Dockerfile b/tooling/docker/mysql.Dockerfile new file mode 100644 index 000000000..966350a87 --- /dev/null +++ b/tooling/docker/mysql.Dockerfile @@ -0,0 +1,3 @@ +# MySQL +# See https://hub.docker.com/_/mysql +FROM docker.io/mysql:9.2.0 diff --git a/tooling/docker/oracle.Dockerfile b/tooling/docker/oracle.Dockerfile new file mode 100644 index 000000000..7dfc6447d --- /dev/null +++ b/tooling/docker/oracle.Dockerfile @@ -0,0 +1,3 @@ +# Oracle Database Free +# See https://hub.docker.com/r/gvenzl/oracle-free +FROM docker.io/gvenzl/oracle-free:23-slim-faststart diff --git a/tooling/docker/postgresql.Dockerfile b/tooling/docker/postgresql.Dockerfile new file mode 100644 index 000000000..fb36f48e8 --- /dev/null +++ b/tooling/docker/postgresql.Dockerfile @@ -0,0 +1,3 @@ +# PostgreSQL +# See https://hub.docker.com/_/postgres +FROM docker.io/postgres:17.5 diff --git a/tooling/docker/sqlserver.Dockerfile b/tooling/docker/sqlserver.Dockerfile new file mode 100644 index 000000000..b4fb34f2f --- /dev/null +++ b/tooling/docker/sqlserver.Dockerfile @@ -0,0 +1,3 @@ +# Microsoft SQL Server +# See https://hub.docker.com/_/microsoft-mssql-server +FROM mcr.microsoft.com/mssql/server:2022-latest From 3f0d965e806dd10a14d038147c9402290d37438c Mon Sep 17 00:00:00 2001 From: Davide D'Alto Date: Mon, 14 Jul 2025 12:40:49 +0200 Subject: [PATCH 111/162] [#1136] Update dependabot configuration ci --- .github/dependabot.yml | 61 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) create mode 100644 .github/dependabot.yml diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 000000000..0d4bc0776 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,61 @@ +# To get started with Dependabot version updates, you'll need to specify which +# package ecosystems to update and where the package manifests are located. +# Please see the documentation for all configuration options: +# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates + +version: 2 +updates: + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "monthly" + groups: + workflow-actions: + patterns: + - "*" + allow: + - dependency-name: "actions/*" + - dependency-name: "redhat-actions/*" + + - package-ecosystem: "gradle" + directory: "/" + schedule: + interval: "weekly" + day: "tuesday" + open-pull-requests-limit: 20 + groups: + hibernate: + patterns: + - "org.hibernate*" + vertx: + patterns: + - "io.vertx*" + mutiny: + patterns: + - "io.smallrye.reactive*" + # Testcontainers plus the JDBC driver we need for testing + testcontainers: + patterns: + - "org.testcontainers*" + - "com.ibm.db2*" + - "com.microsoft.sqlserver*" + - "org.postgresql*" + - "con.ongres.scram*" + - "com.fasterxml.jackson.core*" + - "com.mysql*" + - "org.mariadb.jdbc*" + + ignore: + # Only patches for Hibernate ORM and Vert.x + - dependency-name: "org.hibernate*" + update-types: ["version-update:semver-major", "version-update:semver-minor"] + - dependency-name: "io.vertx*" + update-types: ["version-update:semver-major", "version-update:semver-minor"] + + # Dockerfiles in tooling/docker/, and database services we use for examples (MySQL and PostgreSQL) + - package-ecosystem: "docker" + directory: "/tooling/docker" + schedule: + interval: "weekly" + allow: + - dependency-type: "all" From 7fcd13c5b315db2555a27550263deabbb7aaef8a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 14 Jul 2025 12:59:23 +0000 Subject: [PATCH 112/162] Bump org.asciidoctor.jvm.convert from 4.0.2 to 4.0.4 Bumps org.asciidoctor.jvm.convert from 4.0.2 to 4.0.4. --- updated-dependencies: - dependency-name: org.asciidoctor.jvm.convert dependency-version: 4.0.4 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 8542b3fc6..cada7bb72 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -55,5 +55,5 @@ org-testcontainers-postgresql = { group = "org.testcontainers", name = "postgres [plugins] com-diffplug-spotless = { id = "com.diffplug.spotless", version = "6.25.0" } io-github-gradle-nexus-publish-plugin = { id = "io.github.gradle-nexus.publish-plugin", version = "1.3.0" } -org-asciidoctor-jvm-convert = { id = "org.asciidoctor.jvm.convert", version = "4.0.2" } +org-asciidoctor-jvm-convert = { id = "org.asciidoctor.jvm.convert", version = "4.0.4" } org-hibernate-orm = { id = "org.hibernate.orm", version.ref = "hibernateOrmGradlePluginVersion" } From 2c1d16970c8eb8983ce028010b2c62d68b00a6c1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 14 Jul 2025 13:08:18 +0000 Subject: [PATCH 113/162] Bump the testcontainers group with 5 updates Bumps the testcontainers group with 5 updates: | Package | From | To | | --- | --- | --- | | [com.fasterxml.jackson.core:jackson-databind](https://github.com/FasterXML/jackson) | `2.15.2` | `2.19.1` | | com.ibm.db2:jcc | `12.1.0.0` | `12.1.2.0` | | [com.microsoft.sqlserver:mssql-jdbc](https://github.com/Microsoft/mssql-jdbc) | `12.10.0.jre11` | `13.1.0.jre11-preview` | | [org.mariadb.jdbc:mariadb-java-client](https://github.com/mariadb-corporation/mariadb-connector-j) | `3.5.3` | `3.5.4` | | [org.postgresql:postgresql](https://github.com/pgjdbc/pgjdbc) | `42.7.5` | `42.7.7` | Updates `com.fasterxml.jackson.core:jackson-databind` from 2.15.2 to 2.19.1 - [Commits](https://github.com/FasterXML/jackson/commits) Updates `com.ibm.db2:jcc` from 12.1.0.0 to 12.1.2.0 Updates `com.microsoft.sqlserver:mssql-jdbc` from 12.10.0.jre11 to 13.1.0.jre11-preview - [Release notes](https://github.com/Microsoft/mssql-jdbc/releases) - [Changelog](https://github.com/microsoft/mssql-jdbc/blob/main/CHANGELOG.md) - [Commits](https://github.com/Microsoft/mssql-jdbc/commits) Updates `org.mariadb.jdbc:mariadb-java-client` from 3.5.3 to 3.5.4 - [Release notes](https://github.com/mariadb-corporation/mariadb-connector-j/releases) - [Changelog](https://github.com/mariadb-corporation/mariadb-connector-j/blob/main/CHANGELOG.md) - [Commits](https://github.com/mariadb-corporation/mariadb-connector-j/compare/3.5.3...3.5.4) Updates `org.postgresql:postgresql` from 42.7.5 to 42.7.7 - [Release notes](https://github.com/pgjdbc/pgjdbc/releases) - [Changelog](https://github.com/pgjdbc/pgjdbc/blob/master/CHANGELOG.md) - [Commits](https://github.com/pgjdbc/pgjdbc/compare/REL42.7.5...REL42.7.7) --- updated-dependencies: - dependency-name: com.fasterxml.jackson.core:jackson-databind dependency-version: 2.19.1 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: testcontainers - dependency-name: com.ibm.db2:jcc dependency-version: 12.1.2.0 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: testcontainers - dependency-name: com.microsoft.sqlserver:mssql-jdbc dependency-version: 13.1.0.jre11-preview dependency-type: direct:production update-type: version-update:semver-major dependency-group: testcontainers - dependency-name: org.mariadb.jdbc:mariadb-java-client dependency-version: 3.5.4 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: testcontainers - dependency-name: org.postgresql:postgresql dependency-version: 42.7.7 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: testcontainers ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index cada7bb72..6f4cf7827 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -2,7 +2,7 @@ assertjVersion = "3.27.3" hibernateOrmVersion = "6.6.15.Final" hibernateOrmGradlePluginVersion = "6.6.15.Final" -jacksonDatabindVersion = "2.15.2" +jacksonDatabindVersion = "2.19.1" jbossLoggingAnnotationVersion = "2.2.1.Final" jbossLoggingVersion = "3.5.0.Final" junitVersion = "5.11.3" @@ -14,8 +14,8 @@ vertxWebClientVersion = "4.5.16" [libraries] com-fasterxml-jackson-core-jackson-databind = { group = "com.fasterxml.jackson.core", name = "jackson-databind", version.ref = "jacksonDatabindVersion" } -com-ibm-db2-jcc = { group = "com.ibm.db2", name = "jcc", version = "12.1.0.0" } -com-microsoft-sqlserver-mssql-jdbc = { group = "com.microsoft.sqlserver", name = "mssql-jdbc", version = "12.10.0.jre11" } +com-ibm-db2-jcc = { group = "com.ibm.db2", name = "jcc", version = "12.1.2.0" } +com-microsoft-sqlserver-mssql-jdbc = { group = "com.microsoft.sqlserver", name = "mssql-jdbc", version = "13.1.0.jre11-preview" } com-mysql-mysql-connector-j = { group = "com.mysql", name = "mysql-connector-j", version = "9.3.0" } com-ongres-scram-client = { group = "com.ongres.scram", name = "client", version = "2.1" } io-smallrye-reactive-mutiny = { group = "io.smallrye.reactive", name = "mutiny", version = "2.7.0" } @@ -42,8 +42,8 @@ org-jboss-logging-jboss-logging-annotations = { group = "org.jboss.logging", nam org-jboss-logging-jboss-logging-processor = { group = "org.jboss.logging", name = "jboss-logging-processor", version.ref = "jbossLoggingAnnotationVersion" } org-junit-jupiter-junit-jupiter-api = { group = "org.junit.jupiter", name = "junit-jupiter-api", version.ref = "junitVersion" } org-junit-jupiter-junit-jupiter-engine = { group = "org.junit.jupiter", name = "junit-jupiter-engine", version.ref = "junitVersion" } -org-mariadb-jdbc-mariadb-java-client = { group = "org.mariadb.jdbc", name = "mariadb-java-client", version = "3.5.3" } -org-postgresql-postgresql = { group = "org.postgresql", name = "postgresql", version = "42.7.5" } +org-mariadb-jdbc-mariadb-java-client = { group = "org.mariadb.jdbc", name = "mariadb-java-client", version = "3.5.4" } +org-postgresql-postgresql = { group = "org.postgresql", name = "postgresql", version = "42.7.7" } org-testcontainers-cockroachdb = { group = "org.testcontainers", name = "cockroachdb", version.ref = "testcontainersVersion" } org-testcontainers-db2 = { group = "org.testcontainers", name = "db2", version.ref = "testcontainersVersion" } org-testcontainers-mariadb = { group = "org.testcontainers", name = "mariadb", version.ref = "testcontainersVersion" } From bb3254573ed1605110ff03fb982ae3cab5ed1b03 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 14 Jul 2025 12:59:32 +0000 Subject: [PATCH 114/162] Bump org.apache.logging.log4j:log4j-core from 2.20.0 to 2.25.1 Bumps org.apache.logging.log4j:log4j-core from 2.20.0 to 2.25.1. --- updated-dependencies: - dependency-name: org.apache.logging.log4j:log4j-core dependency-version: 2.25.1 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 6f4cf7827..0ca8199f5 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -6,7 +6,7 @@ jacksonDatabindVersion = "2.19.1" jbossLoggingAnnotationVersion = "2.2.1.Final" jbossLoggingVersion = "3.5.0.Final" junitVersion = "5.11.3" -log4jVersion = "2.20.0" +log4jVersion = "2.25.1" testcontainersVersion = "1.21.3" vertxSqlClientVersion = "4.5.16" vertxWebVersion= "4.5.16" From 705bb4facef9008e80c5b1b3d80fc1424f366096 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 14 Jul 2025 13:17:47 +0000 Subject: [PATCH 115/162] Bump cockroachdb/cockroach from v24.3.13 to v25.2.2 in /tooling/docker Bumps cockroachdb/cockroach from v24.3.13 to v25.2.2. --- updated-dependencies: - dependency-name: cockroachdb/cockroach dependency-version: v25.2.2 dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- tooling/docker/cockroachdb.Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tooling/docker/cockroachdb.Dockerfile b/tooling/docker/cockroachdb.Dockerfile index a4710ad5b..5f92dd720 100644 --- a/tooling/docker/cockroachdb.Dockerfile +++ b/tooling/docker/cockroachdb.Dockerfile @@ -1,3 +1,3 @@ # CockroachDB # See https://hub.docker.com/r/cockroachdb/cockroach -FROM docker.io/cockroachdb/cockroach:v24.3.13 +FROM docker.io/cockroachdb/cockroach:v25.2.2 From 43d74aa67233eabd96fbdb90676179dfa2c28854 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 14 Jul 2025 13:18:48 +0000 Subject: [PATCH 116/162] Bump db2_community/db2 from 12.1.0.0 to 12.1.2.0 in /tooling/docker Bumps db2_community/db2 from 12.1.0.0 to 12.1.2.0. --- updated-dependencies: - dependency-name: db2_community/db2 dependency-version: 12.1.2.0 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- tooling/docker/db2.Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tooling/docker/db2.Dockerfile b/tooling/docker/db2.Dockerfile index 1ccb34906..b70ff8a80 100644 --- a/tooling/docker/db2.Dockerfile +++ b/tooling/docker/db2.Dockerfile @@ -1,3 +1,3 @@ # IBM DB2 # See https://hub.docker.com/r/ibmcom/db2 -FROM icr.io/db2_community/db2:12.1.0.0 +FROM icr.io/db2_community/db2:12.1.2.0 From 1db23c7274ab8dd0a8f0d95ce6528028b2f4b91f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 14 Jul 2025 13:34:30 +0000 Subject: [PATCH 117/162] Bump com.diffplug.spotless from 6.25.0 to 7.1.0 Bumps com.diffplug.spotless from 6.25.0 to 7.1.0. --- updated-dependencies: - dependency-name: com.diffplug.spotless dependency-version: 7.1.0 dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 0ca8199f5..f392470cc 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -53,7 +53,7 @@ org-testcontainers-oracle-xe = { group = "org.testcontainers", name = "oracle-xe org-testcontainers-postgresql = { group = "org.testcontainers", name = "postgresql", version.ref = "testcontainersVersion" } [plugins] -com-diffplug-spotless = { id = "com.diffplug.spotless", version = "6.25.0" } +com-diffplug-spotless = { id = "com.diffplug.spotless", version = "7.1.0" } io-github-gradle-nexus-publish-plugin = { id = "io.github.gradle-nexus.publish-plugin", version = "1.3.0" } org-asciidoctor-jvm-convert = { id = "org.asciidoctor.jvm.convert", version = "4.0.4" } org-hibernate-orm = { id = "org.hibernate.orm", version.ref = "hibernateOrmGradlePluginVersion" } From bcf1df961179ec6a8380858117aa50634d0d0d61 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 14 Jul 2025 15:34:42 +0000 Subject: [PATCH 118/162] Bump junitVersion from 5.11.3 to 5.13.3 Requires extra dependency org.junit.platform:junit-platform-launcher:1.13.3 --- updated-dependencies: - dependency-name: org.junit.jupiter:junit-jupiter-api dependency-version: 5.13.3 dependency-type: direct:production update-type: version-update:semver-minor - dependency-name: org.junit.jupiter:junit-jupiter-engine dependency-version: 5.13.3 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 4 +++- hibernate-reactive-core/build.gradle | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index f392470cc..449f100f4 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -5,7 +5,8 @@ hibernateOrmGradlePluginVersion = "6.6.15.Final" jacksonDatabindVersion = "2.19.1" jbossLoggingAnnotationVersion = "2.2.1.Final" jbossLoggingVersion = "3.5.0.Final" -junitVersion = "5.11.3" +junitVersion = "5.13.3" +junitPlatformVersion = "1.13.3" log4jVersion = "2.25.1" testcontainersVersion = "1.21.3" vertxSqlClientVersion = "4.5.16" @@ -42,6 +43,7 @@ org-jboss-logging-jboss-logging-annotations = { group = "org.jboss.logging", nam org-jboss-logging-jboss-logging-processor = { group = "org.jboss.logging", name = "jboss-logging-processor", version.ref = "jbossLoggingAnnotationVersion" } org-junit-jupiter-junit-jupiter-api = { group = "org.junit.jupiter", name = "junit-jupiter-api", version.ref = "junitVersion" } org-junit-jupiter-junit-jupiter-engine = { group = "org.junit.jupiter", name = "junit-jupiter-engine", version.ref = "junitVersion" } +org-junit-platform-junit-platform-launcher = { group = "org.junit.platform", name = "junit-platform-launcher", version = "junitPlatformVersion" } org-mariadb-jdbc-mariadb-java-client = { group = "org.mariadb.jdbc", name = "mariadb-java-client", version = "3.5.4" } org-postgresql-postgresql = { group = "org.postgresql", name = "postgresql", version = "42.7.7" } org-testcontainers-cockroachdb = { group = "org.testcontainers", name = "cockroachdb", version.ref = "testcontainersVersion" } diff --git a/hibernate-reactive-core/build.gradle b/hibernate-reactive-core/build.gradle index 69f1dc5b8..ba8630386 100644 --- a/hibernate-reactive-core/build.gradle +++ b/hibernate-reactive-core/build.gradle @@ -43,6 +43,7 @@ dependencies { // JUnit Jupiter testImplementation(libs.org.junit.jupiter.junit.jupiter.api) testRuntimeOnly(libs.org.junit.jupiter.junit.jupiter.engine) + testRuntimeOnly(libs.org.junit.platform.junit.platform.launcher) // JDBC driver to test with ORM and PostgreSQL testRuntimeOnly(libs.org.postgresql.postgresql) From b6b7f2f040ee592783e90d8c83aac2ee18f20175 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 15 Jul 2025 06:18:18 +0000 Subject: [PATCH 119/162] Bump mariadb from 11.7.2 to 11.8.2 in /tooling/docker Bumps mariadb from 11.7.2 to 11.8.2. --- updated-dependencies: - dependency-name: mariadb dependency-version: 11.8.2 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- tooling/docker/maria.Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tooling/docker/maria.Dockerfile b/tooling/docker/maria.Dockerfile index 4ccb397c8..fc954df6e 100644 --- a/tooling/docker/maria.Dockerfile +++ b/tooling/docker/maria.Dockerfile @@ -1,3 +1,3 @@ # MariaDB # See https://hub.docker.com/_/mariadb -FROM docker.io/mariadb:11.7.2 +FROM docker.io/mariadb:11.8.2 From ae8f79cb74cac5f016000c86452a022cf6b5fd50 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 14 Jul 2025 13:38:54 +0000 Subject: [PATCH 120/162] Bump mssql/server from 2022-latest to 2025-latest in /tooling/docker Bumps mssql/server from 2022-latest to 2025-latest. --- updated-dependencies: - dependency-name: mssql/server dependency-version: 2025-latest dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- tooling/docker/sqlserver.Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tooling/docker/sqlserver.Dockerfile b/tooling/docker/sqlserver.Dockerfile index b4fb34f2f..94fae1429 100644 --- a/tooling/docker/sqlserver.Dockerfile +++ b/tooling/docker/sqlserver.Dockerfile @@ -1,3 +1,3 @@ # Microsoft SQL Server # See https://hub.docker.com/_/microsoft-mssql-server -FROM mcr.microsoft.com/mssql/server:2022-latest +FROM mcr.microsoft.com/mssql/server:2025-latest From 026c31bf70e522cb11bf3fd6b976b64900729fbb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 14 Jul 2025 13:45:45 +0000 Subject: [PATCH 121/162] [#2270] Change docker image to container-registry.oracle.com/mysql/community-server:9.3.0 from `docker.io/mysql:9.2.0` to `container-registry.oracle.com/mysql/community-server:9.3.0` I found the registry in the official MySQL documentation: https://dev.mysql.com/doc/refman/9.3/en/docker-mysql-getting-started.html#docker-download-image The one from docker.io doesn't seem to work with testcontainers. --- .github/workflows/build.yml | 3 +-- .../java/org/hibernate/reactive/containers/MySQLDatabase.java | 2 +- tooling/docker/mysql.Dockerfile | 2 +- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 07b9bfc3b..c4c9e43f8 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -49,8 +49,7 @@ jobs: services: # Label used to access the service container mysql: - # Docker Hub image - image: mysql:9.2.0 + image: container-registry.oracle.com/mysql/community-server:9.3.0 env: MYSQL_ROOT_PASSWORD: hreact MYSQL_DATABASE: hreact diff --git a/hibernate-reactive-core/src/test/java/org/hibernate/reactive/containers/MySQLDatabase.java b/hibernate-reactive-core/src/test/java/org/hibernate/reactive/containers/MySQLDatabase.java index 142a88c5a..28b3803be 100644 --- a/hibernate-reactive-core/src/test/java/org/hibernate/reactive/containers/MySQLDatabase.java +++ b/hibernate-reactive-core/src/test/java/org/hibernate/reactive/containers/MySQLDatabase.java @@ -87,7 +87,7 @@ class MySQLDatabase implements TestableDatabase { * TIP: To reuse the same containers across multiple runs, set `testcontainers.reuse.enable=true` in a file located * at `$HOME/.testcontainers.properties` (create the file if it does not exist). */ - public static final MySQLContainer mysql = new MySQLContainer<>( fromDockerfile( "mysql" ) ) + public static final MySQLContainer mysql = new MySQLContainer<>( fromDockerfile( "mysql" ).asCompatibleSubstituteFor( "mysql" ) ) .withUsername( DatabaseConfiguration.USERNAME ) .withPassword( DatabaseConfiguration.PASSWORD ) .withDatabaseName( DatabaseConfiguration.DB_NAME ) diff --git a/tooling/docker/mysql.Dockerfile b/tooling/docker/mysql.Dockerfile index 966350a87..69b12ca62 100644 --- a/tooling/docker/mysql.Dockerfile +++ b/tooling/docker/mysql.Dockerfile @@ -1,3 +1,3 @@ # MySQL # See https://hub.docker.com/_/mysql -FROM docker.io/mysql:9.2.0 +FROM container-registry.oracle.com/mysql/community-server:9.3.0 From c74e3602363fd4f90536903af253c02aaba6d6d3 Mon Sep 17 00:00:00 2001 From: Davide D'Alto Date: Tue, 15 Jul 2025 10:14:05 +0200 Subject: [PATCH 122/162] [#2270] Update JBang templates MySQL docker image to `container-registry.oracle.com/mysql/community-server:9.3.0` --- tooling/jbang/MySQLReactiveTest.java.qute | 2 +- tooling/jbang/ReactiveTest.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tooling/jbang/MySQLReactiveTest.java.qute b/tooling/jbang/MySQLReactiveTest.java.qute index 4e1b68993..099184c04 100755 --- a/tooling/jbang/MySQLReactiveTest.java.qute +++ b/tooling/jbang/MySQLReactiveTest.java.qute @@ -72,7 +72,7 @@ public class {baseName} { } @ClassRule - public final static MySQLContainer database = new MySQLContainer<>( imageName( "docker.io", "mysql", "9.2.0" ) ); + public final static MySQLContainer database = new MySQLContainer<>( imageName( "container-registry.oracle.com", "mysql/community-server", "9.3.0" ).asCompatibleSubstituteFor( "mysql" ) ); private Mutiny.SessionFactory sessionFactory; diff --git a/tooling/jbang/ReactiveTest.java b/tooling/jbang/ReactiveTest.java index 8162a9ea7..54e77b3ef 100755 --- a/tooling/jbang/ReactiveTest.java +++ b/tooling/jbang/ReactiveTest.java @@ -229,7 +229,7 @@ public String toString() { */ enum Database { POSTGRESQL( () -> new PostgreSQLContainer( "postgres:17.5" ) ), - MYSQL( () -> new MySQLContainer( "mysql:9.2.0" ) ), + MYSQL( () -> new MySQLContainer( "container-registry.oracle.com/mysql/community-server:9.3.0" ) ), DB2( () -> new Db2Container( "docker.io/icr.io/db2_community/db2:12.1.0.0" ).acceptLicense() ), MARIADB( () -> new MariaDBContainer( "mariadb:11.7.2" ) ), COCKROACHDB( () -> new CockroachContainer( "cockroachdb/cockroach:v24.3.13" ) ); From 3937a8daca99ae0b68649dd6e3fcfdf3a5659f7b Mon Sep 17 00:00:00 2001 From: Davide D'Alto Date: Wed, 16 Jul 2025 09:46:50 +0200 Subject: [PATCH 123/162] [#2368] Remove gradle-nexus:publish-plugin from the catalog We don't use it anymore since the switch to JRelease. This was just a left over. --- build.gradle | 1 - ci/snapshot-publish.Jenkinsfile | 1 - gradle/libs.versions.toml | 1 - 3 files changed, 3 deletions(-) diff --git a/build.gradle b/build.gradle index f9172203e..9d43d4bca 100644 --- a/build.gradle +++ b/build.gradle @@ -5,7 +5,6 @@ plugins { id 'maven-publish' alias(libs.plugins.com.diffplug.spotless) alias(libs.plugins.org.asciidoctor.jvm.convert) apply false - alias(libs.plugins.io.github.gradle.nexus.publish.plugin) } group = "org.hibernate.reactive" diff --git a/ci/snapshot-publish.Jenkinsfile b/ci/snapshot-publish.Jenkinsfile index 9a9ecd707..8af583e13 100644 --- a/ci/snapshot-publish.Jenkinsfile +++ b/ci/snapshot-publish.Jenkinsfile @@ -40,7 +40,6 @@ pipeline { steps { 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: 'central.sonatype.com', passwordVariable: 'ORG_GRADLE_PROJECT_snapshotsPassword', usernameVariable: 'ORG_GRADLE_PROJECT_snapshotsUsername'), diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 449f100f4..549f6abeb 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -56,6 +56,5 @@ org-testcontainers-postgresql = { group = "org.testcontainers", name = "postgres [plugins] com-diffplug-spotless = { id = "com.diffplug.spotless", version = "7.1.0" } -io-github-gradle-nexus-publish-plugin = { id = "io.github.gradle-nexus.publish-plugin", version = "1.3.0" } org-asciidoctor-jvm-convert = { id = "org.asciidoctor.jvm.convert", version = "4.0.4" } org-hibernate-orm = { id = "org.hibernate.orm", version.ref = "hibernateOrmGradlePluginVersion" } From 8731fcbeb1ce47b79d3ef63246fc1f779d2157aa Mon Sep 17 00:00:00 2001 From: Davide D'Alto Date: Tue, 15 Jul 2025 11:17:04 +0200 Subject: [PATCH 124/162] [#1136] Keep Hibernate Validator and expressively consistent Expressly 5 for Hibernate Validator 8 Expressly 6 for Hibernate Validator 9 I've decided to keep it simple and just ignore the upgrades for majors. I will update manually as needed for now, and think of something else if it becomes too much of a chore. We could remove the dependency to expressly by adding an extra configuration file for Hibernate Validator, but then I would have to explain why we need the extra configuraiton file somewhere in the examples. --- .github/dependabot.yml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 0d4bc0776..fbc73fcb5 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -24,6 +24,10 @@ updates: day: "tuesday" open-pull-requests-limit: 20 groups: + hibernate-validator: + patterns: + - "org.hibernate.validator*" + - "org.glassfish.expressly*" hibernate: patterns: - "org.hibernate*" @@ -46,6 +50,9 @@ updates: - "org.mariadb.jdbc*" ignore: + # For Hibernate Validator, we will need to update major version manually as needed (but we only use it in tests) + - dependency-name: "org.glassfish.expressly*" + update-types: ["version-update-:semver-major"] # Only patches for Hibernate ORM and Vert.x - dependency-name: "org.hibernate*" update-types: ["version-update:semver-major", "version-update:semver-minor"] From 4dc3b88433f2002760d371c1a79bba334b482129 Mon Sep 17 00:00:00 2001 From: Davide D'Alto Date: Tue, 22 Jul 2025 16:47:05 +0200 Subject: [PATCH 125/162] [#2381] Fix chaining in ReactiveEmbeddableInitializerImpl#reactiveResolveInstance The code was using .thenAccept instead of .thenCompose --- .../embeddable/internal/ReactiveEmbeddableInitializerImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/sql/results/graph/embeddable/internal/ReactiveEmbeddableInitializerImpl.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/sql/results/graph/embeddable/internal/ReactiveEmbeddableInitializerImpl.java index b7d21216b..d5f9db5e2 100644 --- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/sql/results/graph/embeddable/internal/ReactiveEmbeddableInitializerImpl.java +++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/sql/results/graph/embeddable/internal/ReactiveEmbeddableInitializerImpl.java @@ -89,7 +89,7 @@ public CompletionStage reactiveResolveInstance(EmbeddableInitializerData d data.setState( State.RESOLVED ); return extractRowState( (ReactiveEmbeddableInitializerData) data ) - .thenAccept( unused -> prepareCompositeInstance( (ReactiveEmbeddableInitializerData) data ) ); + .thenCompose( unused -> prepareCompositeInstance( (ReactiveEmbeddableInitializerData) data ) ); } private CompletionStage extractRowState(ReactiveEmbeddableInitializerData data) { From c067ff25f6fef68a96f3284b2cc4da6bf75e173c Mon Sep 17 00:00:00 2001 From: Davide D'Alto Date: Tue, 22 Jul 2025 10:32:15 +0200 Subject: [PATCH 126/162] Bump com.fasterxml.jackson.core:jackson-databind --- updated-dependencies: - dependency-name: com.fasterxml.jackson.core:jackson-databind dependency-version: 2.19.2 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: testcontainers ... --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 549f6abeb..891b35aca 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -2,7 +2,7 @@ assertjVersion = "3.27.3" hibernateOrmVersion = "6.6.15.Final" hibernateOrmGradlePluginVersion = "6.6.15.Final" -jacksonDatabindVersion = "2.19.1" +jacksonDatabindVersion = "2.19.2" jbossLoggingAnnotationVersion = "2.2.1.Final" jbossLoggingVersion = "3.5.0.Final" junitVersion = "5.13.3" From d6b5343f2430c926a296eda7a75a9e160ffacde0 Mon Sep 17 00:00:00 2001 From: Andrea Boriero Date: Wed, 30 Jul 2025 09:55:06 +0200 Subject: [PATCH 127/162] Fix db2 podman script in the documentation (podman.md) * Remove docker.io from the image source (it's wrong) * Upgrade the image to 12.1.2.0 --- podman.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/podman.md b/podman.md index bc4d96ba7..9b9a71af2 100644 --- a/podman.md +++ b/podman.md @@ -158,7 +158,7 @@ and schema to run the tests: podman run --rm -e LICENSE=accept --privileged=true --group-add keep-groups \ --name HibernateTestingDB2 -e DBNAME=hreact -e DB2INSTANCE=hreact \ -e DB2INST1_PASSWORD=hreact -e PERSISTENT_HOME=false -e ARCHIVE_LOGS=false \ - -e AUTOCONFIG=false -p 50000:50000 docker.io/icr.io/db2_community/db2:12.1.0.0 + -e AUTOCONFIG=false -p 50000:50000 icr.io/db2_community/db2:12.1.2.0 ``` When the database has started, you can run the tests on Db2 with: From 152e65c2815589b4474ea27c8e82f55256e2d06a Mon Sep 17 00:00:00 2001 From: Davide D'Alto Date: Mon, 11 Aug 2025 11:05:32 +0200 Subject: [PATCH 128/162] [#2420] Keep only major.minor version in README For Hibernate ORM and Vert.x. The current automated release system and dependabot don't update the readme. It would get out of date at every minor release. I've included a link to the exact version in the catalog, though. --- README.md | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 55dc68c76..6ba9fcc5c 100644 --- a/README.md +++ b/README.md @@ -37,14 +37,18 @@ Hibernate Reactive has been tested with: - CockroachDB v24 - MS SQL Server 2022 - Oracle 23 -- [Hibernate ORM][] 6.6.15.Final -- [Vert.x Reactive PostgreSQL Client](https://vertx.io/docs/vertx-pg-client/java/) 4.5.16 -- [Vert.x Reactive MySQL Client](https://vertx.io/docs/vertx-mysql-client/java/) 4.5.16 -- [Vert.x Reactive Db2 Client](https://vertx.io/docs/vertx-db2-client/java/) 4.5.16 -- [Vert.x Reactive MS SQL Server Client](https://vertx.io/docs/vertx-mssql-client/java/) 4.5.16 -- [Vert.x Reactive Oracle Client](https://vertx.io/docs/vertx-oracle-client/java/) 4.5.16 +- [Hibernate ORM][] 6.6 +- [Vert.x Reactive PostgreSQL Client](https://vertx.io/docs/vertx-pg-client/java/) 4.5 +- [Vert.x Reactive MySQL Client](https://vertx.io/docs/vertx-mysql-client/java/) 4.5 +- [Vert.x Reactive Db2 Client](https://vertx.io/docs/vertx-db2-client/java/) 4.5 +- [Vert.x Reactive MS SQL Server Client](https://vertx.io/docs/vertx-mssql-client/java/) 4.5 +- [Vert.x Reactive Oracle Client](https://vertx.io/docs/vertx-oracle-client/java/) 4.5 - [Quarkus][Quarkus] via the Hibernate Reactive extension +The exact version of the libraries and images are in the +[catalog](https://github.com/hibernate/hibernate-reactive/blob/2.4/gradle/libs.versions.toml) +and in the [tooling/docker](https://github.com/hibernate/hibernate-reactive/tree/2.4/tooling/docker) folder. + [PostgreSQL]: https://www.postgresql.org [MySQL]: https://www.mysql.com [MariaDB]: https://mariadb.com From c842872814a7beada7514c00078f8cb3dac33319 Mon Sep 17 00:00:00 2001 From: marko-bekhta Date: Fri, 19 Sep 2025 13:57:22 +0200 Subject: [PATCH 129/162] [#2516] Use GA version of JDK 25 in the build --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index c4c9e43f8..8db9812c1 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -177,7 +177,7 @@ jobs: - { name: "20", java_version_numeric: 20, jvm_args: '--enable-preview' } - { name: "21", java_version_numeric: 21, jvm_args: '--enable-preview' } - { name: "24", java_version_numeric: 24, from: 'jdk.java.net', jvm_args: '--enable-preview' } - - { name: "25-ea", java_version_numeric: 25, from: 'jdk.java.net', jvm_args: '--enable-preview' } + - { name: "25", java_version_numeric: 25, from: 'jdk.java.net', jvm_args: '--enable-preview' } - { name: "26-ea", java_version_numeric: 26, from: 'jdk.java.net', jvm_args: '--enable-preview' } steps: - name: Checkout ${{ inputs.branch }} From 8c3226f7fe1361a0f4d7a7a5761fa0633290f6a4 Mon Sep 17 00:00:00 2001 From: marko-bekhta Date: Fri, 19 Sep 2025 14:40:05 +0200 Subject: [PATCH 130/162] [#2516] Use temurin distribution for JDK 24 --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 8db9812c1..9a9333466 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -176,7 +176,7 @@ jobs: # and it's useful to test that. - { name: "20", java_version_numeric: 20, jvm_args: '--enable-preview' } - { name: "21", java_version_numeric: 21, jvm_args: '--enable-preview' } - - { name: "24", java_version_numeric: 24, from: 'jdk.java.net', jvm_args: '--enable-preview' } + - { name: "24", java_version_numeric: 24, jvm_args: '--enable-preview' } - { name: "25", java_version_numeric: 25, from: 'jdk.java.net', jvm_args: '--enable-preview' } - { name: "26-ea", java_version_numeric: 26, from: 'jdk.java.net', jvm_args: '--enable-preview' } steps: From 2f341a321149449c9d7eb00298fd93f13f87dc35 Mon Sep 17 00:00:00 2001 From: Andrea Boriero Date: Wed, 24 Sep 2025 11:52:57 +0200 Subject: [PATCH 131/162] [#2519] Migrate to release scripts for documentation publishing --- ci/release/Jenkinsfile | 2 +- release/build.gradle | 12 +++++++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/ci/release/Jenkinsfile b/ci/release/Jenkinsfile index 70a7401df..670d6a537 100644 --- a/ci/release/Jenkinsfile +++ b/ci/release/Jenkinsfile @@ -211,7 +211,7 @@ pipeline { 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']) { + sshagent(['ed25519.Hibernate-CI.github.com', 'hibernate.filemgmt.jboss.org', 'jenkins.in.relation.to', 'hibernate-ci.frs.sourceforge.net']) { // performs documentation upload and Sonatype release // push to github withEnv([ diff --git a/release/build.gradle b/release/build.gradle index 690534750..00b43d2f4 100644 --- a/release/build.gradle +++ b/release/build.gradle @@ -153,11 +153,21 @@ def updateDocumentationTask = tasks.register( 'updateDocumentation' ) { into docWebsiteReactiveFolder.dir("javadocs") } + copy { + from documentationDir.dir("javadocs") + into rootProject.layout.buildDirectory.dir("staging-deploy/documentation/javadocs") + } + // Reference Documentation copy { from documentationDir.dir("asciidoc/reference/html_single") into docWebsiteReactiveFolder.dir("reference/html_single") - } + } + + copy { + from documentationDir.dir("asciidoc/reference/html_single") + into rootProject.layout.buildDirectory.dir("staging-deploy/documentation/reference/html_single") + } } } From f042beb044fd71a85523f28ccf0f7e0d104d2be2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 6 Oct 2025 15:16:08 +0000 Subject: [PATCH 132/162] Bump the hibernate group with 4 updates Bumps the hibernate group with 4 updates: [org.hibernate.orm:hibernate-core](https://github.com/hibernate/hibernate-orm), [org.hibernate.orm:hibernate-jcache](https://github.com/hibernate/hibernate-orm), [org.hibernate.orm:hibernate-jpamodelgen](https://github.com/hibernate/hibernate-orm) and org.hibernate.orm. Updates `org.hibernate.orm:hibernate-core` from 6.6.15.Final to 6.6.31.Final - [Release notes](https://github.com/hibernate/hibernate-orm/releases) - [Changelog](https://github.com/hibernate/hibernate-orm/blob/6.6.31/changelog.txt) - [Commits](https://github.com/hibernate/hibernate-orm/compare/6.6.15...6.6.31) Updates `org.hibernate.orm:hibernate-jcache` from 6.6.15.Final to 6.6.31.Final - [Release notes](https://github.com/hibernate/hibernate-orm/releases) - [Changelog](https://github.com/hibernate/hibernate-orm/blob/6.6.31/changelog.txt) - [Commits](https://github.com/hibernate/hibernate-orm/compare/6.6.15...6.6.31) Updates `org.hibernate.orm:hibernate-jpamodelgen` from 6.6.15.Final to 6.6.31.Final - [Release notes](https://github.com/hibernate/hibernate-orm/releases) - [Changelog](https://github.com/hibernate/hibernate-orm/blob/6.6.31/changelog.txt) - [Commits](https://github.com/hibernate/hibernate-orm/compare/6.6.15...6.6.31) Updates `org.hibernate.orm:hibernate-jcache` from 6.6.15.Final to 6.6.31.Final - [Release notes](https://github.com/hibernate/hibernate-orm/releases) - [Changelog](https://github.com/hibernate/hibernate-orm/blob/6.6.31/changelog.txt) - [Commits](https://github.com/hibernate/hibernate-orm/compare/6.6.15...6.6.31) Updates `org.hibernate.orm:hibernate-jpamodelgen` from 6.6.15.Final to 6.6.31.Final - [Release notes](https://github.com/hibernate/hibernate-orm/releases) - [Changelog](https://github.com/hibernate/hibernate-orm/blob/6.6.31/changelog.txt) - [Commits](https://github.com/hibernate/hibernate-orm/compare/6.6.15...6.6.31) Updates `org.hibernate.orm` from 6.6.15.Final to 6.6.30.Final --- updated-dependencies: - dependency-name: org.hibernate.orm:hibernate-core dependency-version: 6.6.31.Final dependency-type: direct:production update-type: version-update:semver-patch dependency-group: hibernate - dependency-name: org.hibernate.orm:hibernate-jcache dependency-version: 6.6.31.Final dependency-type: direct:production update-type: version-update:semver-patch dependency-group: hibernate - dependency-name: org.hibernate.orm:hibernate-jpamodelgen dependency-version: 6.6.31.Final dependency-type: direct:production update-type: version-update:semver-patch dependency-group: hibernate - dependency-name: org.hibernate.orm:hibernate-jcache dependency-version: 6.6.31.Final dependency-type: direct:production update-type: version-update:semver-patch dependency-group: hibernate - dependency-name: org.hibernate.orm:hibernate-jpamodelgen dependency-version: 6.6.31.Final dependency-type: direct:production update-type: version-update:semver-patch dependency-group: hibernate - dependency-name: org.hibernate.orm dependency-version: 6.6.30.Final dependency-type: direct:production update-type: version-update:semver-patch dependency-group: hibernate ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 891b35aca..26de093e5 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,7 +1,7 @@ [versions] assertjVersion = "3.27.3" -hibernateOrmVersion = "6.6.15.Final" -hibernateOrmGradlePluginVersion = "6.6.15.Final" +hibernateOrmVersion = "6.6.31.Final" +hibernateOrmGradlePluginVersion = "6.6.30.Final" jacksonDatabindVersion = "2.19.2" jbossLoggingAnnotationVersion = "2.2.1.Final" jbossLoggingVersion = "3.5.0.Final" From 0fbb798a8251a06947d739e487a483b82fabac41 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 7 Oct 2025 08:37:57 +0000 Subject: [PATCH 133/162] Bump org.assertj:assertj-core from 3.27.3 to 3.27.6 Bumps [org.assertj:assertj-core](https://github.com/assertj/assertj) from 3.27.3 to 3.27.6. - [Release notes](https://github.com/assertj/assertj/releases) - [Commits](https://github.com/assertj/assertj/compare/assertj-build-3.27.3...assertj-build-3.27.6) --- updated-dependencies: - dependency-name: org.assertj:assertj-core dependency-version: 3.27.6 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 26de093e5..895d57fe7 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,5 +1,5 @@ [versions] -assertjVersion = "3.27.3" +assertjVersion = "3.27.6" hibernateOrmVersion = "6.6.31.Final" hibernateOrmGradlePluginVersion = "6.6.30.Final" jacksonDatabindVersion = "2.19.2" From 609d3dc6b08c7b08147f92156f7b9920fee65000 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 6 Oct 2025 15:15:31 +0000 Subject: [PATCH 134/162] Bump org.asciidoctor.jvm.convert from 4.0.4 to 4.0.5 Bumps org.asciidoctor.jvm.convert from 4.0.4 to 4.0.5. --- updated-dependencies: - dependency-name: org.asciidoctor.jvm.convert dependency-version: 4.0.5 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 895d57fe7..6f75bd7ac 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -56,5 +56,5 @@ org-testcontainers-postgresql = { group = "org.testcontainers", name = "postgres [plugins] com-diffplug-spotless = { id = "com.diffplug.spotless", version = "7.1.0" } -org-asciidoctor-jvm-convert = { id = "org.asciidoctor.jvm.convert", version = "4.0.4" } +org-asciidoctor-jvm-convert = { id = "org.asciidoctor.jvm.convert", version = "4.0.5" } org-hibernate-orm = { id = "org.hibernate.orm", version.ref = "hibernateOrmGradlePluginVersion" } From 3d048a9e341a26ad6213b1da07278604d3007176 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 6 Oct 2025 15:15:35 +0000 Subject: [PATCH 135/162] Bump the vertx group with 10 updates Bumps the vertx group with 10 updates: | Package | From | To | | --- | --- | --- | | [io.vertx:vertx-db2-client](https://github.com/eclipse-vertx/vertx-sql-client) | `4.5.16` | `4.5.21` | | [io.vertx:vertx-junit5](https://github.com/eclipse-vertx/vertx-junit5) | `4.5.16` | `4.5.21` | | [io.vertx:vertx-micrometer-metrics](https://github.com/vert-x3/vertx-micrometer-metrics) | `4.5.16` | `4.5.21` | | [io.vertx:vertx-mssql-client](https://github.com/eclipse-vertx/vertx-sql-client) | `4.5.16` | `4.5.21` | | [io.vertx:vertx-mysql-client](https://github.com/eclipse-vertx/vertx-sql-client) | `4.5.16` | `4.5.21` | | [io.vertx:vertx-oracle-client](https://github.com/eclipse-vertx/vertx-sql-client) | `4.5.16` | `4.5.21` | | [io.vertx:vertx-pg-client](https://github.com/eclipse-vertx/vertx-sql-client) | `4.5.16` | `4.5.21` | | [io.vertx:vertx-sql-client](https://github.com/eclipse-vertx/vertx-sql-client) | `4.5.16` | `4.5.21` | | [io.vertx:vertx-web](https://github.com/vert-x3/vertx-web) | `4.5.16` | `4.5.21` | | [io.vertx:vertx-web-client](https://github.com/vert-x3/vertx-web) | `4.5.16` | `4.5.21` | Updates `io.vertx:vertx-db2-client` from 4.5.16 to 4.5.21 - [Commits](https://github.com/eclipse-vertx/vertx-sql-client/compare/4.5.16...4.5.21) Updates `io.vertx:vertx-junit5` from 4.5.16 to 4.5.21 - [Commits](https://github.com/eclipse-vertx/vertx-junit5/compare/4.5.16...4.5.21) Updates `io.vertx:vertx-micrometer-metrics` from 4.5.16 to 4.5.21 - [Commits](https://github.com/vert-x3/vertx-micrometer-metrics/compare/4.5.16...4.5.21) Updates `io.vertx:vertx-mssql-client` from 4.5.16 to 4.5.21 - [Commits](https://github.com/eclipse-vertx/vertx-sql-client/compare/4.5.16...4.5.21) Updates `io.vertx:vertx-mysql-client` from 4.5.16 to 4.5.21 - [Commits](https://github.com/eclipse-vertx/vertx-sql-client/compare/4.5.16...4.5.21) Updates `io.vertx:vertx-oracle-client` from 4.5.16 to 4.5.21 - [Commits](https://github.com/eclipse-vertx/vertx-sql-client/compare/4.5.16...4.5.21) Updates `io.vertx:vertx-pg-client` from 4.5.16 to 4.5.21 - [Commits](https://github.com/eclipse-vertx/vertx-sql-client/compare/4.5.16...4.5.21) Updates `io.vertx:vertx-sql-client` from 4.5.16 to 4.5.21 - [Commits](https://github.com/eclipse-vertx/vertx-sql-client/compare/4.5.16...4.5.21) Updates `io.vertx:vertx-junit5` from 4.5.16 to 4.5.21 - [Commits](https://github.com/eclipse-vertx/vertx-junit5/compare/4.5.16...4.5.21) Updates `io.vertx:vertx-micrometer-metrics` from 4.5.16 to 4.5.21 - [Commits](https://github.com/vert-x3/vertx-micrometer-metrics/compare/4.5.16...4.5.21) Updates `io.vertx:vertx-mssql-client` from 4.5.16 to 4.5.21 - [Commits](https://github.com/eclipse-vertx/vertx-sql-client/compare/4.5.16...4.5.21) Updates `io.vertx:vertx-mysql-client` from 4.5.16 to 4.5.21 - [Commits](https://github.com/eclipse-vertx/vertx-sql-client/compare/4.5.16...4.5.21) Updates `io.vertx:vertx-oracle-client` from 4.5.16 to 4.5.21 - [Commits](https://github.com/eclipse-vertx/vertx-sql-client/compare/4.5.16...4.5.21) Updates `io.vertx:vertx-pg-client` from 4.5.16 to 4.5.21 - [Commits](https://github.com/eclipse-vertx/vertx-sql-client/compare/4.5.16...4.5.21) Updates `io.vertx:vertx-sql-client` from 4.5.16 to 4.5.21 - [Commits](https://github.com/eclipse-vertx/vertx-sql-client/compare/4.5.16...4.5.21) Updates `io.vertx:vertx-web` from 4.5.16 to 4.5.21 - [Commits](https://github.com/vert-x3/vertx-web/compare/4.5.16...4.5.21) Updates `io.vertx:vertx-web-client` from 4.5.16 to 4.5.21 - [Commits](https://github.com/vert-x3/vertx-web/compare/4.5.16...4.5.21) --- updated-dependencies: - dependency-name: io.vertx:vertx-db2-client dependency-version: 4.5.21 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: vertx - dependency-name: io.vertx:vertx-junit5 dependency-version: 4.5.21 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: vertx - dependency-name: io.vertx:vertx-micrometer-metrics dependency-version: 4.5.21 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: vertx - dependency-name: io.vertx:vertx-mssql-client dependency-version: 4.5.21 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: vertx - dependency-name: io.vertx:vertx-mysql-client dependency-version: 4.5.21 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: vertx - dependency-name: io.vertx:vertx-oracle-client dependency-version: 4.5.21 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: vertx - dependency-name: io.vertx:vertx-pg-client dependency-version: 4.5.21 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: vertx - dependency-name: io.vertx:vertx-sql-client dependency-version: 4.5.21 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: vertx - dependency-name: io.vertx:vertx-junit5 dependency-version: 4.5.21 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: vertx - dependency-name: io.vertx:vertx-micrometer-metrics dependency-version: 4.5.21 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: vertx - dependency-name: io.vertx:vertx-mssql-client dependency-version: 4.5.21 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: vertx - dependency-name: io.vertx:vertx-mysql-client dependency-version: 4.5.21 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: vertx - dependency-name: io.vertx:vertx-oracle-client dependency-version: 4.5.21 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: vertx - dependency-name: io.vertx:vertx-pg-client dependency-version: 4.5.21 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: vertx - dependency-name: io.vertx:vertx-sql-client dependency-version: 4.5.21 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: vertx - dependency-name: io.vertx:vertx-web dependency-version: 4.5.21 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: vertx - dependency-name: io.vertx:vertx-web-client dependency-version: 4.5.21 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: vertx ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 6f75bd7ac..6256c6c95 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -9,9 +9,9 @@ junitVersion = "5.13.3" junitPlatformVersion = "1.13.3" log4jVersion = "2.25.1" testcontainersVersion = "1.21.3" -vertxSqlClientVersion = "4.5.16" -vertxWebVersion= "4.5.16" -vertxWebClientVersion = "4.5.16" +vertxSqlClientVersion = "4.5.21" +vertxWebVersion= "4.5.21" +vertxWebClientVersion = "4.5.21" [libraries] com-fasterxml-jackson-core-jackson-databind = { group = "com.fasterxml.jackson.core", name = "jackson-databind", version.ref = "jacksonDatabindVersion" } From 1c61fa4846818ac98d2b198907589f07cc703df5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 6 Oct 2025 15:15:24 +0000 Subject: [PATCH 136/162] Bump mysql/community-server from 9.3.0 to 9.4.0 in /tooling/docker Bumps mysql/community-server from 9.3.0 to 9.4.0. --- updated-dependencies: - dependency-name: mysql/community-server dependency-version: 9.4.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- tooling/docker/mysql.Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tooling/docker/mysql.Dockerfile b/tooling/docker/mysql.Dockerfile index 69b12ca62..897fbd5ee 100644 --- a/tooling/docker/mysql.Dockerfile +++ b/tooling/docker/mysql.Dockerfile @@ -1,3 +1,3 @@ # MySQL # See https://hub.docker.com/_/mysql -FROM container-registry.oracle.com/mysql/community-server:9.3.0 +FROM container-registry.oracle.com/mysql/community-server:9.4.0 From a028e8b22377637178192de940db8b9900013555 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 6 Oct 2025 15:14:53 +0000 Subject: [PATCH 137/162] Bump org.ehcache:ehcache from 3.10.8 to 3.11.1 Bumps [org.ehcache:ehcache](https://github.com/ehcache/ehcache3) from 3.10.8 to 3.11.1. - [Release notes](https://github.com/ehcache/ehcache3/releases) - [Commits](https://github.com/ehcache/ehcache3/compare/v3.10.8...v3.11.1) --- updated-dependencies: - dependency-name: org.ehcache:ehcache dependency-version: 3.11.1 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 6256c6c95..e7d63c64c 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -32,7 +32,7 @@ io-vertx-vertx-web = { group = "io.vertx", name = "vertx-web", version.ref = "ve io-vertx-vertx-web-client = { group = "io.vertx", name = "vertx-web-client", version.ref = "vertxWebClientVersion" } org-apache-logging-log4j-log4j-core = { group = "org.apache.logging.log4j", name = "log4j-core", version.ref = "log4jVersion" } org-assertj-assertj-core = { group = "org.assertj", name = "assertj-core", version.ref = "assertjVersion" } -org-ehcache-ehcache = { group = "org.ehcache", name = "ehcache", version = "3.10.8" } +org-ehcache-ehcache = { group = "org.ehcache", name = "ehcache", version = "3.11.1" } org-glassfish-expressly-expressly = { group = "org.glassfish.expressly", name = "expressly", version = "5.0.0" } org-hibernate-orm-hibernate-core = { group = "org.hibernate.orm", name = "hibernate-core", version.ref = "hibernateOrmVersion" } org-hibernate-orm-hibernate-jcache = { group = "org.hibernate.orm", name = "hibernate-jcache", version.ref = "hibernateOrmVersion" } From 027b90f9cbb89ae9f3dfb52bf75bd735626cef57 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 6 Oct 2025 15:11:46 +0000 Subject: [PATCH 138/162] Bump org.hibernate.validator:hibernate-validator Bumps the hibernate-validator group with 1 update: [org.hibernate.validator:hibernate-validator](https://github.com/hibernate/hibernate-validator). Updates `org.hibernate.validator:hibernate-validator` from 8.0.2.Final to 8.0.3.Final - [Changelog](https://github.com/hibernate/hibernate-validator/blob/8.0.3.Final/changelog.txt) - [Commits](https://github.com/hibernate/hibernate-validator/compare/8.0.2.Final...8.0.3.Final) --- updated-dependencies: - dependency-name: org.hibernate.validator:hibernate-validator dependency-version: 8.0.3.Final dependency-type: direct:production update-type: version-update:semver-patch dependency-group: hibernate-validator ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index e7d63c64c..e261c62e9 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -37,7 +37,7 @@ org-glassfish-expressly-expressly = { group = "org.glassfish.expressly", name = org-hibernate-orm-hibernate-core = { group = "org.hibernate.orm", name = "hibernate-core", version.ref = "hibernateOrmVersion" } org-hibernate-orm-hibernate-jcache = { group = "org.hibernate.orm", name = "hibernate-jcache", version.ref = "hibernateOrmVersion" } org-hibernate-orm-hibernate-jpamodelgen = { group = "org.hibernate.orm", name = "hibernate-jpamodelgen", version.ref = "hibernateOrmVersion" } -org-hibernate-validator-hibernate-validator = { group = "org.hibernate.validator", name = "hibernate-validator", version = "8.0.2.Final" } +org-hibernate-validator-hibernate-validator = { group = "org.hibernate.validator", name = "hibernate-validator", version = "8.0.3.Final" } org-jboss-logging-jboss-logging = { group = "org.jboss.logging", name = "jboss-logging", version.ref = "jbossLoggingVersion" } org-jboss-logging-jboss-logging-annotations = { group = "org.jboss.logging", name = "jboss-logging-annotations", version.ref = "jbossLoggingAnnotationVersion" } org-jboss-logging-jboss-logging-processor = { group = "org.jboss.logging", name = "jboss-logging-processor", version.ref = "jbossLoggingAnnotationVersion" } From f722a94205cfdd39eb93e2a285ebe437211a3a78 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 6 Oct 2025 15:12:51 +0000 Subject: [PATCH 139/162] Bump cockroachdb/cockroach from v25.2.2 to v25.3.2 in /tooling/docker Bumps cockroachdb/cockroach from v25.2.2 to v25.3.2. --- updated-dependencies: - dependency-name: cockroachdb/cockroach dependency-version: v25.3.2 dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- tooling/docker/cockroachdb.Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tooling/docker/cockroachdb.Dockerfile b/tooling/docker/cockroachdb.Dockerfile index 5f92dd720..484d65520 100644 --- a/tooling/docker/cockroachdb.Dockerfile +++ b/tooling/docker/cockroachdb.Dockerfile @@ -1,3 +1,3 @@ # CockroachDB # See https://hub.docker.com/r/cockroachdb/cockroach -FROM docker.io/cockroachdb/cockroach:v25.2.2 +FROM docker.io/cockroachdb/cockroach:v25.3.2 From 835ef03e0b5c60728b3b7e8f7588f7232d8d814e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 6 Oct 2025 15:12:55 +0000 Subject: [PATCH 140/162] Bump mariadb from 11.8.2 to 12.0.2 in /tooling/docker Bumps mariadb from 11.8.2 to 12.0.2. --- updated-dependencies: - dependency-name: mariadb dependency-version: 12.0.2 dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- tooling/docker/maria.Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tooling/docker/maria.Dockerfile b/tooling/docker/maria.Dockerfile index fc954df6e..6aa9bf898 100644 --- a/tooling/docker/maria.Dockerfile +++ b/tooling/docker/maria.Dockerfile @@ -1,3 +1,3 @@ # MariaDB # See https://hub.docker.com/_/mariadb -FROM docker.io/mariadb:11.8.2 +FROM docker.io/mariadb:12.0.2 From 7ccd96b0dc66b3373d86c74986955eb3d1298670 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 6 Oct 2025 15:13:35 +0000 Subject: [PATCH 141/162] Bump postgres from 17.5 to 18.0 in /tooling/docker Bumps postgres from 17.5 to 18.0. --- updated-dependencies: - dependency-name: postgres dependency-version: '18.0' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- tooling/docker/postgresql.Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tooling/docker/postgresql.Dockerfile b/tooling/docker/postgresql.Dockerfile index fb36f48e8..f2daff3c7 100644 --- a/tooling/docker/postgresql.Dockerfile +++ b/tooling/docker/postgresql.Dockerfile @@ -1,3 +1,3 @@ # PostgreSQL # See https://hub.docker.com/_/postgres -FROM docker.io/postgres:17.5 +FROM docker.io/postgres:18.0 From 8b0baa11f6a7a1cda7cdc27bbfa488c286c06b3c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 7 Oct 2025 08:38:44 +0000 Subject: [PATCH 142/162] Bump the testcontainers group with 5 updates Bumps the testcontainers group with 5 updates: | Package | From | To | | --- | --- | --- | | [com.fasterxml.jackson.core:jackson-databind](https://github.com/FasterXML/jackson) | `2.19.2` | `2.20.0` | | [com.microsoft.sqlserver:mssql-jdbc](https://github.com/Microsoft/mssql-jdbc) | `13.1.0.jre11-preview` | `13.2.0.jre11` | | [com.mysql:mysql-connector-j](https://github.com/mysql/mysql-connector-j) | `9.3.0` | `9.4.0` | | [org.mariadb.jdbc:mariadb-java-client](https://github.com/mariadb-corporation/mariadb-connector-j) | `3.5.4` | `3.5.6` | | [org.postgresql:postgresql](https://github.com/pgjdbc/pgjdbc) | `42.7.7` | `42.7.8` | Updates `com.fasterxml.jackson.core:jackson-databind` from 2.19.2 to 2.20.0 - [Commits](https://github.com/FasterXML/jackson/commits) Updates `com.microsoft.sqlserver:mssql-jdbc` from 13.1.0.jre11-preview to 13.2.0.jre11 - [Release notes](https://github.com/Microsoft/mssql-jdbc/releases) - [Changelog](https://github.com/microsoft/mssql-jdbc/blob/main/CHANGELOG.md) - [Commits](https://github.com/Microsoft/mssql-jdbc/commits) Updates `com.mysql:mysql-connector-j` from 9.3.0 to 9.4.0 - [Changelog](https://github.com/mysql/mysql-connector-j/blob/release/9.x/CHANGES) - [Commits](https://github.com/mysql/mysql-connector-j/compare/9.3.0...9.4.0) Updates `org.mariadb.jdbc:mariadb-java-client` from 3.5.4 to 3.5.6 - [Release notes](https://github.com/mariadb-corporation/mariadb-connector-j/releases) - [Changelog](https://github.com/mariadb-corporation/mariadb-connector-j/blob/main/CHANGELOG.md) - [Commits](https://github.com/mariadb-corporation/mariadb-connector-j/compare/3.5.4...3.5.6) Updates `org.postgresql:postgresql` from 42.7.7 to 42.7.8 - [Release notes](https://github.com/pgjdbc/pgjdbc/releases) - [Changelog](https://github.com/pgjdbc/pgjdbc/blob/master/CHANGELOG.md) - [Commits](https://github.com/pgjdbc/pgjdbc/compare/REL42.7.7...REL42.7.8) --- updated-dependencies: - dependency-name: com.fasterxml.jackson.core:jackson-databind dependency-version: 2.20.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: testcontainers - dependency-name: com.microsoft.sqlserver:mssql-jdbc dependency-version: 13.2.0.jre11 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: testcontainers - dependency-name: com.mysql:mysql-connector-j dependency-version: 9.4.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: testcontainers - dependency-name: org.mariadb.jdbc:mariadb-java-client dependency-version: 3.5.6 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: testcontainers - dependency-name: org.postgresql:postgresql dependency-version: 42.7.8 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: testcontainers ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index e261c62e9..597e856dd 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -2,7 +2,7 @@ assertjVersion = "3.27.6" hibernateOrmVersion = "6.6.31.Final" hibernateOrmGradlePluginVersion = "6.6.30.Final" -jacksonDatabindVersion = "2.19.2" +jacksonDatabindVersion = "2.20.0" jbossLoggingAnnotationVersion = "2.2.1.Final" jbossLoggingVersion = "3.5.0.Final" junitVersion = "5.13.3" @@ -16,8 +16,8 @@ vertxWebClientVersion = "4.5.21" [libraries] com-fasterxml-jackson-core-jackson-databind = { group = "com.fasterxml.jackson.core", name = "jackson-databind", version.ref = "jacksonDatabindVersion" } com-ibm-db2-jcc = { group = "com.ibm.db2", name = "jcc", version = "12.1.2.0" } -com-microsoft-sqlserver-mssql-jdbc = { group = "com.microsoft.sqlserver", name = "mssql-jdbc", version = "13.1.0.jre11-preview" } -com-mysql-mysql-connector-j = { group = "com.mysql", name = "mysql-connector-j", version = "9.3.0" } +com-microsoft-sqlserver-mssql-jdbc = { group = "com.microsoft.sqlserver", name = "mssql-jdbc", version = "13.2.0.jre11" } +com-mysql-mysql-connector-j = { group = "com.mysql", name = "mysql-connector-j", version = "9.4.0" } com-ongres-scram-client = { group = "com.ongres.scram", name = "client", version = "2.1" } io-smallrye-reactive-mutiny = { group = "io.smallrye.reactive", name = "mutiny", version = "2.7.0" } io-vertx-vertx-db2-client = { group = "io.vertx", name = "vertx-db2-client", version.ref = "vertxSqlClientVersion" } @@ -44,8 +44,8 @@ org-jboss-logging-jboss-logging-processor = { group = "org.jboss.logging", name org-junit-jupiter-junit-jupiter-api = { group = "org.junit.jupiter", name = "junit-jupiter-api", version.ref = "junitVersion" } org-junit-jupiter-junit-jupiter-engine = { group = "org.junit.jupiter", name = "junit-jupiter-engine", version.ref = "junitVersion" } org-junit-platform-junit-platform-launcher = { group = "org.junit.platform", name = "junit-platform-launcher", version = "junitPlatformVersion" } -org-mariadb-jdbc-mariadb-java-client = { group = "org.mariadb.jdbc", name = "mariadb-java-client", version = "3.5.4" } -org-postgresql-postgresql = { group = "org.postgresql", name = "postgresql", version = "42.7.7" } +org-mariadb-jdbc-mariadb-java-client = { group = "org.mariadb.jdbc", name = "mariadb-java-client", version = "3.5.6" } +org-postgresql-postgresql = { group = "org.postgresql", name = "postgresql", version = "42.7.8" } org-testcontainers-cockroachdb = { group = "org.testcontainers", name = "cockroachdb", version.ref = "testcontainersVersion" } org-testcontainers-db2 = { group = "org.testcontainers", name = "db2", version.ref = "testcontainersVersion" } org-testcontainers-mariadb = { group = "org.testcontainers", name = "mariadb", version.ref = "testcontainersVersion" } From 4baba42ea0cb17eade2f7ebdfcaa6565d06fb57b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 6 Oct 2025 15:14:21 +0000 Subject: [PATCH 143/162] Bump org.apache.logging.log4j:log4j-core from 2.25.1 to 2.25.2 Bumps org.apache.logging.log4j:log4j-core from 2.25.1 to 2.25.2. --- updated-dependencies: - dependency-name: org.apache.logging.log4j:log4j-core dependency-version: 2.25.2 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 597e856dd..409f15a34 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -7,7 +7,7 @@ jbossLoggingAnnotationVersion = "2.2.1.Final" jbossLoggingVersion = "3.5.0.Final" junitVersion = "5.13.3" junitPlatformVersion = "1.13.3" -log4jVersion = "2.25.1" +log4jVersion = "2.25.2" testcontainersVersion = "1.21.3" vertxSqlClientVersion = "4.5.21" vertxWebVersion= "4.5.21" From fe3e85774e6ae33cbfc401c3f0c427c4a17a1c84 Mon Sep 17 00:00:00 2001 From: Davide D'Alto Date: Wed, 8 Oct 2025 17:57:32 +0200 Subject: [PATCH 144/162] Bump jbossLoggingAnnotationVersion from 2.2.1.Final to 3.0.1.Final Same version as the one in Hibernate ORM --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 409f15a34..2fbf99a09 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -3,7 +3,7 @@ assertjVersion = "3.27.6" hibernateOrmVersion = "6.6.31.Final" hibernateOrmGradlePluginVersion = "6.6.30.Final" jacksonDatabindVersion = "2.20.0" -jbossLoggingAnnotationVersion = "2.2.1.Final" +jbossLoggingAnnotationVersion = "3.0.1.Final" jbossLoggingVersion = "3.5.0.Final" junitVersion = "5.13.3" junitPlatformVersion = "1.13.3" From 0e4759e6f624ab7c4407611e1408edc689b88a61 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 14 Oct 2025 03:06:14 +0000 Subject: [PATCH 145/162] Bump the hibernate group with 4 updates Bumps the hibernate group with 4 updates: [org.hibernate.orm:hibernate-core](https://github.com/hibernate/hibernate-orm), [org.hibernate.orm:hibernate-jcache](https://github.com/hibernate/hibernate-orm), [org.hibernate.orm:hibernate-jpamodelgen](https://github.com/hibernate/hibernate-orm) and org.hibernate.orm. Updates `org.hibernate.orm:hibernate-core` from 6.6.31.Final to 6.6.33.Final - [Release notes](https://github.com/hibernate/hibernate-orm/releases) - [Changelog](https://github.com/hibernate/hibernate-orm/blob/6.6.33/changelog.txt) - [Commits](https://github.com/hibernate/hibernate-orm/compare/6.6.31...6.6.33) Updates `org.hibernate.orm:hibernate-jcache` from 6.6.31.Final to 6.6.33.Final - [Release notes](https://github.com/hibernate/hibernate-orm/releases) - [Changelog](https://github.com/hibernate/hibernate-orm/blob/6.6.33/changelog.txt) - [Commits](https://github.com/hibernate/hibernate-orm/compare/6.6.31...6.6.33) Updates `org.hibernate.orm:hibernate-jpamodelgen` from 6.6.31.Final to 6.6.33.Final - [Release notes](https://github.com/hibernate/hibernate-orm/releases) - [Changelog](https://github.com/hibernate/hibernate-orm/blob/6.6.33/changelog.txt) - [Commits](https://github.com/hibernate/hibernate-orm/compare/6.6.31...6.6.33) Updates `org.hibernate.orm:hibernate-jcache` from 6.6.31.Final to 6.6.33.Final - [Release notes](https://github.com/hibernate/hibernate-orm/releases) - [Changelog](https://github.com/hibernate/hibernate-orm/blob/6.6.33/changelog.txt) - [Commits](https://github.com/hibernate/hibernate-orm/compare/6.6.31...6.6.33) Updates `org.hibernate.orm:hibernate-jpamodelgen` from 6.6.31.Final to 6.6.33.Final - [Release notes](https://github.com/hibernate/hibernate-orm/releases) - [Changelog](https://github.com/hibernate/hibernate-orm/blob/6.6.33/changelog.txt) - [Commits](https://github.com/hibernate/hibernate-orm/compare/6.6.31...6.6.33) Updates `org.hibernate.orm` from 6.6.30.Final to 6.6.33.Final --- updated-dependencies: - dependency-name: org.hibernate.orm:hibernate-core dependency-version: 6.6.33.Final dependency-type: direct:production update-type: version-update:semver-patch dependency-group: hibernate - dependency-name: org.hibernate.orm:hibernate-jcache dependency-version: 6.6.33.Final dependency-type: direct:production update-type: version-update:semver-patch dependency-group: hibernate - dependency-name: org.hibernate.orm:hibernate-jpamodelgen dependency-version: 6.6.33.Final dependency-type: direct:production update-type: version-update:semver-patch dependency-group: hibernate - dependency-name: org.hibernate.orm:hibernate-jcache dependency-version: 6.6.33.Final dependency-type: direct:production update-type: version-update:semver-patch dependency-group: hibernate - dependency-name: org.hibernate.orm:hibernate-jpamodelgen dependency-version: 6.6.33.Final dependency-type: direct:production update-type: version-update:semver-patch dependency-group: hibernate - dependency-name: org.hibernate.orm dependency-version: 6.6.33.Final dependency-type: direct:production update-type: version-update:semver-patch dependency-group: hibernate ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 2fbf99a09..53e55e94b 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,7 +1,7 @@ [versions] assertjVersion = "3.27.6" -hibernateOrmVersion = "6.6.31.Final" -hibernateOrmGradlePluginVersion = "6.6.30.Final" +hibernateOrmVersion = "6.6.33.Final" +hibernateOrmGradlePluginVersion = "6.6.33.Final" jacksonDatabindVersion = "2.20.0" jbossLoggingAnnotationVersion = "3.0.1.Final" jbossLoggingVersion = "3.5.0.Final" From 06545ffac05ed8abf2df048558d9830c408a8198 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 14 Oct 2025 03:06:38 +0000 Subject: [PATCH 146/162] Bump com.microsoft.sqlserver:mssql-jdbc in the testcontainers group Bumps the testcontainers group with 1 update: [com.microsoft.sqlserver:mssql-jdbc](https://github.com/Microsoft/mssql-jdbc). Updates `com.microsoft.sqlserver:mssql-jdbc` from 13.2.0.jre11 to 13.2.1.jre11 - [Release notes](https://github.com/Microsoft/mssql-jdbc/releases) - [Changelog](https://github.com/microsoft/mssql-jdbc/blob/main/CHANGELOG.md) - [Commits](https://github.com/Microsoft/mssql-jdbc/commits) --- updated-dependencies: - dependency-name: com.microsoft.sqlserver:mssql-jdbc dependency-version: 13.2.1.jre11 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: testcontainers ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 53e55e94b..9a03c8437 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -16,7 +16,7 @@ vertxWebClientVersion = "4.5.21" [libraries] com-fasterxml-jackson-core-jackson-databind = { group = "com.fasterxml.jackson.core", name = "jackson-databind", version.ref = "jacksonDatabindVersion" } com-ibm-db2-jcc = { group = "com.ibm.db2", name = "jcc", version = "12.1.2.0" } -com-microsoft-sqlserver-mssql-jdbc = { group = "com.microsoft.sqlserver", name = "mssql-jdbc", version = "13.2.0.jre11" } +com-microsoft-sqlserver-mssql-jdbc = { group = "com.microsoft.sqlserver", name = "mssql-jdbc", version = "13.2.1.jre11" } com-mysql-mysql-connector-j = { group = "com.mysql", name = "mysql-connector-j", version = "9.4.0" } com-ongres-scram-client = { group = "com.ongres.scram", name = "client", version = "2.1" } io-smallrye-reactive-mutiny = { group = "io.smallrye.reactive", name = "mutiny", version = "2.7.0" } From 3d53ca8c9667142c208a9403ac1f726e476f307f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 23 Oct 2025 09:59:59 +0000 Subject: [PATCH 147/162] Bump the vertx group with 10 updates Bumps the vertx group with 10 updates: | Package | From | To | | --- | --- | --- | | [io.vertx:vertx-db2-client](https://github.com/eclipse-vertx/vertx-sql-client) | `4.5.21` | `4.5.22` | | [io.vertx:vertx-junit5](https://github.com/eclipse-vertx/vertx-junit5) | `4.5.21` | `4.5.22` | | [io.vertx:vertx-micrometer-metrics](https://github.com/vert-x3/vertx-micrometer-metrics) | `4.5.21` | `4.5.22` | | [io.vertx:vertx-mssql-client](https://github.com/eclipse-vertx/vertx-sql-client) | `4.5.21` | `4.5.22` | | [io.vertx:vertx-mysql-client](https://github.com/eclipse-vertx/vertx-sql-client) | `4.5.21` | `4.5.22` | | [io.vertx:vertx-oracle-client](https://github.com/eclipse-vertx/vertx-sql-client) | `4.5.21` | `4.5.22` | | [io.vertx:vertx-pg-client](https://github.com/eclipse-vertx/vertx-sql-client) | `4.5.21` | `4.5.22` | | [io.vertx:vertx-sql-client](https://github.com/eclipse-vertx/vertx-sql-client) | `4.5.21` | `4.5.22` | | [io.vertx:vertx-web](https://github.com/vert-x3/vertx-web) | `4.5.21` | `4.5.22` | | [io.vertx:vertx-web-client](https://github.com/vert-x3/vertx-web) | `4.5.21` | `4.5.22` | Updates `io.vertx:vertx-db2-client` from 4.5.21 to 4.5.22 - [Commits](https://github.com/eclipse-vertx/vertx-sql-client/compare/4.5.21...4.5.22) Updates `io.vertx:vertx-junit5` from 4.5.21 to 4.5.22 - [Commits](https://github.com/eclipse-vertx/vertx-junit5/compare/4.5.21...4.5.22) Updates `io.vertx:vertx-micrometer-metrics` from 4.5.21 to 4.5.22 - [Commits](https://github.com/vert-x3/vertx-micrometer-metrics/compare/4.5.21...4.5.22) Updates `io.vertx:vertx-mssql-client` from 4.5.21 to 4.5.22 - [Commits](https://github.com/eclipse-vertx/vertx-sql-client/compare/4.5.21...4.5.22) Updates `io.vertx:vertx-mysql-client` from 4.5.21 to 4.5.22 - [Commits](https://github.com/eclipse-vertx/vertx-sql-client/compare/4.5.21...4.5.22) Updates `io.vertx:vertx-oracle-client` from 4.5.21 to 4.5.22 - [Commits](https://github.com/eclipse-vertx/vertx-sql-client/compare/4.5.21...4.5.22) Updates `io.vertx:vertx-pg-client` from 4.5.21 to 4.5.22 - [Commits](https://github.com/eclipse-vertx/vertx-sql-client/compare/4.5.21...4.5.22) Updates `io.vertx:vertx-sql-client` from 4.5.21 to 4.5.22 - [Commits](https://github.com/eclipse-vertx/vertx-sql-client/compare/4.5.21...4.5.22) Updates `io.vertx:vertx-junit5` from 4.5.21 to 4.5.22 - [Commits](https://github.com/eclipse-vertx/vertx-junit5/compare/4.5.21...4.5.22) Updates `io.vertx:vertx-micrometer-metrics` from 4.5.21 to 4.5.22 - [Commits](https://github.com/vert-x3/vertx-micrometer-metrics/compare/4.5.21...4.5.22) Updates `io.vertx:vertx-mssql-client` from 4.5.21 to 4.5.22 - [Commits](https://github.com/eclipse-vertx/vertx-sql-client/compare/4.5.21...4.5.22) Updates `io.vertx:vertx-mysql-client` from 4.5.21 to 4.5.22 - [Commits](https://github.com/eclipse-vertx/vertx-sql-client/compare/4.5.21...4.5.22) Updates `io.vertx:vertx-oracle-client` from 4.5.21 to 4.5.22 - [Commits](https://github.com/eclipse-vertx/vertx-sql-client/compare/4.5.21...4.5.22) Updates `io.vertx:vertx-pg-client` from 4.5.21 to 4.5.22 - [Commits](https://github.com/eclipse-vertx/vertx-sql-client/compare/4.5.21...4.5.22) Updates `io.vertx:vertx-sql-client` from 4.5.21 to 4.5.22 - [Commits](https://github.com/eclipse-vertx/vertx-sql-client/compare/4.5.21...4.5.22) Updates `io.vertx:vertx-web` from 4.5.21 to 4.5.22 - [Commits](https://github.com/vert-x3/vertx-web/compare/4.5.21...4.5.22) Updates `io.vertx:vertx-web-client` from 4.5.21 to 4.5.22 - [Commits](https://github.com/vert-x3/vertx-web/compare/4.5.21...4.5.22) --- updated-dependencies: - dependency-name: io.vertx:vertx-db2-client dependency-version: 4.5.22 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: vertx - dependency-name: io.vertx:vertx-junit5 dependency-version: 4.5.22 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: vertx - dependency-name: io.vertx:vertx-micrometer-metrics dependency-version: 4.5.22 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: vertx - dependency-name: io.vertx:vertx-mssql-client dependency-version: 4.5.22 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: vertx - dependency-name: io.vertx:vertx-mysql-client dependency-version: 4.5.22 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: vertx - dependency-name: io.vertx:vertx-oracle-client dependency-version: 4.5.22 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: vertx - dependency-name: io.vertx:vertx-pg-client dependency-version: 4.5.22 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: vertx - dependency-name: io.vertx:vertx-sql-client dependency-version: 4.5.22 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: vertx - dependency-name: io.vertx:vertx-junit5 dependency-version: 4.5.22 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: vertx - dependency-name: io.vertx:vertx-micrometer-metrics dependency-version: 4.5.22 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: vertx - dependency-name: io.vertx:vertx-mssql-client dependency-version: 4.5.22 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: vertx - dependency-name: io.vertx:vertx-mysql-client dependency-version: 4.5.22 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: vertx - dependency-name: io.vertx:vertx-oracle-client dependency-version: 4.5.22 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: vertx - dependency-name: io.vertx:vertx-pg-client dependency-version: 4.5.22 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: vertx - dependency-name: io.vertx:vertx-sql-client dependency-version: 4.5.22 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: vertx - dependency-name: io.vertx:vertx-web dependency-version: 4.5.22 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: vertx - dependency-name: io.vertx:vertx-web-client dependency-version: 4.5.22 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: vertx ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 9a03c8437..02c7743cb 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -9,9 +9,9 @@ junitVersion = "5.13.3" junitPlatformVersion = "1.13.3" log4jVersion = "2.25.2" testcontainersVersion = "1.21.3" -vertxSqlClientVersion = "4.5.21" -vertxWebVersion= "4.5.21" -vertxWebClientVersion = "4.5.21" +vertxSqlClientVersion = "4.5.22" +vertxWebVersion= "4.5.22" +vertxWebClientVersion = "4.5.22" [libraries] com-fasterxml-jackson-core-jackson-databind = { group = "com.fasterxml.jackson.core", name = "jackson-databind", version.ref = "jacksonDatabindVersion" } From ffef15a4d57c08bdea94be495508005ddc6cca2b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 23 Oct 2025 09:57:08 +0000 Subject: [PATCH 148/162] Bump cockroachdb/cockroach from v25.3.2 to v25.3.3 in /tooling/docker Bumps cockroachdb/cockroach from v25.3.2 to v25.3.3. --- updated-dependencies: - dependency-name: cockroachdb/cockroach dependency-version: v25.3.3 dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- tooling/docker/cockroachdb.Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tooling/docker/cockroachdb.Dockerfile b/tooling/docker/cockroachdb.Dockerfile index 484d65520..86f837a83 100644 --- a/tooling/docker/cockroachdb.Dockerfile +++ b/tooling/docker/cockroachdb.Dockerfile @@ -1,3 +1,3 @@ # CockroachDB # See https://hub.docker.com/r/cockroachdb/cockroach -FROM docker.io/cockroachdb/cockroach:v25.3.2 +FROM docker.io/cockroachdb/cockroach:v25.3.3 From 5058566099af27c1582811c9b3ea7ac50a1bb2c1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 27 Oct 2025 03:54:47 +0000 Subject: [PATCH 149/162] Bump mysql/community-server from 9.4.0 to 9.5.0 in /tooling/docker Bumps mysql/community-server from 9.4.0 to 9.5.0. --- updated-dependencies: - dependency-name: mysql/community-server dependency-version: 9.5.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- tooling/docker/mysql.Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tooling/docker/mysql.Dockerfile b/tooling/docker/mysql.Dockerfile index 897fbd5ee..03918b8e3 100644 --- a/tooling/docker/mysql.Dockerfile +++ b/tooling/docker/mysql.Dockerfile @@ -1,3 +1,3 @@ # MySQL # See https://hub.docker.com/_/mysql -FROM container-registry.oracle.com/mysql/community-server:9.4.0 +FROM container-registry.oracle.com/mysql/community-server:9.5.0 From 06203516af1ea25e8138360d0fa2149d66b078d0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 28 Oct 2025 03:08:07 +0000 Subject: [PATCH 150/162] Bump the hibernate group with 4 updates Bumps the hibernate group with 4 updates: [org.hibernate.orm:hibernate-core](https://github.com/hibernate/hibernate-orm), [org.hibernate.orm:hibernate-jcache](https://github.com/hibernate/hibernate-orm), [org.hibernate.orm:hibernate-jpamodelgen](https://github.com/hibernate/hibernate-orm) and org.hibernate.orm. Updates `org.hibernate.orm:hibernate-core` from 6.6.33.Final to 6.6.34.Final - [Release notes](https://github.com/hibernate/hibernate-orm/releases) - [Changelog](https://github.com/hibernate/hibernate-orm/blob/6.6.34/changelog.txt) - [Commits](https://github.com/hibernate/hibernate-orm/compare/6.6.33...6.6.34) Updates `org.hibernate.orm:hibernate-jcache` from 6.6.33.Final to 6.6.34.Final - [Release notes](https://github.com/hibernate/hibernate-orm/releases) - [Changelog](https://github.com/hibernate/hibernate-orm/blob/6.6.34/changelog.txt) - [Commits](https://github.com/hibernate/hibernate-orm/compare/6.6.33...6.6.34) Updates `org.hibernate.orm:hibernate-jpamodelgen` from 6.6.33.Final to 6.6.34.Final - [Release notes](https://github.com/hibernate/hibernate-orm/releases) - [Changelog](https://github.com/hibernate/hibernate-orm/blob/6.6.34/changelog.txt) - [Commits](https://github.com/hibernate/hibernate-orm/compare/6.6.33...6.6.34) Updates `org.hibernate.orm:hibernate-jcache` from 6.6.33.Final to 6.6.34.Final - [Release notes](https://github.com/hibernate/hibernate-orm/releases) - [Changelog](https://github.com/hibernate/hibernate-orm/blob/6.6.34/changelog.txt) - [Commits](https://github.com/hibernate/hibernate-orm/compare/6.6.33...6.6.34) Updates `org.hibernate.orm:hibernate-jpamodelgen` from 6.6.33.Final to 6.6.34.Final - [Release notes](https://github.com/hibernate/hibernate-orm/releases) - [Changelog](https://github.com/hibernate/hibernate-orm/blob/6.6.34/changelog.txt) - [Commits](https://github.com/hibernate/hibernate-orm/compare/6.6.33...6.6.34) Updates `org.hibernate.orm` from 6.6.33.Final to 6.6.34.Final --- updated-dependencies: - dependency-name: org.hibernate.orm:hibernate-core dependency-version: 6.6.34.Final dependency-type: direct:production update-type: version-update:semver-patch dependency-group: hibernate - dependency-name: org.hibernate.orm:hibernate-jcache dependency-version: 6.6.34.Final dependency-type: direct:production update-type: version-update:semver-patch dependency-group: hibernate - dependency-name: org.hibernate.orm:hibernate-jpamodelgen dependency-version: 6.6.34.Final dependency-type: direct:production update-type: version-update:semver-patch dependency-group: hibernate - dependency-name: org.hibernate.orm:hibernate-jcache dependency-version: 6.6.34.Final dependency-type: direct:production update-type: version-update:semver-patch dependency-group: hibernate - dependency-name: org.hibernate.orm:hibernate-jpamodelgen dependency-version: 6.6.34.Final dependency-type: direct:production update-type: version-update:semver-patch dependency-group: hibernate - dependency-name: org.hibernate.orm dependency-version: 6.6.34.Final dependency-type: direct:production update-type: version-update:semver-patch dependency-group: hibernate ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 02c7743cb..11eea918e 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,7 +1,7 @@ [versions] assertjVersion = "3.27.6" -hibernateOrmVersion = "6.6.33.Final" -hibernateOrmGradlePluginVersion = "6.6.33.Final" +hibernateOrmVersion = "6.6.34.Final" +hibernateOrmGradlePluginVersion = "6.6.34.Final" jacksonDatabindVersion = "2.20.0" jbossLoggingAnnotationVersion = "3.0.1.Final" jbossLoggingVersion = "3.5.0.Final" From 564be1ea6f9b5ac39713ce972b095e296562bc1f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 28 Oct 2025 03:08:27 +0000 Subject: [PATCH 151/162] Bump com.mysql:mysql-connector-j in the testcontainers group Bumps the testcontainers group with 1 update: [com.mysql:mysql-connector-j](https://github.com/mysql/mysql-connector-j). Updates `com.mysql:mysql-connector-j` from 9.4.0 to 9.5.0 - [Changelog](https://github.com/mysql/mysql-connector-j/blob/release/9.x/CHANGES) - [Commits](https://github.com/mysql/mysql-connector-j/compare/9.4.0...9.5.0) --- updated-dependencies: - dependency-name: com.mysql:mysql-connector-j dependency-version: 9.5.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: testcontainers ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 11eea918e..712e82360 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -17,7 +17,7 @@ vertxWebClientVersion = "4.5.22" com-fasterxml-jackson-core-jackson-databind = { group = "com.fasterxml.jackson.core", name = "jackson-databind", version.ref = "jacksonDatabindVersion" } com-ibm-db2-jcc = { group = "com.ibm.db2", name = "jcc", version = "12.1.2.0" } com-microsoft-sqlserver-mssql-jdbc = { group = "com.microsoft.sqlserver", name = "mssql-jdbc", version = "13.2.1.jre11" } -com-mysql-mysql-connector-j = { group = "com.mysql", name = "mysql-connector-j", version = "9.4.0" } +com-mysql-mysql-connector-j = { group = "com.mysql", name = "mysql-connector-j", version = "9.5.0" } com-ongres-scram-client = { group = "com.ongres.scram", name = "client", version = "2.1" } io-smallrye-reactive-mutiny = { group = "io.smallrye.reactive", name = "mutiny", version = "2.7.0" } io-vertx-vertx-db2-client = { group = "io.vertx", name = "vertx-db2-client", version.ref = "vertxSqlClientVersion" } From 004c675f501b3d514185e6e91601d4c80fd5d6ce Mon Sep 17 00:00:00 2001 From: Davide D'Alto Date: Tue, 28 Oct 2025 12:17:22 +0100 Subject: [PATCH 152/162] [#2570] No longer publish docs to https://hibernate.org --- release/build.gradle | 94 +++----------------------------------------- 1 file changed, 5 insertions(+), 89 deletions(-) diff --git a/release/build.gradle b/release/build.gradle index 00b43d2f4..25163e6e9 100644 --- a/release/build.gradle +++ b/release/build.gradle @@ -1,28 +1,13 @@ import java.nio.charset.StandardCharsets -ext { - // Select which repository to use for publishing the documentation - // Example: - // ./gradlew uploadDocumentation \ - // -PdocPublishRepoUri="git@github.com:DavideD/hibernate.org.git" \ - // -PdocPublishBranch="staging" - if ( !project.hasProperty('docPublishRepoUri') ) { - docPublishRepoUri = 'git@github.com:hibernate/hibernate.org.git' - } - if ( !project.hasProperty('docPublishBranch') ) { - docPublishBranch = 'staging' - } -} - description = 'Release module' // (Optional) before uploading the documentation, you can check // the generated website under release/build/hibernate.org with: // ./gradlew gitPublishCopy -// To publish the documentation: -// 1. Add the relevant SSH key to your SSH agent. -// 2. Execute this: -// ./gradlew uploadDocumentation -PdocPublishBranch=production +// The generated documentation are copied to the +// rootProject.layout.buildDirectory.dir("staging-deploy/documentation") by the updateDocumentationTask +// while the publishing is delegated to the https://github.com/hibernate/hibernate-release-scripts // To tag a version and trigger a release on CI (which will include publishing to Bintray and publishing documentation): // ./gradlew ciRelease -PreleaseVersion=x.y.z.Final -PdevelopmentVersion=x.y.z-SNAPSHOT -PgitRemote=origin -PgitBranch=main @@ -33,9 +18,6 @@ final Directory documentationDir = project(":documentation").layout.buildDirecto // Relative path on the static website where the documentation is located final String docWebsiteRelativePath = "reactive/documentation/${projectVersion.family}" -// The location of the docs when the website has been cloned -final Directory docWebsiteReactiveFolder = project.layout.buildDirectory.dir( "docs-website/${docWebsiteRelativePath}" ).get() - def releaseChecksTask = tasks.register( "releaseChecks" ) { description 'Checks and preparation for release' group 'Release' @@ -98,30 +80,6 @@ def assembleDocumentationTask = tasks.register( 'assembleDocumentation' ) { } assemble.dependsOn assembleDocumentationTask -/** -* Clone the website -*/ -def removeDocsWebsiteTask = tasks.register( 'removeDocsWebsite', Delete ) { - delete project.layout.buildDirectory.dir( "docs-website" ) -} - -def cloneDocsWebsiteTask = tasks.register( 'cloneDocsWebsite', Exec ) { - dependsOn removeDocsWebsiteTask - // Assure that the buildDir exists. Otherwise this task will fail. - dependsOn compileJava - workingDir project.layout.buildDirectory - commandLine 'git', 'clone', docPublishRepoUri, '-b', docPublishBranch, '--sparse', '--depth', '1', 'docs-website' -} - -def sparseCheckoutDocumentationTask = tasks.register( 'sparseCheckoutDocumentation', Exec ) { - dependsOn cloneDocsWebsiteTask - workingDir project.layout.buildDirectory.dir( "docs-website" ) - commandLine 'git', 'sparse-checkout', 'set', docWebsiteRelativePath -} - -/** -* Update the docs on the cloned website -*/ def changeToReleaseVersionTask = tasks.register( 'changeToReleaseVersion' ) { description 'Updates `gradle/version.properties` file to the specified release-version' group 'Release' @@ -136,7 +94,7 @@ def changeToReleaseVersionTask = tasks.register( 'changeToReleaseVersion' ) { def updateDocumentationTask = tasks.register( 'updateDocumentation' ) { description "Update the documentation on the cloned static website" - dependsOn assembleDocumentationTask, sparseCheckoutDocumentationTask + dependsOn assembleDocumentationTask mustRunAfter changeToReleaseVersion // copy documentation outputs into target/documentation: @@ -144,26 +102,13 @@ def updateDocumentationTask = tasks.register( 'updateDocumentation' ) { // * it is also used as a base to build a staged directory for documentation upload doLast { - // delete the folders in case some files have been removed - delete docWebsiteReactiveFolder.dir("javadocs"), docWebsiteReactiveFolder.dir("reference") - // Aggregated JavaDoc - copy { - from documentationDir.dir("javadocs") - into docWebsiteReactiveFolder.dir("javadocs") - } - copy { from documentationDir.dir("javadocs") into rootProject.layout.buildDirectory.dir("staging-deploy/documentation/javadocs") } // Reference Documentation - copy { - from documentationDir.dir("asciidoc/reference/html_single") - into docWebsiteReactiveFolder.dir("reference/html_single") - } - copy { from documentationDir.dir("asciidoc/reference/html_single") into rootProject.layout.buildDirectory.dir("staging-deploy/documentation/reference/html_single") @@ -171,35 +116,6 @@ def updateDocumentationTask = tasks.register( 'updateDocumentation' ) { } } -def stageDocChangesTask = tasks.register( 'stageDocChanges', Exec ) { - dependsOn updateDocumentationTask - workingDir project.layout.buildDirectory.dir( "docs-website" ) - commandLine 'git', 'add', '-A', '.' -} - -def commitDocChangesTask = tasks.register( 'commitDocChanges', Exec ) { - dependsOn stageDocChangesTask - workingDir project.layout.buildDirectory.dir( "docs-website" ) - commandLine 'git', 'commit', '-m', "[HR] Hibernate Reactive documentation for ${projectVersion}" -} - -def pushDocChangesTask = tasks.register( 'pushDocChanges', Exec ) { - description "Push documentation changes on the remote repository" - dependsOn commitDocChangesTask - workingDir project.layout.buildDirectory.dir( "docs-website" ) - commandLine 'git', 'push', '--atomic', 'origin', docPublishBranch -} - -def uploadDocumentationTask = tasks.register( 'uploadDocumentation' ) { - description "Upload documentation on the website" - group "Release" - dependsOn pushDocChangesTask - - doLast { - logger.lifecycle "Documentation published on '${docPublishRepoUri}' branch '${docPublishBranch}'" - } -} - def gitPreparationForReleaseTask = tasks.register( 'gitPreparationForRelease' ) { dependsOn releaseChecksTask, changeToReleaseVersionTask finalizedBy updateDocumentationTask @@ -245,7 +161,7 @@ void updateVersionFile(var version) { } def publishReleaseArtifactsTask = tasks.register( 'publishReleaseArtifacts' ) { - dependsOn uploadDocumentationTask + dependsOn updateDocumentationTask mustRunAfter gitPreparationForReleaseTask } From 0e31b72f0d0f5c7f01022bbfe07757404643f178 Mon Sep 17 00:00:00 2001 From: Davide D'Alto Date: Thu, 30 Oct 2025 14:57:15 +0100 Subject: [PATCH 153/162] [#2666] Test insert with StatelessSession and emebedded id --- .../java/org/hibernate/reactive/EmbeddedIdTest.java | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/hibernate-reactive-core/src/test/java/org/hibernate/reactive/EmbeddedIdTest.java b/hibernate-reactive-core/src/test/java/org/hibernate/reactive/EmbeddedIdTest.java index de3590fab..14ac0d56f 100644 --- a/hibernate-reactive-core/src/test/java/org/hibernate/reactive/EmbeddedIdTest.java +++ b/hibernate-reactive-core/src/test/java/org/hibernate/reactive/EmbeddedIdTest.java @@ -42,6 +42,19 @@ public void populateDb(VertxTestContext context) { test( context, getMutinySessionFactory().withTransaction( s -> s.persistAll( pizza, schnitzel ) ) ); } + @Test + public void testStatelessInsert(VertxTestContext context) { + LocationId nottingham = new LocationId( "UK", "Nottingham" ); + Delivery mushyPeas = new Delivery( nottingham, "Mushy Peas with mint sauce" ); + test( context, getMutinySessionFactory() + .withStatelessTransaction( s -> s.insert( mushyPeas ) ) + .chain( () -> getMutinySessionFactory() + .withTransaction( s -> s.find( Delivery.class, nottingham ) ) + ) + .invoke( result -> assertThat( result ).isEqualTo( mushyPeas ) ) + ); + } + @Test public void testFindSingleId(VertxTestContext context) { test( context, getMutinySessionFactory().withTransaction( s -> s.find( Delivery.class, verbania ) ) From 6e8d1e2ccbf80bd6e5c9077af346931e6a5c575f Mon Sep 17 00:00:00 2001 From: Davide D'Alto Date: Fri, 31 Oct 2025 14:26:28 +0100 Subject: [PATCH 154/162] [#2699] Make sure to close the connection in case of error I've tested it while working on #2518, but I don't know how to create an isolated test. --- .../hibernate/reactive/logging/impl/Log.java | 4 ++++ .../session/impl/ReactiveSessionImpl.java | 21 +++++++++++++++++-- 2 files changed, 23 insertions(+), 2 deletions(-) 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 7e19c58f3..03fd83457 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 @@ -262,6 +262,10 @@ public interface Log extends BasicLogger { @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(); + @LogMessage(level = ERROR) + @Message(id = 86, value = "Error closing reactive connection") + void errorClosingConnection(@Cause Throwable throwable); + // Same method that exists in CoreMessageLogger @LogMessage(level = WARN) @Message(id = 104, value = "firstResult/maxResults specified with collection fetch; applying in memory!" ) diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/session/impl/ReactiveSessionImpl.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/session/impl/ReactiveSessionImpl.java index f3a24808d..a46185772 100644 --- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/session/impl/ReactiveSessionImpl.java +++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/session/impl/ReactiveSessionImpl.java @@ -135,6 +135,7 @@ import static org.hibernate.reactive.persister.entity.impl.ReactiveEntityPersister.forceInitialize; import static org.hibernate.reactive.session.impl.SessionUtil.checkEntityFound; import static org.hibernate.reactive.util.impl.CompletionStages.completedFuture; +import static org.hibernate.reactive.util.impl.CompletionStages.failedFuture; import static org.hibernate.reactive.util.impl.CompletionStages.nullFuture; import static org.hibernate.reactive.util.impl.CompletionStages.rethrow; import static org.hibernate.reactive.util.impl.CompletionStages.returnNullorRethrow; @@ -963,7 +964,7 @@ public CompletionStage reactiveForceFlush(EntityEntry entry) { } if ( getPersistenceContextInternal().getCascadeLevel() > 0 ) { - return CompletionStages.failedFuture( new ObjectDeletedException( + return failedFuture( new ObjectDeletedException( "deleted object would be re-saved by cascade (remove deleted object from associations)", entry.getId(), entry.getPersister().getEntityName() @@ -1616,7 +1617,23 @@ public void close() throws HibernateException { @Override public CompletionStage reactiveClose() { - super.close(); + try { + super.close(); + return closeConnection(); + } + catch (RuntimeException e) { + return closeConnection() + .handle( CompletionStages::handle ) + .thenCompose( closeConnectionHandler -> { + if ( closeConnectionHandler.hasFailed() ) { + LOG.errorClosingConnection( closeConnectionHandler.getThrowable() ); + } + return failedFuture( e ); + } ); + } + } + + private CompletionStage closeConnection() { return reactiveConnection != null ? reactiveConnection.close() : voidFuture(); From c198d00c8e7de66376ea74a5e66c7fdce0bcf874 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 3 Nov 2025 03:47:06 +0000 Subject: [PATCH 155/162] Bump cockroachdb/cockroach from v25.3.3 to v25.3.4 in /tooling/docker Bumps cockroachdb/cockroach from v25.3.3 to v25.3.4. --- updated-dependencies: - dependency-name: cockroachdb/cockroach dependency-version: v25.3.4 dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- tooling/docker/cockroachdb.Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tooling/docker/cockroachdb.Dockerfile b/tooling/docker/cockroachdb.Dockerfile index 86f837a83..0b441f7ca 100644 --- a/tooling/docker/cockroachdb.Dockerfile +++ b/tooling/docker/cockroachdb.Dockerfile @@ -1,3 +1,3 @@ # CockroachDB # See https://hub.docker.com/r/cockroachdb/cockroach -FROM docker.io/cockroachdb/cockroach:v25.3.3 +FROM docker.io/cockroachdb/cockroach:v25.3.4 From 256332672525e09f701479e7bace2b1ad2eac61c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 4 Nov 2025 03:06:14 +0000 Subject: [PATCH 156/162] Bump com.fasterxml.jackson.core:jackson-databind Bumps the testcontainers group with 1 update: [com.fasterxml.jackson.core:jackson-databind](https://github.com/FasterXML/jackson). Updates `com.fasterxml.jackson.core:jackson-databind` from 2.20.0 to 2.20.1 - [Commits](https://github.com/FasterXML/jackson/commits) --- updated-dependencies: - dependency-name: com.fasterxml.jackson.core:jackson-databind dependency-version: 2.20.1 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: testcontainers ... Signed-off-by: dependabot[bot] --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 712e82360..00dcf0fbb 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -2,7 +2,7 @@ assertjVersion = "3.27.6" hibernateOrmVersion = "6.6.34.Final" hibernateOrmGradlePluginVersion = "6.6.34.Final" -jacksonDatabindVersion = "2.20.0" +jacksonDatabindVersion = "2.20.1" jbossLoggingAnnotationVersion = "3.0.1.Final" jbossLoggingVersion = "3.5.0.Final" junitVersion = "5.13.3" From 370f65aac81d2805247d459df336ad31c7234a9f Mon Sep 17 00:00:00 2001 From: Davide D'Alto Date: Fri, 7 Nov 2025 09:44:29 +0100 Subject: [PATCH 157/162] [#2738] Return the correct column data type for Oracle The Oracle schema extractor is only partially implemented, returning data type 0 for most of the SQL column types. This causes the schema validation to fail even if the columns on the table are valid. --- ...leSqlReactiveInformationExtractorImpl.java | 43 ++++++++++++++++--- 1 file changed, 38 insertions(+), 5 deletions(-) diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/provider/service/OracleSqlReactiveInformationExtractorImpl.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/provider/service/OracleSqlReactiveInformationExtractorImpl.java index 67852da79..21f2a0dc1 100644 --- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/provider/service/OracleSqlReactiveInformationExtractorImpl.java +++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/provider/service/OracleSqlReactiveInformationExtractorImpl.java @@ -185,12 +185,45 @@ protected String getResultSetIsNullableLabel() { @Override protected int dataTypeCode(String typeName) { - // ORACLE only supports "float" sql type for double precision - // so return code for double for both double and float column types - if ( typeName.equalsIgnoreCase( "float" ) || - typeName.toLowerCase().startsWith( "double" ) ) { + if ( typeName.equalsIgnoreCase( "float" ) + || typeName.toLowerCase().startsWith( "double" ) + || typeName.equalsIgnoreCase( "binary_double" ) ) { return Types.DOUBLE; } - return super.dataTypeCode( typeName ); + if ( typeName.equalsIgnoreCase( "timestamp" ) ) { + return Types.TIMESTAMP; + } + if ( typeName.equalsIgnoreCase( "timestamp with time zone" ) + || typeName.equalsIgnoreCase( "timestamp with local time zone" ) ) { + return Types.TIMESTAMP_WITH_TIMEZONE; + } + if ( typeName.equalsIgnoreCase( "clob" ) ) { + return Types.CLOB; + } + if ( typeName.equalsIgnoreCase( "blob" ) ) { + return Types.BLOB; + } + if ( typeName.equalsIgnoreCase( "raw" ) ) { + return Types.VARBINARY; + } + if ( typeName.equalsIgnoreCase( "long raw" ) ) { + return Types.LONGVARBINARY; + } + if ( typeName.equalsIgnoreCase( "ref cursor" ) ) { + return Types.REF_CURSOR; + } + if ( typeName.equalsIgnoreCase( "number" ) ) { + return Types.NUMERIC; + } + if ( typeName.equalsIgnoreCase( "date" ) ) { + return Types.DATE; + } + if ( typeName.equalsIgnoreCase( "nvarchar2" ) ) { + return Types.NVARCHAR; + } + if ( typeName.equalsIgnoreCase( "varchar2" ) ) { + return Types.VARCHAR; + } + return 0; } } From 3ff42d8748a8f9c42e1c938a1bd03d4629160d58 Mon Sep 17 00:00:00 2001 From: Davide D'Alto Date: Fri, 7 Nov 2025 11:41:37 +0100 Subject: [PATCH 158/162] [#2738] Test column type validation in Oracle --- .../schema/SchemaValidationTestBase.java | 64 ++++++++++++++++++- .../resources/oracle-SchemaValidationTest.sql | 12 ++++ 2 files changed, 75 insertions(+), 1 deletion(-) create mode 100644 hibernate-reactive-core/src/test/resources/oracle-SchemaValidationTest.sql diff --git a/hibernate-reactive-core/src/test/java/org/hibernate/reactive/schema/SchemaValidationTestBase.java b/hibernate-reactive-core/src/test/java/org/hibernate/reactive/schema/SchemaValidationTestBase.java index 4a5117fee..2034704cc 100644 --- a/hibernate-reactive-core/src/test/java/org/hibernate/reactive/schema/SchemaValidationTestBase.java +++ b/hibernate-reactive-core/src/test/java/org/hibernate/reactive/schema/SchemaValidationTestBase.java @@ -6,11 +6,15 @@ package org.hibernate.reactive.schema; +import java.net.URL; + import org.hibernate.boot.registry.StandardServiceRegistryBuilder; +import org.hibernate.cfg.AvailableSettings; import org.hibernate.cfg.Configuration; import org.hibernate.reactive.BaseReactiveTest; -import org.hibernate.reactive.provider.Settings; import org.hibernate.reactive.annotations.DisabledFor; +import org.hibernate.reactive.annotations.EnabledFor; +import org.hibernate.reactive.provider.Settings; import org.hibernate.tool.schema.spi.SchemaManagementException; import org.junit.jupiter.api.AfterEach; @@ -19,6 +23,7 @@ import io.vertx.junit5.Timeout; import io.vertx.junit5.VertxTestContext; +import jakarta.persistence.Column; import jakarta.persistence.Entity; import jakarta.persistence.GeneratedValue; import jakarta.persistence.Id; @@ -26,6 +31,7 @@ import static java.util.concurrent.TimeUnit.MINUTES; import static org.hibernate.reactive.containers.DatabaseConfiguration.DBType.DB2; +import static org.hibernate.reactive.containers.DatabaseConfiguration.DBType.ORACLE; import static org.hibernate.tool.schema.JdbcMetadaAccessStrategy.GROUPED; import static org.hibernate.tool.schema.JdbcMetadaAccessStrategy.INDIVIDUALLY; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -74,6 +80,11 @@ public void before(VertxTestContext context) { Configuration createConf = constructConfiguration( "create" ); createConf.addAnnotatedClass( BasicTypesTestEntity.class ); + final URL importFileURL = Thread.currentThread() + .getContextClassLoader() + .getResource( "oracle-SchemaValidationTest.sql" ); + createConf.setProperty( AvailableSettings.JAKARTA_HBM2DDL_LOAD_SCRIPT_SOURCE, importFileURL.getFile() ); + // Make sure that the extra table is not in the db Configuration dropConf = constructConfiguration( "drop" ); dropConf.addAnnotatedClass( Extra.class ); @@ -92,6 +103,18 @@ public void after(VertxTestContext context) { closeFactory( context ); } + @Test + @Timeout(value = 10, timeUnit = MINUTES) + @EnabledFor( ORACLE ) + public void testOracleColumnTypeValidation(VertxTestContext context) { + Configuration validateConf = constructConfiguration( "validate" ); + validateConf.addAnnotatedClass( Fruit.class ); + + StandardServiceRegistryBuilder builder = new StandardServiceRegistryBuilder() + .applySettings( validateConf.getProperties() ); + test( context, setupSessionFactory( validateConf ) ); + } + // When we have created the table, the validation should pass @Test @Timeout(value = 10, timeUnit = MINUTES) @@ -139,4 +162,43 @@ public static class Extra { private String description; } + + @Entity(name = "Fruit") + public static class Fruit { + + @Id + @GeneratedValue + private Integer id; + + @Column(name = "something_name", nullable = false, updatable = false) + private String name; + + public Fruit() { + } + + public Fruit(String name) { + this.name = name; + } + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + @Override + public String toString() { + return "Fruit{" + id + "," + name + '}'; + } + } } diff --git a/hibernate-reactive-core/src/test/resources/oracle-SchemaValidationTest.sql b/hibernate-reactive-core/src/test/resources/oracle-SchemaValidationTest.sql new file mode 100644 index 000000000..69a01b357 --- /dev/null +++ b/hibernate-reactive-core/src/test/resources/oracle-SchemaValidationTest.sql @@ -0,0 +1,12 @@ +-- Import file for testing schema validation in SchemaValidationTest +drop table if exists Fruit cascade constraints +drop sequence if exists Fruit_SEQ + +-- Create the table manually, so that we can check if the validation succeeds +create sequence fruit_seq start with 1 increment by 50; +create table Fruit (id number(10,0) not null, something_name nvarchar2(20) not null, primary key (id)) + +INSERT INTO fruit(id, something_name) VALUES (1, 'Cherry'); +INSERT INTO fruit(id, something_name) VALUES (2, 'Apple'); +INSERT INTO fruit(id, something_name) VALUES (3, 'Banana'); +ALTER SEQUENCE fruit_seq RESTART start with 4; \ No newline at end of file From 640fd7788a578ae11f3f7268e2101b2a3cc2e11f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 10 Nov 2025 03:36:58 +0000 Subject: [PATCH 159/162] Bump db2_community/db2 from 12.1.2.0 to 12.1.3.0 in /tooling/docker Bumps db2_community/db2 from 12.1.2.0 to 12.1.3.0. --- updated-dependencies: - dependency-name: db2_community/db2 dependency-version: 12.1.3.0 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- tooling/docker/db2.Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tooling/docker/db2.Dockerfile b/tooling/docker/db2.Dockerfile index b70ff8a80..fbd438115 100644 --- a/tooling/docker/db2.Dockerfile +++ b/tooling/docker/db2.Dockerfile @@ -1,3 +1,3 @@ # IBM DB2 # See https://hub.docker.com/r/ibmcom/db2 -FROM icr.io/db2_community/db2:12.1.2.0 +FROM icr.io/db2_community/db2:12.1.3.0 From 740521986ad015df08fdb6f867e64f70efdff2c3 Mon Sep 17 00:00:00 2001 From: marko-bekhta Date: Fri, 7 Nov 2025 15:53:24 +0100 Subject: [PATCH 160/162] Simplify the release process --- ci/release/Jenkinsfile | 6 +- publish.gradle | 8 ++ release/build.gradle | 252 +---------------------------------------- 3 files changed, 17 insertions(+), 249 deletions(-) diff --git a/ci/release/Jenkinsfile b/ci/release/Jenkinsfile index 670d6a537..1be82bc96 100644 --- a/ci/release/Jenkinsfile +++ b/ci/release/Jenkinsfile @@ -178,7 +178,7 @@ pipeline { configFile(fileId: 'release.config.ssh', targetLocation: "${env.HOME}/.ssh/config"), configFile(fileId: 'release.config.ssh.knownhosts', targetLocation: "${env.HOME}/.ssh/known_hosts") ]) { - sshagent(['ed25519.Hibernate-CI.github.com', 'hibernate.filemgmt.jboss.org', 'hibernate-ci.frs.sourceforge.net']) { + sshagent(['ed25519.Hibernate-CI.github.com']) { // set release version // update changelog from JIRA // tags the version @@ -211,7 +211,7 @@ pipeline { 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', 'jenkins.in.relation.to', 'hibernate-ci.frs.sourceforge.net']) { + sshagent(['ed25519.Hibernate-CI.github.com', 'jenkins.in.relation.to']) { // performs documentation upload and Sonatype release // push to github withEnv([ @@ -237,7 +237,7 @@ pipeline { withCredentials([ gitUsernamePassword(credentialsId: 'username-and-token.Hibernate-CI.github.com', gitToolName: 'Default') ]) { - sshagent( ['ed25519.Hibernate-CI.github.com', 'hibernate.filemgmt.jboss.org', 'hibernate-ci.frs.sourceforge.net'] ) { + sshagent( ['ed25519.Hibernate-CI.github.com'] ) { dir( '.release/hibernate.org' ) { checkout scmGit( branches: [[name: '*/production']], diff --git a/publish.gradle b/publish.gradle index 6d05724fa..747415921 100644 --- a/publish.gradle +++ b/publish.gradle @@ -88,3 +88,11 @@ publishing { } } } + +def releasePrepareTask = tasks.register("releasePrepare") { + description "Prepares all the artifacts and documentation for a JReleaser release." + group "Release" + + // Create all the published artifacts (i.e. jars) and move them to the staging directory (for JReleaser): + dependsOn publishAllPublicationsToStagingRepository +} diff --git a/release/build.gradle b/release/build.gradle index 25163e6e9..c50d1c658 100644 --- a/release/build.gradle +++ b/release/build.gradle @@ -18,58 +18,6 @@ final Directory documentationDir = project(":documentation").layout.buildDirecto // Relative path on the static website where the documentation is located final String docWebsiteRelativePath = "reactive/documentation/${projectVersion.family}" -def releaseChecksTask = tasks.register( "releaseChecks" ) { - description 'Checks and preparation for release' - group 'Release' - - doFirst { - logger.lifecycle("Checking that the working tree is clean...") - String uncommittedFiles = executeGitCommand('status', '--porcelain') - if (!uncommittedFiles.isEmpty()) { - throw new GradleException( - "Cannot release because there are uncommitted or untracked files in the working tree.\n" + - "Commit or stash your changes first.\n" + - "Uncommitted files:\n " + - uncommittedFiles - ) - } - - String gitBranchLocal = project.hasProperty( 'gitBranch' ) && !project.property( 'gitBranch' ).isEmpty() - ? project.property( 'gitBranch' ) - : executeGitCommand( 'branch', '--show-current' ).trim() - - String gitRemoteLocal - if ( project.hasProperty( 'gitRemote' ) && !project.property( 'gitRemote' ).isEmpty() ) { - gitRemoteLocal = project.property( 'gitRemote' ) - } - else { - final String remotes = executeGitCommand( 'remote', 'show' ).trim() - final List tokens = remotes.tokenize() - if ( tokens.size() != 1 ) { - throw new GradleException( "Could not determine `gitRemote` property for `releaseChecks` tasks." ) - } - gitRemoteLocal = tokens.get( 0 ) - } - - project.ext { - gitBranch = gitBranchLocal - gitRemote = gitRemoteLocal - } - - logger.lifecycle( "Switching to branch '${project.gitBranch}'..." ) - executeGitCommand( 'checkout', project.gitBranch ) - - logger.lifecycle( "Checking that all commits are pushed..." ) - String diffWithUpstream = executeGitCommand( 'diff', '@{u}' ) - if ( !diffWithUpstream.isEmpty() ) { - throw new GradleException( - "Cannot perform `ciRelease` tasks because there are un-pushed local commits .\n" + - "Push your commits first." - ) - } - } -} - /** * Assembles all documentation into the {buildDir}/documentation directory. */ @@ -80,22 +28,9 @@ def assembleDocumentationTask = tasks.register( 'assembleDocumentation' ) { } assemble.dependsOn assembleDocumentationTask -def changeToReleaseVersionTask = tasks.register( 'changeToReleaseVersion' ) { - description 'Updates `gradle/version.properties` file to the specified release-version' - group 'Release' - - dependsOn releaseChecksTask - - doFirst { - logger.lifecycle( "Updating version-file to release-version : `${project.releaseVersion}`" ) - updateVersionFile( "${project.releaseVersion}" ) - } -} - def updateDocumentationTask = tasks.register( 'updateDocumentation' ) { description "Update the documentation on the cloned static website" dependsOn assembleDocumentationTask - mustRunAfter changeToReleaseVersion // copy documentation outputs into target/documentation: // * this is used in building the dist bundles @@ -116,188 +51,13 @@ def updateDocumentationTask = tasks.register( 'updateDocumentation' ) { } } -def gitPreparationForReleaseTask = tasks.register( 'gitPreparationForRelease' ) { - dependsOn releaseChecksTask, changeToReleaseVersionTask - finalizedBy updateDocumentationTask - - doLast { - logger.lifecycle( "Performing pre-steps Git commit : `${project.releaseVersion}`" ) - executeGitCommand( 'add', '.' ) - executeGitCommand( 'commit', '-m', "Update project version to : `${project.releaseVersion}`" ) - } -} - -def changeToDevelopmentVersionTask = tasks.register( 'changeToDevelopmentVersion' ) { - description 'Updates `gradle/version.properties` file to the specified development-version' - group 'Release' - - dependsOn releaseChecksTask - - doFirst { - logger.lifecycle( "Updating version-file to development-version : `${project.developmentVersion}`" ) - updateVersionFile( "${project.developmentVersion}" ) - } -} - -def releasePreparePostGitTask = tasks.register( 'gitTasksAfterRelease' ) { - dependsOn changeToDevelopmentVersionTask - - doLast { - if ( project.createTag ) { - logger.lifecycle( "Tagging release : `${project.releaseTag}`..." ) - executeGitCommand( 'tag', '-a', project.releaseTag, '-m', "Release $project.projectVersion" ) - } - - logger.lifecycle( "Performing post-steps Git commit : `${project.releaseVersion}`" ) - executeGitCommand( 'add', '.' ) - executeGitCommand( 'commit', '-m', "Update project version to : `${project.developmentVersion}`" ) - } -} - -void updateVersionFile(var version) { - logger.lifecycle( "Updating `gradle/version.properties` version to `${version}`" ) - project.versionFile.text = "projectVersion=${version}" - project.version = version -} - -def publishReleaseArtifactsTask = tasks.register( 'publishReleaseArtifacts' ) { - dependsOn updateDocumentationTask - - mustRunAfter gitPreparationForReleaseTask -} - -def releasePerformPostGitTask = tasks.register( 'gitTasksAfterReleasePerform' ) { - - doLast { - if ( project.createTag ) { - logger.lifecycle( "Pushing branch and tag to remote `${project.gitRemote}`..." ) - executeGitCommand( 'push', '--atomic', project.gitRemote, project.gitBranch, project.releaseTag ) - } - else { - logger.lifecycle( "Pushing branch to remote `${project.gitRemote}`..." ) - executeGitCommand( 'push', project.gitRemote, project.gitBranch ) - } - } -} - def releasePrepareTask = tasks.register( "releasePrepare" ) { - description "On a local checkout, performs all the changes required for the release, website updates included" - group "Release" - - dependsOn gitPreparationForReleaseTask - - finalizedBy releasePreparePostGitTask -} - -def releasePerformTask = tasks.register( 'releasePerform' ) { - group 'Release' - description 'Performs a release on local check-out, including updating changelog and ' - - dependsOn publishReleaseArtifactsTask - - finalizedBy releasePerformPostGitTask -} - -/* -* Release everything -*/ -def releaseTask = tasks.register( 'release' ) { - description 'Performs a release on local check-out' - group 'Release' - - dependsOn releasePrepareTask - dependsOn releasePerformTask -} - -def ciReleaseTask = tasks.register( 'ciRelease' ) { - description "Triggers the release on CI: creates commits to change the version (release, then development), creates a tag, pushes everything. Then CI will take over and perform the release." + description "Prepares all the artifacts and documentation for a JReleaser release." group "Release" - dependsOn releaseTask -} - -static String executeGitCommand(Object ... subcommand){ - List command = ['git'] - Collections.addAll( command, subcommand ) - def proc = command.execute() - def code = proc.waitFor() - def stdout = inputStreamToString( proc.getInputStream() ) - def stderr = inputStreamToString( proc.getErrorStream() ) - if ( code != 0 ) { - throw new GradleException( "An error occurred while executing " + command + "\n\nstdout:\n" + stdout + "\n\nstderr:\n" + stderr ) - } - return stdout -} - -static String inputStreamToString(InputStream inputStream) { - inputStream.withCloseable { ins -> - new BufferedInputStream(ins).withCloseable { bis -> - new ByteArrayOutputStream().withCloseable { buf -> - int result = bis.read() - while (result != -1) { - buf.write((byte) result) - result = bis.read() - } - return buf.toString(StandardCharsets.UTF_8.name()) - } - } - } -} - -gradle.getTaskGraph().whenReady { tg-> - if ( ( tg.hasTask( project.tasks.releasePrepare ) || tg.hasTask( project.tasks.releasePerform ) ) - && ! project.getGradle().getStartParameter().isDryRun() ) { - String releaseVersionLocal - String developmentVersionLocal - - def console = tg.hasTask( project.tasks.release ) && !tg.hasTask( project.tasks.ciRelease ) - ? System.console() - : null - - if (project.hasProperty('releaseVersion')) { - releaseVersionLocal = project.property('releaseVersion') - } - else { - if (console) { - // prompt for `releaseVersion` - releaseVersionLocal = console.readLine('> Enter the release version: ') - } - else { - throw new GradleException( - "`release`-related tasks require the following properties: 'releaseVersion', 'developmentVersion'" - ) - } - } - - if (project.hasProperty('developmentVersion')) { - developmentVersionLocal = project.property('developmentVersion') - } - else { - if (console) { - // prompt for `developmentVersion` - developmentVersionLocal = console.readLine('> Enter the next development version: ') - } - else { - throw new GradleException( - "`release`-related tasks require the following properties: 'releaseVersion', 'developmentVersion'" - ) - } - } - - assert releaseVersionLocal != null && developmentVersionLocal != null - - // set up information for the release-related tasks - project.ext { - releaseVersion = releaseVersionLocal - developmentVersion = developmentVersionLocal - createTag = !project.hasProperty('noTag') - releaseTag = project.createTag ? determineReleaseTag(releaseVersionLocal) : '' - } - } -} - -static String determineReleaseTag(String releaseVersion) { - return releaseVersion.endsWith( '.Final' ) - ? releaseVersion.replace( ".Final", "" ) - : releaseVersion + // Render the Documentation/Javadocs and move them to the staging directory (for JReleaser): + dependsOn updateDocumentationTask + // Create all the published artifacts (i.e. jars) and move them to the staging directory (for JReleaser): + // this one is defined in the publish.gradle + // dependsOn project.getTasksByName(publishAllPublicationsToStagingRepository, false) } From 54569245e1a5b004447ff987119ec34fecc1591f Mon Sep 17 00:00:00 2001 From: Andrea Boriero Date: Thu, 13 Nov 2025 15:47:49 +0100 Subject: [PATCH 161/162] Simplify the release process, removed anymore used docWebsiteRelativePath --- release/build.gradle | 3 --- 1 file changed, 3 deletions(-) diff --git a/release/build.gradle b/release/build.gradle index c50d1c658..ff80aff49 100644 --- a/release/build.gradle +++ b/release/build.gradle @@ -15,9 +15,6 @@ description = 'Release module' // The folder containing the rendered documentation final Directory documentationDir = project(":documentation").layout.buildDirectory.get() -// Relative path on the static website where the documentation is located -final String docWebsiteRelativePath = "reactive/documentation/${projectVersion.family}" - /** * Assembles all documentation into the {buildDir}/documentation directory. */ From 84e90968d4c4593f017aa0bc33f83826157a63ce Mon Sep 17 00:00:00 2001 From: marko-bekhta Date: Thu, 13 Nov 2025 12:22:02 +0100 Subject: [PATCH 162/162] Add a GitHub release "extra notes" template --- ci/release/Jenkinsfile | 3 ++- github_release_notes.md | 3 +++ 2 files changed, 5 insertions(+), 1 deletion(-) create mode 100644 github_release_notes.md diff --git a/ci/release/Jenkinsfile b/ci/release/Jenkinsfile index 1be82bc96..037d6eefb 100644 --- a/ci/release/Jenkinsfile +++ b/ci/release/Jenkinsfile @@ -217,7 +217,8 @@ pipeline { withEnv([ "DISABLE_REMOTE_GRADLE_CACHE=true" ]) { - sh ".release/scripts/publish.sh -j ${env.SCRIPT_OPTIONS} ${env.PROJECT} ${env.RELEASE_VERSION} ${env.DEVELOPMENT_VERSION} ${env.GIT_BRANCH}" + def ghReleaseNote = sh('realpath -e github_release_notes.md 2>/dev/null', returnStdout: true).trim() + sh ".release/scripts/publish.sh -j ${ghReleaseNote != '' ? '--notes=' + ghReleaseNote : ''} ${env.SCRIPT_OPTIONS} ${env.PROJECT} ${env.RELEASE_VERSION} ${env.DEVELOPMENT_VERSION} ${env.GIT_BRANCH}" } } } diff --git a/github_release_notes.md b/github_release_notes.md new file mode 100644 index 000000000..db3469c5d --- /dev/null +++ b/github_release_notes.md @@ -0,0 +1,3 @@ + +* See the [website](https://hibernate.org/reactive/releases/{{releaseVersionFamily}}) for requirements and compatibilities. +* See the [What's New](https://hibernate.org/reactive/releases/{{releaseVersionFamily}}/#whats-new) guide for details about new features and capabilities.