diff --git a/.github/dco.yml b/.github/dco.yml
new file mode 100644
index 0000000000..0c4b142e9a
--- /dev/null
+++ b/.github/dco.yml
@@ -0,0 +1,2 @@
+require:
+ members: false
diff --git a/.github/workflows/project.yml b/.github/workflows/project.yml
index 606226523e..a5f764579a 100644
--- a/.github/workflows/project.yml
+++ b/.github/workflows/project.yml
@@ -13,35 +13,28 @@ on:
jobs:
Inbox:
runs-on: ubuntu-latest
- if: github.repository_owner == 'spring-projects' && (github.event.action == 'opened' || github.event.action == 'reopened') && github.event.pull_request == null
+ if: github.repository_owner == 'spring-projects' && (github.event.action == 'opened' || github.event.action == 'reopened') && github.event.pull_request == null && !contains(join(github.event.issue.labels.*.name, ', '), 'dependency-upgrade') && !contains(github.event.issue.title, 'Release ')
steps:
- name: Create or Update Issue Card
- uses: peter-evans/create-or-update-project-card@v1.1.2
+ uses: actions/add-to-project@v1.0.2
with:
- project-name: 'Spring Data'
- column-name: 'Inbox'
- project-location: 'spring-projects'
- token: ${{ secrets.GH_ISSUES_TOKEN_SPRING_DATA }}
+ project-url: https://github.com/orgs/spring-projects/projects/25
+ github-token: ${{ secrets.GH_ISSUES_TOKEN_SPRING_DATA }}
Pull-Request:
runs-on: ubuntu-latest
if: github.repository_owner == 'spring-projects' && (github.event.action == 'opened' || github.event.action == 'reopened') && github.event.pull_request != null
steps:
- name: Create or Update Pull Request Card
- uses: peter-evans/create-or-update-project-card@v1.1.2
+ uses: actions/add-to-project@v1.0.2
with:
- project-name: 'Spring Data'
- column-name: 'Review pending'
- project-location: 'spring-projects'
- issue-number: ${{ github.event.pull_request.number }}
- token: ${{ secrets.GH_ISSUES_TOKEN_SPRING_DATA }}
+ project-url: https://github.com/orgs/spring-projects/projects/25
+ github-token: ${{ secrets.GH_ISSUES_TOKEN_SPRING_DATA }}
Feedback-Provided:
runs-on: ubuntu-latest
if: github.repository_owner == 'spring-projects' && github.event_name == 'issue_comment' && github.event.action == 'created' && github.actor != 'spring-projects-issues' && github.event.pull_request == null && github.event.issue.state == 'open' && contains(toJSON(github.event.issue.labels), 'waiting-for-feedback')
steps:
- name: Update Project Card
- uses: peter-evans/create-or-update-project-card@v1.1.2
+ uses: actions/add-to-project@v1.0.2
with:
- project-name: 'Spring Data'
- column-name: 'Feedback provided'
- project-location: 'spring-projects'
- token: ${{ secrets.GH_ISSUES_TOKEN_SPRING_DATA }}
+ project-url: https://github.com/orgs/spring-projects/projects/25
+ github-token: ${{ secrets.GH_ISSUES_TOKEN_SPRING_DATA }}
diff --git a/.gitignore b/.gitignore
index be372b6209..27b7a78896 100644
--- a/.gitignore
+++ b/.gitignore
@@ -15,4 +15,9 @@ src/ant/.ant-targets-upload-dist.xml
atlassian-ide-plugin.xml
/.gradle/
/.idea/
-*.graphml
\ No newline at end of file
+*.graphml
+build/
+node_modules
+node
+package-lock.json
+.mvn/.develocity
diff --git a/.mvn/extensions.xml b/.mvn/extensions.xml
new file mode 100644
index 0000000000..e0857eaa25
--- /dev/null
+++ b/.mvn/extensions.xml
@@ -0,0 +1,8 @@
+
+
+
+ io.spring.develocity.conventions
+ develocity-conventions-maven-extension
+ 0.0.22
+
+
diff --git a/.mvn/jvm.config b/.mvn/jvm.config
new file mode 100644
index 0000000000..e27f6e8f5e
--- /dev/null
+++ b/.mvn/jvm.config
@@ -0,0 +1,14 @@
+--add-exports jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED
+--add-exports jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED
+--add-exports jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED
+--add-exports jdk.compiler/com.sun.tools.javac.model=ALL-UNNAMED
+--add-exports jdk.compiler/com.sun.tools.javac.parser=ALL-UNNAMED
+--add-exports jdk.compiler/com.sun.tools.javac.processing=ALL-UNNAMED
+--add-exports jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED
+--add-exports jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED
+--add-opens jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED
+--add-opens jdk.compiler/com.sun.tools.javac.comp=ALL-UNNAMED
+--add-opens=java.base/java.util=ALL-UNNAMED
+--add-opens=java.base/java.lang.reflect=ALL-UNNAMED
+--add-opens=java.base/java.text=ALL-UNNAMED
+--add-opens=java.desktop/java.awt.font=ALL-UNNAMED
diff --git a/.mvn/wrapper/maven-wrapper.properties b/.mvn/wrapper/maven-wrapper.properties
index 00d32aab1d..5f3193b363 100755
--- a/.mvn/wrapper/maven-wrapper.properties
+++ b/.mvn/wrapper/maven-wrapper.properties
@@ -1 +1,2 @@
-distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.5.4/apache-maven-3.5.4-bin.zip
\ No newline at end of file
+#Thu Nov 07 09:47:19 CET 2024
+distributionUrl=https\://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.9/apache-maven-3.9.9-bin.zip
diff --git a/CI.adoc b/CI.adoc
index 4e95939a34..057100a955 100644
--- a/CI.adoc
+++ b/CI.adoc
@@ -16,7 +16,7 @@ All of these use cases are great reasons to essentially run what the CI server d
IMPORTANT: To do this you must have Docker installed on your machine.
-1. `docker run -it --mount type=bind,source="$(pwd)",target=/spring-data-mongodb-github springci/spring-data-openjdk8-with-mongodb-4.0:latest /bin/bash`
+1. `docker run -it --mount type=bind,source="$(pwd)",target=/spring-data-mongodb-github springci/spring-data-openjdk17-with-mongodb-5.0.3:latest /bin/bash`
+
This will launch the Docker image and mount your source code at `spring-data-mongodb-github`.
+
diff --git a/Jenkinsfile b/Jenkinsfile
index 1eb84755a5..0e83b47e2f 100644
--- a/Jenkinsfile
+++ b/Jenkinsfile
@@ -1,3 +1,9 @@
+def p = [:]
+node {
+ checkout scm
+ p = readProperties interpolate: true, file: 'ci/pipeline.properties'
+}
+
pipeline {
agent none
@@ -14,49 +20,58 @@ pipeline {
stages {
stage("Docker images") {
parallel {
- stage('Publish JDK 8 + MongoDB 4.0') {
+ stage('Publish JDK (Java 17) + MongoDB 6.0') {
when {
- changeset "ci/openjdk8-mongodb-4.0/**"
+ anyOf {
+ changeset "ci/openjdk17-mongodb-6.0/**"
+ changeset "ci/pipeline.properties"
+ }
}
agent { label 'data' }
options { timeout(time: 30, unit: 'MINUTES') }
steps {
script {
- def image = docker.build("springci/spring-data-openjdk8-with-mongodb-4.0.23", "ci/openjdk8-mongodb-4.0/")
- docker.withRegistry('', 'hub.docker.com-springbuildmaster') {
+ def image = docker.build("springci/spring-data-with-mongodb-6.0:${p['java.main.tag']}", "--build-arg BASE=${p['docker.java.main.image']} --build-arg MONGODB=${p['docker.mongodb.6.0.version']} ci/openjdk17-mongodb-6.0/")
+ docker.withRegistry(p['docker.registry'], p['docker.credentials']) {
image.push()
}
}
}
}
- stage('Publish JDK 8 + MongoDB 4.4') {
+ stage('Publish JDK (Java 17) + MongoDB 7.0') {
when {
- changeset "ci/openjdk8-mongodb-4.4/**"
- }
- agent { label 'data' }
- options { timeout(time: 30, unit: 'MINUTES') }
+ anyOf {
+ changeset "ci/openjdk17-mongodb-7.0/**"
+ changeset "ci/pipeline.properties"
+ }
+ }
+ agent { label 'data' }
+ options { timeout(time: 30, unit: 'MINUTES') }
steps {
script {
- def image = docker.build("springci/spring-data-openjdk8-with-mongodb-4.4.4", "ci/openjdk8-mongodb-4.4/")
- docker.withRegistry('', 'hub.docker.com-springbuildmaster') {
+ def image = docker.build("springci/spring-data-with-mongodb-7.0:${p['java.main.tag']}", "--build-arg BASE=${p['docker.java.main.image']} --build-arg MONGODB=${p['docker.mongodb.7.0.version']} ci/openjdk17-mongodb-7.0/")
+ docker.withRegistry(p['docker.registry'], p['docker.credentials']) {
image.push()
}
}
}
}
- stage('Publish JDK 16 + MongoDB 4.4') {
+ stage('Publish JDK (Java.next) + MongoDB 8.0') {
when {
- changeset "ci/openjdk16-mongodb-4.4/**"
+ anyOf {
+ changeset "ci/openjdk17-mongodb-8.0/**"
+ changeset "ci/pipeline.properties"
+ }
}
agent { label 'data' }
options { timeout(time: 30, unit: 'MINUTES') }
steps {
script {
- def image = docker.build("springci/spring-data-openjdk16-with-mongodb-4.4.4", "ci/openjdk16-mongodb-4.4/")
- docker.withRegistry('', 'hub.docker.com-springbuildmaster') {
+ def image = docker.build("springci/spring-data-with-mongodb-8.0:${p['java.next.tag']}", "--build-arg BASE=${p['docker.java.next.image']} --build-arg MONGODB=${p['docker.mongodb.8.0.version']} ci/openjdk23-mongodb-8.0/")
+ docker.withRegistry(p['docker.registry'], p['docker.credentials']) {
image.push()
}
}
@@ -65,10 +80,11 @@ pipeline {
}
}
- stage("test: baseline (jdk8)") {
+ stage("test: baseline (main)") {
when {
+ beforeAgent(true)
anyOf {
- branch 'main'
+ branch(pattern: "main|(\\d\\.\\d\\.x)", comparator: "REGEXP")
not { triggeredBy 'UpstreamCause' }
}
}
@@ -77,18 +93,16 @@ pipeline {
}
options { timeout(time: 30, unit: 'MINUTES') }
environment {
- ARTIFACTORY = credentials('02bd1690-b54f-4c9f-819d-a77cb7a9822c')
+ ARTIFACTORY = credentials("${p['artifactory.credentials']}")
+ DEVELOCITY_ACCESS_KEY = credentials("${p['develocity.access-key']}")
}
steps {
script {
- docker.withRegistry('', 'hub.docker.com-springbuildmaster') {
- docker.image('springci/spring-data-openjdk8-with-mongodb-4.0.23:latest').inside('-v $HOME:/tmp/jenkins-home') {
- sh 'mkdir -p /tmp/mongodb/db /tmp/mongodb/log'
- sh 'mongod --setParameter transactionLifetimeLimitSeconds=90 --setParameter maxTransactionLockRequestTimeoutMillis=10000 --dbpath /tmp/mongodb/db --replSet rs0 --fork --logpath /tmp/mongodb/log/mongod.log &'
- sh 'sleep 10'
- sh 'mongo --eval "rs.initiate({_id: \'rs0\', members:[{_id: 0, host: \'127.0.0.1:27017\'}]});"'
- sh 'sleep 15'
- sh 'MAVEN_OPTS="-Duser.name=jenkins -Duser.home=/tmp/jenkins-home" ./mvnw -s settings.xml clean dependency:list test -Duser.name=jenkins -Dsort -U -B'
+ docker.withRegistry(p['docker.proxy.registry'], p['docker.proxy.credentials']) {
+ docker.image("springci/spring-data-with-mongodb-6.0:${p['java.main.tag']}").inside(p['docker.java.inside.docker']) {
+ sh 'ci/start-replica.sh'
+ sh 'MAVEN_OPTS="-Duser.name=' + "${p['jenkins.user.name']}" + ' -Duser.home=/tmp/jenkins-home" ' +
+ "./mvnw -s settings.xml -Ddevelocity.storage.directory=/tmp/jenkins-home/.develocity-root -Dmaven.repo.local=/tmp/jenkins-home/.m2/spring-data-mongodb clean dependency:list test -Dsort -U -B"
}
}
}
@@ -97,78 +111,51 @@ pipeline {
stage("Test other configurations") {
when {
+ beforeAgent(true)
allOf {
- branch 'main'
+ branch(pattern: "main|(\\d\\.\\d\\.x)", comparator: "REGEXP")
not { triggeredBy 'UpstreamCause' }
}
}
parallel {
- stage("test: mongodb 4.0 (jdk8)") {
- agent {
- label 'data'
- }
- options { timeout(time: 30, unit: 'MINUTES') }
- environment {
- ARTIFACTORY = credentials('02bd1690-b54f-4c9f-819d-a77cb7a9822c')
- }
- steps {
- script {
- docker.withRegistry('', 'hub.docker.com-springbuildmaster') {
- docker.image('springci/spring-data-openjdk8-with-mongodb-4.0.23:latest').inside('-v $HOME:/tmp/jenkins-home') {
- sh 'mkdir -p /tmp/mongodb/db /tmp/mongodb/log'
- sh 'mongod --setParameter transactionLifetimeLimitSeconds=90 --setParameter maxTransactionLockRequestTimeoutMillis=10000 --dbpath /tmp/mongodb/db --replSet rs0 --fork --logpath /tmp/mongodb/log/mongod.log &'
- sh 'sleep 10'
- sh 'mongo --eval "rs.initiate({_id: \'rs0\', members:[{_id: 0, host: \'127.0.0.1:27017\'}]});"'
- sh 'sleep 15'
- sh 'MAVEN_OPTS="-Duser.name=jenkins -Duser.home=/tmp/jenkins-home" ./mvnw -s settings.xml clean dependency:list test -Duser.name=jenkins -Dsort -U -B'
- }
- }
- }
- }
- }
-
- stage("test: mongodb 4.4 (jdk8)") {
+ stage("test: MongoDB 7.0 (main)") {
agent {
label 'data'
}
options { timeout(time: 30, unit: 'MINUTES') }
environment {
- ARTIFACTORY = credentials('02bd1690-b54f-4c9f-819d-a77cb7a9822c')
+ ARTIFACTORY = credentials("${p['artifactory.credentials']}")
+ DEVELOCITY_ACCESS_KEY = credentials("${p['develocity.access-key']}")
}
steps {
script {
- docker.withRegistry('', 'hub.docker.com-springbuildmaster') {
- docker.image('springci/spring-data-openjdk8-with-mongodb-4.4.4:latest').inside('-v $HOME:/tmp/jenkins-home') {
- sh 'mkdir -p /tmp/mongodb/db /tmp/mongodb/log'
- sh 'mongod --setParameter transactionLifetimeLimitSeconds=90 --setParameter maxTransactionLockRequestTimeoutMillis=10000 --dbpath /tmp/mongodb/db --replSet rs0 --fork --logpath /tmp/mongodb/log/mongod.log &'
- sh 'sleep 10'
- sh 'mongo --eval "rs.initiate({_id: \'rs0\', members:[{_id: 0, host: \'127.0.0.1:27017\'}]});"'
- sh 'sleep 15'
- sh 'MAVEN_OPTS="-Duser.name=jenkins -Duser.home=/tmp/jenkins-home" ./mvnw -s settings.xml clean dependency:list test -Duser.name=jenkins -Dsort -U -B'
+ docker.withRegistry(p['docker.proxy.registry'], p['docker.proxy.credentials']) {
+ docker.image("springci/spring-data-with-mongodb-7.0:${p['java.main.tag']}").inside(p['docker.java.inside.docker']) {
+ sh 'ci/start-replica.sh'
+ sh 'MAVEN_OPTS="-Duser.name=' + "${p['jenkins.user.name']}" + ' -Duser.home=/tmp/jenkins-home" ' +
+ "./mvnw -s settings.xml -Ddevelocity.storage.directory=/tmp/jenkins-home/.develocity-root -Dmaven.repo.local=/tmp/jenkins-home/.m2/spring-data-mongodb clean dependency:list test -Dsort -U -B"
}
}
}
}
}
- stage("test: baseline (jdk16)") {
+ stage("test: MongoDB 8.0") {
agent {
label 'data'
}
options { timeout(time: 30, unit: 'MINUTES') }
environment {
- ARTIFACTORY = credentials('02bd1690-b54f-4c9f-819d-a77cb7a9822c')
+ ARTIFACTORY = credentials("${p['artifactory.credentials']}")
+ DEVELOCITY_ACCESS_KEY = credentials("${p['develocity.access-key']}")
}
steps {
script {
- docker.withRegistry('', 'hub.docker.com-springbuildmaster') {
- docker.image('springci/spring-data-openjdk16-with-mongodb-4.4.4:latest').inside('-v $HOME:/tmp/jenkins-home') {
- sh 'mkdir -p /tmp/mongodb/db /tmp/mongodb/log'
- sh 'mongod --setParameter transactionLifetimeLimitSeconds=90 --setParameter maxTransactionLockRequestTimeoutMillis=10000 --dbpath /tmp/mongodb/db --replSet rs0 --fork --logpath /tmp/mongodb/log/mongod.log &'
- sh 'sleep 10'
- sh 'mongo --eval "rs.initiate({_id: \'rs0\', members:[{_id: 0, host: \'127.0.0.1:27017\'}]});"'
- sh 'sleep 15'
- sh 'MAVEN_OPTS="-Duser.name=jenkins -Duser.home=/tmp/jenkins-home" ./mvnw -s settings.xml -Pjava11 clean dependency:list test -Duser.name=jenkins -Dsort -U -B'
+ docker.withRegistry(p['docker.proxy.registry'], p['docker.proxy.credentials']) {
+ docker.image("springci/spring-data-with-mongodb-8.0:${p['java.next.tag']}").inside(p['docker.java.inside.docker']) {
+ sh 'ci/start-replica.sh'
+ sh 'MAVEN_OPTS="-Duser.name=' + "${p['jenkins.user.name']}" + ' -Duser.home=/tmp/jenkins-home" ' +
+ "./mvnw -s settings.xml -Ddevelocity.storage.directory=/tmp/jenkins-home/.develocity-root -Dmaven.repo.local=/tmp/jenkins-home/.m2/spring-data-mongodb clean dependency:list test -Dsort -U -B"
}
}
}
@@ -179,8 +166,9 @@ pipeline {
stage('Release to artifactory') {
when {
+ beforeAgent(true)
anyOf {
- branch 'main'
+ branch(pattern: "main|(\\d\\.\\d\\.x)", comparator: "REGEXP")
not { triggeredBy 'UpstreamCause' }
}
}
@@ -188,52 +176,25 @@ pipeline {
label 'data'
}
options { timeout(time: 20, unit: 'MINUTES') }
-
environment {
- ARTIFACTORY = credentials('02bd1690-b54f-4c9f-819d-a77cb7a9822c')
+ ARTIFACTORY = credentials("${p['artifactory.credentials']}")
+ DEVELOCITY_ACCESS_KEY = credentials("${p['develocity.access-key']}")
}
-
steps {
script {
- docker.withRegistry('', 'hub.docker.com-springbuildmaster') {
- docker.image('adoptopenjdk/openjdk8:latest').inside('-v $HOME:/tmp/jenkins-home') {
- sh 'MAVEN_OPTS="-Duser.name=jenkins -Duser.home=/tmp/jenkins-home" ./mvnw -s settings.xml -Pci,artifactory ' +
- '-Dartifactory.server=https://repo.spring.io ' +
+ docker.withRegistry(p['docker.proxy.registry'], p['docker.proxy.credentials']) {
+ docker.image(p['docker.java.main.image']).inside(p['docker.java.inside.docker']) {
+ sh 'MAVEN_OPTS="-Duser.name=' + "${p['jenkins.user.name']}" + ' -Duser.home=/tmp/jenkins-home" ' +
+ "./mvnw -s settings.xml -Pci,artifactory " +
+ "-Ddevelocity.storage.directory=/tmp/jenkins-home/.develocity-root " +
+ "-Dartifactory.server=${p['artifactory.url']} " +
"-Dartifactory.username=${ARTIFACTORY_USR} " +
"-Dartifactory.password=${ARTIFACTORY_PSW} " +
- "-Dartifactory.staging-repository=libs-snapshot-local " +
+ "-Dartifactory.staging-repository=${p['artifactory.repository.snapshot']} " +
"-Dartifactory.build-name=spring-data-mongodb " +
- "-Dartifactory.build-number=${BUILD_NUMBER} " +
- '-Dmaven.test.skip=true clean deploy -U -B'
- }
- }
- }
- }
- }
-
- stage('Publish documentation') {
- when {
- branch 'main'
- }
- agent {
- label 'data'
- }
- options { timeout(time: 20, unit: 'MINUTES') }
-
- environment {
- ARTIFACTORY = credentials('02bd1690-b54f-4c9f-819d-a77cb7a9822c')
- }
-
- steps {
- script {
- docker.withRegistry('', 'hub.docker.com-springbuildmaster') {
- docker.image('adoptopenjdk/openjdk8:latest').inside('-v $HOME:/tmp/jenkins-home') {
- sh 'MAVEN_OPTS="-Duser.name=jenkins -Duser.home=/tmp/jenkins-home" ./mvnw -s settings.xml -Pci,distribute ' +
- '-Dartifactory.server=https://repo.spring.io ' +
- "-Dartifactory.username=${ARTIFACTORY_USR} " +
- "-Dartifactory.password=${ARTIFACTORY_PSW} " +
- "-Dartifactory.distribution-repository=temp-private-local " +
- '-Dmaven.test.skip=true clean deploy -U -B'
+ "-Dartifactory.build-number=spring-data-mongodb-${BRANCH_NAME}-build-${BUILD_NUMBER} " +
+ "-Dmaven.repo.local=/tmp/jenkins-home/.m2/spring-data-mongodb " +
+ "-Dmaven.test.skip=true clean deploy -U -B"
}
}
}
@@ -244,10 +205,6 @@ pipeline {
post {
changed {
script {
- slackSend(
- color: (currentBuild.currentResult == 'SUCCESS') ? 'good' : 'danger',
- channel: '#spring-data-dev',
- message: "${currentBuild.fullDisplayName} - `${currentBuild.currentResult}`\n${env.BUILD_URL}")
emailext(
subject: "[${currentBuild.fullDisplayName}] ${currentBuild.currentResult}",
mimeType: 'text/html',
diff --git a/README.adoc b/README.adoc
index e80d6ac4ef..61b956fbfc 100644
--- a/README.adoc
+++ b/README.adoc
@@ -1,17 +1,19 @@
-image:https://spring.io/badges/spring-data-mongodb/ga.svg[Spring Data MongoDB,link=https://projects.spring.io/spring-data-mongodb#quick-start] image:https://spring.io/badges/spring-data-mongodb/snapshot.svg[Spring Data MongoDB,link=https://projects.spring.io/spring-data-mongodb#quick-start]
+image:https://spring.io/badges/spring-data-mongodb/ga.svg[Spring Data MongoDB,link=https://spring.io/projects/spring-data-mongodb#quick-start] image:https://spring.io/badges/spring-data-mongodb/snapshot.svg[Spring Data MongoDB,link=https://spring.io/projects/spring-data-mongodb#quick-start]
-= Spring Data MongoDB image:https://jenkins.spring.io/buildStatus/icon?job=spring-data-mongodb%2Fmain&subject=Build[link=https://jenkins.spring.io/view/SpringData/job/spring-data-mongodb/] https://gitter.im/spring-projects/spring-data[image:https://badges.gitter.im/spring-projects/spring-data.svg[Gitter]]
+= Spring Data MongoDB image:https://jenkins.spring.io/buildStatus/icon?job=spring-data-mongodb%2Fmain&subject=Build[link=https://jenkins.spring.io/view/SpringData/job/spring-data-mongodb/] image:https://img.shields.io/badge/Revved%20up%20by-Develocity-06A0CE?logo=Gradle&labelColor=02303A["Revved up by Develocity", link="https://ge.spring.io/scans?search.rootProjectNames=Spring Data MongoDB"]
-The primary goal of the https://projects.spring.io/spring-data[Spring Data] project is to make it easier to build Spring-powered applications that use new data access technologies such as non-relational databases, map-reduce frameworks, and cloud based data services.
+The primary goal of the https://spring.io/projects/spring-data[Spring Data] project is to make it easier to build Spring-powered applications that use new data access technologies such as non-relational databases, map-reduce frameworks, and cloud based data services.
The Spring Data MongoDB project aims to provide a familiar and consistent Spring-based programming model for new datastores while retaining store-specific features and capabilities.
The Spring Data MongoDB project provides integration with the MongoDB document database.
Key functional areas of Spring Data MongoDB are a POJO centric model for interacting with a MongoDB `+Document+` and easily writing a repository style data access layer.
+[[code-of-conduct]]
== Code of Conduct
This project is governed by the https://github.com/spring-projects/.github/blob/e3cc2ff230d8f1dca06535aa6b5a4a23815861d4/CODE_OF_CONDUCT.md[Spring Code of Conduct]. By participating, you are expected to uphold this code of conduct. Please report unacceptable behavior to spring-code-of-conduct@pivotal.io.
+[[getting-started]]
== Getting Started
Here is a quick teaser of an application using Spring Data Repositories in Java:
@@ -59,6 +61,7 @@ class ApplicationConfig extends AbstractMongoClientConfiguration {
}
----
+[[maven-configuration]]
=== Maven configuration
Add the Maven dependency:
@@ -68,200 +71,148 @@ Add the Maven dependency:
org.springframework.dataspring-data-mongodb
- ${version}.RELEASE
+ ${version}
----
-If you'd rather like the latest snapshots of the upcoming major version, use our Maven snapshot repository and declare the appropriate dependency version.
+If you'd rather like the latest snapshots of the upcoming major version, use our Maven snapshot repository
+and declare the appropriate dependency version.
[source,xml]
----
org.springframework.dataspring-data-mongodb
- ${version}.BUILD-SNAPSHOT
+ ${version}-SNAPSHOT
- spring-libs-snapshot
+ spring-snapshotSpring Snapshot Repository
- https://repo.spring.io/libs-snapshot
+ https://repo.spring.io/snapshot
----
-== Upgrading from 2.x
+[[upgrading]]
+== Upgrading
-The 4.0 MongoDB Java Driver does no longer support certain features that have already been deprecated in one of the last minor versions.
-Some of the changes affect the initial setup configuration as well as compile/runtime features. We summarized the most typical changes one might encounter.
+Instructions for how to upgrade from earlier versions of Spring Data are provided on the project https://github.com/spring-projects/spring-data-commons/wiki[wiki].
+Follow the links in the https://github.com/spring-projects/spring-data-commons/wiki#release-notes[release notes section] to find the version that you want to upgrade to.
-=== XML Namespace
-
-.Changed XML Namespace Elements and Attributes:
-|===
-Element / Attribute | 2.x | 3.x
-
-| ``
-| Used to create a `com.mongodb.MongoClient`
-| Now exposes a `com.mongodb.client.MongoClient`
-
-| ``
-| Was a comma delimited list of replica set members (host/port)
-| Now defines the replica set name. +
-Use `` instead
-
-| ``
-| NONE, NORMAL, SAFE, FSYNC_SAFE, REPLICAS_SAFE, MAJORITY
-| W1, W2, W3, UNAKNOWLEDGED, AKNOWLEDGED, JOURNALED, MAJORITY
-|===
-
-.Removed XML Namespace Elements and Attributes:
-|===
-Element / Attribute | Replacement in 3.x | Comment
-
-| ``
-| ``
-| Referencing a `com.mongodb.client.MongoClient`.
-
-| ``
-| ``
-| Single authentication data instead of list.
-
-| ``
-| ``
-| See `com.mongodb.MongoClientSettings` for details.
-|===
+[[getting-help]]
+== Getting Help
-.New XML Namespace Elements and Attributes:
-|===
-Element | Comment
+Having trouble with Spring Data? We’d love to help!
-| ``
-| Replacement for ``
+* Check the
+https://docs.spring.io/spring-data/mongodb/reference/[reference documentation], and https://docs.spring.io/spring-data/mongodb/docs/current/api/[Javadocs]
+* Learn the Spring basics – Spring Data builds on Spring Framework, check the https://spring.io[spring.io] web-site for a wealth of reference documentation.
+If you are just starting out with Spring, try one of the https://spring.io/guides[guides].
+* If you are upgrading, check out the https://docs.spring.io/spring-data/mongodb/docs/current/changelog.txt[changelog] for "`new and noteworthy`" features.
+* Ask a question - we monitor https://stackoverflow.com[stackoverflow.com] for questions tagged with https://stackoverflow.com/tags/spring-data[`spring-data-mongodb`].
+* Report bugs with Spring Data MongoDB at https://github.com/spring-projects/spring-data-mongodb/issues[github.com/spring-projects/spring-data-mongodb/issues].
-| ``
-| Replacement for `uri` and `client-uri`.
+[[reporting-issues]]
+== Reporting Issues
-| ``
-| Replacement for `uri` and `client-uri`.
+Spring Data uses Github as issue tracking system to record bugs and feature requests.
+If you want to raise an issue, please follow the recommendations below:
-| ``
-| Namespace element for `com.mongodb.MongoClientSettings`.
+* Before you log a bug, please search the https://github.com/spring-projects/spring-data-mongodb/issues[issue tracker] to see if someone has already reported the problem.
+* If the issue does not already exist, https://github.com/spring-projects/spring-data-mongodb/issues/new[create a new issue].
+* Please provide as much information as possible with the issue report, we like to know the version of Spring Data that you are using, the JVM version, Stacktrace, etc.
+* If you need to paste code, or include a stack trace use https://guides.github.com/features/mastering-markdown/[Markdown] code fences +++```+++.
-|===
+[[guides]]
+== Guides
-=== Java Configuration
+The https://spring.io/[spring.io] site contains several guides that show how to use Spring Data step-by-step:
-.Java API changes
-|===
-Type | Comment
+* https://spring.io/guides/gs/accessing-data-mongodb/[Accessing Data with MongoDB] is a very basic guide that shows you how to create a simple application and how to access data using repositories.
+* https://spring.io/guides/gs/accessing-mongodb-data-rest/[Accessing MongoDB Data with REST] is a guide to creating a REST web service exposing data stored in MongoDB through repositories.
-| `MongoClientFactoryBean`
-| Creates `com.mongodb.client.MongoClient` instead of `com.mongodb.MongoClient` +
-Uses `MongoClientSettings` instead of `MongoClientOptions`.
+[[examples]]
+== Examples
-| `MongoDataIntegrityViolationException`
-| Uses `WriteConcernResult` instead of `WriteResult`.
+* https://github.com/spring-projects/spring-data-examples/[Spring Data Examples] contains example projects that explain specific features in more detail.
-| `BulkOperationException`
-| Uses `MongoBulkWriteException` and `com.mongodb.bulk.BulkWriteError` instead of `BulkWriteException` and `com.mongodb.BulkWriteError`
+[[building-from-source]]
+== Building from Source
-| `ReactiveMongoClientFactoryBean`
-| Uses `com.mongodb.MongoClientSettings` instead of `com.mongodb.async.client.MongoClientSettings`
+You do not need to build from source to use Spring Data. Binaries are available in https://repo.spring.io[repo.spring.io]
+and accessible from Maven using the Maven configuration noted <>.
-| `ReactiveMongoClientSettingsFactoryBean`
-| Now produces `com.mongodb.MongoClientSettings` instead of `com.mongodb.async.client.MongoClientSettings`
-|===
+NOTE: Configuration for Gradle is similar to Maven.
-.Removed Java API:
-|===
-2.x | Replacement in 3.x | Comment
+The best way to get started is by creating a Spring Boot project using MongoDB on https://start.spring.io[start.spring.io].
+Follow this https://start.spring.io/#type=maven-project&language=java&platformVersion=3.0.0&packaging=jar&jvmVersion=17&groupId=com.example&artifactId=demo&name=demo&description=Demo%20project%20for%20Spring%20Boot&packageName=com.example.demo&dependencies=data-mongodb[link]
+to build an imperative application and this https://start.spring.io/#type=maven-project&language=java&platformVersion=3.0.0&packaging=jar&jvmVersion=17&groupId=com.example&artifactId=demo&name=demo&description=Demo%20project%20for%20Spring%20Boot&packageName=com.example.demo&dependencies=data-mongodb-reactive[link]
+to build a reactive one.
-| `MongoClientOptionsFactoryBean`
-| `MongoClientSettingsFactoryBean`
-| Creating a `com.mongodb.MongoClientSettings`.
+However, if you want to try out the latest and greatest, Spring Data MongoDB can be easily built with the https://github.com/takari/maven-wrapper[Maven wrapper]
+and minimally, JDK 17 (https://www.oracle.com/java/technologies/downloads/[JDK downloads]).
-| `AbstractMongoConfiguration`
-| `AbstractMongoClientConfiguration` +
-(Available since 2.1)
-| Using `com.mongodb.client.MongoClient`.
+In order to build Spring Data MongoDB, you will need to https://www.mongodb.com/try/download/community[download]
+and https://docs.mongodb.com/manual/installation/[install a MongoDB distribution].
-| `MongoDbFactory#getLegacyDb()`
-| -
-| -
+Once you have installed MongoDB, you need to start a MongoDB server. It is convenient to set an environment variable to
+your MongoDB installation directory (e.g. `MONGODB_HOME`).
-| `SimpleMongoDbFactory`
-| `SimpleMongoClientDbFactory` +
-(Available since 2.1)
-|
+To run the full test suite, a https://docs.mongodb.com/manual/tutorial/deploy-replica-set/[MongoDB Replica Set]
+is required.
-| `MapReduceOptions#getOutputType()`
-| `MapReduceOptions#getMapReduceAction()`
-| Returns `MapReduceAction` instead of `MapReduceCommand.OutputType`.
+To run the MongoDB server enter the following command from a command-line:
-| `Meta\|Query` maxScan & snapshot
-|
-|
-|===
+[source,bash]
+----
+$ $MONGODB_HOME/bin/mongod --dbpath $MONGODB_HOME/runtime/data --ipv6 --port 27017 --replSet rs0
+...
+"msg":"Successfully connected to host"
+----
-=== Other Changes
+Once the MongoDB server starts up, you should see the message (`msg`), "_Successfully connected to host_".
-==== UUID Types
+Notice the `--dbpath` option to the `mongod` command. You can set this to anything you like, but in this case, we set
+the absolute path to a sub-directory (`runtime/data/`) under the MongoDB installation directory (in `$MONGODB_HOME`).
-The MongoDB UUID representation can now be configured with different formats.
-This has to be done via `MongoClientSettings` as shown in the snippet below.
+You need to initialize the MongoDB replica set only once on the first time the MongoDB server is started.
+To initialize the replica set, start a mongo client:
-.UUID Codec Configuration
-====
-[source,java]
+[source,bash]
----
-static class Config extends AbstractMongoClientConfiguration {
-
- @Override
- public void configureClientSettings(MongoClientSettings.Builder builder) {
- builder.uuidRepresentation(UuidRepresentation.STANDARD);
- }
-
- // ...
-}
+$ $MONGODB_HOME/bin/mongo
+MongoDB server version: 6.0.0
+...
----
-====
-
-== Getting Help
-
-Having trouble with Spring Data? We’d love to help!
-* Check the
-https://docs.spring.io/spring-data/mongodb/docs/current/reference/html/[reference documentation], and https://docs.spring.io/spring-data/mongodb/docs/current/api/[Javadocs].
-* Learn the Spring basics – Spring Data builds on Spring Framework, check the https://spring.io[spring.io] web-site for a wealth of reference documentation.
-If you are just starting out with Spring, try one of the https://spring.io/guides[guides].
-* If you are upgrading, check out the https://docs.spring.io/spring-data/mongodb/docs/current/changelog.txt[changelog] for "`new and noteworthy`" features.
-* Ask a question - we monitor https://stackoverflow.com[stackoverflow.com] for questions tagged with https://stackoverflow.com/tags/spring-data[`spring-data-mongodb`].
-You can also chat with the community on https://gitter.im/spring-projects/spring-data[Gitter].
-* Report bugs with Spring Data MongoDB at https://github.com/spring-projects/spring-data-mongodb/issues[github.com/spring-projects/spring-data-mongodb/issues].
+Then enter the following command:
-== Reporting Issues
+[source,bash]
+----
+mongo> rs.initiate({ _id: 'rs0', members: [ { _id: 0, host: '127.0.0.1:27017' } ] })
+----
-Spring Data uses Github as issue tracking system to record bugs and feature requests.
-If you want to raise an issue, please follow the recommendations below:
+Finally, on UNIX-based system (for example, Linux or Mac OS X) you may need to adjust the `ulimit`.
+In case you need to, you can adjust the `ulimit` with the following command (32768 is just a recommendation):
-* Before you log a bug, please search the https://github.com/spring-projects/spring-data-mongodb/issues[issue tracker] to see if someone has already reported the problem.
-* If the issue does not already exist, https://github.com/spring-projects/spring-data-mongodb/issues/new[create a new issue].
-* Please provide as much information as possible with the issue report, we like to know the version of Spring Data that you are using, the JVM version, Stacktrace, etc.
-* If you need to paste code, or include a stack trace use https://guides.github.com/features/mastering-markdown/[Markdown] code fences +++```+++.
+[source,bash]
+----
+$ ulimit -n 32768
+----
-== Building from Source
+You can use `ulimit -a` again to verify the `ulimit` for "_open files_" was set appropriately.
-You don’t need to build from source to use Spring Data (binaries in https://repo.spring.io[repo.spring.io]), but if you want to try out the latest and greatest, Spring Data can be easily built with the https://github.com/takari/maven-wrapper[maven wrapper].
-You also need JDK 1.8.
+Now you are ready to build Spring Data MongoDB. Simply enter the following `mvnw` (Maven Wrapper) command:
[source,bash]
----
$ ./mvnw clean install
----
-If you want to build with the regular `mvn` command, you will need https://maven.apache.org/run-maven/index.html[Maven v3.5.0 or above].
+If you want to build with the regular `mvn` command, you will need https://maven.apache.org/run-maven/index.html[Maven v3.8.0 or above].
-_Also see link:CONTRIBUTING.adoc[CONTRIBUTING.adoc] if you wish to submit pull requests, and in particular please sign the https://cla.pivotal.io/sign/spring[Contributor’s Agreement] before your first non-trivial change._
+_Also see link:CONTRIBUTING.adoc[CONTRIBUTING.adoc] if you wish to submit pull requests, and in particular, please sign
+the https://cla.pivotal.io/sign/spring[Contributor’s Agreement] before your first non-trivial change._
=== Building reference documentation
@@ -269,22 +220,12 @@ Building the documentation builds also the project without running tests.
[source,bash]
----
- $ ./mvnw clean install -Pdistribute
+ $ ./mvnw clean install -Pantora
----
-The generated documentation is available from `target/site/reference/html/index.html`.
-
-== Guides
-
-The https://spring.io/[spring.io] site contains several guides that show how to use Spring Data step-by-step:
-
-* https://spring.io/guides/gs/accessing-data-mongodb/[Accessing Data with MongoDB] is a very basic guide that shows you how to create a simple application and how to access data using repositories.
-* https://spring.io/guides/gs/accessing-mongodb-data-rest/[Accessing MongoDB Data with REST] is a guide to creating a REST web service exposing data stored in MongoDB through repositories.
-
-== Examples
-
-* https://github.com/spring-projects/spring-data-examples/[Spring Data Examples] contains example projects that explain specific features in more detail.
+The generated documentation is available from `target/antora/site/index.html`.
+[[license]]
== License
Spring Data MongoDB is Open Source software released under the https://www.apache.org/licenses/LICENSE-2.0.html[Apache 2.0 license].
diff --git a/ci/README.adoc b/ci/README.adoc
index 3e65271901..f1c11d8496 100644
--- a/ci/README.adoc
+++ b/ci/README.adoc
@@ -10,7 +10,7 @@ All of these use cases are great reasons to essentially run what Concourse does
IMPORTANT: To do this you must have Docker installed on your machine.
-1. `docker run -it --mount type=bind,source="$(pwd)",target=/spring-data-mongodb-github springci/spring-data-8-jdk-with-mongodb /bin/bash`
+1. `docker run -it --mount type=bind,source="$(pwd)",target=/spring-data-mongodb-github springci/spring-data-openjdk17-with-mongodb-5.0.3 /bin/bash`
+
This will launch the Docker image and mount your source code at `spring-data-mongodb-github`.
+
@@ -23,7 +23,7 @@ Since the container is binding to your source, you can make edits from your IDE
If you need to test the `build.sh` script, do this:
1. `mkdir /tmp/spring-data-mongodb-artifactory`
-2. `docker run -it --mount type=bind,source="$(pwd)",target=/spring-data-mongodb-github --mount type=bind,source="/tmp/spring-data-mongodb-artifactory",target=/spring-data-mongodb-artifactory springci/spring-data-8-jdk-with-mongodb /bin/bash`
+2. `docker run -it --mount type=bind,source="$(pwd)",target=/spring-data-mongodb-github --mount type=bind,source="/tmp/spring-data-mongodb-artifactory",target=/spring-data-mongodb-artifactory springci/spring-data-openjdk17-with-mongodb-5.0.3 /bin/bash`
+
This will launch the Docker image and mount your source code at `spring-data-mongodb-github` and the temporary
artifactory output directory at `spring-data-mongodb-artifactory`.
@@ -36,4 +36,4 @@ IMPORTANT: `build.sh` doesn't actually push to Artifactory so don't worry about
It just deploys to a local folder. That way, the `artifactory-resource` later in the pipeline can pick up these artifacts
and deliver them to artifactory.
-NOTE: Docker containers can eat up disk space fast! From time to time, run `docker system prune` to clean out old images.
\ No newline at end of file
+NOTE: Docker containers can eat up disk space fast! From time to time, run `docker system prune` to clean out old images.
diff --git a/ci/openjdk11-mongodb-4.4/Dockerfile b/ci/openjdk11-mongodb-4.4/Dockerfile
deleted file mode 100644
index 6c94ac38ff..0000000000
--- a/ci/openjdk11-mongodb-4.4/Dockerfile
+++ /dev/null
@@ -1,15 +0,0 @@
-FROM adoptopenjdk/openjdk11:latest
-
-ENV TZ=Etc/UTC
-ENV DEBIAN_FRONTEND=noninteractive
-
-RUN set -eux; \
- apt-get update && apt-get install -y apt-transport-https apt-utils gnupg2 ; \
- apt-key adv --keyserver hkps://keyserver.ubuntu.com:443 --recv 656408E390CFB1F5 ; \
- echo "deb [ arch=amd64 ] https://repo.mongodb.org/apt/ubuntu bionic/mongodb-org/4.4 multiverse" | tee /etc/apt/sources.list.d/mongodb-org-4.4.list; \
- echo ${TZ} > /etc/timezone;
-
-RUN apt-get update ; \
- apt-get install -y mongodb-org=4.4.4 mongodb-org-server=4.4.4 mongodb-org-shell=4.4.4 mongodb-org-mongos=4.4.4 mongodb-org-tools=4.4.4 ; \
- apt-get clean; \
- rm -rf /var/lib/apt/lists/*;
diff --git a/ci/openjdk16-mongodb-4.4/Dockerfile b/ci/openjdk16-mongodb-4.4/Dockerfile
deleted file mode 100644
index 7a1e47cf00..0000000000
--- a/ci/openjdk16-mongodb-4.4/Dockerfile
+++ /dev/null
@@ -1,15 +0,0 @@
-FROM adoptopenjdk/openjdk16:latest
-
-ENV TZ=Etc/UTC
-ENV DEBIAN_FRONTEND=noninteractive
-
-RUN set -eux; \
- apt-get update && apt-get install -y apt-transport-https apt-utils gnupg2 ; \
- apt-key adv --keyserver hkps://keyserver.ubuntu.com:443 --recv 656408E390CFB1F5 ; \
- echo "deb [ arch=amd64 ] https://repo.mongodb.org/apt/ubuntu bionic/mongodb-org/4.4 multiverse" | tee /etc/apt/sources.list.d/mongodb-org-4.4.list; \
- echo ${TZ} > /etc/timezone;
-
-RUN apt-get update ; \
- apt-get install -y mongodb-org=4.4.4 mongodb-org-server=4.4.4 mongodb-org-shell=4.4.4 mongodb-org-mongos=4.4.4 mongodb-org-tools=4.4.4 ; \
- apt-get clean; \
- rm -rf /var/lib/apt/lists/*;
diff --git a/ci/openjdk17-mongodb-6.0/Dockerfile b/ci/openjdk17-mongodb-6.0/Dockerfile
new file mode 100644
index 0000000000..fd2580e23a
--- /dev/null
+++ b/ci/openjdk17-mongodb-6.0/Dockerfile
@@ -0,0 +1,25 @@
+ARG BASE
+FROM ${BASE}
+# Any ARG statements before FROM are cleared.
+ARG MONGODB
+
+ENV TZ=Etc/UTC
+ENV DEBIAN_FRONTEND=noninteractive
+ENV MONGO_VERSION=${MONGODB}
+
+RUN set -eux; \
+ sed -i -e 's/archive.ubuntu.com/mirror.one.com/g' /etc/apt/sources.list && \
+ sed -i -e 's/security.ubuntu.com/mirror.one.com/g' /etc/apt/sources.list && \
+ sed -i -e 's/ports.ubuntu.com/mirrors.ocf.berkeley.edu/g' /etc/apt/sources.list && \
+ sed -i -e 's/http/https/g' /etc/apt/sources.list && \
+ apt-get update && apt-get install -y apt-transport-https apt-utils gnupg2 wget && \
+ # MongoDB 6.0 release signing key
+ wget -qO - https://www.mongodb.org/static/pgp/server-6.0.asc | apt-key add - && \
+ # Needed when MongoDB creates a 6.0 folder.
+ echo "deb [ arch=amd64,arm64 ] https://repo.mongodb.org/apt/ubuntu focal/mongodb-org/6.0 multiverse" | tee /etc/apt/sources.list.d/mongodb-org-6.0.list && \
+ echo ${TZ} > /etc/timezone
+
+RUN apt-get update && \
+ apt-get install -y mongodb-org=${MONGODB} mongodb-org-server=${MONGODB} mongodb-org-shell=${MONGODB} mongodb-org-mongos=${MONGODB} mongodb-org-tools=${MONGODB} && \
+ apt-get clean && \
+ rm -rf /var/lib/apt/lists/*
diff --git a/ci/openjdk17-mongodb-7.0/Dockerfile b/ci/openjdk17-mongodb-7.0/Dockerfile
new file mode 100644
index 0000000000..5701ab9fbc
--- /dev/null
+++ b/ci/openjdk17-mongodb-7.0/Dockerfile
@@ -0,0 +1,25 @@
+ARG BASE
+FROM ${BASE}
+# Any ARG statements before FROM are cleared.
+ARG MONGODB
+
+ENV TZ=Etc/UTC
+ENV DEBIAN_FRONTEND=noninteractive
+ENV MONGO_VERSION=${MONGODB}
+
+RUN set -eux; \
+ sed -i -e 's/archive.ubuntu.com/mirror.one.com/g' /etc/apt/sources.list && \
+ sed -i -e 's/security.ubuntu.com/mirror.one.com/g' /etc/apt/sources.list && \
+ sed -i -e 's/ports.ubuntu.com/mirrors.ocf.berkeley.edu/g' /etc/apt/sources.list && \
+ sed -i -e 's/http/https/g' /etc/apt/sources.list && \
+ apt-get update && apt-get install -y apt-transport-https apt-utils gnupg2 wget && \
+ # MongoDB 6.0 release signing key
+ wget -qO - https://www.mongodb.org/static/pgp/server-7.0.asc | apt-key add - && \
+ # Needed when MongoDB creates a 7.0 folder.
+ echo "deb [ arch=amd64,arm64 ] https://repo.mongodb.org/apt/ubuntu focal/mongodb-org/7.0 multiverse" | tee /etc/apt/sources.list.d/mongodb-org-7.0.list && \
+ echo ${TZ} > /etc/timezone
+
+RUN apt-get update && \
+ apt-get install -y mongodb-org=${MONGODB} mongodb-org-server=${MONGODB} mongodb-org-shell=${MONGODB} mongodb-org-mongos=${MONGODB} mongodb-org-tools=${MONGODB} && \
+ apt-get clean && \
+ rm -rf /var/lib/apt/lists/*
diff --git a/ci/openjdk23-mongodb-8.0/Dockerfile b/ci/openjdk23-mongodb-8.0/Dockerfile
new file mode 100644
index 0000000000..0cb80001bf
--- /dev/null
+++ b/ci/openjdk23-mongodb-8.0/Dockerfile
@@ -0,0 +1,25 @@
+ARG BASE
+FROM ${BASE}
+# Any ARG statements before FROM are cleared.
+ARG MONGODB
+
+ENV TZ=Etc/UTC
+ENV DEBIAN_FRONTEND=noninteractive
+ENV MONGO_VERSION=${MONGODB}
+
+RUN set -eux; \
+ sed -i -e 's/archive.ubuntu.com/mirror.one.com/g' /etc/apt/sources.list && \
+ sed -i -e 's/security.ubuntu.com/mirror.one.com/g' /etc/apt/sources.list && \
+ sed -i -e 's/ports.ubuntu.com/mirrors.ocf.berkeley.edu/g' /etc/apt/sources.list && \
+ sed -i -e 's/http/https/g' /etc/apt/sources.list && \
+ apt-get update && apt-get install -y apt-transport-https apt-utils gnupg2 wget && \
+ # MongoDB 8.0 release signing key
+ wget -qO - https://www.mongodb.org/static/pgp/server-8.0.asc | apt-key add - && \
+ # Needed when MongoDB creates a 8.0 folder.
+ echo "deb [ arch=amd64,arm64 ] https://repo.mongodb.org/apt/ubuntu noble/mongodb-org/8.0 multiverse" | tee /etc/apt/sources.list.d/mongodb-org-8.0.list && \
+ echo ${TZ} > /etc/timezone
+
+RUN apt-get update && \
+ apt-get install -y mongodb-org=${MONGODB} mongodb-org-server=${MONGODB} mongodb-org-shell=${MONGODB} mongodb-org-mongos=${MONGODB} mongodb-org-tools=${MONGODB} && \
+ apt-get clean && \
+ rm -rf /var/lib/apt/lists/*
diff --git a/ci/openjdk8-mongodb-4.0/Dockerfile b/ci/openjdk8-mongodb-4.0/Dockerfile
deleted file mode 100644
index e05068ab32..0000000000
--- a/ci/openjdk8-mongodb-4.0/Dockerfile
+++ /dev/null
@@ -1,15 +0,0 @@
-FROM adoptopenjdk/openjdk8:latest
-
-ENV TZ=Etc/UTC
-ENV DEBIAN_FRONTEND=noninteractive
-
-RUN RUN set -eux; \
- apt-get update && apt-get install -y apt-transport-https apt-utils gnupg2 ; \
- apt-key adv --keyserver hkps://keyserver.ubuntu.com:443 --recv 9DA31620334BD75D9DCB49F368818C72E52529D4 ; \
- echo "deb [ arch=amd64 ] https://repo.mongodb.org/apt/ubuntu bionic/mongodb-org/4.0 multiverse" | tee /etc/apt/sources.list.d/mongodb-org-4.0.list; \
- echo ${TZ} > /etc/timezone;
-
-RUN apt-get update ; \
- apt-get install -y mongodb-org=4.0.23 mongodb-org-server=4.0.23 mongodb-org-shell=4.0.23 mongodb-org-mongos=4.0.23 mongodb-org-tools=4.0.23 ; \
- apt-get clean; \
- rm -rf /var/lib/apt/lists/*;
diff --git a/ci/openjdk8-mongodb-4.4/Dockerfile b/ci/openjdk8-mongodb-4.4/Dockerfile
deleted file mode 100644
index 79774dd269..0000000000
--- a/ci/openjdk8-mongodb-4.4/Dockerfile
+++ /dev/null
@@ -1,17 +0,0 @@
-FROM adoptopenjdk/openjdk8:latest
-
-ENV TZ=Etc/UTC
-ENV DEBIAN_FRONTEND=noninteractive
-
-RUN set -eux; \
- apt-get update && apt-get install -y apt-transport-https apt-utils gnupg2 ; \
- apt-key adv --keyserver hkps://keyserver.ubuntu.com:443 --recv 656408E390CFB1F5 ; \
- echo "deb [ arch=amd64 ] https://repo.mongodb.org/apt/ubuntu bionic/mongodb-org/4.4 multiverse" | tee /etc/apt/sources.list.d/mongodb-org-4.4.list; \
- echo ${TZ} > /etc/timezone;
-
-RUN apt-get update ; \
- ln -T /bin/true /usr/bin/systemctl ; \
- apt-get install -y mongodb-org=4.4.4 mongodb-org-server=4.4.4 mongodb-org-shell=4.4.4 mongodb-org-mongos=4.4.4 mongodb-org-tools=4.4.4 ; \
- rm /usr/bin/systemctl ; \
- apt-get clean; \
- rm -rf /var/lib/apt/lists/*;
diff --git a/ci/pipeline.properties b/ci/pipeline.properties
new file mode 100644
index 0000000000..8dd2295acc
--- /dev/null
+++ b/ci/pipeline.properties
@@ -0,0 +1,32 @@
+# Java versions
+java.main.tag=17.0.15_6-jdk-focal
+java.next.tag=24.0.1_9-jdk-noble
+
+# Docker container images - standard
+docker.java.main.image=library/eclipse-temurin:${java.main.tag}
+docker.java.next.image=library/eclipse-temurin:${java.next.tag}
+
+# Supported versions of MongoDB
+docker.mongodb.6.0.version=6.0.23
+docker.mongodb.7.0.version=7.0.20
+docker.mongodb.8.0.version=8.0.9
+
+# Supported versions of Redis
+docker.redis.6.version=6.2.13
+docker.redis.7.version=7.2.4
+docker.valkey.8.version=8.1.1
+
+# Docker environment settings
+docker.java.inside.basic=-v $HOME:/tmp/jenkins-home
+docker.java.inside.docker=-u root -v /var/run/docker.sock:/var/run/docker.sock -v /usr/bin/docker:/usr/bin/docker -v $HOME:/tmp/jenkins-home
+
+# Credentials
+docker.registry=
+docker.credentials=hub.docker.com-springbuildmaster
+docker.proxy.registry=https://docker-hub.usw1.packages.broadcom.com
+docker.proxy.credentials=usw1_packages_broadcom_com-jenkins-token
+artifactory.credentials=02bd1690-b54f-4c9f-819d-a77cb7a9822c
+artifactory.url=https://repo.spring.io
+artifactory.repository.snapshot=libs-snapshot-local
+develocity.access-key=gradle_enterprise_secret_access_key
+jenkins.user.name=spring-builds+jenkins
diff --git a/ci/start-replica.sh b/ci/start-replica.sh
new file mode 100755
index 0000000000..9124976f39
--- /dev/null
+++ b/ci/start-replica.sh
@@ -0,0 +1,6 @@
+#!/bin/sh
+mkdir -p /tmp/mongodb/db /tmp/mongodb/log
+mongod --setParameter transactionLifetimeLimitSeconds=90 --setParameter maxTransactionLockRequestTimeoutMillis=10000 --dbpath /tmp/mongodb/db --replSet rs0 --fork --logpath /tmp/mongodb/log/mongod.log &
+sleep 10
+mongosh --eval "rs.initiate({_id: 'rs0', members:[{_id: 0, host: '127.0.0.1:27017'}]});"
+sleep 15
diff --git a/pom.xml b/pom.xml
index a6d5da9170..962ae73ffe 100644
--- a/pom.xml
+++ b/pom.xml
@@ -5,17 +5,17 @@
org.springframework.dataspring-data-mongodb-parent
- 3.3.0-SNAPSHOT
+ 4.5.0-SNAPSHOTpomSpring Data MongoDBMongoDB support for Spring Data
- https://projects.spring.io/spring-data-mongodb
+ https://spring.io/projects/spring-data-mongodborg.springframework.data.buildspring-data-parent
- 2.6.0-SNAPSHOT
+ 3.5.0-SNAPSHOT
@@ -26,9 +26,8 @@
multispring-data-mongodb
- 2.6.0-SNAPSHOT
- 4.2.3
- ${mongo}
+ 3.5.0-SNAPSHOT
+ 5.5.01.19
@@ -112,52 +111,66 @@
+
+ scm:git:https://github.com/spring-projects/spring-data-mongodb.git
+ scm:git:git@github.com:spring-projects/spring-data-mongodb.git
+ https://github.com/spring-projects/spring-data-mongodb
+
+
+
+ GitHub
+ https://github.com/spring-projects/spring-data-mongodb/issues
+
+
- benchmarks
-
- spring-data-mongodb
- spring-data-mongodb-distribution
- spring-data-mongodb-benchmarks
-
+ jmh
+
+
+ jitpack.io
+ https://jitpack.io
+
+
+
+
+ mongo-4.x
+
+ 4.11.1
+ 1.8.0
+
+
-
-
-
- org.mongodb
- mongodb-driver-core
- ${mongo}
-
-
+
+
+
+
+ org.mongodb
+ mongodb-driver-bom
+ ${mongo}
+ pom
+ import
+
+
+
+
- spring-libs-snapshot
- https://repo.spring.io/libs-snapshot
+ spring-snapshot
+ https://repo.spring.io/snapshot
+
+ true
+
+
+ false
+
- sonatype-libs-snapshot
- https://oss.sonatype.org/content/repositories/snapshots
-
- false
-
-
- true
-
+ spring-milestone
+ https://repo.spring.io/milestone
-
-
- spring-plugins-release
- https://repo.spring.io/plugins-release
-
-
- spring-libs-milestone
- https://repo.spring.io/libs-milestone
-
-
-
diff --git a/spring-data-mongodb-benchmarks/README.md b/spring-data-mongodb-benchmarks/README.md
deleted file mode 100644
index ca14cc11a9..0000000000
--- a/spring-data-mongodb-benchmarks/README.md
+++ /dev/null
@@ -1,76 +0,0 @@
-# Benchmarks
-
-Benchmarks are based on [JMH](https://openjdk.java.net/projects/code-tools/jmh/).
-
-# Running Benchmarks
-
-Running benchmarks is disabled by default and can be activated via the `benchmarks` profile.
-To run the benchmarks with default settings use.
-
-```bash
-mvn -P benchmarks clean test
-```
-
-A basic report will be printed to the CLI.
-
-```bash
-# Run complete. Total time: 00:00:15
-
-Benchmark Mode Cnt Score Error Units
-MappingMongoConverterBenchmark.readObject thrpt 10 1920157,631 ± 64310,809 ops/s
-MappingMongoConverterBenchmark.writeObject thrpt 10 782732,857 ± 53804,130 ops/s
-```
-
-## Running all Benchmarks of a specific class
-
-To run all Benchmarks of a specific class, just provide its simple class name via the `benchmark` command line argument.
-
-```bash
-mvn -P benchmarks clean test -D benchmark=MappingMongoConverterBenchmark
-```
-
-## Running a single Benchmark
-
-To run a single Benchmark provide its containing class simple name followed by `#` and the method name via the `benchmark` command line argument.
-
-```bash
-mvn -P benchmarks clean test -D benchmark=MappingMongoConverterBenchmark#readObjectWith2Properties
-```
-
-# Saving Benchmark Results
-
-A detailed benchmark report is stored in JSON format in the `/target/reports/performance` directory.
-To store the report in a different location use the `benchmarkReportDir` command line argument.
-
-## MongoDB
-
-Results can be directly piped to MongoDB by providing a valid [Connection String](https://docs.mongodb.com/manual/reference/connection-string/) via the `publishTo` command line argument.
-
-```bash
-mvn -P benchmarks clean test -D publishTo=mongodb://127.0.0.1:27017
-```
-
-NOTE: If the uri does not explicitly define a database the default `spring-data-mongodb-benchmarks` is used.
-
-## HTTP Endpoint
-
-The benchmark report can also be posted as `application/json` to an HTTP Endpoint by providing a valid URl via the `publishTo` command line argument.
-
-```bash
-mvn -P benchmarks clean test -D publishTo=http://127.0.0.1:8080/capture-benchmarks
-```
-
-# Customizing Benchmarks
-
-Following options can be set via command line.
-
-Option | Default Value
---- | ---
-warmupIterations | 10
-warmupTime | 1 (seconds)
-measurementIterations | 10
-measurementTime | 1 (seconds)
-forks | 1
-benchmarkReportDir | /target/reports/performance (always relative to project root dir)
-benchmark | .* (single benchmark via `classname#benchmark`)
-publishTo | \[not set\] (mongodb-uri or http-endpoint)
\ No newline at end of file
diff --git a/spring-data-mongodb-benchmarks/pom.xml b/spring-data-mongodb-benchmarks/pom.xml
deleted file mode 100644
index 0033bd11d5..0000000000
--- a/spring-data-mongodb-benchmarks/pom.xml
+++ /dev/null
@@ -1,112 +0,0 @@
-
-
-
- 4.0.0
-
-
- org.springframework.data
- spring-data-mongodb-parent
- 3.3.0-SNAPSHOT
- ../pom.xml
-
-
- spring-data-mongodb-benchmarks
- jar
-
- Spring Data MongoDB - Microbenchmarks
-
-
-
- true
-
-
-
-
-
- ${project.groupId}
- spring-data-mongodb
- ${project.version}
-
-
-
- junit
- junit
- ${junit}
- compile
-
-
-
- org.openjdk.jmh
- jmh-core
- ${jmh.version}
-
-
-
- org.openjdk.jmh
- jmh-generator-annprocess
- ${jmh.version}
- provided
-
-
-
-
-
-
-
- benchmarks
-
- false
-
-
-
-
-
-
-
- pl.project13.maven
- git-commit-id-plugin
- 2.2.2
-
-
-
- revision
-
-
-
-
-
- maven-jar-plugin
-
-
- default-jar
- never
-
-
-
-
- maven-surefire-plugin
-
- false
- ${project.build.sourceDirectory}
- ${project.build.outputDirectory}
-
- **/AbstractMicrobenchmark.java
- **/*$*.class
- **/generated/*.class
-
-
- **/*Benchmark*
-
-
- ${project.build.directory}/reports/performance
- ${project.version}
- ${git.dirty}
- ${git.commit.id}
- ${git.branch}
-
-
-
-
-
-
diff --git a/spring-data-mongodb-benchmarks/src/main/resources/logback.xml b/spring-data-mongodb-benchmarks/src/main/resources/logback.xml
deleted file mode 100644
index bccb2dc4fa..0000000000
--- a/spring-data-mongodb-benchmarks/src/main/resources/logback.xml
+++ /dev/null
@@ -1,14 +0,0 @@
-
-
-
-
-
- %d %5p %40.40c:%4L - %m%n
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/spring-data-mongodb-distribution/package.json b/spring-data-mongodb-distribution/package.json
new file mode 100644
index 0000000000..4689506b3f
--- /dev/null
+++ b/spring-data-mongodb-distribution/package.json
@@ -0,0 +1,10 @@
+{
+ "dependencies": {
+ "antora": "3.2.0-alpha.6",
+ "@antora/atlas-extension": "1.0.0-alpha.2",
+ "@antora/collector-extension": "1.0.0-alpha.7",
+ "@asciidoctor/tabs": "1.0.0-beta.6",
+ "@springio/antora-extensions": "1.13.0",
+ "@springio/asciidoctor-extensions": "1.0.0-alpha.11"
+ }
+}
diff --git a/spring-data-mongodb-distribution/pom.xml b/spring-data-mongodb-distribution/pom.xml
index f62c8dc7f4..58c63dfc97 100644
--- a/spring-data-mongodb-distribution/pom.xml
+++ b/spring-data-mongodb-distribution/pom.xml
@@ -1,6 +1,7 @@
-
+4.0.0
@@ -14,30 +15,59 @@
org.springframework.dataspring-data-mongodb-parent
- 3.3.0-SNAPSHOT
+ 4.5.0-SNAPSHOT../pom.xml${basedir}/..
- SDMONGO
+ ${project.basedir}/../src/main/antora/antora-playbook.yml
+
+
+ ${project.basedir}/../src/main/antora/resources/antora-resources
+ true
+
+
+
+ org.codehaus.mojo
+ build-helper-maven-plugin
+ 3.4.0
+
+
+ timestamp-property
+
+ timestamp-property
+
+ validate
+
+ current.year
+ yyyy
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-resources-plugin
+
+
+
+ resources
+
+
+
+ org.apache.maven.pluginsmaven-assembly-plugin
- org.asciidoctor
- asciidoctor-maven-plugin
-
-
- ${mongo.reactivestreams}
- ${reactor}
-
-
+ org.antora
+ antora-maven-plugin
diff --git a/spring-data-mongodb/pom.xml b/spring-data-mongodb/pom.xml
index 1f157e75bc..b842a2def3 100644
--- a/spring-data-mongodb/pom.xml
+++ b/spring-data-mongodb/pom.xml
@@ -1,5 +1,7 @@
-
+4.0.0
@@ -11,7 +13,7 @@
org.springframework.dataspring-data-mongodb-parent
- 3.3.0-SNAPSHOT
+ 4.5.0-SNAPSHOT../pom.xml
@@ -25,6 +27,30 @@
+
+
+ org.mongodb
+ mongodb-driver-core
+
+
+
+ org.mongodb
+ mongodb-driver-sync
+ true
+
+
+
+ org.mongodb
+ mongodb-driver-reactivestreams
+ true
+
+
+
+ org.mongodb
+ mongodb-crypt
+ true
+
+
org.springframework
@@ -94,22 +120,6 @@
true
-
-
-
- org.mongodb
- mongodb-driver-sync
- ${mongo}
- true
-
-
-
- org.mongodb
- mongodb-driver-reactivestreams
- ${mongo.reactivestreams}
- true
-
-
io.projectreactorreactor-core
@@ -123,24 +133,10 @@
- io.reactivex
- rxjava
- ${rxjava}
- true
-
-
-
- io.reactivex
- rxjava-reactive-streams
- ${rxjava-reactive-streams}
- true
-
-
-
- io.reactivex.rxjava2
- rxjava
- ${rxjava2}
- true
+ org.awaitility
+ awaitility
+ ${awaitility}
+ test
@@ -152,13 +148,6 @@
-
- org.apache.geronimo.specs
- geronimo-jcdi_2.0_spec
- 1.0.1
- test
-
-
javax.interceptorjavax.interceptor-api
@@ -167,17 +156,17 @@
- javax.enterprise
- cdi-api
+ jakarta.enterprise
+ jakarta.enterprise.cdi-api${cdi}providedtrue
- javax.annotation
- javax.annotation-api
- ${javax-annotation-api}
+ jakarta.annotation
+ jakarta.annotation-api
+ ${jakarta-annotation-api}test
@@ -190,8 +179,8 @@
- javax.validation
- validation-api
+ jakarta.validation
+ jakarta.validation-api${validation}true
@@ -204,44 +193,44 @@
- org.hibernate
- hibernate-validator
- 5.4.3.Final
- test
+ io.micrometer
+ micrometer-observation
+ true
- org.glassfish
- javax.el
- 3.0.1-b11
- test
+ io.micrometer
+ micrometer-tracing
+ true
- joda-time
- joda-time
- ${jodatime}
+ org.hibernate.validator
+ hibernate-validator
+ 7.0.1.Finaltest
- org.threeten
- threetenbp
- ${threetenbp}
+ jakarta.el
+ jakarta.el-api
+ 4.0.0
+ providedtrue
- com.fasterxml.jackson.core
- jackson-databind
+ org.glassfish
+ jakarta.el
+ 4.0.2
+ providedtrue
- org.slf4j
- jul-to-slf4j
- ${slf4j}
- test
+ com.fasterxml.jackson.core
+ jackson-databind
+ true
@@ -279,9 +268,29 @@
- javax.transaction
- jta
- 1.1
+ org.junit.platform
+ junit-platform-launcher
+ test
+
+
+
+ org.testcontainers
+ junit-jupiter
+ ${testcontainers}
+ test
+
+
+
+ org.testcontainers
+ mongodb
+ ${testcontainers}
+ test
+
+
+
+ jakarta.transaction
+ jakarta.transaction-api
+ 2.0.0test
@@ -312,17 +321,62 @@
io.mockk
- mockk
+ mockk-jvm${mockk}test
+
+ io.micrometer
+ micrometer-test
+ test
+
+
+ com.github.tomakehurst
+ wiremock-jre8-standalone
+
+
+
+
+ io.micrometer
+ micrometer-tracing-test
+ test
+
+
+
+ io.micrometer
+ micrometer-tracing-integration-test
+ test
+
+
+
+
+ org.jmolecules
+ jmolecules-ddd
+ ${jmolecules}
+ test
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+
+
+
+ org.openjdk.jmh
+ jmh-generator-annprocess
+ ${jmh}
+
+
+
+
+
com.mysema.mavenapt-maven-plugin
@@ -341,8 +395,11 @@
test-process
- target/generated-test-sources
- org.springframework.data.mongodb.repository.support.MongoAnnotationProcessor
+ target/generated-test-sources
+
+
+ org.springframework.data.mongodb.repository.support.MongoAnnotationProcessor
+
@@ -362,7 +419,11 @@
**/ReactivePerformanceTests.java
- src/test/resources/logging.properties
+ ${mongo}
+ ${env.MONGO_VERSION}
+
+ src/test/resources/logging.properties
+ true
diff --git a/spring-data-mongodb-benchmarks/src/main/java/org/springframework/data/mongodb/core/ProjectionsBenchmark.java b/spring-data-mongodb/src/jmh/java/org/springframework/data/mongodb/core/ProjectionsBenchmark.java
similarity index 95%
rename from spring-data-mongodb-benchmarks/src/main/java/org/springframework/data/mongodb/core/ProjectionsBenchmark.java
rename to spring-data-mongodb/src/jmh/java/org/springframework/data/mongodb/core/ProjectionsBenchmark.java
index 79e64ff4be..3b0c72cc0b 100644
--- a/spring-data-mongodb-benchmarks/src/main/java/org/springframework/data/mongodb/core/ProjectionsBenchmark.java
+++ b/spring-data-mongodb/src/jmh/java/org/springframework/data/mongodb/core/ProjectionsBenchmark.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2017-2021 the original author or authors.
+ * Copyright 2017-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -19,6 +19,7 @@
import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.annotations.Setup;
import org.openjdk.jmh.annotations.TearDown;
+
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.ExecutableFindOperation.FindWithQuery;
@@ -27,8 +28,8 @@
import org.springframework.data.mongodb.core.query.BasicQuery;
import org.springframework.data.mongodb.microbenchmark.AbstractMicrobenchmark;
-import com.mongodb.MongoClient;
-import com.mongodb.ServerAddress;
+import com.mongodb.client.MongoClient;
+import com.mongodb.client.MongoClients;
import com.mongodb.client.MongoCollection;
/**
@@ -56,7 +57,7 @@ public class ProjectionsBenchmark extends AbstractMicrobenchmark {
@Setup
public void setUp() {
- client = new MongoClient(new ServerAddress());
+ client = MongoClients.create();
template = new MongoTemplate(client, DB_NAME);
source = new Person();
@@ -83,7 +84,7 @@ public void setUp() {
@TearDown
public void tearDown() {
- client.dropDatabase(DB_NAME);
+ client.getDatabase(DB_NAME).drop();
client.close();
}
diff --git a/spring-data-mongodb-benchmarks/src/main/java/org/springframework/data/mongodb/core/convert/DbRefMappingBenchmark.java b/spring-data-mongodb/src/jmh/java/org/springframework/data/mongodb/core/convert/DbRefMappingBenchmark.java
similarity index 78%
rename from spring-data-mongodb-benchmarks/src/main/java/org/springframework/data/mongodb/core/convert/DbRefMappingBenchmark.java
rename to spring-data-mongodb/src/jmh/java/org/springframework/data/mongodb/core/convert/DbRefMappingBenchmark.java
index 83eeec9eab..53f64f2a50 100644
--- a/spring-data-mongodb-benchmarks/src/main/java/org/springframework/data/mongodb/core/convert/DbRefMappingBenchmark.java
+++ b/spring-data-mongodb/src/jmh/java/org/springframework/data/mongodb/core/convert/DbRefMappingBenchmark.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2017-2021 the original author or authors.
+ * Copyright 2017-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -18,8 +18,6 @@
import static org.springframework.data.mongodb.core.query.Criteria.*;
import static org.springframework.data.mongodb.core.query.Query.*;
-import lombok.Data;
-
import java.util.ArrayList;
import java.util.List;
@@ -29,14 +27,15 @@
import org.openjdk.jmh.annotations.Setup;
import org.openjdk.jmh.annotations.State;
import org.openjdk.jmh.annotations.TearDown;
+
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.mapping.DBRef;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.microbenchmark.AbstractMicrobenchmark;
-import com.mongodb.MongoClient;
-import com.mongodb.ServerAddress;
+import com.mongodb.client.MongoClient;
+import com.mongodb.client.MongoClients;
/**
* @author Christoph Strobl
@@ -55,7 +54,7 @@ public class DbRefMappingBenchmark extends AbstractMicrobenchmark {
@Setup
public void setUp() throws Exception {
- client = new MongoClient(new ServerAddress());
+ client = MongoClients.create();
template = new MongoTemplate(client, DB_NAME);
List refObjects = new ArrayList<>();
@@ -80,7 +79,7 @@ public void setUp() throws Exception {
@TearDown
public void tearDown() {
- client.dropDatabase(DB_NAME);
+ client.getDatabase(DB_NAME).drop();
client.close();
}
@@ -94,18 +93,56 @@ public ObjectWithDBRef readMultipleDbRefs() {
return template.findOne(queryObjectWithDBRefList, ObjectWithDBRef.class);
}
- @Data
static class ObjectWithDBRef {
private @Id ObjectId id;
private @DBRef RefObject ref;
private @DBRef List refList;
+
+ public ObjectId getId() {
+ return id;
+ }
+
+ public void setId(ObjectId id) {
+ this.id = id;
+ }
+
+ public RefObject getRef() {
+ return ref;
+ }
+
+ public void setRef(RefObject ref) {
+ this.ref = ref;
+ }
+
+ public List getRefList() {
+ return refList;
+ }
+
+ public void setRefList(List refList) {
+ this.refList = refList;
+ }
}
- @Data
static class RefObject {
private @Id String id;
private String someValue;
+
+ public String getId() {
+ return id;
+ }
+
+ public void setId(String id) {
+ this.id = id;
+ }
+
+ public String getSomeValue() {
+ return someValue;
+ }
+
+ public void setSomeValue(String someValue) {
+ this.someValue = someValue;
+ }
}
}
diff --git a/spring-data-mongodb-benchmarks/src/main/java/org/springframework/data/mongodb/core/convert/MappingMongoConverterBenchmark.java b/spring-data-mongodb/src/jmh/java/org/springframework/data/mongodb/core/convert/MappingMongoConverterBenchmark.java
similarity index 74%
rename from spring-data-mongodb-benchmarks/src/main/java/org/springframework/data/mongodb/core/convert/MappingMongoConverterBenchmark.java
rename to spring-data-mongodb/src/jmh/java/org/springframework/data/mongodb/core/convert/MappingMongoConverterBenchmark.java
index 0941d9c0ac..00d2e7034a 100644
--- a/spring-data-mongodb-benchmarks/src/main/java/org/springframework/data/mongodb/core/convert/MappingMongoConverterBenchmark.java
+++ b/spring-data-mongodb/src/jmh/java/org/springframework/data/mongodb/core/convert/MappingMongoConverterBenchmark.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2017-2021 the original author or authors.
+ * Copyright 2017-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -15,11 +15,6 @@
*/
package org.springframework.data.mongodb.core.convert;
-import lombok.AllArgsConstructor;
-import lombok.Data;
-import lombok.Getter;
-import lombok.RequiredArgsConstructor;
-
import java.util.Arrays;
import java.util.Collections;
import java.util.LinkedHashMap;
@@ -29,25 +24,29 @@
import org.bson.Document;
import org.bson.types.ObjectId;
+import org.junit.platform.commons.annotation.Testable;
import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.annotations.Scope;
import org.openjdk.jmh.annotations.Setup;
import org.openjdk.jmh.annotations.State;
import org.openjdk.jmh.annotations.TearDown;
+
import org.springframework.data.annotation.Id;
import org.springframework.data.geo.Point;
-import org.springframework.data.mongodb.core.SimpleMongoDbFactory;
+import org.springframework.data.mongodb.core.SimpleMongoClientDatabaseFactory;
import org.springframework.data.mongodb.core.mapping.Field;
import org.springframework.data.mongodb.core.mapping.MongoMappingContext;
import org.springframework.data.mongodb.microbenchmark.AbstractMicrobenchmark;
+import org.springframework.util.ObjectUtils;
-import com.mongodb.MongoClient;
-import com.mongodb.ServerAddress;
+import com.mongodb.client.MongoClient;
+import com.mongodb.client.MongoClients;
/**
* @author Christoph Strobl
*/
@State(Scope.Benchmark)
+@Testable
public class MappingMongoConverterBenchmark extends AbstractMicrobenchmark {
private static final String DB_NAME = "mapping-mongo-converter-benchmark";
@@ -64,13 +63,13 @@ public class MappingMongoConverterBenchmark extends AbstractMicrobenchmark {
@Setup
public void setUp() throws Exception {
- client = new MongoClient(new ServerAddress());
+ client = MongoClients.create();
this.mappingContext = new MongoMappingContext();
this.mappingContext.setInitialEntitySet(Collections.singleton(Customer.class));
this.mappingContext.afterPropertiesSet();
- DbRefResolver dbRefResolver = new DefaultDbRefResolver(new SimpleMongoDbFactory(client, DB_NAME));
+ DbRefResolver dbRefResolver = new DefaultDbRefResolver(new SimpleMongoClientDatabaseFactory(client, DB_NAME));
this.converter = new MappingMongoConverter(dbRefResolver, mappingContext);
this.converter.setCustomConversions(new MongoCustomConversions(Collections.emptyList()));
@@ -116,7 +115,7 @@ public void setUp() throws Exception {
@TearDown
public void tearDown() {
- client.dropDatabase(DB_NAME);
+ client.getDatabase(DB_NAME).drop();
client.close();
}
@@ -151,22 +150,36 @@ public Object writeObjectWithListAndMapsOfComplexType() {
return sink;
}
- @Getter
- @RequiredArgsConstructor
static class Customer {
private @Id ObjectId id;
private final String firstname, lastname;
private final Address address;
+
+ public Customer(String firstname, String lastname, Address address) {
+ this.firstname = firstname;
+ this.lastname = lastname;
+ this.address = address;
+ }
}
- @Getter
- @AllArgsConstructor
static class Address {
private String zipCode, city;
+
+ public Address(String zipCode, String city) {
+ this.zipCode = zipCode;
+ this.city = city;
+ }
+
+ public String getZipCode() {
+ return zipCode;
+ }
+
+ public String getCity() {
+ return city;
+ }
}
- @Data
static class SlightlyMoreComplexObject {
@Id String id;
@@ -177,5 +190,59 @@ static class SlightlyMoreComplexObject {
Customer customer;
List addressList;
Map customerMap;
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (!(o instanceof SlightlyMoreComplexObject)) {
+ return false;
+ }
+ SlightlyMoreComplexObject that = (SlightlyMoreComplexObject) o;
+ if (intOne != that.intOne) {
+ return false;
+ }
+ if (intTwo != that.intTwo) {
+ return false;
+ }
+ if (!ObjectUtils.nullSafeEquals(id, that.id)) {
+ return false;
+ }
+ if (!ObjectUtils.nullSafeEquals(stringOne, that.stringOne)) {
+ return false;
+ }
+ if (!ObjectUtils.nullSafeEquals(stringTwo, that.stringTwo)) {
+ return false;
+ }
+ if (!ObjectUtils.nullSafeEquals(renamedField, that.renamedField)) {
+ return false;
+ }
+ if (!ObjectUtils.nullSafeEquals(location, that.location)) {
+ return false;
+ }
+ if (!ObjectUtils.nullSafeEquals(customer, that.customer)) {
+ return false;
+ }
+ if (!ObjectUtils.nullSafeEquals(addressList, that.addressList)) {
+ return false;
+ }
+ return ObjectUtils.nullSafeEquals(customerMap, that.customerMap);
+ }
+
+ @Override
+ public int hashCode() {
+ int result = ObjectUtils.nullSafeHashCode(id);
+ result = 31 * result + intOne;
+ result = 31 * result + intTwo;
+ result = 31 * result + ObjectUtils.nullSafeHashCode(stringOne);
+ result = 31 * result + ObjectUtils.nullSafeHashCode(stringTwo);
+ result = 31 * result + ObjectUtils.nullSafeHashCode(renamedField);
+ result = 31 * result + ObjectUtils.nullSafeHashCode(location);
+ result = 31 * result + ObjectUtils.nullSafeHashCode(customer);
+ result = 31 * result + ObjectUtils.nullSafeHashCode(addressList);
+ result = 31 * result + ObjectUtils.nullSafeHashCode(customerMap);
+ return result;
+ }
}
}
diff --git a/spring-data-mongodb-benchmarks/src/main/java/org/springframework/data/mongodb/microbenchmark/AbstractMicrobenchmark.java b/spring-data-mongodb/src/jmh/java/org/springframework/data/mongodb/microbenchmark/AbstractMicrobenchmark.java
similarity index 97%
rename from spring-data-mongodb-benchmarks/src/main/java/org/springframework/data/mongodb/microbenchmark/AbstractMicrobenchmark.java
rename to spring-data-mongodb/src/jmh/java/org/springframework/data/mongodb/microbenchmark/AbstractMicrobenchmark.java
index 5c99c07fa6..615500904d 100644
--- a/spring-data-mongodb-benchmarks/src/main/java/org/springframework/data/mongodb/microbenchmark/AbstractMicrobenchmark.java
+++ b/spring-data-mongodb/src/jmh/java/org/springframework/data/mongodb/microbenchmark/AbstractMicrobenchmark.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2017-2021 the original author or authors.
+ * Copyright 2017-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -21,7 +21,6 @@
import java.util.Collection;
import java.util.Date;
-import org.junit.Test;
import org.openjdk.jmh.annotations.Fork;
import org.openjdk.jmh.annotations.Measurement;
import org.openjdk.jmh.annotations.Scope;
@@ -33,6 +32,7 @@
import org.openjdk.jmh.runner.options.ChainedOptionsBuilder;
import org.openjdk.jmh.runner.options.OptionsBuilder;
import org.openjdk.jmh.runner.options.TimeValue;
+
import org.springframework.core.env.StandardEnvironment;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ResourceUtils;
@@ -41,8 +41,8 @@
/**
* @author Christoph Strobl
*/
-@Warmup(iterations = AbstractMicrobenchmark.WARMUP_ITERATIONS)
-@Measurement(iterations = AbstractMicrobenchmark.MEASUREMENT_ITERATIONS)
+@Warmup(iterations = AbstractMicrobenchmark.WARMUP_ITERATIONS, time = 2)
+@Measurement(iterations = AbstractMicrobenchmark.MEASUREMENT_ITERATIONS, time = 2)
@Fork(AbstractMicrobenchmark.FORKS)
@State(Scope.Thread)
public class AbstractMicrobenchmark {
@@ -62,7 +62,6 @@ public class AbstractMicrobenchmark {
* @throws Exception
* @see #options(String)
*/
- @Test
public void run() throws Exception {
String includes = includes();
@@ -322,7 +321,7 @@ private void publishResults(Collection results) {
try {
ResultsWriter.forUri(uri).write(results);
} catch (Exception e) {
- System.err.println(String.format("Cannot save benchmark results to '%s'. Error was %s.", uri, e));
+ System.err.println(String.format("Cannot save benchmark results to '%s'; Error was %s", uri, e));
}
}
}
diff --git a/spring-data-mongodb-benchmarks/src/main/java/org/springframework/data/mongodb/microbenchmark/HttpResultsWriter.java b/spring-data-mongodb/src/jmh/java/org/springframework/data/mongodb/microbenchmark/HttpResultsWriter.java
similarity index 91%
rename from spring-data-mongodb-benchmarks/src/main/java/org/springframework/data/mongodb/microbenchmark/HttpResultsWriter.java
rename to spring-data-mongodb/src/jmh/java/org/springframework/data/mongodb/microbenchmark/HttpResultsWriter.java
index 8d3e57eecc..af56908755 100644
--- a/spring-data-mongodb-benchmarks/src/main/java/org/springframework/data/mongodb/microbenchmark/HttpResultsWriter.java
+++ b/spring-data-mongodb/src/jmh/java/org/springframework/data/mongodb/microbenchmark/HttpResultsWriter.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2017-2021 the original author or authors.
+ * Copyright 2017-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -15,8 +15,8 @@
*/
package org.springframework.data.mongodb.microbenchmark;
-import lombok.SneakyThrows;
+import java.io.IOException;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
@@ -43,13 +43,20 @@ class HttpResultsWriter implements ResultsWriter {
}
@Override
- @SneakyThrows
public void write(Collection results) {
if (CollectionUtils.isEmpty(results)) {
return;
}
+ try {
+ doWrite(results);
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ private void doWrite(Collection results) throws IOException {
StandardEnvironment env = new StandardEnvironment();
String projectVersion = env.getProperty("project.version", "unknown");
diff --git a/spring-data-mongodb-benchmarks/src/main/java/org/springframework/data/mongodb/microbenchmark/MongoResultsWriter.java b/spring-data-mongodb/src/jmh/java/org/springframework/data/mongodb/microbenchmark/MongoResultsWriter.java
similarity index 86%
rename from spring-data-mongodb-benchmarks/src/main/java/org/springframework/data/mongodb/microbenchmark/MongoResultsWriter.java
rename to spring-data-mongodb/src/jmh/java/org/springframework/data/mongodb/microbenchmark/MongoResultsWriter.java
index 4167d3c01d..2114d2a06a 100644
--- a/spring-data-mongodb-benchmarks/src/main/java/org/springframework/data/mongodb/microbenchmark/MongoResultsWriter.java
+++ b/spring-data-mongodb/src/jmh/java/org/springframework/data/mongodb/microbenchmark/MongoResultsWriter.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2017-2021 the original author or authors.
+ * Copyright 2017-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -21,15 +21,16 @@
import org.bson.Document;
import org.openjdk.jmh.results.RunResult;
+
import org.springframework.core.env.StandardEnvironment;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import com.mongodb.BasicDBObject;
-import com.mongodb.MongoClient;
-import com.mongodb.MongoClientURI;
+import com.mongodb.ConnectionString;
+import com.mongodb.client.MongoClient;
+import com.mongodb.client.MongoClients;
import com.mongodb.client.MongoDatabase;
-import com.mongodb.util.JSON;
/**
* MongoDB specific {@link ResultsWriter} implementation.
@@ -56,13 +57,14 @@ public void write(Collection results) {
String gitDirty = env.getProperty("git.dirty", "no");
String gitCommitId = env.getProperty("git.commit.id", "unknown");
- MongoClientURI uri = new MongoClientURI(this.uri);
- MongoClient client = new MongoClient(uri);
+ ConnectionString connectionString = new ConnectionString(this.uri);
+ MongoClient client = MongoClients.create(this.uri);
- String dbName = StringUtils.hasText(uri.getDatabase()) ? uri.getDatabase() : "spring-data-mongodb-benchmarks";
+ String dbName = StringUtils.hasText(connectionString.getDatabase()) ? connectionString.getDatabase()
+ : "spring-data-mongodb-benchmarks";
MongoDatabase db = client.getDatabase(dbName);
- for (BasicDBObject dbo : (List) JSON.parse(ResultsWriter.jsonifyResults(results))) {
+ for (Document dbo : (List) Document.parse(ResultsWriter.jsonifyResults(results))) {
String collectionName = extractClass(dbo.get("benchmark").toString());
diff --git a/spring-data-mongodb-benchmarks/src/main/java/org/springframework/data/mongodb/microbenchmark/ResultsWriter.java b/spring-data-mongodb/src/jmh/java/org/springframework/data/mongodb/microbenchmark/ResultsWriter.java
similarity index 89%
rename from spring-data-mongodb-benchmarks/src/main/java/org/springframework/data/mongodb/microbenchmark/ResultsWriter.java
rename to spring-data-mongodb/src/jmh/java/org/springframework/data/mongodb/microbenchmark/ResultsWriter.java
index c55e10daaa..95da1750bc 100644
--- a/spring-data-mongodb-benchmarks/src/main/java/org/springframework/data/mongodb/microbenchmark/ResultsWriter.java
+++ b/spring-data-mongodb/src/jmh/java/org/springframework/data/mongodb/microbenchmark/ResultsWriter.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2017-2021 the original author or authors.
+ * Copyright 2017-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -15,8 +15,6 @@
*/
package org.springframework.data.mongodb.microbenchmark;
-import lombok.SneakyThrows;
-
import java.io.ByteArrayOutputStream;
import java.io.PrintStream;
import java.nio.charset.StandardCharsets;
@@ -54,13 +52,12 @@ static ResultsWriter forUri(String uri) {
*
* @param results
* @return json string representation of results.
- * @see org.openjdk.jmh.results.format.JSONResultFormat
*/
- @SneakyThrows
static String jsonifyResults(Collection results) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
- ResultFormatFactory.getInstance(ResultFormatType.JSON, new PrintStream(baos, true, "UTF-8")).writeOut(results);
+ ResultFormatFactory.getInstance(ResultFormatType.JSON, new PrintStream(baos, true, StandardCharsets.UTF_8))
+ .writeOut(results);
return new String(baos.toByteArray(), StandardCharsets.UTF_8);
}
diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/BindableMongoExpression.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/BindableMongoExpression.java
index 982f683d53..1f6875c080 100644
--- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/BindableMongoExpression.java
+++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/BindableMongoExpression.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2021 the original author or authors.
+ * Copyright 2021-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -23,15 +23,16 @@
import org.springframework.data.mongodb.util.json.ParameterBindingDocumentCodec;
import org.springframework.data.util.Lazy;
import org.springframework.lang.Nullable;
+import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
/**
* A {@link MongoExpression} using the {@link ParameterBindingDocumentCodec} for parsing a raw ({@literal json})
* expression. The expression will be wrapped within { ... } if necessary. The actual parsing and parameter
- * binding of placeholders like {@code ?0} is delayed upon first call on the the target {@link Document} via
+ * binding of placeholders like {@code ?0} is delayed upon first call on the target {@link Document} via
* {@link #toDocument()}.
- *
+ *
*
*
* $toUpper : $name -> { '$toUpper' : '$name' }
@@ -45,6 +46,7 @@
* containing the required {@link org.bson.codecs.Codec codec} via {@link #withCodecRegistry(CodecRegistry)}.
*
* @author Christoph Strobl
+ * @author Giacomo Baso
* @since 3.2
*/
public class BindableMongoExpression implements MongoExpression {
@@ -77,6 +79,8 @@ public BindableMongoExpression(String expression, @Nullable Object[] args) {
public BindableMongoExpression(String expression, @Nullable CodecRegistryProvider codecRegistryProvider,
@Nullable Object[] args) {
+ Assert.notNull(expression, "Expression must not be null");
+
this.expressionString = expression;
this.codecRegistryProvider = codecRegistryProvider;
this.args = args;
@@ -103,19 +107,11 @@ public BindableMongoExpression bind(Object... args) {
return new BindableMongoExpression(expressionString, codecRegistryProvider, args);
}
- /*
- * (non-Javadoc)
- * @see org.springframework.data.mongodb.MongoExpression#toDocument()
- */
@Override
public Document toDocument() {
return target.get();
}
- /*
- * (non-Javadoc)
- * @see java.lang.Object#toString()
- */
@Override
public String toString() {
return "BindableMongoExpression{" + "expressionString='" + expressionString + '\'' + ", args="
@@ -143,10 +139,11 @@ private Document parse() {
private static String wrapJsonIfNecessary(String json) {
- if (StringUtils.hasText(json) && (json.startsWith("{") && json.endsWith("}"))) {
+ if(!StringUtils.hasText(json)) {
return json;
}
- return "{" + json + "}";
+ String raw = json.trim();
+ return (raw.startsWith("{") && raw.endsWith("}")) ? raw : "{%s}".formatted(raw);
}
}
diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/BulkOperationException.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/BulkOperationException.java
index 03fadff0fe..b36382a58e 100644
--- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/BulkOperationException.java
+++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/BulkOperationException.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2015-2021 the original author or authors.
+ * Copyright 2015-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/ClientSessionException.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/ClientSessionException.java
index fae652c7f4..53acf65470 100644
--- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/ClientSessionException.java
+++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/ClientSessionException.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2018-2021 the original author or authors.
+ * Copyright 2018-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/CodecRegistryProvider.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/CodecRegistryProvider.java
index 60b2027763..53515f9fcd 100644
--- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/CodecRegistryProvider.java
+++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/CodecRegistryProvider.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2017-2021 the original author or authors.
+ * Copyright 2017-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -62,7 +62,7 @@ default boolean hasCodecFor(Class> type) {
*/
default Optional> getCodecFor(Class type) {
- Assert.notNull(type, "Type must not be null!");
+ Assert.notNull(type, "Type must not be null");
try {
return Optional.of(getCodecRegistry().get(type));
diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/DefaultMongoTransactionOptionsResolver.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/DefaultMongoTransactionOptionsResolver.java
new file mode 100644
index 0000000000..c07e2dbe4a
--- /dev/null
+++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/DefaultMongoTransactionOptionsResolver.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2024-2025 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.data.mongodb;
+
+import java.util.Map;
+import java.util.Set;
+
+import org.springframework.lang.Nullable;
+
+/**
+ * Default implementation of {@link MongoTransactionOptions} using {@literal mongo:} as {@link #getLabelPrefix() label
+ * prefix} creating {@link SimpleMongoTransactionOptions} out of a given argument {@link Map}. Uses
+ * {@link SimpleMongoTransactionOptions#KNOWN_KEYS} to validate entries in arguments to resolve and errors on unknown
+ * entries.
+ *
+ * @author Christoph Strobl
+ * @since 4.3
+ */
+enum DefaultMongoTransactionOptionsResolver implements MongoTransactionOptionsResolver {
+
+ INSTANCE;
+
+ private static final String PREFIX = "mongo:";
+
+ @Override
+ public MongoTransactionOptions convert(Map options) {
+
+ validateKeys(options.keySet());
+ return SimpleMongoTransactionOptions.of(options);
+ }
+
+ @Nullable
+ @Override
+ public String getLabelPrefix() {
+ return PREFIX;
+ }
+
+ private static void validateKeys(Set keys) {
+
+ if (!SimpleMongoTransactionOptions.KNOWN_KEYS.containsAll(keys)) {
+
+ throw new IllegalArgumentException("Transaction labels contained invalid values. Has to be one of %s"
+ .formatted(SimpleMongoTransactionOptions.KNOWN_KEYS));
+ }
+ }
+}
diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/InvalidMongoDbApiUsageException.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/InvalidMongoDbApiUsageException.java
index 89e035ae69..f95a3c5310 100644
--- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/InvalidMongoDbApiUsageException.java
+++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/InvalidMongoDbApiUsageException.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2010-2021 the original author or authors.
+ * Copyright 2010-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/LazyLoadingException.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/LazyLoadingException.java
index 855a59c55d..3fc3f82fbf 100644
--- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/LazyLoadingException.java
+++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/LazyLoadingException.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2013-2021 the original author or authors.
+ * Copyright 2013-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/MongoCollectionUtils.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/MongoCollectionUtils.java
index 3d85a33dcb..72b2794d05 100644
--- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/MongoCollectionUtils.java
+++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/MongoCollectionUtils.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2011-2021 the original author or authors.
+ * Copyright 2011-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -20,8 +20,8 @@
/**
* Helper class featuring helper methods for working with MongoDb collections.
- *
- *
+ *
+ *
* Mainly intended for internal use within the framework.
*
* @author Thomas Risberg
diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/MongoDatabaseFactory.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/MongoDatabaseFactory.java
index 612c3eeb3e..1fcd5de516 100644
--- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/MongoDatabaseFactory.java
+++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/MongoDatabaseFactory.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2011-2021 the original author or authors.
+ * Copyright 2011-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/MongoDatabaseUtils.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/MongoDatabaseUtils.java
index ba8efa536c..f73f9fb7ed 100644
--- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/MongoDatabaseUtils.java
+++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/MongoDatabaseUtils.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2018-2021 the original author or authors.
+ * Copyright 2018-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -30,7 +30,7 @@
* Helper class for managing a {@link MongoDatabase} instances via {@link MongoDatabaseFactory}. Used for obtaining
* {@link ClientSession session bound} resources, such as {@link MongoDatabase} and
* {@link com.mongodb.client.MongoCollection} suitable for transactional usage.
- *
+ *
* Note: Intended for internal usage only.
*
* @author Christoph Strobl
@@ -43,7 +43,7 @@ public class MongoDatabaseUtils {
/**
* Obtain the default {@link MongoDatabase database} form the given {@link MongoDatabaseFactory factory} using
* {@link SessionSynchronization#ON_ACTUAL_TRANSACTION native session synchronization}.
- *
+ *
* Registers a {@link MongoSessionSynchronization MongoDB specific transaction synchronization} within the current
* {@link Thread} if {@link TransactionSynchronizationManager#isSynchronizationActive() synchronization is active}.
*
@@ -56,7 +56,7 @@ public static MongoDatabase getDatabase(MongoDatabaseFactory factory) {
/**
* Obtain the default {@link MongoDatabase database} form the given {@link MongoDatabaseFactory factory}.
- *
+ *
* Registers a {@link MongoSessionSynchronization MongoDB specific transaction synchronization} within the current
* {@link Thread} if {@link TransactionSynchronizationManager#isSynchronizationActive() synchronization is active}.
*
@@ -71,7 +71,7 @@ public static MongoDatabase getDatabase(MongoDatabaseFactory factory, SessionSyn
/**
* Obtain the {@link MongoDatabase database} with given name form the given {@link MongoDatabaseFactory factory} using
* {@link SessionSynchronization#ON_ACTUAL_TRANSACTION native session synchronization}.
- *
+ *
* Registers a {@link MongoSessionSynchronization MongoDB specific transaction synchronization} within the current
* {@link Thread} if {@link TransactionSynchronizationManager#isSynchronizationActive() synchronization is active}.
*
@@ -85,7 +85,7 @@ public static MongoDatabase getDatabase(@Nullable String dbName, MongoDatabaseFa
/**
* Obtain the {@link MongoDatabase database} with given name form the given {@link MongoDatabaseFactory factory}.
- *
+ *
* Registers a {@link MongoSessionSynchronization MongoDB specific transaction synchronization} within the current
* {@link Thread} if {@link TransactionSynchronizationManager#isSynchronizationActive() synchronization is active}.
*
@@ -102,9 +102,10 @@ public static MongoDatabase getDatabase(@Nullable String dbName, MongoDatabaseFa
private static MongoDatabase doGetMongoDatabase(@Nullable String dbName, MongoDatabaseFactory factory,
SessionSynchronization sessionSynchronization) {
- Assert.notNull(factory, "Factory must not be null!");
+ Assert.notNull(factory, "Factory must not be null");
- if (!TransactionSynchronizationManager.isSynchronizationActive()) {
+ if (sessionSynchronization == SessionSynchronization.NEVER
+ || !TransactionSynchronizationManager.isSynchronizationActive()) {
return StringUtils.hasText(dbName) ? factory.getMongoDatabase(dbName) : factory.getMongoDatabase();
}
@@ -192,19 +193,11 @@ private static class MongoSessionSynchronization extends ResourceHolderSynchroni
this.resourceHolder = resourceHolder;
}
- /*
- * (non-Javadoc)
- * @see org.springframework.transaction.support.ResourceHolderSynchronization#shouldReleaseBeforeCompletion()
- */
@Override
protected boolean shouldReleaseBeforeCompletion() {
return false;
}
- /*
- * (non-Javadoc)
- * @see org.springframework.transaction.support.ResourceHolderSynchronization#processResourceAfterCommit(java.lang.Object)
- */
@Override
protected void processResourceAfterCommit(MongoResourceHolder resourceHolder) {
@@ -213,10 +206,6 @@ protected void processResourceAfterCommit(MongoResourceHolder resourceHolder) {
}
}
- /*
- * (non-Javadoc)
- * @see org.springframework.transaction.support.ResourceHolderSynchronization#afterCompletion(int)
- */
@Override
public void afterCompletion(int status) {
@@ -227,10 +216,6 @@ public void afterCompletion(int status) {
super.afterCompletion(status);
}
- /*
- * (non-Javadoc)
- * @see org.springframework.transaction.support.ResourceHolderSynchronization#releaseResource(java.lang.Object, java.lang.Object)
- */
@Override
protected void releaseResource(MongoResourceHolder resourceHolder, Object resourceKey) {
diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/MongoDbFactory.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/MongoDbFactory.java
deleted file mode 100644
index 9356a9e7d3..0000000000
--- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/MongoDbFactory.java
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright 2011-2021 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.springframework.data.mongodb;
-
-import org.springframework.dao.DataAccessException;
-
-import com.mongodb.client.MongoDatabase;
-
-/**
- * Interface for factories creating {@link MongoDatabase} instances.
- *
- * @author Mark Pollack
- * @author Thomas Darimont
- * @author Christoph Strobl
- * @deprecated since 3.0, use {@link MongoDatabaseFactory} instead.
- */
-@Deprecated
-public interface MongoDbFactory extends MongoDatabaseFactory {
-
- /**
- * Creates a default {@link MongoDatabase} instance.
- *
- * @return never {@literal null}.
- * @throws DataAccessException
- * @deprecated since 3.0. Use {@link #getMongoDatabase()} instead.
- */
- @Deprecated
- default MongoDatabase getDb() throws DataAccessException {
- return getMongoDatabase();
- }
-
- /**
- * Obtain a {@link MongoDatabase} instance to access the database with the given name.
- *
- * @param dbName must not be {@literal null} or empty.
- * @return never {@literal null}.
- * @throws DataAccessException
- * @deprecated since 3.0. Use {@link #getMongoDatabase(String)} instead.
- */
- @Deprecated
- default MongoDatabase getDb(String dbName) throws DataAccessException {
- return getMongoDatabase(dbName);
- }
-}
diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/MongoExpression.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/MongoExpression.java
index 541118b114..a087439d72 100644
--- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/MongoExpression.java
+++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/MongoExpression.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2021 the original author or authors.
+ * Copyright 2021-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -18,7 +18,7 @@
/**
* Wrapper object for MongoDB expressions like {@code $toUpper : $name} that manifest as {@link org.bson.Document} when
* passed on to the driver.
- *
+ *
* A set of predefined {@link MongoExpression expressions}, including a
* {@link org.springframework.data.mongodb.core.aggregation.AggregationSpELExpression SpEL based variant} for method
* like expressions (eg. {@code toUpper(name)}) are available via the
diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/MongoManagedTypes.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/MongoManagedTypes.java
new file mode 100644
index 0000000000..39c4815d47
--- /dev/null
+++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/MongoManagedTypes.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2022-2025 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.data.mongodb;
+
+import java.util.Arrays;
+import java.util.function.Consumer;
+
+import org.springframework.data.domain.ManagedTypes;
+
+/**
+ * @author Christoph Strobl
+ * @since 4.0
+ */
+public final class MongoManagedTypes implements ManagedTypes {
+
+ private final ManagedTypes delegate;
+
+ private MongoManagedTypes(ManagedTypes types) {
+ this.delegate = types;
+ }
+
+ /**
+ * Wraps an existing {@link ManagedTypes} object with {@link MongoManagedTypes}.
+ *
+ * @param managedTypes
+ * @return
+ */
+ public static MongoManagedTypes from(ManagedTypes managedTypes) {
+ return new MongoManagedTypes(managedTypes);
+ }
+
+ /**
+ * Factory method used to construct {@link MongoManagedTypes} from the given array of {@link Class types}.
+ *
+ * @param types array of {@link Class types} used to initialize the {@link ManagedTypes}; must not be {@literal null}.
+ * @return new instance of {@link MongoManagedTypes} initialized from {@link Class types}.
+ */
+ public static MongoManagedTypes from(Class>... types) {
+ return fromIterable(Arrays.asList(types));
+ }
+
+ /**
+ * Factory method used to construct {@link MongoManagedTypes} from the given, required {@link Iterable} of
+ * {@link Class types}.
+ *
+ * @param types {@link Iterable} of {@link Class types} used to initialize the {@link ManagedTypes}; must not be
+ * {@literal null}.
+ * @return new instance of {@link MongoManagedTypes} initialized the given, required {@link Iterable} of {@link Class
+ * types}.
+ */
+ public static MongoManagedTypes fromIterable(Iterable extends Class>> types) {
+ return from(ManagedTypes.fromIterable(types));
+ }
+
+ /**
+ * Factory method to return an empty {@link MongoManagedTypes} object.
+ *
+ * @return an empty {@link MongoManagedTypes} object.
+ */
+ public static MongoManagedTypes empty() {
+ return from(ManagedTypes.empty());
+ }
+
+ @Override
+ public void forEach(Consumer> action) {
+ delegate.forEach(action);
+ }
+}
diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/MongoResourceHolder.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/MongoResourceHolder.java
index 90a3b32023..a1e8344a9f 100644
--- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/MongoResourceHolder.java
+++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/MongoResourceHolder.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2018-2021 the original author or authors.
+ * Copyright 2018-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -24,7 +24,7 @@
/**
* MongoDB specific {@link ResourceHolderSupport resource holder}, wrapping a {@link ClientSession}.
* {@link MongoTransactionManager} binds instances of this class to the thread.
- *
+ *
* Note: Intended for internal usage only.
*
* @author Christoph Strobl
@@ -68,7 +68,7 @@ ClientSession getRequiredSession() {
ClientSession session = getSession();
if (session == null) {
- throw new IllegalStateException("No session available!");
+ throw new IllegalStateException("No session available");
}
return session;
diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/MongoSessionProvider.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/MongoSessionProvider.java
index 79a68e83ac..645b3508db 100644
--- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/MongoSessionProvider.java
+++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/MongoSessionProvider.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2018-2021 the original author or authors.
+ * Copyright 2018-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/MongoTransactionException.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/MongoTransactionException.java
index b2a998548a..4215479f62 100644
--- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/MongoTransactionException.java
+++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/MongoTransactionException.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2018-2021 the original author or authors.
+ * Copyright 2018-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/MongoTransactionManager.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/MongoTransactionManager.java
index 1e6013d73d..eda657f5f1 100644
--- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/MongoTransactionManager.java
+++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/MongoTransactionManager.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2018-2021 the original author or authors.
+ * Copyright 2018-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -37,18 +37,18 @@
/**
* A {@link org.springframework.transaction.PlatformTransactionManager} implementation that manages
* {@link ClientSession} based transactions for a single {@link MongoDatabaseFactory}.
- *
+ *
* Binds a {@link ClientSession} from the specified {@link MongoDatabaseFactory} to the thread.
- *
+ *
* {@link TransactionDefinition#isReadOnly() Readonly} transactions operate on a {@link ClientSession} and enable causal
* consistency, and also {@link ClientSession#startTransaction() start}, {@link ClientSession#commitTransaction()
* commit} or {@link ClientSession#abortTransaction() abort} a transaction.
- *
+ *
* Application code is required to retrieve the {@link com.mongodb.client.MongoDatabase} via
* {@link MongoDatabaseUtils#getDatabase(MongoDatabaseFactory)} instead of a standard
* {@link MongoDatabaseFactory#getMongoDatabase()} call. Spring classes such as
* {@link org.springframework.data.mongodb.core.MongoTemplate} use this strategy implicitly.
- *
+ *
* By default failure of a {@literal commit} operation raises a {@link TransactionSystemException}. One may override
* {@link #doCommit(MongoTransactionObject)} to implement the
* Retry Commit Operation
@@ -64,52 +64,65 @@
public class MongoTransactionManager extends AbstractPlatformTransactionManager
implements ResourceTransactionManager, InitializingBean {
- private @Nullable MongoDatabaseFactory dbFactory;
- private @Nullable TransactionOptions options;
+ private @Nullable MongoDatabaseFactory databaseFactory;
+ private MongoTransactionOptions options;
+ private final MongoTransactionOptionsResolver transactionOptionsResolver;
/**
- * Create a new {@link MongoTransactionManager} for bean-style usage.
- *
+ * Create a new {@link MongoTransactionManager} for bean-style usage.
* Note:The {@link MongoDatabaseFactory db factory} has to be
- * {@link #setDbFactory(MongoDatabaseFactory) set} before using the instance. Use this constructor to prepare a
- * {@link MongoTransactionManager} via a {@link org.springframework.beans.factory.BeanFactory}.
- *
+ * {@link #setDatabaseFactory(MongoDatabaseFactory) set} before using the instance. Use this constructor to prepare a
+ * {@link MongoTransactionManager} via a {@link org.springframework.beans.factory.BeanFactory}.
* Optionally it is possible to set default {@link TransactionOptions transaction options} defining
* {@link com.mongodb.ReadConcern} and {@link com.mongodb.WriteConcern}.
*
- * @see #setDbFactory(MongoDatabaseFactory)
+ * @see #setDatabaseFactory(MongoDatabaseFactory)
* @see #setTransactionSynchronization(int)
*/
- public MongoTransactionManager() {}
+ public MongoTransactionManager() {
+ this.transactionOptionsResolver = MongoTransactionOptionsResolver.defaultResolver();
+ }
/**
* Create a new {@link MongoTransactionManager} obtaining sessions from the given {@link MongoDatabaseFactory}.
*
- * @param dbFactory must not be {@literal null}.
+ * @param databaseFactory must not be {@literal null}.
*/
- public MongoTransactionManager(MongoDatabaseFactory dbFactory) {
- this(dbFactory, null);
+ public MongoTransactionManager(MongoDatabaseFactory databaseFactory) {
+ this(databaseFactory, null);
}
/**
* Create a new {@link MongoTransactionManager} obtaining sessions from the given {@link MongoDatabaseFactory}
* applying the given {@link TransactionOptions options}, if present, when starting a new transaction.
*
- * @param dbFactory must not be {@literal null}.
+ * @param databaseFactory must not be {@literal null}.
* @param options can be {@literal null}.
*/
- public MongoTransactionManager(MongoDatabaseFactory dbFactory, @Nullable TransactionOptions options) {
+ public MongoTransactionManager(MongoDatabaseFactory databaseFactory, @Nullable TransactionOptions options) {
+ this(databaseFactory, MongoTransactionOptionsResolver.defaultResolver(), MongoTransactionOptions.of(options));
+ }
- Assert.notNull(dbFactory, "DbFactory must not be null!");
+ /**
+ * Create a new {@link MongoTransactionManager} obtaining sessions from the given {@link MongoDatabaseFactory}
+ * applying the given {@link TransactionOptions options}, if present, when starting a new transaction.
+ *
+ * @param databaseFactory must not be {@literal null}.
+ * @param transactionOptionsResolver must not be {@literal null}.
+ * @param defaultTransactionOptions can be {@literal null}.
+ * @since 4.3
+ */
+ public MongoTransactionManager(MongoDatabaseFactory databaseFactory,
+ MongoTransactionOptionsResolver transactionOptionsResolver, MongoTransactionOptions defaultTransactionOptions) {
+
+ Assert.notNull(databaseFactory, "MongoDatabaseFactory must not be null");
+ Assert.notNull(transactionOptionsResolver, "MongoTransactionOptionsResolver must not be null");
- this.dbFactory = dbFactory;
- this.options = options;
+ this.databaseFactory = databaseFactory;
+ this.transactionOptionsResolver = transactionOptionsResolver;
+ this.options = defaultTransactionOptions;
}
- /*
- * (non-Javadoc)
- * org.springframework.transaction.support.AbstractPlatformTransactionManager#doGetTransaction()
- */
@Override
protected Object doGetTransaction() throws TransactionException {
@@ -118,19 +131,11 @@ protected Object doGetTransaction() throws TransactionException {
return new MongoTransactionObject(resourceHolder);
}
- /*
- * (non-Javadoc)
- * org.springframework.transaction.support.AbstractPlatformTransactionManager#isExistingTransaction(java.lang.Object)
- */
@Override
protected boolean isExistingTransaction(Object transaction) throws TransactionException {
return extractMongoTransaction(transaction).hasResourceHolder();
}
- /*
- * (non-Javadoc)
- * org.springframework.transaction.support.AbstractPlatformTransactionManager#doBegin(java.lang.Object, org.springframework.transaction.TransactionDefinition)
- */
@Override
protected void doBegin(Object transaction, TransactionDefinition definition) throws TransactionException {
@@ -146,7 +151,8 @@ protected void doBegin(Object transaction, TransactionDefinition definition) thr
}
try {
- mongoTransactionObject.startTransaction(options);
+ MongoTransactionOptions mongoTransactionOptions = transactionOptionsResolver.resolve(definition).mergeWith(options);
+ mongoTransactionObject.startTransaction(mongoTransactionOptions.toDriverOptions());
} catch (MongoException ex) {
throw new TransactionSystemException(String.format("Could not start Mongo transaction for session %s.",
debugString(mongoTransactionObject.getSession())), ex);
@@ -160,10 +166,6 @@ protected void doBegin(Object transaction, TransactionDefinition definition) thr
TransactionSynchronizationManager.bindResource(getRequiredDbFactory(), resourceHolder);
}
- /*
- * (non-Javadoc)
- * org.springframework.transaction.support.AbstractPlatformTransactionManager#doSuspend(java.lang.Object)
- */
@Override
protected Object doSuspend(Object transaction) throws TransactionException {
@@ -173,19 +175,11 @@ protected Object doSuspend(Object transaction) throws TransactionException {
return TransactionSynchronizationManager.unbindResource(getRequiredDbFactory());
}
- /*
- * (non-Javadoc)
- * org.springframework.transaction.support.AbstractPlatformTransactionManager#doResume(java.lang.Object, java.lang.Object)
- */
@Override
protected void doResume(@Nullable Object transaction, Object suspendedResources) {
TransactionSynchronizationManager.bindResource(getRequiredDbFactory(), suspendedResources);
}
- /*
- * (non-Javadoc)
- * org.springframework.transaction.support.AbstractPlatformTransactionManager#doCommit(org.springframework.transaction.support.DefaultTransactionStatus)
- */
@Override
protected final void doCommit(DefaultTransactionStatus status) throws TransactionException {
@@ -212,8 +206,8 @@ protected final void doCommit(DefaultTransactionStatus status) throws Transactio
* By default those labels are ignored, nevertheless one might check for
* {@link MongoException#UNKNOWN_TRANSACTION_COMMIT_RESULT_LABEL transient commit errors labels} and retry the the
* commit.
+ *
*
- *
* int retries = 3;
* do {
* try {
@@ -226,8 +220,8 @@ protected final void doCommit(DefaultTransactionStatus status) throws Transactio
* }
* Thread.sleep(500);
* } while (--retries > 0);
- *
*
+ *
*
* @param transactionObject never {@literal null}.
* @throws Exception in case of transaction errors.
@@ -236,10 +230,6 @@ protected void doCommit(MongoTransactionObject transactionObject) throws Excepti
transactionObject.commitTransaction();
}
- /*
- * (non-Javadoc)
- * org.springframework.transaction.support.AbstractPlatformTransactionManager#doRollback(org.springframework.transaction.support.DefaultTransactionStatus)
- */
@Override
protected void doRollback(DefaultTransactionStatus status) throws TransactionException {
@@ -259,10 +249,6 @@ protected void doRollback(DefaultTransactionStatus status) throws TransactionExc
}
}
- /*
- * (non-Javadoc)
- * org.springframework.transaction.support.AbstractPlatformTransactionManager#doSetRollbackOnly(org.springframework.transaction.support.DefaultTransactionStatus)
- */
@Override
protected void doSetRollbackOnly(DefaultTransactionStatus status) throws TransactionException {
@@ -270,10 +256,6 @@ protected void doSetRollbackOnly(DefaultTransactionStatus status) throws Transac
transactionObject.getRequiredResourceHolder().setRollbackOnly();
}
- /*
- * (non-Javadoc)
- * org.springframework.transaction.support.AbstractPlatformTransactionManager#doCleanupAfterCompletion(java.lang.Object)
- */
@Override
protected void doCleanupAfterCompletion(Object transaction) {
@@ -298,12 +280,12 @@ protected void doCleanupAfterCompletion(Object transaction) {
/**
* Set the {@link MongoDatabaseFactory} that this instance should manage transactions for.
*
- * @param dbFactory must not be {@literal null}.
+ * @param databaseFactory must not be {@literal null}.
*/
- public void setDbFactory(MongoDatabaseFactory dbFactory) {
+ public void setDatabaseFactory(MongoDatabaseFactory databaseFactory) {
- Assert.notNull(dbFactory, "DbFactory must not be null!");
- this.dbFactory = dbFactory;
+ Assert.notNull(databaseFactory, "DbFactory must not be null");
+ this.databaseFactory = databaseFactory;
}
/**
@@ -312,7 +294,7 @@ public void setDbFactory(MongoDatabaseFactory dbFactory) {
* @param options can be {@literal null}.
*/
public void setOptions(@Nullable TransactionOptions options) {
- this.options = options;
+ this.options = MongoTransactionOptions.of(options);
}
/**
@@ -321,23 +303,15 @@ public void setOptions(@Nullable TransactionOptions options) {
* @return can be {@literal null}.
*/
@Nullable
- public MongoDatabaseFactory getDbFactory() {
- return dbFactory;
+ public MongoDatabaseFactory getDatabaseFactory() {
+ return databaseFactory;
}
- /*
- * (non-Javadoc)
- * @see org.springframework.transaction.support.ResourceTransactionManager#getResourceFactory()
- */
@Override
public MongoDatabaseFactory getResourceFactory() {
return getRequiredDbFactory();
}
- /*
- * (non-Javadoc)
- * @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
- */
@Override
public void afterPropertiesSet() {
getRequiredDbFactory();
@@ -354,14 +328,14 @@ private MongoResourceHolder newResourceHolder(TransactionDefinition definition,
}
/**
- * @throws IllegalStateException if {@link #dbFactory} is {@literal null}.
+ * @throws IllegalStateException if {@link #databaseFactory} is {@literal null}.
*/
private MongoDatabaseFactory getRequiredDbFactory() {
- Assert.state(dbFactory != null,
- "MongoTransactionManager operates upon a MongoDbFactory. Did you forget to provide one? It's required.");
+ Assert.state(databaseFactory != null,
+ "MongoTransactionManager operates upon a MongoDbFactory; Did you forget to provide one; It's required");
- return dbFactory;
+ return databaseFactory;
}
private static MongoTransactionObject extractMongoTransaction(Object transaction) {
@@ -397,7 +371,7 @@ private static String debugString(@Nullable ClientSession session) {
debugString += String.format("causallyConsistent = %s, ", session.isCausallyConsistent());
debugString += String.format("txActive = %s, ", session.hasActiveTransaction());
debugString += String.format("txNumber = %d, ", session.getServerSession().getTransactionNumber());
- debugString += String.format("closed = %d, ", session.getServerSession().isClosed());
+ debugString += String.format("closed = %b, ", session.getServerSession().isClosed());
debugString += String.format("clusterTime = %s", session.getClusterTime());
} else {
debugString += "id = n/a";
@@ -494,30 +468,22 @@ public ClientSession getSession() {
private MongoResourceHolder getRequiredResourceHolder() {
- Assert.state(resourceHolder != null, "MongoResourceHolder is required but not present. o_O");
+ Assert.state(resourceHolder != null, "MongoResourceHolder is required but not present; o_O");
return resourceHolder;
}
private ClientSession getRequiredSession() {
ClientSession session = getSession();
- Assert.state(session != null, "A Session is required but it turned out to be null.");
+ Assert.state(session != null, "A Session is required but it turned out to be null");
return session;
}
- /*
- * (non-Javadoc)
- * @see org.springframework.transaction.support.SmartTransactionObject#isRollbackOnly()
- */
@Override
public boolean isRollbackOnly() {
return this.resourceHolder != null && this.resourceHolder.isRollbackOnly();
}
- /*
- * (non-Javadoc)
- * @see org.springframework.transaction.support.SmartTransactionObject#flush()
- */
@Override
public void flush() {
TransactionSynchronizationUtils.triggerFlush();
diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/MongoTransactionOptions.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/MongoTransactionOptions.java
new file mode 100644
index 0000000000..e411bd5d2d
--- /dev/null
+++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/MongoTransactionOptions.java
@@ -0,0 +1,204 @@
+/*
+ * Copyright 2024-2025 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.data.mongodb;
+
+import java.time.Duration;
+import java.util.concurrent.TimeUnit;
+import java.util.function.Function;
+
+import org.springframework.data.mongodb.core.ReadConcernAware;
+import org.springframework.data.mongodb.core.ReadPreferenceAware;
+import org.springframework.data.mongodb.core.WriteConcernAware;
+import org.springframework.lang.Nullable;
+
+import com.mongodb.ReadConcern;
+import com.mongodb.ReadPreference;
+import com.mongodb.TransactionOptions;
+import com.mongodb.WriteConcern;
+
+/**
+ * Options to be applied within a specific transaction scope.
+ *
+ * @author Christoph Strobl
+ * @since 4.3
+ */
+public interface MongoTransactionOptions
+ extends TransactionMetadata, ReadConcernAware, ReadPreferenceAware, WriteConcernAware {
+
+ /**
+ * Value Object representing empty options enforcing client defaults. Returns {@literal null} for all getter methods.
+ */
+ MongoTransactionOptions NONE = new MongoTransactionOptions() {
+
+ @Nullable
+ @Override
+ public Duration getMaxCommitTime() {
+ return null;
+ }
+
+ @Nullable
+ @Override
+ public ReadConcern getReadConcern() {
+ return null;
+ }
+
+ @Nullable
+ @Override
+ public ReadPreference getReadPreference() {
+ return null;
+ }
+
+ @Nullable
+ @Override
+ public WriteConcern getWriteConcern() {
+ return null;
+ }
+ };
+
+ /**
+ * Merge current options with given ones. Will return first non {@literal null} value from getters whereas the
+ * {@literal this} has precedence over the given fallbackOptions.
+ *
+ * @param fallbackOptions can be {@literal null}.
+ * @return new instance of {@link MongoTransactionOptions} or this if {@literal fallbackOptions} is {@literal null} or
+ * {@link #NONE}.
+ */
+ default MongoTransactionOptions mergeWith(@Nullable MongoTransactionOptions fallbackOptions) {
+
+ if (fallbackOptions == null || MongoTransactionOptions.NONE.equals(fallbackOptions)) {
+ return this;
+ }
+
+ return new MongoTransactionOptions() {
+
+ @Nullable
+ @Override
+ public Duration getMaxCommitTime() {
+ return MongoTransactionOptions.this.hasMaxCommitTime() ? MongoTransactionOptions.this.getMaxCommitTime()
+ : fallbackOptions.getMaxCommitTime();
+ }
+
+ @Nullable
+ @Override
+ public ReadConcern getReadConcern() {
+ return MongoTransactionOptions.this.hasReadConcern() ? MongoTransactionOptions.this.getReadConcern()
+ : fallbackOptions.getReadConcern();
+ }
+
+ @Nullable
+ @Override
+ public ReadPreference getReadPreference() {
+ return MongoTransactionOptions.this.hasReadPreference() ? MongoTransactionOptions.this.getReadPreference()
+ : fallbackOptions.getReadPreference();
+ }
+
+ @Nullable
+ @Override
+ public WriteConcern getWriteConcern() {
+ return MongoTransactionOptions.this.hasWriteConcern() ? MongoTransactionOptions.this.getWriteConcern()
+ : fallbackOptions.getWriteConcern();
+ }
+ };
+ }
+
+ /**
+ * Apply the current options using the given mapping {@link Function} and return its result.
+ *
+ * @param mappingFunction
+ * @return result of the mapping function.
+ */
+ default T map(Function mappingFunction) {
+ return mappingFunction.apply(this);
+ }
+
+ /**
+ * @return MongoDB driver native {@link TransactionOptions}.
+ * @see MongoTransactionOptions#map(Function)
+ */
+ @Nullable
+ default TransactionOptions toDriverOptions() {
+
+ return map(it -> {
+
+ if (MongoTransactionOptions.NONE.equals(it)) {
+ return null;
+ }
+
+ TransactionOptions.Builder builder = TransactionOptions.builder();
+ if (it.hasMaxCommitTime()) {
+ builder.maxCommitTime(it.getMaxCommitTime().toMillis(), TimeUnit.MILLISECONDS);
+ }
+ if (it.hasReadConcern()) {
+ builder.readConcern(it.getReadConcern());
+ }
+ if (it.hasReadPreference()) {
+ builder.readPreference(it.getReadPreference());
+ }
+ if (it.hasWriteConcern()) {
+ builder.writeConcern(it.getWriteConcern());
+ }
+ return builder.build();
+ });
+ }
+
+ /**
+ * Factory method to wrap given MongoDB driver native {@link TransactionOptions} into {@link MongoTransactionOptions}.
+ *
+ * @param options
+ * @return {@link MongoTransactionOptions#NONE} if given object is {@literal null}.
+ */
+ static MongoTransactionOptions of(@Nullable TransactionOptions options) {
+
+ if (options == null) {
+ return NONE;
+ }
+
+ return new MongoTransactionOptions() {
+
+ @Nullable
+ @Override
+ public Duration getMaxCommitTime() {
+
+ Long millis = options.getMaxCommitTime(TimeUnit.MILLISECONDS);
+ return millis != null ? Duration.ofMillis(millis) : null;
+ }
+
+ @Nullable
+ @Override
+ public ReadConcern getReadConcern() {
+ return options.getReadConcern();
+ }
+
+ @Nullable
+ @Override
+ public ReadPreference getReadPreference() {
+ return options.getReadPreference();
+ }
+
+ @Nullable
+ @Override
+ public WriteConcern getWriteConcern() {
+ return options.getWriteConcern();
+ }
+
+ @Nullable
+ @Override
+ public TransactionOptions toDriverOptions() {
+ return options;
+ }
+ };
+ }
+}
diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/MongoTransactionOptionsResolver.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/MongoTransactionOptionsResolver.java
new file mode 100644
index 0000000000..b73b079a99
--- /dev/null
+++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/MongoTransactionOptionsResolver.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright 2024-2025 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.data.mongodb;
+
+import java.util.Map;
+import java.util.stream.Collectors;
+
+import org.springframework.lang.Nullable;
+import org.springframework.transaction.TransactionDefinition;
+import org.springframework.transaction.interceptor.TransactionAttribute;
+import org.springframework.util.Assert;
+import org.springframework.util.StringUtils;
+
+/**
+ * A {@link TransactionOptionResolver} reading MongoDB specific {@link MongoTransactionOptions transaction options} from
+ * a {@link TransactionDefinition}. Implementations of {@link MongoTransactionOptions} may choose a specific
+ * {@link #getLabelPrefix() prefix} for {@link TransactionAttribute#getLabels() transaction attribute labels} to avoid
+ * evaluating non-store specific ones.
+ *
+ * {@link TransactionAttribute#getLabels()} evaluated by default should follow the property style using {@code =} to
+ * separate key and value pairs.
+ *
+ * By default {@link #resolve(TransactionDefinition)} will filter labels by the {@link #getLabelPrefix() prefix} and
+ * strip the prefix from the label before handing the pruned {@link Map} to the {@link #convert(Map)} function.
+ *
+ * A transaction definition with labels targeting MongoDB may look like the following:
+ *
+ *
+ * @Transactional(label = { "mongo:readConcern=majority" })
+ *
+ *
+ * @author Christoph Strobl
+ * @since 4.3
+ */
+public interface MongoTransactionOptionsResolver extends TransactionOptionResolver {
+
+ /**
+ * Obtain the default {@link MongoTransactionOptionsResolver} implementation using a {@literal mongo:}
+ * {@link #getLabelPrefix() prefix}.
+ *
+ * @return instance of default {@link MongoTransactionOptionsResolver} implementation.
+ */
+ static MongoTransactionOptionsResolver defaultResolver() {
+ return DefaultMongoTransactionOptionsResolver.INSTANCE;
+ }
+
+ /**
+ * Get the prefix used to filter applicable {@link TransactionAttribute#getLabels() labels}.
+ *
+ * @return {@literal null} if no label defined.
+ */
+ @Nullable
+ String getLabelPrefix();
+
+ /**
+ * Resolve {@link MongoTransactionOptions} from a given {@link TransactionDefinition} by evaluating
+ * {@link TransactionAttribute#getLabels()} labels if possible.
+ *
+ * Splits applicable labels property style using {@literal =} as deliminator and removes a potential
+ * {@link #getLabelPrefix() prefix} before calling {@link #convert(Map)} with filtered label values.
+ *
+ * @param definition
+ * @return {@link MongoTransactionOptions#NONE} in case the given {@link TransactionDefinition} is not a
+ * {@link TransactionAttribute} if no matching {@link TransactionAttribute#getLabels() labels} could be found.
+ * @throws IllegalArgumentException for options that do not map to valid transactions options or malformatted labels.
+ */
+ @Override
+ default MongoTransactionOptions resolve(TransactionDefinition definition) {
+
+ if (!(definition instanceof TransactionAttribute attribute)) {
+ return MongoTransactionOptions.NONE;
+ }
+
+ if (attribute.getLabels().isEmpty()) {
+ return MongoTransactionOptions.NONE;
+ }
+
+ Map attributeMap = attribute.getLabels().stream()
+ .filter(it -> !StringUtils.hasText(getLabelPrefix()) || it.startsWith(getLabelPrefix()))
+ .map(it -> StringUtils.hasText(getLabelPrefix()) ? it.substring(getLabelPrefix().length()) : it).map(it -> {
+
+ String[] kvPair = StringUtils.split(it, "=");
+ Assert.isTrue(kvPair != null && kvPair.length == 2,
+ () -> "No value present for transaction option %s".formatted(kvPair != null ? kvPair[0] : it));
+ return kvPair;
+ })
+
+ .collect(Collectors.toMap(it -> it[0].trim(), it -> it[1].trim()));
+
+ return attributeMap.isEmpty() ? MongoTransactionOptions.NONE : convert(attributeMap);
+ }
+
+ /**
+ * Convert the given {@link Map} into an instance of {@link MongoTransactionOptions}.
+ *
+ * @param options never {@literal null}.
+ * @return never {@literal null}.
+ * @throws IllegalArgumentException for invalid options.
+ */
+ MongoTransactionOptions convert(Map options);
+}
diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/ReactiveMongoDatabaseFactory.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/ReactiveMongoDatabaseFactory.java
index eba2aceb9f..f2a6714a95 100644
--- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/ReactiveMongoDatabaseFactory.java
+++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/ReactiveMongoDatabaseFactory.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2016-2021 the original author or authors.
+ * Copyright 2016-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/ReactiveMongoDatabaseUtils.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/ReactiveMongoDatabaseUtils.java
index 711947a30d..f397818a4c 100644
--- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/ReactiveMongoDatabaseUtils.java
+++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/ReactiveMongoDatabaseUtils.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2019-2021 the original author or authors.
+ * Copyright 2019-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -36,7 +36,7 @@
* Helper class for managing reactive {@link MongoDatabase} instances via {@link ReactiveMongoDatabaseFactory}. Used for
* obtaining {@link ClientSession session bound} resources, such as {@link MongoDatabase} and {@link MongoCollection}
* suitable for transactional usage.
- *
+ *
* Note: Intended for internal usage only.
*
* @author Mark Paluch
@@ -75,7 +75,7 @@ public static Mono isTransactionActive(ReactiveMongoDatabaseFactory dat
/**
* Obtain the default {@link MongoDatabase database} form the given {@link ReactiveMongoDatabaseFactory factory} using
* {@link SessionSynchronization#ON_ACTUAL_TRANSACTION native session synchronization}.
- *
+ *
* Registers a {@link MongoSessionSynchronization MongoDB specific transaction synchronization} within the subscriber
* {@link Context} if {@link TransactionSynchronizationManager#isSynchronizationActive() synchronization is active}.
*
@@ -88,7 +88,7 @@ public static Mono getDatabase(ReactiveMongoDatabaseFactory facto
/**
* Obtain the default {@link MongoDatabase database} form the given {@link ReactiveMongoDatabaseFactory factory}.
- *
+ *
* Registers a {@link MongoSessionSynchronization MongoDB specific transaction synchronization} within the subscriber
* {@link Context} if {@link TransactionSynchronizationManager#isSynchronizationActive() synchronization is active}.
*
@@ -104,7 +104,7 @@ public static Mono getDatabase(ReactiveMongoDatabaseFactory facto
/**
* Obtain the {@link MongoDatabase database} with given name form the given {@link ReactiveMongoDatabaseFactory
* factory} using {@link SessionSynchronization#ON_ACTUAL_TRANSACTION native session synchronization}.
- *
+ *
* Registers a {@link MongoSessionSynchronization MongoDB specific transaction synchronization} within the subscriber
* {@link Context} if {@link TransactionSynchronizationManager#isSynchronizationActive() synchronization is active}.
*
@@ -119,7 +119,7 @@ public static Mono getDatabase(String dbName, ReactiveMongoDataba
/**
* Obtain the {@link MongoDatabase database} with given name form the given {@link ReactiveMongoDatabaseFactory
* factory}.
- *
+ *
* Registers a {@link MongoSessionSynchronization MongoDB specific transaction synchronization} within the subscriber
* {@link Context} if {@link TransactionSynchronizationManager#isSynchronizationActive() synchronization is active}.
*
@@ -136,7 +136,11 @@ public static Mono getDatabase(String dbName, ReactiveMongoDataba
private static Mono doGetMongoDatabase(@Nullable String dbName, ReactiveMongoDatabaseFactory factory,
SessionSynchronization sessionSynchronization) {
- Assert.notNull(factory, "DatabaseFactory must not be null!");
+ Assert.notNull(factory, "DatabaseFactory must not be null");
+
+ if (sessionSynchronization == SessionSynchronization.NEVER) {
+ return getMongoDatabaseOrDefault(dbName, factory);
+ }
return TransactionSynchronizationManager.forCurrentTransaction()
.filter(TransactionSynchronizationManager::isSynchronizationActive) //
@@ -210,19 +214,11 @@ private static class MongoSessionSynchronization
this.resourceHolder = resourceHolder;
}
- /*
- * (non-Javadoc)
- * @see org.springframework.transaction.reactive.ReactiveResourceSynchronization#shouldReleaseBeforeCompletion()
- */
@Override
protected boolean shouldReleaseBeforeCompletion() {
return false;
}
- /*
- * (non-Javadoc)
- * @see org.springframework.transaction.reactive.ReactiveResourceSynchronization#processResourceAfterCommit(java.lang.Object)
- */
@Override
protected Mono processResourceAfterCommit(ReactiveMongoResourceHolder resourceHolder) {
@@ -233,10 +229,6 @@ protected Mono processResourceAfterCommit(ReactiveMongoResourceHolder reso
return Mono.empty();
}
- /*
- * (non-Javadoc)
- * @see org.springframework.transaction.reactive.ReactiveResourceSynchronization#afterCompletion(int)
- */
@Override
public Mono afterCompletion(int status) {
@@ -252,10 +244,6 @@ public Mono afterCompletion(int status) {
});
}
- /*
- * (non-Javadoc)
- * @see org.springframework.transaction.reactive.ReactiveResourceSynchronization#releaseResource(java.lang.Object, java.lang.Object)
- */
@Override
protected Mono releaseResource(ReactiveMongoResourceHolder resourceHolder, Object resourceKey) {
diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/ReactiveMongoResourceHolder.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/ReactiveMongoResourceHolder.java
index b1f1c06d08..33caa5e7fe 100644
--- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/ReactiveMongoResourceHolder.java
+++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/ReactiveMongoResourceHolder.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2019-2021 the original author or authors.
+ * Copyright 2019-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -24,7 +24,7 @@
/**
* MongoDB specific resource holder, wrapping a {@link ClientSession}. {@link ReactiveMongoTransactionManager} binds
* instances of this class to the subscriber context.
- *
+ *
* Note: Intended for internal usage only.
*
* @author Mark Paluch
diff --git a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/ReactiveMongoTransactionManager.java b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/ReactiveMongoTransactionManager.java
index 63706eff8a..2c65c26b79 100644
--- a/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/ReactiveMongoTransactionManager.java
+++ b/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/ReactiveMongoTransactionManager.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2019-2021 the original author or authors.
+ * Copyright 2019-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -37,22 +37,19 @@
/**
* A {@link org.springframework.transaction.ReactiveTransactionManager} implementation that manages
* {@link com.mongodb.reactivestreams.client.ClientSession} based transactions for a single
- * {@link org.springframework.data.mongodb.ReactiveMongoDatabaseFactory}.
- *
+ * {@link org.springframework.data.mongodb.ReactiveMongoDatabaseFactory}.
* Binds a {@link ClientSession} from the specified
* {@link org.springframework.data.mongodb.ReactiveMongoDatabaseFactory} to the subscriber
- * {@link reactor.util.context.Context}.
- *
+ * {@link reactor.util.context.Context}.
* {@link org.springframework.transaction.TransactionDefinition#isReadOnly() Readonly} transactions operate on a
* {@link ClientSession} and enable causal consistency, and also {@link ClientSession#startTransaction() start},
* {@link com.mongodb.reactivestreams.client.ClientSession#commitTransaction() commit} or
- * {@link ClientSession#abortTransaction() abort} a transaction.
- *
+ * {@link ClientSession#abortTransaction() abort} a transaction.
* Application code is required to retrieve the {@link com.mongodb.reactivestreams.client.MongoDatabase} via
* {@link org.springframework.data.mongodb.ReactiveMongoDatabaseUtils#getDatabase(ReactiveMongoDatabaseFactory)} instead
* of a standard {@link org.springframework.data.mongodb.ReactiveMongoDatabaseFactory#getMongoDatabase()} call. Spring
* classes such as {@link org.springframework.data.mongodb.core.ReactiveMongoTemplate} use this strategy implicitly.
- *
+ *
* By default failure of a {@literal commit} operation raises a {@link TransactionSystemException}. You can override
* {@link #doCommit(TransactionSynchronizationManager, ReactiveMongoTransactionObject)} to implement the
* Retry Commit Operation
@@ -67,21 +64,23 @@
public class ReactiveMongoTransactionManager extends AbstractReactiveTransactionManager implements InitializingBean {
private @Nullable ReactiveMongoDatabaseFactory databaseFactory;
- private @Nullable TransactionOptions options;
+ private @Nullable MongoTransactionOptions options;
+ private final MongoTransactionOptionsResolver transactionOptionsResolver;
/**
- * Create a new {@link ReactiveMongoTransactionManager} for bean-style usage.
- *
+ * Create a new {@link ReactiveMongoTransactionManager} for bean-style usage.
* Note:The {@link org.springframework.data.mongodb.ReactiveMongoDatabaseFactory db factory} has to
* be {@link #setDatabaseFactory(ReactiveMongoDatabaseFactory)} set} before using the instance. Use this constructor
* to prepare a {@link ReactiveMongoTransactionManager} via a {@link org.springframework.beans.factory.BeanFactory}.
- *
+ *
* Optionally it is possible to set default {@link TransactionOptions transaction options} defining
* {@link com.mongodb.ReadConcern} and {@link com.mongodb.WriteConcern}.
*
* @see #setDatabaseFactory(ReactiveMongoDatabaseFactory)
*/
- public ReactiveMongoTransactionManager() {}
+ public ReactiveMongoTransactionManager() {
+ this.transactionOptionsResolver = MongoTransactionOptionsResolver.defaultResolver();
+ }
/**
* Create a new {@link ReactiveMongoTransactionManager} obtaining sessions from the given
@@ -103,17 +102,31 @@ public ReactiveMongoTransactionManager(ReactiveMongoDatabaseFactory databaseFact
*/
public ReactiveMongoTransactionManager(ReactiveMongoDatabaseFactory databaseFactory,
@Nullable TransactionOptions options) {
+ this(databaseFactory, MongoTransactionOptionsResolver.defaultResolver(), MongoTransactionOptions.of(options));
+ }
+
+ /**
+ * Create a new {@link ReactiveMongoTransactionManager} obtaining sessions from the given
+ * {@link ReactiveMongoDatabaseFactory} applying the given {@link TransactionOptions options}, if present, when
+ * starting a new transaction.
+ *
+ * @param databaseFactory must not be {@literal null}.
+ * @param transactionOptionsResolver must not be {@literal null}.
+ * @param defaultTransactionOptions can be {@literal null}.
+ * @since 4.3
+ */
+ public ReactiveMongoTransactionManager(ReactiveMongoDatabaseFactory databaseFactory,
+ MongoTransactionOptionsResolver transactionOptionsResolver,
+ @Nullable MongoTransactionOptions defaultTransactionOptions) {
- Assert.notNull(databaseFactory, "DatabaseFactory must not be null!");
+ Assert.notNull(databaseFactory, "DatabaseFactory must not be null");
+ Assert.notNull(transactionOptionsResolver, "MongoTransactionOptionsResolver must not be null");
this.databaseFactory = databaseFactory;
- this.options = options;
+ this.transactionOptionsResolver = transactionOptionsResolver;
+ this.options = defaultTransactionOptions;
}
- /*
- * (non-Javadoc)
- * @see org.springframework.transaction.reactive.AbstractReactiveTransactionManager#doGetTransaction(org.springframework.transaction.reactive.TransactionSynchronizationManager)
- */
@Override
protected Object doGetTransaction(TransactionSynchronizationManager synchronizationManager)
throws TransactionException {
@@ -123,19 +136,11 @@ protected Object doGetTransaction(TransactionSynchronizationManager synchronizat
return new ReactiveMongoTransactionObject(resourceHolder);
}
- /*
- * (non-Javadoc)
- * @see org.springframework.transaction.reactive.AbstractReactiveTransactionManager#isExistingTransaction(java.lang.Object)
- */
@Override
protected boolean isExistingTransaction(Object transaction) throws TransactionException {
return extractMongoTransaction(transaction).hasResourceHolder();
}
- /*
- * (non-Javadoc)
- * @see org.springframework.transaction.reactive.AbstractReactiveTransactionManager#doBegin(org.springframework.transaction.reactive.TransactionSynchronizationManager, java.lang.Object, org.springframework.transaction.TransactionDefinition)
- */
@Override
protected Mono doBegin(TransactionSynchronizationManager synchronizationManager, Object transaction,
TransactionDefinition definition) throws TransactionException {
@@ -158,7 +163,9 @@ protected Mono doBegin(TransactionSynchronizationManager synchronizationMa
}).doOnNext(resourceHolder -> {
- mongoTransactionObject.startTransaction(options);
+ MongoTransactionOptions mongoTransactionOptions = transactionOptionsResolver.resolve(definition)
+ .mergeWith(options);
+ mongoTransactionObject.startTransaction(mongoTransactionOptions.toDriverOptions());
if (logger.isDebugEnabled()) {
logger.debug(String.format("Started transaction for session %s.", debugString(resourceHolder.getSession())));
@@ -175,10 +182,6 @@ protected Mono doBegin(TransactionSynchronizationManager synchronizationMa
});
}
- /*
- * (non-Javadoc)
- * @see org.springframework.transaction.reactive.AbstractReactiveTransactionManager#doSuspend(org.springframework.transaction.reactive.TransactionSynchronizationManager, java.lang.Object)
- */
@Override
protected Mono