Compare commits
214 Commits
3.0.0.M2
...
2.1.14.REL
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8e51d005d5 | ||
|
|
1940a5c2c2 | ||
|
|
5a274029d7 | ||
|
|
c342bf266e | ||
|
|
11baf455d2 | ||
|
|
05882813ac | ||
|
|
bd3f26c928 | ||
|
|
5555aa970b | ||
|
|
e74fe05abd | ||
|
|
d579254fbc | ||
|
|
71c8e4cc02 | ||
|
|
a087c7d17c | ||
|
|
90cec275a6 | ||
|
|
e4eefe577d | ||
|
|
b57a6612f6 | ||
|
|
62b2d54e0d | ||
|
|
aff823da57 | ||
|
|
d45b630724 | ||
|
|
fc8c97aeb0 | ||
|
|
004e7f01b2 | ||
|
|
5c80ee0087 | ||
|
|
adb9dc29a2 | ||
|
|
6eb6feadbb | ||
|
|
166aab39c4 | ||
|
|
fa94c22c2a | ||
|
|
e0f88a8b84 | ||
|
|
59aa8051d3 | ||
|
|
205a06e79a | ||
|
|
899b43a29b | ||
|
|
0f0a4ed31b | ||
|
|
9acc8d5268 | ||
|
|
313ffb5426 | ||
|
|
dc859953f4 | ||
|
|
bc29f2b24e | ||
|
|
686cdac73f | ||
|
|
b7b339577b | ||
|
|
2166a6e953 | ||
|
|
3c601a699a | ||
|
|
37211fc6d7 | ||
|
|
a45c9040c4 | ||
|
|
23c0a07b93 | ||
|
|
f3a7d6a20e | ||
|
|
0d22d831f8 | ||
|
|
6b0e2ab5de | ||
|
|
5d02b84856 | ||
|
|
93e911985e | ||
|
|
e7faa1a1ec | ||
|
|
631714941a | ||
|
|
db9428cebe | ||
|
|
4be53ac952 | ||
|
|
564acd75d5 | ||
|
|
95ccdf4c20 | ||
|
|
291ef4bb75 | ||
|
|
c7461928f4 | ||
|
|
f5a5d3e96b | ||
|
|
b213aada80 | ||
|
|
403e5043cb | ||
|
|
bdbda459c0 | ||
|
|
0bf6d5f7fa | ||
|
|
f2ae14206a | ||
|
|
049159374d | ||
|
|
79f8e06fc1 | ||
|
|
370db2dce5 | ||
|
|
74325d5193 | ||
|
|
e6ea2e1379 | ||
|
|
cb85f3cfa6 | ||
|
|
aff8b89006 | ||
|
|
0ad8857368 | ||
|
|
46de82fe0b | ||
|
|
387348b615 | ||
|
|
8fd41faac6 | ||
|
|
8a15e1086b | ||
|
|
8502786648 | ||
|
|
d7107d49bf | ||
|
|
f42cb1e2f0 | ||
|
|
a9403b526f | ||
|
|
5f6291ed32 | ||
|
|
676ee80434 | ||
|
|
b54641ff86 | ||
|
|
6930c720ca | ||
|
|
611cfe9c11 | ||
|
|
507a1fbf34 | ||
|
|
087649de35 | ||
|
|
1f01f34377 | ||
|
|
295c43c6ff | ||
|
|
5a62d449bf | ||
|
|
1cbbe692b5 | ||
|
|
5bfe125160 | ||
|
|
1b6722324e | ||
|
|
a212f5f79d | ||
|
|
2879348d4b | ||
|
|
10097311c7 | ||
|
|
b8303a56b6 | ||
|
|
f9e468aebb | ||
|
|
b900dc6c09 | ||
|
|
bede55714c | ||
|
|
3ec426352f | ||
|
|
c6293e0ebd | ||
|
|
74e49a2326 | ||
|
|
69c451f69f | ||
|
|
9af8160e05 | ||
|
|
fdf4ea1e60 | ||
|
|
8c7afe012f | ||
|
|
6ba258a1f3 | ||
|
|
059c8cf1dd | ||
|
|
2b8955f583 | ||
|
|
23fde167f6 | ||
|
|
9470f82e9b | ||
|
|
1e88e241d4 | ||
|
|
0b8396c43c | ||
|
|
b602e4cb26 | ||
|
|
500393e596 | ||
|
|
7e4cbdb8b0 | ||
|
|
1d6d8ff8e6 | ||
|
|
8ea4cbe9ea | ||
|
|
45a0c36184 | ||
|
|
599c79bce2 | ||
|
|
eda6d40aa7 | ||
|
|
22b844c87f | ||
|
|
bdf7ec7c9b | ||
|
|
13db06d345 | ||
|
|
365ecd53c4 | ||
|
|
dc40c42815 | ||
|
|
49415efb8c | ||
|
|
dc234906f4 | ||
|
|
a7f51a7c85 | ||
|
|
9b0bd11d09 | ||
|
|
d7ad883f69 | ||
|
|
44308bfbe1 | ||
|
|
9b673d342f | ||
|
|
5517198310 | ||
|
|
819a04f3db | ||
|
|
f7202067a5 | ||
|
|
f20a0f20c9 | ||
|
|
02216d5941 | ||
|
|
79f2094322 | ||
|
|
afbc5cfa25 | ||
|
|
a3882a5e5c | ||
|
|
8194772388 | ||
|
|
12f18850dc | ||
|
|
816c1da248 | ||
|
|
5a78f19781 | ||
|
|
698837921b | ||
|
|
0f7fc7880b | ||
|
|
6e42f49b08 | ||
|
|
bdfe4e99ed | ||
|
|
85aa3927a6 | ||
|
|
33c4e4294f | ||
|
|
a89ab387cc | ||
|
|
e52b8c9d38 | ||
|
|
4dbf4795db | ||
|
|
8e4c6f68ae | ||
|
|
fddbd126ea | ||
|
|
ee5b26ab1c | ||
|
|
01e9a2ed67 | ||
|
|
10107c7b81 | ||
|
|
abe7876086 | ||
|
|
a759dff5fd | ||
|
|
9f8d081ef3 | ||
|
|
b8f6030441 | ||
|
|
267decf189 | ||
|
|
3a7492c68d | ||
|
|
273088b6a8 | ||
|
|
723b481f82 | ||
|
|
8a34bc46a2 | ||
|
|
bb4c16f4cd | ||
|
|
cf5b7c9763 | ||
|
|
f4414e98a2 | ||
|
|
a97bfd2a37 | ||
|
|
9fe0f5c984 | ||
|
|
718a7ffe8c | ||
|
|
f7106dc425 | ||
|
|
0698f8bcb8 | ||
|
|
3effd9ae6f | ||
|
|
7002cd1456 | ||
|
|
a15d488657 | ||
|
|
44651581b1 | ||
|
|
6d64f5b2b2 | ||
|
|
0c52a29ba8 | ||
|
|
bd8bd4f568 | ||
|
|
c75f29dc42 | ||
|
|
e493af7266 | ||
|
|
8d892e5924 | ||
|
|
053299f243 | ||
|
|
872659cc00 | ||
|
|
96978a6194 | ||
|
|
2253d3e301 | ||
|
|
5982ee84f7 | ||
|
|
dd2af6462d | ||
|
|
622643bf24 | ||
|
|
51cc55baac | ||
|
|
0b106e5649 | ||
|
|
8975d93ab3 | ||
|
|
e25b6c49f5 | ||
|
|
7a70c205de | ||
|
|
6045efa450 | ||
|
|
7b0816b3ee | ||
|
|
14e4ea736d | ||
|
|
32e7d9ab7f | ||
|
|
7f35ad9e45 | ||
|
|
60228f6e5a | ||
|
|
7604492b7f | ||
|
|
4680fe0e77 | ||
|
|
b4228c88d3 | ||
|
|
f6ef8c94c8 | ||
|
|
0d0dafa85e | ||
|
|
29aa34619f | ||
|
|
7f19f769c4 | ||
|
|
a40e89d90a | ||
|
|
6b2350200a | ||
|
|
fb50b0f6e7 | ||
|
|
ab568229b5 | ||
|
|
7f9c1bd774 | ||
|
|
670a0978da |
@@ -16,12 +16,9 @@ before_install:
|
|||||||
|
|
||||||
env:
|
env:
|
||||||
matrix:
|
matrix:
|
||||||
- MONGO_VERSION=4.1.10
|
|
||||||
- MONGO_VERSION=4.0.4
|
|
||||||
- MONGO_VERSION=3.6.12
|
|
||||||
- MONGO_VERSION=3.4.20
|
|
||||||
global:
|
|
||||||
- PROFILE=ci
|
- PROFILE=ci
|
||||||
|
global:
|
||||||
|
- MONGO_VERSION=4.0.0
|
||||||
|
|
||||||
addons:
|
addons:
|
||||||
apt:
|
apt:
|
||||||
|
|||||||
132
Jenkinsfile
vendored
132
Jenkinsfile
vendored
@@ -3,7 +3,7 @@ pipeline {
|
|||||||
|
|
||||||
triggers {
|
triggers {
|
||||||
pollSCM 'H/10 * * * *'
|
pollSCM 'H/10 * * * *'
|
||||||
upstream(upstreamProjects: "spring-data-commons/master", threshold: hudson.model.Result.SUCCESS)
|
upstream(upstreamProjects: "spring-data-commons/2.1.x", threshold: hudson.model.Result.SUCCESS)
|
||||||
}
|
}
|
||||||
|
|
||||||
options {
|
options {
|
||||||
@@ -12,94 +12,15 @@ pipeline {
|
|||||||
}
|
}
|
||||||
|
|
||||||
stages {
|
stages {
|
||||||
stage("Docker images") {
|
stage("Test") {
|
||||||
|
when {
|
||||||
|
anyOf {
|
||||||
|
branch '2.1.x'
|
||||||
|
not { triggeredBy 'UpstreamCause' }
|
||||||
|
}
|
||||||
|
}
|
||||||
parallel {
|
parallel {
|
||||||
stage('Publish JDK 8 + MongoDB 4.0') {
|
|
||||||
when {
|
|
||||||
changeset "ci/openjdk8-mongodb-4.0/**"
|
|
||||||
}
|
|
||||||
agent { label 'data' }
|
|
||||||
options { timeout(time: 30, unit: 'MINUTES') }
|
|
||||||
|
|
||||||
steps {
|
|
||||||
script {
|
|
||||||
def image = docker.build("springci/spring-data-openjdk8-with-mongodb-4.0", "ci/openjdk8-mongodb-4.0/")
|
|
||||||
docker.withRegistry('', 'hub.docker.com-springbuildmaster') {
|
|
||||||
image.push()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
stage('Publish JDK 8 + MongoDB 4.1') {
|
|
||||||
when {
|
|
||||||
changeset "ci/openjdk8-mongodb-4.1/**"
|
|
||||||
}
|
|
||||||
agent { label 'data' }
|
|
||||||
options { timeout(time: 30, unit: 'MINUTES') }
|
|
||||||
|
|
||||||
steps {
|
|
||||||
script {
|
|
||||||
def image = docker.build("springci/spring-data-openjdk8-with-mongodb-4.1", "ci/openjdk8-mongodb-4.1/")
|
|
||||||
docker.withRegistry('', 'hub.docker.com-springbuildmaster') {
|
|
||||||
image.push()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
stage('Publish JDK 8 + MongoDB 4.2') {
|
|
||||||
when {
|
|
||||||
changeset "ci/openjdk8-mongodb-4.2/**"
|
|
||||||
}
|
|
||||||
agent { label 'data' }
|
|
||||||
options { timeout(time: 30, unit: 'MINUTES') }
|
|
||||||
|
|
||||||
steps {
|
|
||||||
script {
|
|
||||||
def image = docker.build("springci/spring-data-openjdk8-with-mongodb-4.2", "ci/openjdk8-mongodb-4.2/")
|
|
||||||
docker.withRegistry('', 'hub.docker.com-springbuildmaster') {
|
|
||||||
image.push()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
stage("test: baseline") {
|
stage("test: baseline") {
|
||||||
when {
|
|
||||||
anyOf {
|
|
||||||
branch 'master'
|
|
||||||
not { triggeredBy 'UpstreamCause' }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
agent {
|
|
||||||
docker {
|
|
||||||
image 'springci/spring-data-openjdk8-with-mongodb-4.2:latest'
|
|
||||||
label 'data'
|
|
||||||
args '-v $HOME:/tmp/jenkins-home'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
options { timeout(time: 30, unit: 'MINUTES') }
|
|
||||||
steps {
|
|
||||||
sh 'rm -rf ?'
|
|
||||||
sh 'mkdir -p /tmp/mongodb/db /tmp/mongodb/log'
|
|
||||||
sh 'mongod --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 clean dependency:list test -Dsort -U -B'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
stage("Test other configurations") {
|
|
||||||
when {
|
|
||||||
anyOf {
|
|
||||||
branch 'master'
|
|
||||||
not { triggeredBy 'UpstreamCause' }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
parallel {
|
|
||||||
stage("test: mongodb 4.0") {
|
|
||||||
agent {
|
agent {
|
||||||
docker {
|
docker {
|
||||||
image 'springci/spring-data-openjdk8-with-mongodb-4.0:latest'
|
image 'springci/spring-data-openjdk8-with-mongodb-4.0:latest'
|
||||||
@@ -118,35 +39,15 @@ pipeline {
|
|||||||
sh 'MAVEN_OPTS="-Duser.name=jenkins -Duser.home=/tmp/jenkins-home" ./mvnw clean dependency:list test -Dsort -U -B'
|
sh 'MAVEN_OPTS="-Duser.name=jenkins -Duser.home=/tmp/jenkins-home" ./mvnw clean dependency:list test -Dsort -U -B'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
stage("test: mongodb 4.1") {
|
|
||||||
agent {
|
|
||||||
docker {
|
|
||||||
image 'springci/spring-data-openjdk8-with-mongodb-4.1:latest'
|
|
||||||
label 'data'
|
|
||||||
args '-v $HOME:/tmp/jenkins-home'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
options { timeout(time: 30, unit: 'MINUTES') }
|
|
||||||
steps {
|
|
||||||
sh 'rm -rf ?'
|
|
||||||
sh 'mkdir -p /tmp/mongodb/db /tmp/mongodb/log'
|
|
||||||
sh 'mongod --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 clean dependency:list test -Dsort -U -B'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
stage('Release to artifactory') {
|
stage('Release to artifactory') {
|
||||||
when {
|
when {
|
||||||
anyOf {
|
branch 'issue/*'
|
||||||
branch 'master'
|
|
||||||
not { triggeredBy 'UpstreamCause' }
|
not { triggeredBy 'UpstreamCause' }
|
||||||
}
|
}
|
||||||
}
|
|
||||||
agent {
|
agent {
|
||||||
docker {
|
docker {
|
||||||
image 'adoptopenjdk/openjdk8:latest'
|
image 'adoptopenjdk/openjdk8:latest'
|
||||||
@@ -167,15 +68,15 @@ pipeline {
|
|||||||
"-Dartifactory.username=${ARTIFACTORY_USR} " +
|
"-Dartifactory.username=${ARTIFACTORY_USR} " +
|
||||||
"-Dartifactory.password=${ARTIFACTORY_PSW} " +
|
"-Dartifactory.password=${ARTIFACTORY_PSW} " +
|
||||||
"-Dartifactory.staging-repository=libs-snapshot-local " +
|
"-Dartifactory.staging-repository=libs-snapshot-local " +
|
||||||
"-Dartifactory.build-name=spring-data-mongodb " +
|
"-Dartifactory.build-name=spring-data-mongodb-2.1 " +
|
||||||
"-Dartifactory.build-number=${BUILD_NUMBER} " +
|
"-Dartifactory.build-number=${BUILD_NUMBER} " +
|
||||||
'-Dmaven.test.skip=true clean deploy -U -B'
|
'-Dmaven.test.skip=true clean deploy -U -B'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
stage('Publish documentation') {
|
stage('Release to artifactory with docs') {
|
||||||
when {
|
when {
|
||||||
branch 'master'
|
branch '2.1.x'
|
||||||
}
|
}
|
||||||
agent {
|
agent {
|
||||||
docker {
|
docker {
|
||||||
@@ -191,11 +92,14 @@ pipeline {
|
|||||||
}
|
}
|
||||||
|
|
||||||
steps {
|
steps {
|
||||||
sh 'MAVEN_OPTS="-Duser.name=jenkins -Duser.home=/tmp/jenkins-home" ./mvnw -Pci,distribute ' +
|
sh 'rm -rf ?'
|
||||||
|
sh 'MAVEN_OPTS="-Duser.name=jenkins -Duser.home=/tmp/jenkins-home" ./mvnw -Pci,artifactory ' +
|
||||||
'-Dartifactory.server=https://repo.spring.io ' +
|
'-Dartifactory.server=https://repo.spring.io ' +
|
||||||
"-Dartifactory.username=${ARTIFACTORY_USR} " +
|
"-Dartifactory.username=${ARTIFACTORY_USR} " +
|
||||||
"-Dartifactory.password=${ARTIFACTORY_PSW} " +
|
"-Dartifactory.password=${ARTIFACTORY_PSW} " +
|
||||||
"-Dartifactory.distribution-repository=temp-private-local " +
|
"-Dartifactory.staging-repository=libs-snapshot-local " +
|
||||||
|
"-Dartifactory.build-name=spring-data-mongodb-2.1 " +
|
||||||
|
"-Dartifactory.build-number=${BUILD_NUMBER} " +
|
||||||
'-Dmaven.test.skip=true clean deploy -U -B'
|
'-Dmaven.test.skip=true clean deploy -U -B'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +0,0 @@
|
|||||||
# Security Policy
|
|
||||||
|
|
||||||
## Supported Versions
|
|
||||||
|
|
||||||
Please see the https://spring.io/projects/spring-data-mongodb[Spring Data MongoDB] project page for supported versions.
|
|
||||||
|
|
||||||
## Reporting a Vulnerability
|
|
||||||
|
|
||||||
Please don't raise security vulnerabilities here. Head over to https://pivotal.io/security to learn how to disclose them responsibly.
|
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
== Running CI tasks locally
|
|
||||||
|
|
||||||
Since Concourse is built on top of Docker, it's easy to:
|
|
||||||
|
|
||||||
* Debug what went wrong on your local machine.
|
|
||||||
* Test out a a tweak to your `test.sh` script before sending it out.
|
|
||||||
* Experiment against a new image before submitting your pull request.
|
|
||||||
|
|
||||||
All of these use cases are great reasons to essentially run what Concourse does on your local machine.
|
|
||||||
|
|
||||||
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`
|
|
||||||
+
|
|
||||||
This will launch the Docker image and mount your source code at `spring-data-mongodb-github`.
|
|
||||||
+
|
|
||||||
Next, run the `test.sh` script from inside the container:
|
|
||||||
+
|
|
||||||
2. `PROFILE=none spring-data-mongodb-github/ci/test.sh`
|
|
||||||
|
|
||||||
Since the container is binding to your source, you can make edits from your IDE and continue to run build jobs.
|
|
||||||
|
|
||||||
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`
|
|
||||||
+
|
|
||||||
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`.
|
|
||||||
+
|
|
||||||
Next, run the `build.sh` script from inside the container:
|
|
||||||
+
|
|
||||||
3. `spring-data-mongodb-github/ci/build.sh`
|
|
||||||
|
|
||||||
IMPORTANT: `build.sh` doesn't actually push to Artifactory so don't worry about accidentally deploying anything.
|
|
||||||
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.
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
FROM adoptopenjdk/openjdk8:latest
|
|
||||||
|
|
||||||
RUN apt-get update && apt-get install -y apt-transport-https apt-utils gnupg2
|
|
||||||
|
|
||||||
RUN apt-key adv --keyserver hkps://keyserver.ubuntu.com:443 --recv e162f504a20cdf15827f718d4b7c549a058f8b6b
|
|
||||||
|
|
||||||
RUN echo "deb [ arch=amd64 ] https://repo.mongodb.org/apt/ubuntu bionic/mongodb-org/4.2 multiverse" | tee /etc/apt/sources.list.d/mongodb-org-4.2.list
|
|
||||||
|
|
||||||
RUN apt-get update
|
|
||||||
|
|
||||||
RUN apt-get install -y mongodb-org=4.2.0 mongodb-org-server=4.2.0 mongodb-org-shell=4.2.0 mongodb-org-mongos=4.2.0 mongodb-org-tools=4.2.0
|
|
||||||
|
|
||||||
RUN apt-get clean \
|
|
||||||
&& rm -rf /var/lib/apt/lists/*
|
|
||||||
35
pom.xml
35
pom.xml
@@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
<groupId>org.springframework.data</groupId>
|
<groupId>org.springframework.data</groupId>
|
||||||
<artifactId>spring-data-mongodb-parent</artifactId>
|
<artifactId>spring-data-mongodb-parent</artifactId>
|
||||||
<version>3.0.0.M2</version>
|
<version>2.1.14.RELEASE</version>
|
||||||
<packaging>pom</packaging>
|
<packaging>pom</packaging>
|
||||||
|
|
||||||
<name>Spring Data MongoDB</name>
|
<name>Spring Data MongoDB</name>
|
||||||
@@ -15,20 +15,21 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>org.springframework.data.build</groupId>
|
<groupId>org.springframework.data.build</groupId>
|
||||||
<artifactId>spring-data-parent</artifactId>
|
<artifactId>spring-data-parent</artifactId>
|
||||||
<version>2.3.0.M2</version>
|
<version>2.1.14.RELEASE</version>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<modules>
|
<modules>
|
||||||
<module>spring-data-mongodb</module>
|
<module>spring-data-mongodb</module>
|
||||||
|
<module>spring-data-mongodb-cross-store</module>
|
||||||
<module>spring-data-mongodb-distribution</module>
|
<module>spring-data-mongodb-distribution</module>
|
||||||
</modules>
|
</modules>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
<project.type>multi</project.type>
|
<project.type>multi</project.type>
|
||||||
<dist.id>spring-data-mongodb</dist.id>
|
<dist.id>spring-data-mongodb</dist.id>
|
||||||
<springdata.commons>2.3.0.M2</springdata.commons>
|
<springdata.commons>2.1.14.RELEASE</springdata.commons>
|
||||||
<mongo>3.12.0</mongo>
|
<mongo>3.8.2</mongo>
|
||||||
<mongo.reactivestreams>1.13.0</mongo.reactivestreams>
|
<mongo.reactivestreams>1.9.2</mongo.reactivestreams>
|
||||||
<jmh.version>1.19</jmh.version>
|
<jmh.version>1.19</jmh.version>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
@@ -117,10 +118,30 @@
|
|||||||
<id>benchmarks</id>
|
<id>benchmarks</id>
|
||||||
<modules>
|
<modules>
|
||||||
<module>spring-data-mongodb</module>
|
<module>spring-data-mongodb</module>
|
||||||
|
<module>spring-data-mongodb-cross-store</module>
|
||||||
<module>spring-data-mongodb-distribution</module>
|
<module>spring-data-mongodb-distribution</module>
|
||||||
<module>spring-data-mongodb-benchmarks</module>
|
<module>spring-data-mongodb-benchmarks</module>
|
||||||
</modules>
|
</modules>
|
||||||
</profile>
|
</profile>
|
||||||
|
|
||||||
|
<profile>
|
||||||
|
<id>distribute</id>
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.asciidoctor</groupId>
|
||||||
|
<artifactId>asciidoctor-maven-plugin</artifactId>
|
||||||
|
<configuration>
|
||||||
|
<attributes>
|
||||||
|
<mongo-reactivestreams>${mongo.reactivestreams}</mongo-reactivestreams>
|
||||||
|
<reactor>${reactor}</reactor>
|
||||||
|
</attributes>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
</profile>
|
||||||
|
|
||||||
</profiles>
|
</profiles>
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
@@ -134,8 +155,8 @@
|
|||||||
|
|
||||||
<repositories>
|
<repositories>
|
||||||
<repository>
|
<repository>
|
||||||
<id>spring-libs-milestone</id>
|
<id>spring-libs-release</id>
|
||||||
<url>https://repo.spring.io/libs-milestone</url>
|
<url>https://repo.spring.io/libs-release</url>
|
||||||
</repository>
|
</repository>
|
||||||
</repositories>
|
</repositories>
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>org.springframework.data</groupId>
|
<groupId>org.springframework.data</groupId>
|
||||||
<artifactId>spring-data-mongodb-parent</artifactId>
|
<artifactId>spring-data-mongodb-parent</artifactId>
|
||||||
<version>3.0.0.M2</version>
|
<version>2.1.14.RELEASE</version>
|
||||||
<relativePath>../pom.xml</relativePath>
|
<relativePath>../pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
@@ -87,7 +87,6 @@
|
|||||||
<plugin>
|
<plugin>
|
||||||
<artifactId>maven-surefire-plugin</artifactId>
|
<artifactId>maven-surefire-plugin</artifactId>
|
||||||
<configuration>
|
<configuration>
|
||||||
<useSystemClassLoader>false</useSystemClassLoader>
|
|
||||||
<testSourceDirectory>${project.build.sourceDirectory}</testSourceDirectory>
|
<testSourceDirectory>${project.build.sourceDirectory}</testSourceDirectory>
|
||||||
<testClassesDirectory>${project.build.outputDirectory}</testClassesDirectory>
|
<testClassesDirectory>${project.build.outputDirectory}</testClassesDirectory>
|
||||||
<excludes>
|
<excludes>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2017-2020 the original author or authors.
|
* Copyright 2017-2019 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2017-2020 the original author or authors.
|
* Copyright 2017-2019 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2017-2020 the original author or authors.
|
* Copyright 2017-2019 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2017-2020 the original author or authors.
|
* Copyright 2017-2019 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2017-2020 the original author or authors.
|
* Copyright 2017-2019 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2017-2020 the original author or authors.
|
* Copyright 2017-2019 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2017-2020 the original author or authors.
|
* Copyright 2017-2019 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|||||||
7
spring-data-mongodb-cross-store/aop.xml
Normal file
7
spring-data-mongodb-cross-store/aop.xml
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<aspectj>
|
||||||
|
<aspects>
|
||||||
|
<aspect name="org.springframework.beans.factory.aspectj.AnnotationBeanConfigurerAspect" />
|
||||||
|
<aspect name="org.springframework.data.mongodb.crossstore.MongoDocumentBacking" />
|
||||||
|
</aspects>
|
||||||
|
</aspectj>
|
||||||
148
spring-data-mongodb-cross-store/pom.xml
Normal file
148
spring-data-mongodb-cross-store/pom.xml
Normal file
@@ -0,0 +1,148 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/maven-v4_0_0.xsd">
|
||||||
|
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<parent>
|
||||||
|
<groupId>org.springframework.data</groupId>
|
||||||
|
<artifactId>spring-data-mongodb-parent</artifactId>
|
||||||
|
<version>2.1.14.RELEASE</version>
|
||||||
|
<relativePath>../pom.xml</relativePath>
|
||||||
|
</parent>
|
||||||
|
|
||||||
|
<artifactId>spring-data-mongodb-cross-store</artifactId>
|
||||||
|
<name>Spring Data MongoDB - Cross-Store Support</name>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<jpa>2.1.1</jpa>
|
||||||
|
<hibernate>5.2.1.Final</hibernate>
|
||||||
|
<java-module-name>spring.data.mongodb.cross.store</java-module-name>
|
||||||
|
<project.root>${basedir}/..</project.root>
|
||||||
|
</properties>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
|
||||||
|
<!-- Spring -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework</groupId>
|
||||||
|
<artifactId>spring-beans</artifactId>
|
||||||
|
<exclusions>
|
||||||
|
<exclusion>
|
||||||
|
<groupId>commons-logging</groupId>
|
||||||
|
<artifactId>commons-logging</artifactId>
|
||||||
|
</exclusion>
|
||||||
|
</exclusions>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework</groupId>
|
||||||
|
<artifactId>spring-tx</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework</groupId>
|
||||||
|
<artifactId>spring-aspects</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework</groupId>
|
||||||
|
<artifactId>spring-orm</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- Spring Data -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.data</groupId>
|
||||||
|
<artifactId>spring-data-mongodb</artifactId>
|
||||||
|
<version>2.1.14.RELEASE</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- reactive -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.projectreactor</groupId>
|
||||||
|
<artifactId>reactor-core</artifactId>
|
||||||
|
<optional>true</optional>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.aspectj</groupId>
|
||||||
|
<artifactId>aspectjrt</artifactId>
|
||||||
|
<version>${aspectj}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- JPA -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.eclipse.persistence</groupId>
|
||||||
|
<artifactId>javax.persistence</artifactId>
|
||||||
|
<version>${jpa}</version>
|
||||||
|
<optional>true</optional>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- For Tests -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.hibernate</groupId>
|
||||||
|
<artifactId>hibernate-entitymanager</artifactId>
|
||||||
|
<version>${hibernate}</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>hsqldb</groupId>
|
||||||
|
<artifactId>hsqldb</artifactId>
|
||||||
|
<version>1.8.0.10</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>javax.validation</groupId>
|
||||||
|
<artifactId>validation-api</artifactId>
|
||||||
|
<version>${validation}</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.hibernate</groupId>
|
||||||
|
<artifactId>hibernate-validator</artifactId>
|
||||||
|
<version>5.2.4.Final</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.codehaus.mojo</groupId>
|
||||||
|
<artifactId>aspectj-maven-plugin</artifactId>
|
||||||
|
<version>1.6</version>
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.aspectj</groupId>
|
||||||
|
<artifactId>aspectjrt</artifactId>
|
||||||
|
<version>${aspectj}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.aspectj</groupId>
|
||||||
|
<artifactId>aspectjtools</artifactId>
|
||||||
|
<version>${aspectj}</version>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<goals>
|
||||||
|
<goal>compile</goal>
|
||||||
|
<goal>test-compile</goal>
|
||||||
|
</goals>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
<configuration>
|
||||||
|
<outxml>true</outxml>
|
||||||
|
<aspectLibraries>
|
||||||
|
<aspectLibrary>
|
||||||
|
<groupId>org.springframework</groupId>
|
||||||
|
<artifactId>spring-aspects</artifactId>
|
||||||
|
</aspectLibrary>
|
||||||
|
</aspectLibraries>
|
||||||
|
<complianceLevel>${source.level}</complianceLevel>
|
||||||
|
<source>${source.level}</source>
|
||||||
|
<target>${source.level}</target>
|
||||||
|
<xmlConfigured>aop.xml</xmlConfigured>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
|
||||||
|
</project>
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2019-2020 the original author or authors.
|
* Copyright 2011-2019 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -13,15 +13,16 @@
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
package org.springframework.data.mongodb.repository;
|
package org.springframework.data.mongodb.crossstore;
|
||||||
|
|
||||||
import lombok.Value;
|
import org.springframework.data.crossstore.ChangeSetBacked;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Christoph Strobl
|
* @author Thomas Risberg
|
||||||
|
* @author Oliver Gierke
|
||||||
|
* @deprecated will be removed without replacement.
|
||||||
*/
|
*/
|
||||||
@Value
|
@Deprecated
|
||||||
class SumAge {
|
public interface DocumentBacked extends ChangeSetBacked {
|
||||||
|
|
||||||
private Long total;
|
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,214 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2011-2019 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.crossstore;
|
||||||
|
|
||||||
|
import javax.persistence.EntityManagerFactory;
|
||||||
|
|
||||||
|
import org.bson.Document;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.dao.DataAccessException;
|
||||||
|
import org.springframework.dao.DataAccessResourceFailureException;
|
||||||
|
import org.springframework.dao.DataIntegrityViolationException;
|
||||||
|
import org.springframework.data.crossstore.ChangeSet;
|
||||||
|
import org.springframework.data.crossstore.ChangeSetBacked;
|
||||||
|
import org.springframework.data.crossstore.ChangeSetPersister;
|
||||||
|
import org.springframework.data.mongodb.core.CollectionCallback;
|
||||||
|
import org.springframework.data.mongodb.core.MongoTemplate;
|
||||||
|
import org.springframework.util.ClassUtils;
|
||||||
|
|
||||||
|
import com.mongodb.MongoException;
|
||||||
|
import com.mongodb.client.MongoCollection;
|
||||||
|
import com.mongodb.client.model.Filters;
|
||||||
|
import com.mongodb.client.result.DeleteResult;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Thomas Risberg
|
||||||
|
* @author Oliver Gierke
|
||||||
|
* @author Alex Vengrovsk
|
||||||
|
* @author Mark Paluch
|
||||||
|
* @deprecated will be removed without replacement.
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
|
public class MongoChangeSetPersister implements ChangeSetPersister<Object> {
|
||||||
|
|
||||||
|
private static final String ENTITY_CLASS = "_entity_class";
|
||||||
|
private static final String ENTITY_ID = "_entity_id";
|
||||||
|
private static final String ENTITY_FIELD_NAME = "_entity_field_name";
|
||||||
|
private static final String ENTITY_FIELD_CLASS = "_entity_field_class";
|
||||||
|
|
||||||
|
private final Logger log = LoggerFactory.getLogger(getClass());
|
||||||
|
|
||||||
|
private MongoTemplate mongoTemplate;
|
||||||
|
private EntityManagerFactory entityManagerFactory;
|
||||||
|
|
||||||
|
public void setMongoTemplate(MongoTemplate mongoTemplate) {
|
||||||
|
this.mongoTemplate = mongoTemplate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEntityManagerFactory(EntityManagerFactory entityManagerFactory) {
|
||||||
|
this.entityManagerFactory = entityManagerFactory;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.springframework.data.crossstore.ChangeSetPersister#getPersistentState(java.lang.Class, java.lang.Object, org.springframework.data.crossstore.ChangeSet)
|
||||||
|
*/
|
||||||
|
public void getPersistentState(Class<? extends ChangeSetBacked> entityClass, Object id, final ChangeSet changeSet)
|
||||||
|
throws DataAccessException, NotFoundException {
|
||||||
|
|
||||||
|
if (id == null) {
|
||||||
|
log.debug("Unable to load MongoDB data for null id");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
String collName = getCollectionNameForEntity(entityClass);
|
||||||
|
|
||||||
|
final Document dbk = new Document();
|
||||||
|
dbk.put(ENTITY_ID, id);
|
||||||
|
dbk.put(ENTITY_CLASS, entityClass.getName());
|
||||||
|
if (log.isDebugEnabled()) {
|
||||||
|
log.debug("Loading MongoDB data for {}", dbk);
|
||||||
|
}
|
||||||
|
mongoTemplate.execute(collName, new CollectionCallback<Object>() {
|
||||||
|
public Object doInCollection(MongoCollection<Document> collection) throws MongoException, DataAccessException {
|
||||||
|
for (Document dbo : collection.find(dbk)) {
|
||||||
|
String key = (String) dbo.get(ENTITY_FIELD_NAME);
|
||||||
|
if (log.isDebugEnabled()) {
|
||||||
|
log.debug("Processing key: {}", key);
|
||||||
|
}
|
||||||
|
if (!changeSet.getValues().containsKey(key)) {
|
||||||
|
String className = (String) dbo.get(ENTITY_FIELD_CLASS);
|
||||||
|
if (className == null) {
|
||||||
|
throw new DataIntegrityViolationException(
|
||||||
|
"Unble to convert property " + key + ": Invalid metadata, " + ENTITY_FIELD_CLASS + " not available");
|
||||||
|
}
|
||||||
|
Class<?> clazz = ClassUtils.resolveClassName(className, ClassUtils.getDefaultClassLoader());
|
||||||
|
Object value = mongoTemplate.getConverter().read(clazz, dbo);
|
||||||
|
if (log.isDebugEnabled()) {
|
||||||
|
log.debug("Adding to ChangeSet: {}", key);
|
||||||
|
}
|
||||||
|
changeSet.set(key, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.springframework.data.crossstore.ChangeSetPersister#getPersistentId(org.springframework.data.crossstore.ChangeSetBacked, org.springframework.data.crossstore.ChangeSet)
|
||||||
|
*/
|
||||||
|
public Object getPersistentId(ChangeSetBacked entity, ChangeSet cs) throws DataAccessException {
|
||||||
|
if (log.isDebugEnabled()) {
|
||||||
|
log.debug("getPersistentId called on {}", entity);
|
||||||
|
}
|
||||||
|
if (entityManagerFactory == null) {
|
||||||
|
throw new DataAccessResourceFailureException("EntityManagerFactory cannot be null");
|
||||||
|
}
|
||||||
|
|
||||||
|
return entityManagerFactory.getPersistenceUnitUtil().getIdentifier(entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.springframework.data.crossstore.ChangeSetPersister#persistState(org.springframework.data.crossstore.ChangeSetBacked, org.springframework.data.crossstore.ChangeSet)
|
||||||
|
*/
|
||||||
|
public Object persistState(ChangeSetBacked entity, ChangeSet cs) throws DataAccessException {
|
||||||
|
if (cs == null) {
|
||||||
|
log.debug("Flush: changeset was null, nothing to flush.");
|
||||||
|
return 0L;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (log.isDebugEnabled()) {
|
||||||
|
log.debug("Flush: changeset: {}", cs.getValues());
|
||||||
|
}
|
||||||
|
|
||||||
|
String collName = getCollectionNameForEntity(entity.getClass());
|
||||||
|
if (mongoTemplate.getCollection(collName) == null) {
|
||||||
|
mongoTemplate.createCollection(collName);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (String key : cs.getValues().keySet()) {
|
||||||
|
if (key != null && !key.startsWith("_") && !key.equals(ChangeSetPersister.ID_KEY)) {
|
||||||
|
Object value = cs.getValues().get(key);
|
||||||
|
final Document dbQuery = new Document();
|
||||||
|
dbQuery.put(ENTITY_ID, getPersistentId(entity, cs));
|
||||||
|
dbQuery.put(ENTITY_CLASS, entity.getClass().getName());
|
||||||
|
dbQuery.put(ENTITY_FIELD_NAME, key);
|
||||||
|
final Document dbId = mongoTemplate.execute(collName, new CollectionCallback<Document>() {
|
||||||
|
public Document doInCollection(MongoCollection<Document> collection)
|
||||||
|
throws MongoException, DataAccessException {
|
||||||
|
Document id = collection.find(dbQuery).first();
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (value == null) {
|
||||||
|
if (log.isDebugEnabled()) {
|
||||||
|
log.debug("Flush: removing: {}", dbQuery);
|
||||||
|
}
|
||||||
|
mongoTemplate.execute(collName, new CollectionCallback<Object>() {
|
||||||
|
public Object doInCollection(MongoCollection<Document> collection)
|
||||||
|
throws MongoException, DataAccessException {
|
||||||
|
DeleteResult dr = collection.deleteMany(dbQuery);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
final Document dbDoc = new Document();
|
||||||
|
dbDoc.putAll(dbQuery);
|
||||||
|
if (log.isDebugEnabled()) {
|
||||||
|
log.debug("Flush: saving: {}", dbQuery);
|
||||||
|
}
|
||||||
|
mongoTemplate.getConverter().write(value, dbDoc);
|
||||||
|
dbDoc.put(ENTITY_FIELD_CLASS, value.getClass().getName());
|
||||||
|
if (dbId != null) {
|
||||||
|
dbDoc.put("_id", dbId.get("_id"));
|
||||||
|
}
|
||||||
|
mongoTemplate.execute(collName, new CollectionCallback<Object>() {
|
||||||
|
public Object doInCollection(MongoCollection<Document> collection)
|
||||||
|
throws MongoException, DataAccessException {
|
||||||
|
|
||||||
|
if (dbId != null) {
|
||||||
|
collection.replaceOne(Filters.eq("_id", dbId.get("_id")), dbDoc);
|
||||||
|
} else {
|
||||||
|
|
||||||
|
if (dbDoc.containsKey("_id") && dbDoc.get("_id") == null) {
|
||||||
|
dbDoc.remove("_id");
|
||||||
|
}
|
||||||
|
collection.insertOne(dbDoc);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0L;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the collection the given entity type shall be persisted to.
|
||||||
|
*
|
||||||
|
* @param entityClass must not be {@literal null}.
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private String getCollectionNameForEntity(Class<? extends ChangeSetBacked> entityClass) {
|
||||||
|
return mongoTemplate.getCollectionName(entityClass);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,272 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2011-2019 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.crossstore;
|
||||||
|
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
|
||||||
|
import javax.persistence.EntityManager;
|
||||||
|
import javax.persistence.Transient;
|
||||||
|
import javax.persistence.Entity;
|
||||||
|
|
||||||
|
import org.aspectj.lang.JoinPoint;
|
||||||
|
import org.aspectj.lang.reflect.FieldSignature;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.dao.DataAccessException;
|
||||||
|
import org.springframework.data.mongodb.crossstore.RelatedDocument;
|
||||||
|
import org.springframework.data.mongodb.crossstore.DocumentBacked;
|
||||||
|
import org.springframework.data.crossstore.ChangeSetBackedTransactionSynchronization;
|
||||||
|
import org.springframework.data.crossstore.ChangeSet;
|
||||||
|
import org.springframework.data.crossstore.ChangeSetPersister;
|
||||||
|
import org.springframework.data.crossstore.ChangeSetPersister.NotFoundException;
|
||||||
|
import org.springframework.data.crossstore.HashMapChangeSet;
|
||||||
|
import org.springframework.transaction.support.TransactionSynchronizationManager;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Aspect to turn an object annotated with @Document into a persistent document using Mongo.
|
||||||
|
*
|
||||||
|
* @author Thomas Risberg
|
||||||
|
* @deprecated will be removed without replacement.
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
|
public aspect MongoDocumentBacking {
|
||||||
|
|
||||||
|
private static final Logger LOGGER = LoggerFactory.getLogger(MongoDocumentBacking.class);
|
||||||
|
|
||||||
|
// Aspect shared config
|
||||||
|
private ChangeSetPersister<Object> changeSetPersister;
|
||||||
|
|
||||||
|
public void setChangeSetPersister(ChangeSetPersister<Object> changeSetPersister) {
|
||||||
|
this.changeSetPersister = changeSetPersister;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ITD to introduce N state to Annotated objects
|
||||||
|
declare parents : (@Entity *) implements DocumentBacked;
|
||||||
|
|
||||||
|
// The annotated fields that will be persisted in MongoDB rather than with JPA
|
||||||
|
declare @field: @RelatedDocument * (@Entity+ *).*:@Transient;
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
// Advise user-defined constructors of ChangeSetBacked objects to create a new
|
||||||
|
// backing ChangeSet
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
pointcut arbitraryUserConstructorOfChangeSetBackedObject(DocumentBacked entity) :
|
||||||
|
execution((DocumentBacked+).new(..)) &&
|
||||||
|
!execution((DocumentBacked+).new(ChangeSet)) &&
|
||||||
|
this(entity);
|
||||||
|
|
||||||
|
pointcut finderConstructorOfChangeSetBackedObject(DocumentBacked entity, ChangeSet cs) :
|
||||||
|
execution((DocumentBacked+).new(ChangeSet)) &&
|
||||||
|
this(entity) &&
|
||||||
|
args(cs);
|
||||||
|
|
||||||
|
protected pointcut entityFieldGet(DocumentBacked entity) :
|
||||||
|
get(@RelatedDocument * DocumentBacked+.*) &&
|
||||||
|
this(entity) &&
|
||||||
|
!get(* DocumentBacked.*);
|
||||||
|
|
||||||
|
protected pointcut entityFieldSet(DocumentBacked entity, Object newVal) :
|
||||||
|
set(@RelatedDocument * DocumentBacked+.*) &&
|
||||||
|
this(entity) &&
|
||||||
|
args(newVal) &&
|
||||||
|
!set(* DocumentBacked.*);
|
||||||
|
|
||||||
|
// intercept EntityManager.merge calls
|
||||||
|
public pointcut entityManagerMerge(EntityManager em, Object entity) :
|
||||||
|
call(* EntityManager.merge(Object)) &&
|
||||||
|
target(em) &&
|
||||||
|
args(entity);
|
||||||
|
|
||||||
|
// intercept EntityManager.remove calls
|
||||||
|
// public pointcut entityManagerRemove(EntityManager em, Object entity) :
|
||||||
|
// call(* EntityManager.remove(Object)) &&
|
||||||
|
// target(em) &&
|
||||||
|
// args(entity);
|
||||||
|
|
||||||
|
// move changeSet from detached entity to the newly merged persistent object
|
||||||
|
Object around(EntityManager em, Object entity) : entityManagerMerge(em, entity) {
|
||||||
|
Object mergedEntity = proceed(em, entity);
|
||||||
|
if (entity instanceof DocumentBacked && mergedEntity instanceof DocumentBacked) {
|
||||||
|
((DocumentBacked) mergedEntity).changeSet = ((DocumentBacked) entity).getChangeSet();
|
||||||
|
}
|
||||||
|
return mergedEntity;
|
||||||
|
}
|
||||||
|
|
||||||
|
// clear changeSet from removed entity
|
||||||
|
// Object around(EntityManager em, Object entity) : entityManagerRemove(em, entity) {
|
||||||
|
// if (entity instanceof DocumentBacked) {
|
||||||
|
// removeChangeSetValues((DocumentBacked)entity);
|
||||||
|
// }
|
||||||
|
// return proceed(em, entity);
|
||||||
|
// }
|
||||||
|
|
||||||
|
private static void removeChangeSetValues(DocumentBacked entity) {
|
||||||
|
LOGGER.debug("Removing all change-set values for " + entity);
|
||||||
|
ChangeSet nulledCs = new HashMapChangeSet();
|
||||||
|
DocumentBacked documentEntity = (DocumentBacked) entity;
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
ChangeSetPersister<Object> changeSetPersister = (ChangeSetPersister<Object>) documentEntity.itdChangeSetPersister;
|
||||||
|
try {
|
||||||
|
changeSetPersister.getPersistentState(documentEntity.getClass(), documentEntity.get_persistent_id(),
|
||||||
|
documentEntity.getChangeSet());
|
||||||
|
} catch (DataAccessException e) {
|
||||||
|
} catch (NotFoundException e) {
|
||||||
|
}
|
||||||
|
for (String key : entity.getChangeSet().getValues().keySet()) {
|
||||||
|
nulledCs.set(key, null);
|
||||||
|
}
|
||||||
|
entity.setChangeSet(nulledCs);
|
||||||
|
}
|
||||||
|
|
||||||
|
before(DocumentBacked entity) : arbitraryUserConstructorOfChangeSetBackedObject(entity) {
|
||||||
|
LOGGER.debug("User-defined constructor called on DocumentBacked object of class " + entity.getClass());
|
||||||
|
// Populate all ITD fields
|
||||||
|
entity.setChangeSet(new HashMapChangeSet());
|
||||||
|
entity.itdChangeSetPersister = changeSetPersister;
|
||||||
|
entity.itdTransactionSynchronization = new ChangeSetBackedTransactionSynchronization(changeSetPersister, entity);
|
||||||
|
// registerTransactionSynchronization(entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void registerTransactionSynchronization(DocumentBacked entity) {
|
||||||
|
if (TransactionSynchronizationManager.isSynchronizationActive()) {
|
||||||
|
if (!TransactionSynchronizationManager.getSynchronizations().contains(entity.itdTransactionSynchronization)) {
|
||||||
|
if (LOGGER.isDebugEnabled()) {
|
||||||
|
LOGGER.debug("Adding transaction synchronization for " + entity);
|
||||||
|
}
|
||||||
|
TransactionSynchronizationManager.registerSynchronization(entity.itdTransactionSynchronization);
|
||||||
|
} else {
|
||||||
|
if (LOGGER.isDebugEnabled()) {
|
||||||
|
LOGGER.debug("Transaction synchronization already active for " + entity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (LOGGER.isDebugEnabled()) {
|
||||||
|
LOGGER.debug("Transaction synchronization is not active for " + entity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
// ChangeSet-related mixins
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
// Introduced field
|
||||||
|
@Transient
|
||||||
|
private ChangeSet DocumentBacked.changeSet;
|
||||||
|
|
||||||
|
@Transient
|
||||||
|
private ChangeSetPersister<?> DocumentBacked.itdChangeSetPersister;
|
||||||
|
|
||||||
|
@Transient
|
||||||
|
private ChangeSetBackedTransactionSynchronization DocumentBacked.itdTransactionSynchronization;
|
||||||
|
|
||||||
|
public void DocumentBacked.setChangeSet(ChangeSet cs) {
|
||||||
|
this.changeSet = cs;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ChangeSet DocumentBacked.getChangeSet() {
|
||||||
|
return changeSet;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Flush the entity state to the persistent store
|
||||||
|
public void DocumentBacked.flush() {
|
||||||
|
Object id = itdChangeSetPersister.getPersistentId(this, this.changeSet);
|
||||||
|
itdChangeSetPersister.persistState(this, this.changeSet);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object DocumentBacked.get_persistent_id() {
|
||||||
|
return itdChangeSetPersister.getPersistentId(this, this.changeSet);
|
||||||
|
}
|
||||||
|
|
||||||
|
// lifecycle methods
|
||||||
|
@javax.persistence.PostPersist
|
||||||
|
public void DocumentBacked.itdPostPersist() {
|
||||||
|
if (LOGGER.isDebugEnabled()) {
|
||||||
|
LOGGER.debug("JPA lifecycle event PrePersist: " + this.getClass().getName());
|
||||||
|
}
|
||||||
|
registerTransactionSynchronization(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@javax.persistence.PreUpdate
|
||||||
|
public void DocumentBacked.itdPreUpdate() {
|
||||||
|
if (LOGGER.isDebugEnabled()) {
|
||||||
|
LOGGER.debug("JPA lifecycle event PreUpdate: " + this.getClass().getName() + " :: " + this);
|
||||||
|
}
|
||||||
|
registerTransactionSynchronization(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@javax.persistence.PostUpdate
|
||||||
|
public void DocumentBacked.itdPostUpdate() {
|
||||||
|
if (LOGGER.isDebugEnabled()) {
|
||||||
|
LOGGER.debug("JPA lifecycle event PostUpdate: " + this.getClass().getName() + " :: " + this);
|
||||||
|
}
|
||||||
|
registerTransactionSynchronization(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@javax.persistence.PostRemove
|
||||||
|
public void DocumentBacked.itdPostRemove() {
|
||||||
|
if (LOGGER.isDebugEnabled()) {
|
||||||
|
LOGGER.debug("JPA lifecycle event PostRemove: " + this.getClass().getName() + " :: " + this);
|
||||||
|
}
|
||||||
|
registerTransactionSynchronization(this);
|
||||||
|
removeChangeSetValues(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@javax.persistence.PostLoad
|
||||||
|
public void DocumentBacked.itdPostLoad() {
|
||||||
|
if (LOGGER.isDebugEnabled()) {
|
||||||
|
LOGGER.debug("JPA lifecycle event PostLoad: " + this.getClass().getName() + " :: " + this);
|
||||||
|
}
|
||||||
|
registerTransactionSynchronization(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* delegates field reads to the state accessors instance
|
||||||
|
*/
|
||||||
|
Object around(DocumentBacked entity): entityFieldGet(entity) {
|
||||||
|
Field f = field(thisJoinPoint);
|
||||||
|
String propName = f.getName();
|
||||||
|
LOGGER.trace("GET " + f + " -> ChangeSet value property [" + propName + "] using: " + entity.getChangeSet());
|
||||||
|
if (entity.getChangeSet().getValues().get(propName) == null) {
|
||||||
|
try {
|
||||||
|
this.changeSetPersister
|
||||||
|
.getPersistentState(entity.getClass(), entity.get_persistent_id(), entity.getChangeSet());
|
||||||
|
} catch (NotFoundException e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Object fValue = entity.getChangeSet().getValues().get(propName);
|
||||||
|
if (fValue != null) {
|
||||||
|
return fValue;
|
||||||
|
}
|
||||||
|
return proceed(entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* delegates field writes to the state accessors instance
|
||||||
|
*/
|
||||||
|
Object around(DocumentBacked entity, Object newVal) : entityFieldSet(entity, newVal) {
|
||||||
|
Field f = field(thisJoinPoint);
|
||||||
|
String propName = f.getName();
|
||||||
|
LOGGER.trace("SET " + f + " -> ChangeSet number value property [" + propName + "] with value=[" + newVal + "]");
|
||||||
|
entity.getChangeSet().set(propName, newVal);
|
||||||
|
return proceed(entity, newVal);
|
||||||
|
}
|
||||||
|
|
||||||
|
Field field(JoinPoint joinPoint) {
|
||||||
|
FieldSignature fieldSignature = (FieldSignature) joinPoint.getSignature();
|
||||||
|
return fieldSignature.getField();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2019-2020 the original author or authors.
|
* Copyright 2011-2019 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -13,27 +13,19 @@
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
package org.springframework.data.mongodb.test.util;
|
package org.springframework.data.mongodb.crossstore;
|
||||||
|
|
||||||
import java.lang.annotation.Documented;
|
|
||||||
import java.lang.annotation.ElementType;
|
import java.lang.annotation.ElementType;
|
||||||
import java.lang.annotation.Retention;
|
import java.lang.annotation.Retention;
|
||||||
import java.lang.annotation.RetentionPolicy;
|
import java.lang.annotation.RetentionPolicy;
|
||||||
import java.lang.annotation.Target;
|
import java.lang.annotation.Target;
|
||||||
|
|
||||||
import org.junit.jupiter.api.Tag;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@link EnableIfReplicaSetAvailable} marks a specific test class or method to be only executed against a server running in
|
* @author Thomas Risberg
|
||||||
* replicaSet mode. Intended to be used along with {@link MongoServerCondition}.
|
* @deprecated will be removed without replacement.
|
||||||
*
|
|
||||||
* @author Christoph Strobl
|
|
||||||
* @since 3.0
|
|
||||||
*/
|
*/
|
||||||
@Target({ ElementType.TYPE, ElementType.METHOD })
|
@Deprecated
|
||||||
@Retention(RetentionPolicy.RUNTIME)
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
@Documented
|
@Target({ ElementType.FIELD })
|
||||||
@Tag("replSet")
|
public @interface RelatedDocument {
|
||||||
public @interface EnableIfReplicaSetAvailable {
|
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
/**
|
||||||
|
* Infrastructure for Spring Data's MongoDB cross store support.
|
||||||
|
*/
|
||||||
|
package org.springframework.data.mongodb.crossstore;
|
||||||
|
|
||||||
@@ -0,0 +1,195 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2011-2019 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.crossstore;
|
||||||
|
|
||||||
|
import javax.persistence.EntityManager;
|
||||||
|
import javax.persistence.PersistenceContext;
|
||||||
|
|
||||||
|
import org.bson.Document;
|
||||||
|
import org.junit.After;
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.data.mongodb.core.MongoTemplate;
|
||||||
|
import org.springframework.data.mongodb.crossstore.test.Address;
|
||||||
|
import org.springframework.data.mongodb.crossstore.test.Person;
|
||||||
|
import org.springframework.data.mongodb.crossstore.test.Resume;
|
||||||
|
import org.springframework.test.context.ContextConfiguration;
|
||||||
|
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||||
|
import org.springframework.transaction.PlatformTransactionManager;
|
||||||
|
import org.springframework.transaction.TransactionStatus;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
import org.springframework.transaction.support.TransactionCallback;
|
||||||
|
import org.springframework.transaction.support.TransactionTemplate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Integration tests for MongoDB cross-store persistence (mainly {@link MongoChangeSetPersister}).
|
||||||
|
*
|
||||||
|
* @author Thomas Risberg
|
||||||
|
* @author Oliver Gierke
|
||||||
|
*/
|
||||||
|
@RunWith(SpringJUnit4ClassRunner.class)
|
||||||
|
@ContextConfiguration("classpath:/META-INF/spring/applicationContext.xml")
|
||||||
|
public class CrossStoreMongoTests {
|
||||||
|
|
||||||
|
@Autowired MongoTemplate mongoTemplate;
|
||||||
|
|
||||||
|
@PersistenceContext EntityManager entityManager;
|
||||||
|
|
||||||
|
@Autowired PlatformTransactionManager transactionManager;
|
||||||
|
TransactionTemplate txTemplate;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() {
|
||||||
|
|
||||||
|
txTemplate = new TransactionTemplate(transactionManager);
|
||||||
|
|
||||||
|
clearData(Person.class);
|
||||||
|
|
||||||
|
Address address = new Address(12, "MAin St.", "Boston", "MA", "02101");
|
||||||
|
|
||||||
|
Resume resume = new Resume();
|
||||||
|
resume.addEducation("Skanstulls High School, 1975");
|
||||||
|
resume.addEducation("Univ. of Stockholm, 1980");
|
||||||
|
resume.addJob("DiMark, DBA, 1990-2000");
|
||||||
|
resume.addJob("VMware, Developer, 2007-");
|
||||||
|
|
||||||
|
final Person person = new Person("Thomas", 20);
|
||||||
|
person.setAddress(address);
|
||||||
|
person.setResume(resume);
|
||||||
|
person.setId(1L);
|
||||||
|
|
||||||
|
txTemplate.execute(new TransactionCallback<Void>() {
|
||||||
|
public Void doInTransaction(TransactionStatus status) {
|
||||||
|
entityManager.persist(person);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@After
|
||||||
|
public void tearDown() {
|
||||||
|
txTemplate.execute(new TransactionCallback<Void>() {
|
||||||
|
public Void doInTransaction(TransactionStatus status) {
|
||||||
|
entityManager.remove(entityManager.find(Person.class, 1L));
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void clearData(Class<?> domainType) {
|
||||||
|
|
||||||
|
String collectionName = mongoTemplate.getCollectionName(domainType);
|
||||||
|
mongoTemplate.dropCollection(collectionName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Transactional
|
||||||
|
public void testReadJpaToMongoEntityRelationship() {
|
||||||
|
|
||||||
|
Person found = entityManager.find(Person.class, 1L);
|
||||||
|
Assert.assertNotNull(found);
|
||||||
|
Assert.assertEquals(Long.valueOf(1), found.getId());
|
||||||
|
Assert.assertNotNull(found);
|
||||||
|
Assert.assertEquals(Long.valueOf(1), found.getId());
|
||||||
|
Assert.assertNotNull(found.getResume());
|
||||||
|
Assert.assertEquals("DiMark, DBA, 1990-2000" + "; " + "VMware, Developer, 2007-", found.getResume().getJobs());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Transactional
|
||||||
|
public void testUpdatedJpaToMongoEntityRelationship() {
|
||||||
|
|
||||||
|
Person found = entityManager.find(Person.class, 1L);
|
||||||
|
found.setAge(44);
|
||||||
|
found.getResume().addJob("SpringDeveloper.com, Consultant, 2005-2006");
|
||||||
|
|
||||||
|
entityManager.merge(found);
|
||||||
|
|
||||||
|
Assert.assertNotNull(found);
|
||||||
|
Assert.assertEquals(Long.valueOf(1), found.getId());
|
||||||
|
Assert.assertNotNull(found);
|
||||||
|
Assert.assertEquals(Long.valueOf(1), found.getId());
|
||||||
|
Assert.assertNotNull(found.getResume());
|
||||||
|
Assert.assertEquals("DiMark, DBA, 1990-2000" + "; " + "VMware, Developer, 2007-" + "; "
|
||||||
|
+ "SpringDeveloper.com, Consultant, 2005-2006", found.getResume().getJobs());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testMergeJpaEntityWithMongoDocument() {
|
||||||
|
|
||||||
|
final Person detached = entityManager.find(Person.class, 1L);
|
||||||
|
entityManager.detach(detached);
|
||||||
|
detached.getResume().addJob("TargetRx, Developer, 2000-2005");
|
||||||
|
|
||||||
|
Person merged = txTemplate.execute(new TransactionCallback<Person>() {
|
||||||
|
public Person doInTransaction(TransactionStatus status) {
|
||||||
|
Person result = entityManager.merge(detached);
|
||||||
|
entityManager.flush();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Assert.assertTrue(detached.getResume().getJobs().contains("TargetRx, Developer, 2000-2005"));
|
||||||
|
Assert.assertTrue(merged.getResume().getJobs().contains("TargetRx, Developer, 2000-2005"));
|
||||||
|
final Person updated = entityManager.find(Person.class, 1L);
|
||||||
|
Assert.assertTrue(updated.getResume().getJobs().contains("TargetRx, Developer, 2000-2005"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRemoveJpaEntityWithMongoDocument() {
|
||||||
|
|
||||||
|
txTemplate.execute(new TransactionCallback<Person>() {
|
||||||
|
public Person doInTransaction(TransactionStatus status) {
|
||||||
|
Person p2 = new Person("Thomas", 20);
|
||||||
|
Resume r2 = new Resume();
|
||||||
|
r2.addEducation("Skanstulls High School, 1975");
|
||||||
|
r2.addJob("DiMark, DBA, 1990-2000");
|
||||||
|
p2.setResume(r2);
|
||||||
|
p2.setId(2L);
|
||||||
|
entityManager.persist(p2);
|
||||||
|
Person p3 = new Person("Thomas", 20);
|
||||||
|
Resume r3 = new Resume();
|
||||||
|
r3.addEducation("Univ. of Stockholm, 1980");
|
||||||
|
r3.addJob("VMware, Developer, 2007-");
|
||||||
|
p3.setResume(r3);
|
||||||
|
p3.setId(3L);
|
||||||
|
entityManager.persist(p3);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
txTemplate.execute(new TransactionCallback<Person>() {
|
||||||
|
public Person doInTransaction(TransactionStatus status) {
|
||||||
|
final Person found2 = entityManager.find(Person.class, 2L);
|
||||||
|
entityManager.remove(found2);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
boolean weFound3 = false;
|
||||||
|
|
||||||
|
for (Document dbo : this.mongoTemplate.getCollection(mongoTemplate.getCollectionName(Person.class)).find()) {
|
||||||
|
Assert.assertTrue(!dbo.get("_entity_id").equals(2L));
|
||||||
|
if (dbo.get("_entity_id").equals(3L)) {
|
||||||
|
weFound3 = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Assert.assertTrue(weFound3);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,75 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2011-2019 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.crossstore.test;
|
||||||
|
|
||||||
|
public class Address {
|
||||||
|
|
||||||
|
private Integer streetNumber;
|
||||||
|
private String streetName;
|
||||||
|
private String city;
|
||||||
|
private String state;
|
||||||
|
private String zip;
|
||||||
|
|
||||||
|
public Address(Integer streetNumber, String streetName, String city, String state, String zip) {
|
||||||
|
super();
|
||||||
|
this.streetNumber = streetNumber;
|
||||||
|
this.streetName = streetName;
|
||||||
|
this.city = city;
|
||||||
|
this.state = state;
|
||||||
|
this.zip = zip;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getStreetNumber() {
|
||||||
|
return streetNumber;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setStreetNumber(Integer streetNumber) {
|
||||||
|
this.streetNumber = streetNumber;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getStreetName() {
|
||||||
|
return streetName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setStreetName(String streetName) {
|
||||||
|
this.streetName = streetName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCity() {
|
||||||
|
return city;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCity(String city) {
|
||||||
|
this.city = city;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getState() {
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setState(String state) {
|
||||||
|
this.state = state;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getZip() {
|
||||||
|
return zip;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setZip(String zip) {
|
||||||
|
this.zip = zip;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,102 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2011-2019 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.crossstore.test;
|
||||||
|
|
||||||
|
import javax.persistence.Entity;
|
||||||
|
import javax.persistence.Id;
|
||||||
|
|
||||||
|
import org.springframework.data.mongodb.crossstore.RelatedDocument;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
public class Person {
|
||||||
|
|
||||||
|
@Id
|
||||||
|
Long id;
|
||||||
|
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
private int age;
|
||||||
|
|
||||||
|
private java.util.Date birthDate;
|
||||||
|
|
||||||
|
@RelatedDocument
|
||||||
|
private Address address;
|
||||||
|
|
||||||
|
@RelatedDocument
|
||||||
|
private Resume resume;
|
||||||
|
|
||||||
|
public Person() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public Person(String name, int age) {
|
||||||
|
this.name = name;
|
||||||
|
this.age = age;
|
||||||
|
this.birthDate = new java.util.Date();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void birthday() {
|
||||||
|
++age;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(Long id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getAge() {
|
||||||
|
return age;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAge(int age) {
|
||||||
|
this.age = age;
|
||||||
|
}
|
||||||
|
|
||||||
|
public java.util.Date getBirthDate() {
|
||||||
|
return birthDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setBirthDate(java.util.Date birthDate) {
|
||||||
|
this.birthDate = birthDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Resume getResume() {
|
||||||
|
return resume;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setResume(Resume resume) {
|
||||||
|
this.resume = resume;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Address getAddress() {
|
||||||
|
return address;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAddress(Address address) {
|
||||||
|
this.address = address;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2011-2019 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.crossstore.test;
|
||||||
|
|
||||||
|
import org.apache.commons.logging.Log;
|
||||||
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
import org.bson.types.ObjectId;
|
||||||
|
import org.springframework.data.annotation.Id;
|
||||||
|
import org.springframework.data.mongodb.core.mapping.Document;
|
||||||
|
|
||||||
|
@Document
|
||||||
|
public class Resume {
|
||||||
|
|
||||||
|
private static final Log LOGGER = LogFactory.getLog(Resume.class);
|
||||||
|
|
||||||
|
@Id
|
||||||
|
private ObjectId id;
|
||||||
|
|
||||||
|
private String education = "";
|
||||||
|
|
||||||
|
private String jobs = "";
|
||||||
|
|
||||||
|
public String getId() {
|
||||||
|
return id.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getEducation() {
|
||||||
|
return education;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addEducation(String education) {
|
||||||
|
LOGGER.debug("Adding education " + education);
|
||||||
|
this.education = this.education + (this.education.length() > 0 ? "; " : "") + education;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getJobs() {
|
||||||
|
return jobs;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addJob(String job) {
|
||||||
|
LOGGER.debug("Adding job " + job);
|
||||||
|
this.jobs = this.jobs + (this.jobs.length() > 0 ? "; " : "") + job;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "Resume [education=" + education + ", jobs=" + jobs + "]";
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<persistence xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
version="2.0"
|
||||||
|
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
|
||||||
|
<persistence-unit name="test" transaction-type="RESOURCE_LOCAL">
|
||||||
|
<provider>org.hibernate.ejb.HibernatePersistence</provider>
|
||||||
|
<class>org.springframework.data.mongodb.crossstore.test.Person</class>
|
||||||
|
<properties>
|
||||||
|
<property name="hibernate.dialect" value="org.hibernate.dialect.HSQLDialect"/>
|
||||||
|
<!--value='create' to build a new database on each run; value='update' to modify an existing database; value='create-drop' means the same as 'create' but also drops tables when Hibernate closes; value='validate' makes no changes to the database-->
|
||||||
|
<property name="hibernate.hbm2ddl.auto" value="update"/>
|
||||||
|
<property name="hibernate.ejb.naming_strategy" value="org.hibernate.cfg.ImprovedNamingStrategy"/>
|
||||||
|
</properties>
|
||||||
|
</persistence-unit>
|
||||||
|
</persistence>
|
||||||
@@ -0,0 +1,72 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xmlns:tx="http://www.springframework.org/schema/tx"
|
||||||
|
xmlns:jdbc="http://www.springframework.org/schema/jdbc"
|
||||||
|
xmlns:context="http://www.springframework.org/schema/context"
|
||||||
|
xmlns:mongo="http://www.springframework.org/schema/data/mongo"
|
||||||
|
xsi:schemaLocation="http://www.springframework.org/schema/data/mongo https://www.springframework.org/schema/data/mongo/spring-mongo.xsd
|
||||||
|
http://www.springframework.org/schema/jdbc https://www.springframework.org/schema/jdbc/spring-jdbc-3.0.xsd
|
||||||
|
http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans-3.0.xsd
|
||||||
|
http://www.springframework.org/schema/tx https://www.springframework.org/schema/tx/spring-tx-3.0.xsd
|
||||||
|
http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context-3.0.xsd">
|
||||||
|
|
||||||
|
<context:spring-configured/>
|
||||||
|
|
||||||
|
<context:component-scan base-package="org.springframework.persistence.mongodb.test">
|
||||||
|
<context:exclude-filter expression="org.springframework.stereotype.Controller" type="annotation"/>
|
||||||
|
</context:component-scan>
|
||||||
|
|
||||||
|
<mongo:mapping-converter/>
|
||||||
|
|
||||||
|
<!-- Mongo config -->
|
||||||
|
<bean id="mongoClient" class="org.springframework.data.mongodb.core.MongoClientFactoryBean">
|
||||||
|
<property name="host" value="localhost"/>
|
||||||
|
<property name="port" value="27017"/>
|
||||||
|
</bean>
|
||||||
|
|
||||||
|
<bean id="mongoDbFactory" class="org.springframework.data.mongodb.core.SimpleMongoDbFactory">
|
||||||
|
<constructor-arg name="mongoClient" ref="mongoClient"/>
|
||||||
|
<constructor-arg name="databaseName" value="database"/>
|
||||||
|
</bean>
|
||||||
|
|
||||||
|
<bean id="mongoTemplate" class="org.springframework.data.mongodb.core.MongoTemplate">
|
||||||
|
<constructor-arg name="mongoDbFactory" ref="mongoDbFactory"/>
|
||||||
|
<constructor-arg name="mongoConverter" ref="mappingConverter"/>
|
||||||
|
</bean>
|
||||||
|
|
||||||
|
<bean class="org.springframework.data.mongodb.core.MongoExceptionTranslator"/>
|
||||||
|
|
||||||
|
<!-- Mongo aspect config -->
|
||||||
|
<bean class="org.springframework.data.mongodb.crossstore.MongoDocumentBacking"
|
||||||
|
factory-method="aspectOf">
|
||||||
|
<property name="changeSetPersister" ref="mongoChangeSetPersister"/>
|
||||||
|
</bean>
|
||||||
|
<bean id="mongoChangeSetPersister"
|
||||||
|
class="org.springframework.data.mongodb.crossstore.MongoChangeSetPersister">
|
||||||
|
<property name="mongoTemplate" ref="mongoTemplate"/>
|
||||||
|
<property name="entityManagerFactory" ref="entityManagerFactory"/>
|
||||||
|
</bean>
|
||||||
|
|
||||||
|
<jdbc:embedded-database id="dataSource" type="HSQL">
|
||||||
|
</jdbc:embedded-database>
|
||||||
|
|
||||||
|
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
|
||||||
|
<property name="entityManagerFactory" ref="entityManagerFactory"/>
|
||||||
|
</bean>
|
||||||
|
|
||||||
|
<tx:annotation-driven mode="aspectj" transaction-manager="transactionManager"/>
|
||||||
|
|
||||||
|
<bean class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" id="entityManagerFactory">
|
||||||
|
<property name="persistenceUnitName" value="test"/>
|
||||||
|
<property name="dataSource" ref="dataSource"/>
|
||||||
|
<property name="jpaVendorAdapter">
|
||||||
|
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
|
||||||
|
<property name="showSql" value="true"/>
|
||||||
|
<property name="generateDdl" value="true"/>
|
||||||
|
<property name="databasePlatform" value="org.hibernate.dialect.HSQLDialect"/>
|
||||||
|
</bean>
|
||||||
|
</property>
|
||||||
|
</bean>
|
||||||
|
|
||||||
|
</beans>
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<configuration>
|
||||||
|
|
||||||
|
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
|
||||||
|
<encoder>
|
||||||
|
<pattern>%d %5p %40.40c:%4L - %m%n</pattern>
|
||||||
|
</encoder>
|
||||||
|
</appender>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
<logger name="org.springframework" level="debug" />
|
||||||
|
-->
|
||||||
|
|
||||||
|
<root level="error">
|
||||||
|
<appender-ref ref="console" />
|
||||||
|
</root>
|
||||||
|
|
||||||
|
</configuration>
|
||||||
@@ -1,6 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
|
||||||
|
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
@@ -14,7 +13,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>org.springframework.data</groupId>
|
<groupId>org.springframework.data</groupId>
|
||||||
<artifactId>spring-data-mongodb-parent</artifactId>
|
<artifactId>spring-data-mongodb-parent</artifactId>
|
||||||
<version>3.0.0.M2</version>
|
<version>2.1.14.RELEASE</version>
|
||||||
<relativePath>../pom.xml</relativePath>
|
<relativePath>../pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
@@ -32,15 +31,8 @@
|
|||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.asciidoctor</groupId>
|
<groupId>org.asciidoctor</groupId>
|
||||||
<artifactId>asciidoctor-maven-plugin</artifactId>
|
<artifactId>asciidoctor-maven-plugin</artifactId>
|
||||||
<configuration>
|
|
||||||
<attributes>
|
|
||||||
<mongo-reactivestreams>${mongo.reactivestreams}</mongo-reactivestreams>
|
|
||||||
<reactor>${reactor}</reactor>
|
|
||||||
</attributes>
|
|
||||||
</configuration>
|
|
||||||
</plugin>
|
</plugin>
|
||||||
</plugins>
|
</plugins>
|
||||||
|
|
||||||
</build>
|
</build>
|
||||||
|
|
||||||
</project>
|
</project>
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>org.springframework.data</groupId>
|
<groupId>org.springframework.data</groupId>
|
||||||
<artifactId>spring-data-mongodb-parent</artifactId>
|
<artifactId>spring-data-mongodb-parent</artifactId>
|
||||||
<version>3.0.0.M2</version>
|
<version>2.1.14.RELEASE</version>
|
||||||
<relativePath>../pom.xml</relativePath>
|
<relativePath>../pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
@@ -264,25 +264,20 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.jetbrains.kotlin</groupId>
|
<groupId>org.jetbrains.kotlin</groupId>
|
||||||
<artifactId>kotlin-stdlib</artifactId>
|
<artifactId>kotlin-stdlib</artifactId>
|
||||||
|
<version>${kotlin}</version>
|
||||||
<optional>true</optional>
|
<optional>true</optional>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.jetbrains.kotlin</groupId>
|
<groupId>org.jetbrains.kotlin</groupId>
|
||||||
<artifactId>kotlin-reflect</artifactId>
|
<artifactId>kotlin-reflect</artifactId>
|
||||||
|
<version>${kotlin}</version>
|
||||||
<optional>true</optional>
|
<optional>true</optional>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.jetbrains.kotlinx</groupId>
|
<groupId>org.jetbrains.kotlin</groupId>
|
||||||
<artifactId>kotlinx-coroutines-core</artifactId>
|
<artifactId>kotlin-test</artifactId>
|
||||||
<optional>true</optional>
|
<version>${kotlin}</version>
|
||||||
</dependency>
|
<scope>test</scope>
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.jetbrains.kotlinx</groupId>
|
|
||||||
<artifactId>kotlinx-coroutines-reactor</artifactId>
|
|
||||||
<optional>true</optional>
|
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
@@ -327,7 +322,6 @@
|
|||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
<artifactId>maven-surefire-plugin</artifactId>
|
<artifactId>maven-surefire-plugin</artifactId>
|
||||||
<configuration>
|
<configuration>
|
||||||
<useSystemClassLoader>false</useSystemClassLoader>
|
|
||||||
<useFile>false</useFile>
|
<useFile>false</useFile>
|
||||||
<includes>
|
<includes>
|
||||||
<include>**/*Tests.java</include>
|
<include>**/*Tests.java</include>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2015-2020 the original author or authors.
|
* Copyright 2015-2019 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|||||||
@@ -0,0 +1,69 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2019 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.DataAccessResourceFailureException;
|
||||||
|
import org.springframework.data.authentication.UserCredentials;
|
||||||
|
import org.springframework.lang.Nullable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exception being thrown in case we cannot connect to a MongoDB instance.
|
||||||
|
*
|
||||||
|
* @author Oliver Gierke
|
||||||
|
* @author Mark Paluch
|
||||||
|
*/
|
||||||
|
public class CannotGetMongoDbConnectionException extends DataAccessResourceFailureException {
|
||||||
|
|
||||||
|
private final UserCredentials credentials;
|
||||||
|
private final @Nullable String database;
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1172099106475265589L;
|
||||||
|
|
||||||
|
public CannotGetMongoDbConnectionException(String msg, Throwable cause) {
|
||||||
|
super(msg, cause);
|
||||||
|
this.database = null;
|
||||||
|
this.credentials = UserCredentials.NO_CREDENTIALS;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CannotGetMongoDbConnectionException(String msg) {
|
||||||
|
this(msg, null, UserCredentials.NO_CREDENTIALS);
|
||||||
|
}
|
||||||
|
|
||||||
|
public CannotGetMongoDbConnectionException(String msg, @Nullable String database, UserCredentials credentials) {
|
||||||
|
super(msg);
|
||||||
|
this.database = database;
|
||||||
|
this.credentials = credentials;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the {@link UserCredentials} that were used when trying to connect to the MongoDB instance.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public UserCredentials getCredentials() {
|
||||||
|
return this.credentials;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the name of the database trying to be accessed.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
public String getDatabase() {
|
||||||
|
return database;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2018-2020 the original author or authors.
|
* Copyright 2018-2019 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2017-2020 the original author or authors.
|
* Copyright 2017-2019 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2010-2020 the original author or authors.
|
* Copyright 2010-2019 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2013-2020 the original author or authors.
|
* Copyright 2013-2019 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2011-2020 the original author or authors.
|
* Copyright 2011-2019 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2018-2020 the original author or authors.
|
* Copyright 2018-2019 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2011-2020 the original author or authors.
|
* Copyright 2011-2019 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2018-2020 the original author or authors.
|
* Copyright 2018-2019 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2018-2020 the original author or authors.
|
* Copyright 2018-2019 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2018-2020 the original author or authors.
|
* Copyright 2018-2019 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2018-2020 the original author or authors.
|
* Copyright 2018-2019 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2016-2020 the original author or authors.
|
* Copyright 2016-2019 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -13,6 +13,7 @@
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.springframework.data.mongodb;
|
package org.springframework.data.mongodb;
|
||||||
|
|
||||||
import reactor.core.publisher.Mono;
|
import reactor.core.publisher.Mono;
|
||||||
@@ -87,16 +88,4 @@ public interface ReactiveMongoDatabaseFactory extends CodecRegistryProvider {
|
|||||||
* @since 2.1
|
* @since 2.1
|
||||||
*/
|
*/
|
||||||
ReactiveMongoDatabaseFactory withSession(ClientSession session);
|
ReactiveMongoDatabaseFactory withSession(ClientSession session);
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns if the given {@link ReactiveMongoDatabaseFactory} is bound to a
|
|
||||||
* {@link com.mongodb.reactivestreams.client.ClientSession} that has an
|
|
||||||
* {@link com.mongodb.reactivestreams.client.ClientSession#hasActiveTransaction() active transaction}.
|
|
||||||
*
|
|
||||||
* @return {@literal true} if there's an active transaction, {@literal false} otherwise.
|
|
||||||
* @since 2.2
|
|
||||||
*/
|
|
||||||
default boolean isTransactionActive() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,278 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2019-2020 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 reactor.core.publisher.Mono;
|
|
||||||
import reactor.util.context.Context;
|
|
||||||
|
|
||||||
import org.springframework.lang.Nullable;
|
|
||||||
import org.springframework.transaction.NoTransactionException;
|
|
||||||
import org.springframework.transaction.reactive.ReactiveResourceSynchronization;
|
|
||||||
import org.springframework.transaction.reactive.TransactionSynchronization;
|
|
||||||
import org.springframework.transaction.reactive.TransactionSynchronizationManager;
|
|
||||||
import org.springframework.transaction.support.ResourceHolderSynchronization;
|
|
||||||
import org.springframework.util.Assert;
|
|
||||||
import org.springframework.util.StringUtils;
|
|
||||||
|
|
||||||
import com.mongodb.ClientSessionOptions;
|
|
||||||
import com.mongodb.reactivestreams.client.ClientSession;
|
|
||||||
import com.mongodb.reactivestreams.client.MongoCollection;
|
|
||||||
import com.mongodb.reactivestreams.client.MongoDatabase;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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.
|
|
||||||
* <p />
|
|
||||||
* <strong>Note:</strong> Intended for internal usage only.
|
|
||||||
*
|
|
||||||
* @author Mark Paluch
|
|
||||||
* @author Christoph Strobl
|
|
||||||
* @since 2.2
|
|
||||||
*/
|
|
||||||
public class ReactiveMongoDatabaseUtils {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check if the {@link ReactiveMongoDatabaseFactory} is actually bound to a
|
|
||||||
* {@link com.mongodb.reactivestreams.client.ClientSession} that has an active transaction, or if a
|
|
||||||
* {@link org.springframework.transaction.reactive.TransactionSynchronization} has been registered for the
|
|
||||||
* {@link ReactiveMongoDatabaseFactory resource} and if the associated
|
|
||||||
* {@link com.mongodb.reactivestreams.client.ClientSession} has an
|
|
||||||
* {@link com.mongodb.reactivestreams.client.ClientSession#hasActiveTransaction() active transaction}.
|
|
||||||
*
|
|
||||||
* @param databaseFactory the resource to check transactions for. Must not be {@literal null}.
|
|
||||||
* @return a {@link Mono} emitting {@literal true} if the factory has an ongoing transaction.
|
|
||||||
*/
|
|
||||||
public static Mono<Boolean> isTransactionActive(ReactiveMongoDatabaseFactory databaseFactory) {
|
|
||||||
|
|
||||||
if (databaseFactory.isTransactionActive()) {
|
|
||||||
return Mono.just(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
return TransactionSynchronizationManager.forCurrentTransaction() //
|
|
||||||
.map(it -> {
|
|
||||||
|
|
||||||
ReactiveMongoResourceHolder holder = (ReactiveMongoResourceHolder) it.getResource(databaseFactory);
|
|
||||||
return holder != null && holder.hasActiveTransaction();
|
|
||||||
}) //
|
|
||||||
.onErrorResume(NoTransactionException.class, e -> Mono.just(false));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Obtain the default {@link MongoDatabase database} form the given {@link ReactiveMongoDatabaseFactory factory} using
|
|
||||||
* {@link SessionSynchronization#ON_ACTUAL_TRANSACTION native session synchronization}.
|
|
||||||
* <p />
|
|
||||||
* Registers a {@link MongoSessionSynchronization MongoDB specific transaction synchronization} within the subscriber
|
|
||||||
* {@link Context} if {@link TransactionSynchronizationManager#isSynchronizationActive() synchronization is active}.
|
|
||||||
*
|
|
||||||
* @param factory the {@link ReactiveMongoDatabaseFactory} to get the {@link MongoDatabase} from.
|
|
||||||
* @return the {@link MongoDatabase} that is potentially associated with a transactional {@link ClientSession}.
|
|
||||||
*/
|
|
||||||
public static Mono<MongoDatabase> getDatabase(ReactiveMongoDatabaseFactory factory) {
|
|
||||||
return doGetMongoDatabase(null, factory, SessionSynchronization.ON_ACTUAL_TRANSACTION);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Obtain the default {@link MongoDatabase database} form the given {@link ReactiveMongoDatabaseFactory factory}.
|
|
||||||
* <p />
|
|
||||||
* Registers a {@link MongoSessionSynchronization MongoDB specific transaction synchronization} within the subscriber
|
|
||||||
* {@link Context} if {@link TransactionSynchronizationManager#isSynchronizationActive() synchronization is active}.
|
|
||||||
*
|
|
||||||
* @param factory the {@link ReactiveMongoDatabaseFactory} to get the {@link MongoDatabase} from.
|
|
||||||
* @param sessionSynchronization the synchronization to use. Must not be {@literal null}.
|
|
||||||
* @return the {@link MongoDatabase} that is potentially associated with a transactional {@link ClientSession}.
|
|
||||||
*/
|
|
||||||
public static Mono<MongoDatabase> getDatabase(ReactiveMongoDatabaseFactory factory,
|
|
||||||
SessionSynchronization sessionSynchronization) {
|
|
||||||
return doGetMongoDatabase(null, factory, sessionSynchronization);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Obtain the {@link MongoDatabase database} with given name form the given {@link ReactiveMongoDatabaseFactory
|
|
||||||
* factory} using {@link SessionSynchronization#ON_ACTUAL_TRANSACTION native session synchronization}.
|
|
||||||
* <p />
|
|
||||||
* Registers a {@link MongoSessionSynchronization MongoDB specific transaction synchronization} within the subscriber
|
|
||||||
* {@link Context} if {@link TransactionSynchronizationManager#isSynchronizationActive() synchronization is active}.
|
|
||||||
*
|
|
||||||
* @param dbName the name of the {@link MongoDatabase} to get.
|
|
||||||
* @param factory the {@link ReactiveMongoDatabaseFactory} to get the {@link MongoDatabase} from.
|
|
||||||
* @return the {@link MongoDatabase} that is potentially associated with a transactional {@link ClientSession}.
|
|
||||||
*/
|
|
||||||
public static Mono<MongoDatabase> getDatabase(String dbName, ReactiveMongoDatabaseFactory factory) {
|
|
||||||
return doGetMongoDatabase(dbName, factory, SessionSynchronization.ON_ACTUAL_TRANSACTION);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Obtain the {@link MongoDatabase database} with given name form the given {@link ReactiveMongoDatabaseFactory
|
|
||||||
* factory}.
|
|
||||||
* <p />
|
|
||||||
* Registers a {@link MongoSessionSynchronization MongoDB specific transaction synchronization} within the subscriber
|
|
||||||
* {@link Context} if {@link TransactionSynchronizationManager#isSynchronizationActive() synchronization is active}.
|
|
||||||
*
|
|
||||||
* @param dbName the name of the {@link MongoDatabase} to get.
|
|
||||||
* @param factory the {@link ReactiveMongoDatabaseFactory} to get the {@link MongoDatabase} from.
|
|
||||||
* @param sessionSynchronization the synchronization to use. Must not be {@literal null}.
|
|
||||||
* @return the {@link MongoDatabase} that is potentially associated with a transactional {@link ClientSession}.
|
|
||||||
*/
|
|
||||||
public static Mono<MongoDatabase> getDatabase(String dbName, ReactiveMongoDatabaseFactory factory,
|
|
||||||
SessionSynchronization sessionSynchronization) {
|
|
||||||
return doGetMongoDatabase(dbName, factory, sessionSynchronization);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Mono<MongoDatabase> doGetMongoDatabase(@Nullable String dbName, ReactiveMongoDatabaseFactory factory,
|
|
||||||
SessionSynchronization sessionSynchronization) {
|
|
||||||
|
|
||||||
Assert.notNull(factory, "DatabaseFactory must not be null!");
|
|
||||||
|
|
||||||
return TransactionSynchronizationManager.forCurrentTransaction()
|
|
||||||
.filter(TransactionSynchronizationManager::isSynchronizationActive) //
|
|
||||||
.flatMap(synchronizationManager -> {
|
|
||||||
|
|
||||||
return doGetSession(synchronizationManager, factory, sessionSynchronization) //
|
|
||||||
.map(it -> getMongoDatabaseOrDefault(dbName, factory.withSession(it)));
|
|
||||||
})
|
|
||||||
.onErrorResume(NoTransactionException.class,
|
|
||||||
e -> Mono.fromSupplier(() -> getMongoDatabaseOrDefault(dbName, factory)))
|
|
||||||
.defaultIfEmpty(getMongoDatabaseOrDefault(dbName, factory));
|
|
||||||
}
|
|
||||||
|
|
||||||
private static MongoDatabase getMongoDatabaseOrDefault(@Nullable String dbName,
|
|
||||||
ReactiveMongoDatabaseFactory factory) {
|
|
||||||
return StringUtils.hasText(dbName) ? factory.getMongoDatabase(dbName) : factory.getMongoDatabase();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Mono<ClientSession> doGetSession(TransactionSynchronizationManager synchronizationManager,
|
|
||||||
ReactiveMongoDatabaseFactory dbFactory, SessionSynchronization sessionSynchronization) {
|
|
||||||
|
|
||||||
final ReactiveMongoResourceHolder registeredHolder = (ReactiveMongoResourceHolder) synchronizationManager
|
|
||||||
.getResource(dbFactory);
|
|
||||||
|
|
||||||
// check for native MongoDB transaction
|
|
||||||
if (registeredHolder != null
|
|
||||||
&& (registeredHolder.hasSession() || registeredHolder.isSynchronizedWithTransaction())) {
|
|
||||||
|
|
||||||
return registeredHolder.hasSession() ? Mono.just(registeredHolder.getSession())
|
|
||||||
: createClientSession(dbFactory).map(registeredHolder::setSessionIfAbsent);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (SessionSynchronization.ON_ACTUAL_TRANSACTION.equals(sessionSynchronization)) {
|
|
||||||
return Mono.empty();
|
|
||||||
}
|
|
||||||
|
|
||||||
// init a non native MongoDB transaction by registering a MongoSessionSynchronization
|
|
||||||
return createClientSession(dbFactory).map(session -> {
|
|
||||||
|
|
||||||
ReactiveMongoResourceHolder newHolder = new ReactiveMongoResourceHolder(session, dbFactory);
|
|
||||||
newHolder.getRequiredSession().startTransaction();
|
|
||||||
|
|
||||||
synchronizationManager
|
|
||||||
.registerSynchronization(new MongoSessionSynchronization(synchronizationManager, newHolder, dbFactory));
|
|
||||||
newHolder.setSynchronizedWithTransaction(true);
|
|
||||||
synchronizationManager.bindResource(dbFactory, newHolder);
|
|
||||||
|
|
||||||
return newHolder.getSession();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Mono<ClientSession> createClientSession(ReactiveMongoDatabaseFactory dbFactory) {
|
|
||||||
return dbFactory.getSession(ClientSessionOptions.builder().causallyConsistent(true).build());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* MongoDB specific {@link ResourceHolderSynchronization} for resource cleanup at the end of a transaction when
|
|
||||||
* participating in a non-native MongoDB transaction, such as a R2CBC transaction.
|
|
||||||
*
|
|
||||||
* @author Mark Paluch
|
|
||||||
* @since 2.2
|
|
||||||
*/
|
|
||||||
private static class MongoSessionSynchronization
|
|
||||||
extends ReactiveResourceSynchronization<ReactiveMongoResourceHolder, Object> {
|
|
||||||
|
|
||||||
private final ReactiveMongoResourceHolder resourceHolder;
|
|
||||||
|
|
||||||
MongoSessionSynchronization(TransactionSynchronizationManager synchronizationManager,
|
|
||||||
ReactiveMongoResourceHolder resourceHolder, ReactiveMongoDatabaseFactory dbFactory) {
|
|
||||||
|
|
||||||
super(resourceHolder, dbFactory, synchronizationManager);
|
|
||||||
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<Void> processResourceAfterCommit(ReactiveMongoResourceHolder resourceHolder) {
|
|
||||||
|
|
||||||
if (isTransactionActive(resourceHolder)) {
|
|
||||||
return Mono.from(resourceHolder.getRequiredSession().commitTransaction());
|
|
||||||
}
|
|
||||||
|
|
||||||
return Mono.empty();
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* (non-Javadoc)
|
|
||||||
* @see org.springframework.transaction.reactive.ReactiveResourceSynchronization#afterCompletion(int)
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public Mono<Void> afterCompletion(int status) {
|
|
||||||
|
|
||||||
return Mono.defer(() -> {
|
|
||||||
|
|
||||||
if (status == TransactionSynchronization.STATUS_ROLLED_BACK && isTransactionActive(this.resourceHolder)) {
|
|
||||||
|
|
||||||
return Mono.from(resourceHolder.getRequiredSession().abortTransaction()) //
|
|
||||||
.then(super.afterCompletion(status));
|
|
||||||
}
|
|
||||||
|
|
||||||
return super.afterCompletion(status);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* (non-Javadoc)
|
|
||||||
* @see org.springframework.transaction.reactive.ReactiveResourceSynchronization#releaseResource(java.lang.Object, java.lang.Object)
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
protected Mono<Void> releaseResource(ReactiveMongoResourceHolder resourceHolder, Object resourceKey) {
|
|
||||||
|
|
||||||
return Mono.fromRunnable(() -> {
|
|
||||||
if (resourceHolder.hasActiveSession()) {
|
|
||||||
resourceHolder.getRequiredSession().close();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean isTransactionActive(ReactiveMongoResourceHolder resourceHolder) {
|
|
||||||
|
|
||||||
if (!resourceHolder.hasSession()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return resourceHolder.getRequiredSession().hasActiveTransaction();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,155 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2019-2020 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.data.mongodb.core.ReactiveMongoTemplate;
|
|
||||||
import org.springframework.lang.Nullable;
|
|
||||||
import org.springframework.transaction.support.ResourceHolderSupport;
|
|
||||||
|
|
||||||
import com.mongodb.reactivestreams.client.ClientSession;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* MongoDB specific resource holder, wrapping a {@link ClientSession}. {@link ReactiveMongoTransactionManager} binds
|
|
||||||
* instances of this class to the subscriber context.
|
|
||||||
* <p />
|
|
||||||
* <strong>Note:</strong> Intended for internal usage only.
|
|
||||||
*
|
|
||||||
* @author Mark Paluch
|
|
||||||
* @author Christoph Strobl
|
|
||||||
* @since 2.2
|
|
||||||
* @see ReactiveMongoTransactionManager
|
|
||||||
* @see ReactiveMongoTemplate
|
|
||||||
*/
|
|
||||||
class ReactiveMongoResourceHolder extends ResourceHolderSupport {
|
|
||||||
|
|
||||||
private @Nullable ClientSession session;
|
|
||||||
private ReactiveMongoDatabaseFactory databaseFactory;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new {@link ReactiveMongoResourceHolder} for a given {@link ClientSession session}.
|
|
||||||
*
|
|
||||||
* @param session the associated {@link ClientSession}. Can be {@literal null}.
|
|
||||||
* @param databaseFactory the associated {@link MongoDbFactory}. must not be {@literal null}.
|
|
||||||
*/
|
|
||||||
ReactiveMongoResourceHolder(@Nullable ClientSession session, ReactiveMongoDatabaseFactory databaseFactory) {
|
|
||||||
|
|
||||||
this.session = session;
|
|
||||||
this.databaseFactory = databaseFactory;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return the associated {@link ClientSession}. Can be {@literal null}.
|
|
||||||
*/
|
|
||||||
@Nullable
|
|
||||||
ClientSession getSession() {
|
|
||||||
return session;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return the required associated {@link ClientSession}.
|
|
||||||
* @throws IllegalStateException if no session is associated.
|
|
||||||
*/
|
|
||||||
ClientSession getRequiredSession() {
|
|
||||||
|
|
||||||
ClientSession session = getSession();
|
|
||||||
|
|
||||||
if (session == null) {
|
|
||||||
throw new IllegalStateException("No ClientSession associated");
|
|
||||||
}
|
|
||||||
return session;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return the associated {@link ReactiveMongoDatabaseFactory}.
|
|
||||||
*/
|
|
||||||
public ReactiveMongoDatabaseFactory getDatabaseFactory() {
|
|
||||||
return databaseFactory;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the {@link ClientSession} to guard.
|
|
||||||
*
|
|
||||||
* @param session can be {@literal null}.
|
|
||||||
*/
|
|
||||||
public void setSession(@Nullable ClientSession session) {
|
|
||||||
this.session = session;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return {@literal true} if session is not {@literal null}.
|
|
||||||
*/
|
|
||||||
boolean hasSession() {
|
|
||||||
return session != null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* If the {@link ReactiveMongoResourceHolder} is {@link #hasSession() not already associated} with a
|
|
||||||
* {@link ClientSession} the given value is {@link #setSession(ClientSession) set} and returned, otherwise the current
|
|
||||||
* bound session is returned.
|
|
||||||
*
|
|
||||||
* @param session
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
@Nullable
|
|
||||||
public ClientSession setSessionIfAbsent(@Nullable ClientSession session) {
|
|
||||||
|
|
||||||
if (!hasSession()) {
|
|
||||||
setSession(session);
|
|
||||||
}
|
|
||||||
|
|
||||||
return session;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return {@literal true} if the session is active and has not been closed.
|
|
||||||
*/
|
|
||||||
boolean hasActiveSession() {
|
|
||||||
|
|
||||||
if (!hasSession()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return hasServerSession() && !getRequiredSession().getServerSession().isClosed();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return {@literal true} if the session has an active transaction.
|
|
||||||
* @see #hasActiveSession()
|
|
||||||
*/
|
|
||||||
boolean hasActiveTransaction() {
|
|
||||||
|
|
||||||
if (!hasActiveSession()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return getRequiredSession().hasActiveTransaction();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return {@literal true} if the {@link ClientSession} has a {@link com.mongodb.session.ServerSession} associated
|
|
||||||
* that is accessible via {@link ClientSession#getServerSession()}.
|
|
||||||
*/
|
|
||||||
boolean hasServerSession() {
|
|
||||||
|
|
||||||
try {
|
|
||||||
return getRequiredSession().getServerSession() != null;
|
|
||||||
} catch (IllegalStateException serverSessionClosed) {
|
|
||||||
// ignore
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,530 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2019-2020 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 reactor.core.publisher.Mono;
|
|
||||||
|
|
||||||
import org.springframework.beans.factory.InitializingBean;
|
|
||||||
import org.springframework.lang.Nullable;
|
|
||||||
import org.springframework.transaction.TransactionDefinition;
|
|
||||||
import org.springframework.transaction.TransactionException;
|
|
||||||
import org.springframework.transaction.TransactionSystemException;
|
|
||||||
import org.springframework.transaction.reactive.AbstractReactiveTransactionManager;
|
|
||||||
import org.springframework.transaction.reactive.GenericReactiveTransaction;
|
|
||||||
import org.springframework.transaction.reactive.TransactionSynchronizationManager;
|
|
||||||
import org.springframework.transaction.support.SmartTransactionObject;
|
|
||||||
import org.springframework.util.Assert;
|
|
||||||
import org.springframework.util.ClassUtils;
|
|
||||||
|
|
||||||
import com.mongodb.ClientSessionOptions;
|
|
||||||
import com.mongodb.MongoException;
|
|
||||||
import com.mongodb.TransactionOptions;
|
|
||||||
import com.mongodb.reactivestreams.client.ClientSession;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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}.
|
|
||||||
* <p />
|
|
||||||
* Binds a {@link ClientSession} from the specified
|
|
||||||
* {@link org.springframework.data.mongodb.ReactiveMongoDatabaseFactory} to the subscriber
|
|
||||||
* {@link reactor.util.context.Context}.
|
|
||||||
* <p />
|
|
||||||
* {@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.
|
|
||||||
* <p />
|
|
||||||
* 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.
|
|
||||||
* <p />
|
|
||||||
* By default failure of a {@literal commit} operation raises a {@link TransactionSystemException}. You can override
|
|
||||||
* {@link #doCommit(TransactionSynchronizationManager, ReactiveMongoTransactionObject)} to implement the
|
|
||||||
* <a href="https://docs.mongodb.com/manual/core/transactions/#retry-commit-operation">Retry Commit Operation</a>
|
|
||||||
* behavior as outlined in the MongoDB reference manual.
|
|
||||||
*
|
|
||||||
* @author Christoph Strobl
|
|
||||||
* @author Mark Paluch
|
|
||||||
* @since 2.2
|
|
||||||
* @see <a href="https://www.mongodb.com/transactions">MongoDB Transaction Documentation</a>
|
|
||||||
* @see ReactiveMongoDatabaseUtils#getDatabase(ReactiveMongoDatabaseFactory, SessionSynchronization)
|
|
||||||
*/
|
|
||||||
public class ReactiveMongoTransactionManager extends AbstractReactiveTransactionManager implements InitializingBean {
|
|
||||||
|
|
||||||
private @Nullable ReactiveMongoDatabaseFactory databaseFactory;
|
|
||||||
private @Nullable TransactionOptions options;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new {@link ReactiveMongoTransactionManager} for bean-style usage.
|
|
||||||
* <p />
|
|
||||||
* <strong>Note:</strong>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}.
|
|
||||||
* <p />
|
|
||||||
* 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() {}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new {@link ReactiveMongoTransactionManager} obtaining sessions from the given
|
|
||||||
* {@link ReactiveMongoDatabaseFactory}.
|
|
||||||
*
|
|
||||||
* @param databaseFactory must not be {@literal null}.
|
|
||||||
*/
|
|
||||||
public ReactiveMongoTransactionManager(ReactiveMongoDatabaseFactory databaseFactory) {
|
|
||||||
this(databaseFactory, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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 options can be {@literal null}.
|
|
||||||
*/
|
|
||||||
public ReactiveMongoTransactionManager(ReactiveMongoDatabaseFactory databaseFactory,
|
|
||||||
@Nullable TransactionOptions options) {
|
|
||||||
|
|
||||||
Assert.notNull(databaseFactory, "DatabaseFactory must not be null!");
|
|
||||||
|
|
||||||
this.databaseFactory = databaseFactory;
|
|
||||||
this.options = options;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* (non-Javadoc)
|
|
||||||
* @see org.springframework.transaction.reactive.AbstractReactiveTransactionManager#doGetTransaction(org.springframework.transaction.reactive.TransactionSynchronizationManager)
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
protected Object doGetTransaction(TransactionSynchronizationManager synchronizationManager)
|
|
||||||
throws TransactionException {
|
|
||||||
|
|
||||||
ReactiveMongoResourceHolder resourceHolder = (ReactiveMongoResourceHolder) synchronizationManager
|
|
||||||
.getResource(getRequiredDatabaseFactory());
|
|
||||||
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<Void> doBegin(TransactionSynchronizationManager synchronizationManager, Object transaction,
|
|
||||||
TransactionDefinition definition) throws TransactionException {
|
|
||||||
|
|
||||||
return Mono.defer(() -> {
|
|
||||||
|
|
||||||
ReactiveMongoTransactionObject mongoTransactionObject = extractMongoTransaction(transaction);
|
|
||||||
|
|
||||||
Mono<ReactiveMongoResourceHolder> holder = newResourceHolder(definition,
|
|
||||||
ClientSessionOptions.builder().causallyConsistent(true).build());
|
|
||||||
|
|
||||||
return holder.doOnNext(resourceHolder -> {
|
|
||||||
|
|
||||||
mongoTransactionObject.setResourceHolder(resourceHolder);
|
|
||||||
|
|
||||||
if (logger.isDebugEnabled()) {
|
|
||||||
logger.debug(
|
|
||||||
String.format("About to start transaction for session %s.", debugString(resourceHolder.getSession())));
|
|
||||||
}
|
|
||||||
|
|
||||||
}).doOnNext(resourceHolder -> {
|
|
||||||
|
|
||||||
mongoTransactionObject.startTransaction(options);
|
|
||||||
|
|
||||||
if (logger.isDebugEnabled()) {
|
|
||||||
logger.debug(String.format("Started transaction for session %s.", debugString(resourceHolder.getSession())));
|
|
||||||
}
|
|
||||||
|
|
||||||
})//
|
|
||||||
.onErrorMap(
|
|
||||||
ex -> new TransactionSystemException(String.format("Could not start Mongo transaction for session %s.",
|
|
||||||
debugString(mongoTransactionObject.getSession())), ex))
|
|
||||||
.doOnSuccess(resourceHolder -> {
|
|
||||||
|
|
||||||
synchronizationManager.bindResource(getRequiredDatabaseFactory(), resourceHolder);
|
|
||||||
}).then();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* (non-Javadoc)
|
|
||||||
* @see org.springframework.transaction.reactive.AbstractReactiveTransactionManager#doSuspend(org.springframework.transaction.reactive.TransactionSynchronizationManager, java.lang.Object)
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
protected Mono<Object> doSuspend(TransactionSynchronizationManager synchronizationManager, Object transaction)
|
|
||||||
throws TransactionException {
|
|
||||||
|
|
||||||
return Mono.fromSupplier(() -> {
|
|
||||||
|
|
||||||
ReactiveMongoTransactionObject mongoTransactionObject = extractMongoTransaction(transaction);
|
|
||||||
mongoTransactionObject.setResourceHolder(null);
|
|
||||||
|
|
||||||
return synchronizationManager.unbindResource(getRequiredDatabaseFactory());
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* (non-Javadoc)
|
|
||||||
* @see org.springframework.transaction.reactive.AbstractReactiveTransactionManager#doResume(org.springframework.transaction.reactive.TransactionSynchronizationManager, java.lang.Object, java.lang.Object)
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
protected Mono<Void> doResume(TransactionSynchronizationManager synchronizationManager, @Nullable Object transaction,
|
|
||||||
Object suspendedResources) {
|
|
||||||
return Mono
|
|
||||||
.fromRunnable(() -> synchronizationManager.bindResource(getRequiredDatabaseFactory(), suspendedResources));
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* (non-Javadoc)
|
|
||||||
* @see org.springframework.transaction.reactive.AbstractReactiveTransactionManager#doCommit(org.springframework.transaction.reactive.TransactionSynchronizationManager, org.springframework.transaction.reactive.GenericReactiveTransaction)
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
protected final Mono<Void> doCommit(TransactionSynchronizationManager synchronizationManager,
|
|
||||||
GenericReactiveTransaction status) throws TransactionException {
|
|
||||||
|
|
||||||
return Mono.defer(() -> {
|
|
||||||
|
|
||||||
ReactiveMongoTransactionObject mongoTransactionObject = extractMongoTransaction(status);
|
|
||||||
|
|
||||||
if (logger.isDebugEnabled()) {
|
|
||||||
logger.debug(String.format("About to commit transaction for session %s.",
|
|
||||||
debugString(mongoTransactionObject.getSession())));
|
|
||||||
}
|
|
||||||
|
|
||||||
return doCommit(synchronizationManager, mongoTransactionObject).onErrorMap(ex -> {
|
|
||||||
return new TransactionSystemException(String.format("Could not commit Mongo transaction for session %s.",
|
|
||||||
debugString(mongoTransactionObject.getSession())), ex);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Customization hook to perform an actual commit of the given transaction.<br />
|
|
||||||
* If a commit operation encounters an error, the MongoDB driver throws a {@link MongoException} holding
|
|
||||||
* {@literal error labels}. <br />
|
|
||||||
* 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.
|
|
||||||
*
|
|
||||||
* @param synchronizationManager reactive synchronization manager.
|
|
||||||
* @param transactionObject never {@literal null}.
|
|
||||||
*/
|
|
||||||
protected Mono<Void> doCommit(TransactionSynchronizationManager synchronizationManager,
|
|
||||||
ReactiveMongoTransactionObject transactionObject) {
|
|
||||||
return transactionObject.commitTransaction();
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* (non-Javadoc)
|
|
||||||
* @see org.springframework.transaction.reactive.AbstractReactiveTransactionManager#doRollback(org.springframework.transaction.reactive.TransactionSynchronizationManager, org.springframework.transaction.reactive.GenericReactiveTransaction)
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
protected Mono<Void> doRollback(TransactionSynchronizationManager synchronizationManager,
|
|
||||||
GenericReactiveTransaction status) {
|
|
||||||
|
|
||||||
return Mono.defer(() -> {
|
|
||||||
|
|
||||||
ReactiveMongoTransactionObject mongoTransactionObject = extractMongoTransaction(status);
|
|
||||||
|
|
||||||
if (logger.isDebugEnabled()) {
|
|
||||||
logger.debug(String.format("About to abort transaction for session %s.",
|
|
||||||
debugString(mongoTransactionObject.getSession())));
|
|
||||||
}
|
|
||||||
|
|
||||||
return mongoTransactionObject.abortTransaction().onErrorResume(MongoException.class, ex -> {
|
|
||||||
return Mono
|
|
||||||
.error(new TransactionSystemException(String.format("Could not abort Mongo transaction for session %s.",
|
|
||||||
debugString(mongoTransactionObject.getSession())), ex));
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* (non-Javadoc)
|
|
||||||
* @see org.springframework.transaction.reactive.AbstractReactiveTransactionManager#doSetRollbackOnly(org.springframework.transaction.reactive.TransactionSynchronizationManager, org.springframework.transaction.reactive.GenericReactiveTransaction)
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
protected Mono<Void> doSetRollbackOnly(TransactionSynchronizationManager synchronizationManager,
|
|
||||||
GenericReactiveTransaction status) throws TransactionException {
|
|
||||||
|
|
||||||
return Mono.fromRunnable(() -> {
|
|
||||||
ReactiveMongoTransactionObject transactionObject = extractMongoTransaction(status);
|
|
||||||
transactionObject.getRequiredResourceHolder().setRollbackOnly();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* (non-Javadoc)
|
|
||||||
* @see org.springframework.transaction.reactive.AbstractReactiveTransactionManager#doCleanupAfterCompletion(org.springframework.transaction.reactive.TransactionSynchronizationManager, java.lang.Object)
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
protected Mono<Void> doCleanupAfterCompletion(TransactionSynchronizationManager synchronizationManager,
|
|
||||||
Object transaction) {
|
|
||||||
|
|
||||||
Assert.isInstanceOf(ReactiveMongoTransactionObject.class, transaction,
|
|
||||||
() -> String.format("Expected to find a %s but it turned out to be %s.", ReactiveMongoTransactionObject.class,
|
|
||||||
transaction.getClass()));
|
|
||||||
|
|
||||||
return Mono.fromRunnable(() -> {
|
|
||||||
ReactiveMongoTransactionObject mongoTransactionObject = (ReactiveMongoTransactionObject) transaction;
|
|
||||||
|
|
||||||
// Remove the connection holder from the thread.
|
|
||||||
synchronizationManager.unbindResource(getRequiredDatabaseFactory());
|
|
||||||
mongoTransactionObject.getRequiredResourceHolder().clear();
|
|
||||||
|
|
||||||
if (logger.isDebugEnabled()) {
|
|
||||||
logger.debug(String.format("About to release Session %s after transaction.",
|
|
||||||
debugString(mongoTransactionObject.getSession())));
|
|
||||||
}
|
|
||||||
|
|
||||||
mongoTransactionObject.closeSession();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the {@link ReactiveMongoDatabaseFactory} that this instance should manage transactions for.
|
|
||||||
*
|
|
||||||
* @param databaseFactory must not be {@literal null}.
|
|
||||||
*/
|
|
||||||
public void setDatabaseFactory(ReactiveMongoDatabaseFactory databaseFactory) {
|
|
||||||
|
|
||||||
Assert.notNull(databaseFactory, "DatabaseFactory must not be null!");
|
|
||||||
this.databaseFactory = databaseFactory;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the {@link TransactionOptions} to be applied when starting transactions.
|
|
||||||
*
|
|
||||||
* @param options can be {@literal null}.
|
|
||||||
*/
|
|
||||||
public void setOptions(@Nullable TransactionOptions options) {
|
|
||||||
this.options = options;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the {@link ReactiveMongoDatabaseFactory} that this instance manages transactions for.
|
|
||||||
*
|
|
||||||
* @return can be {@literal null}.
|
|
||||||
*/
|
|
||||||
@Nullable
|
|
||||||
public ReactiveMongoDatabaseFactory getDatabaseFactory() {
|
|
||||||
return databaseFactory;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* (non-Javadoc)
|
|
||||||
* @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void afterPropertiesSet() {
|
|
||||||
getRequiredDatabaseFactory();
|
|
||||||
}
|
|
||||||
|
|
||||||
private Mono<ReactiveMongoResourceHolder> newResourceHolder(TransactionDefinition definition,
|
|
||||||
ClientSessionOptions options) {
|
|
||||||
|
|
||||||
ReactiveMongoDatabaseFactory dbFactory = getRequiredDatabaseFactory();
|
|
||||||
|
|
||||||
return dbFactory.getSession(options).map(session -> new ReactiveMongoResourceHolder(session, dbFactory));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @throws IllegalStateException if {@link #databaseFactory} is {@literal null}.
|
|
||||||
*/
|
|
||||||
private ReactiveMongoDatabaseFactory getRequiredDatabaseFactory() {
|
|
||||||
|
|
||||||
Assert.state(databaseFactory != null,
|
|
||||||
"ReactiveMongoTransactionManager operates upon a ReactiveMongoDatabaseFactory. Did you forget to provide one? It's required.");
|
|
||||||
|
|
||||||
return databaseFactory;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static ReactiveMongoTransactionObject extractMongoTransaction(Object transaction) {
|
|
||||||
|
|
||||||
Assert.isInstanceOf(ReactiveMongoTransactionObject.class, transaction,
|
|
||||||
() -> String.format("Expected to find a %s but it turned out to be %s.", ReactiveMongoTransactionObject.class,
|
|
||||||
transaction.getClass()));
|
|
||||||
|
|
||||||
return (ReactiveMongoTransactionObject) transaction;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static ReactiveMongoTransactionObject extractMongoTransaction(GenericReactiveTransaction status) {
|
|
||||||
|
|
||||||
Assert.isInstanceOf(ReactiveMongoTransactionObject.class, status.getTransaction(),
|
|
||||||
() -> String.format("Expected to find a %s but it turned out to be %s.", ReactiveMongoTransactionObject.class,
|
|
||||||
status.getTransaction().getClass()));
|
|
||||||
|
|
||||||
return (ReactiveMongoTransactionObject) status.getTransaction();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static String debugString(@Nullable ClientSession session) {
|
|
||||||
|
|
||||||
if (session == null) {
|
|
||||||
return "null";
|
|
||||||
}
|
|
||||||
|
|
||||||
String debugString = String.format("[%s@%s ", ClassUtils.getShortName(session.getClass()),
|
|
||||||
Integer.toHexString(session.hashCode()));
|
|
||||||
|
|
||||||
try {
|
|
||||||
if (session.getServerSession() != null) {
|
|
||||||
debugString += String.format("id = %s, ", session.getServerSession().getIdentifier());
|
|
||||||
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("clusterTime = %s", session.getClusterTime());
|
|
||||||
} else {
|
|
||||||
debugString += "id = n/a";
|
|
||||||
debugString += String.format("causallyConsistent = %s, ", session.isCausallyConsistent());
|
|
||||||
debugString += String.format("txActive = %s, ", session.hasActiveTransaction());
|
|
||||||
debugString += String.format("clusterTime = %s", session.getClusterTime());
|
|
||||||
}
|
|
||||||
} catch (RuntimeException e) {
|
|
||||||
debugString += String.format("error = %s", e.getMessage());
|
|
||||||
}
|
|
||||||
|
|
||||||
debugString += "]";
|
|
||||||
|
|
||||||
return debugString;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* MongoDB specific transaction object, representing a {@link MongoResourceHolder}. Used as transaction object by
|
|
||||||
* {@link ReactiveMongoTransactionManager}.
|
|
||||||
*
|
|
||||||
* @author Christoph Strobl
|
|
||||||
* @author Mark Paluch
|
|
||||||
* @since 2.2
|
|
||||||
* @see ReactiveMongoResourceHolder
|
|
||||||
*/
|
|
||||||
protected static class ReactiveMongoTransactionObject implements SmartTransactionObject {
|
|
||||||
|
|
||||||
private @Nullable ReactiveMongoResourceHolder resourceHolder;
|
|
||||||
|
|
||||||
ReactiveMongoTransactionObject(@Nullable ReactiveMongoResourceHolder resourceHolder) {
|
|
||||||
this.resourceHolder = resourceHolder;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the {@link MongoResourceHolder}.
|
|
||||||
*
|
|
||||||
* @param resourceHolder can be {@literal null}.
|
|
||||||
*/
|
|
||||||
void setResourceHolder(@Nullable ReactiveMongoResourceHolder resourceHolder) {
|
|
||||||
this.resourceHolder = resourceHolder;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return {@literal true} if a {@link MongoResourceHolder} is set.
|
|
||||||
*/
|
|
||||||
final boolean hasResourceHolder() {
|
|
||||||
return resourceHolder != null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Start a MongoDB transaction optionally given {@link TransactionOptions}.
|
|
||||||
*
|
|
||||||
* @param options can be {@literal null}
|
|
||||||
*/
|
|
||||||
void startTransaction(@Nullable TransactionOptions options) {
|
|
||||||
|
|
||||||
ClientSession session = getRequiredSession();
|
|
||||||
if (options != null) {
|
|
||||||
session.startTransaction(options);
|
|
||||||
} else {
|
|
||||||
session.startTransaction();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Commit the transaction.
|
|
||||||
*/
|
|
||||||
public Mono<Void> commitTransaction() {
|
|
||||||
return Mono.from(getRequiredSession().commitTransaction());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Rollback (abort) the transaction.
|
|
||||||
*/
|
|
||||||
public Mono<Void> abortTransaction() {
|
|
||||||
return Mono.from(getRequiredSession().abortTransaction());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Close a {@link ClientSession} without regard to its transactional state.
|
|
||||||
*/
|
|
||||||
void closeSession() {
|
|
||||||
|
|
||||||
ClientSession session = getRequiredSession();
|
|
||||||
if (session.getServerSession() != null && !session.getServerSession().isClosed()) {
|
|
||||||
session.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
public ClientSession getSession() {
|
|
||||||
return resourceHolder != null ? resourceHolder.getSession() : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private ReactiveMongoResourceHolder getRequiredResourceHolder() {
|
|
||||||
|
|
||||||
Assert.state(resourceHolder != null, "ReactiveMongoResourceHolder 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.");
|
|
||||||
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() {
|
|
||||||
throw new UnsupportedOperationException("flush() not supported");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2018-2020 the original author or authors.
|
* Copyright 2018-2019 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2018-2020 the original author or authors.
|
* Copyright 2018-2019 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2010-2020 the original author or authors.
|
* Copyright 2010-2019 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2018-2020 the original author or authors.
|
* Copyright 2018-2019 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -105,7 +105,6 @@ public abstract class AbstractMongoClientConfiguration extends MongoConfiguratio
|
|||||||
DbRefResolver dbRefResolver = new DefaultDbRefResolver(mongoDbFactory());
|
DbRefResolver dbRefResolver = new DefaultDbRefResolver(mongoDbFactory());
|
||||||
MappingMongoConverter converter = new MappingMongoConverter(dbRefResolver, mongoMappingContext());
|
MappingMongoConverter converter = new MappingMongoConverter(dbRefResolver, mongoMappingContext());
|
||||||
converter.setCustomConversions(customConversions());
|
converter.setCustomConversions(customConversions());
|
||||||
converter.setCodecRegistryProvider(mongoDbFactory());
|
|
||||||
|
|
||||||
return converter;
|
return converter;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2011-2020 the original author or authors.
|
* Copyright 2011-2019 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -42,10 +42,8 @@ import com.mongodb.MongoClient;
|
|||||||
* @author Mark Paluch
|
* @author Mark Paluch
|
||||||
* @see MongoConfigurationSupport
|
* @see MongoConfigurationSupport
|
||||||
* @see AbstractMongoClientConfiguration
|
* @see AbstractMongoClientConfiguration
|
||||||
* @deprecated since 2.2 in favor of {@link AbstractMongoClientConfiguration}.
|
|
||||||
*/
|
*/
|
||||||
@Configuration
|
@Configuration
|
||||||
@Deprecated
|
|
||||||
public abstract class AbstractMongoConfiguration extends MongoConfigurationSupport {
|
public abstract class AbstractMongoConfiguration extends MongoConfigurationSupport {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -113,7 +111,6 @@ public abstract class AbstractMongoConfiguration extends MongoConfigurationSuppo
|
|||||||
DbRefResolver dbRefResolver = new DefaultDbRefResolver(mongoDbFactory());
|
DbRefResolver dbRefResolver = new DefaultDbRefResolver(mongoDbFactory());
|
||||||
MappingMongoConverter converter = new MappingMongoConverter(dbRefResolver, mongoMappingContext());
|
MappingMongoConverter converter = new MappingMongoConverter(dbRefResolver, mongoMappingContext());
|
||||||
converter.setCustomConversions(customConversions());
|
converter.setCustomConversions(customConversions());
|
||||||
converter.setCodecRegistryProvider(mongoDbFactory());
|
|
||||||
|
|
||||||
return converter;
|
return converter;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2016-2020 the original author or authors.
|
* Copyright 2016-2019 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -83,7 +83,6 @@ public abstract class AbstractReactiveMongoConfiguration extends MongoConfigurat
|
|||||||
|
|
||||||
MappingMongoConverter converter = new MappingMongoConverter(NoOpDbRefResolver.INSTANCE, mongoMappingContext());
|
MappingMongoConverter converter = new MappingMongoConverter(NoOpDbRefResolver.INSTANCE, mongoMappingContext());
|
||||||
converter.setCustomConversions(customConversions());
|
converter.setCustomConversions(customConversions());
|
||||||
converter.setCodecRegistryProvider(reactiveMongoDbFactory());
|
|
||||||
|
|
||||||
return converter;
|
return converter;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2011-2020 the original author or authors.
|
* Copyright 2011-2019 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2013-2020 the original author or authors.
|
* Copyright 2013-2019 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2015-2020 the original author or authors.
|
* Copyright 2015-2019 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2013-2020 the original author or authors.
|
* Copyright 2013-2019 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2011-2020 the original author or authors.
|
* Copyright 2011-2019 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -51,6 +51,7 @@ import org.springframework.core.type.filter.AssignableTypeFilter;
|
|||||||
import org.springframework.core.type.filter.TypeFilter;
|
import org.springframework.core.type.filter.TypeFilter;
|
||||||
import org.springframework.data.annotation.Persistent;
|
import org.springframework.data.annotation.Persistent;
|
||||||
import org.springframework.data.config.BeanComponentDefinitionBuilder;
|
import org.springframework.data.config.BeanComponentDefinitionBuilder;
|
||||||
|
import org.springframework.data.mapping.context.MappingContextIsNewStrategyFactory;
|
||||||
import org.springframework.data.mapping.model.CamelCaseAbbreviatingFieldNamingStrategy;
|
import org.springframework.data.mapping.model.CamelCaseAbbreviatingFieldNamingStrategy;
|
||||||
import org.springframework.data.mongodb.core.convert.MappingMongoConverter;
|
import org.springframework.data.mongodb.core.convert.MappingMongoConverter;
|
||||||
import org.springframework.data.mongodb.core.convert.MongoCustomConversions;
|
import org.springframework.data.mongodb.core.convert.MongoCustomConversions;
|
||||||
@@ -101,6 +102,8 @@ public class MappingMongoConverterParser implements BeanDefinitionParser {
|
|||||||
BeanDefinition conversionsDefinition = getCustomConversions(element, parserContext);
|
BeanDefinition conversionsDefinition = getCustomConversions(element, parserContext);
|
||||||
String ctxRef = potentiallyCreateMappingContext(element, parserContext, conversionsDefinition, id);
|
String ctxRef = potentiallyCreateMappingContext(element, parserContext, conversionsDefinition, id);
|
||||||
|
|
||||||
|
createIsNewStrategyFactoryBeanDefinition(ctxRef, parserContext, element);
|
||||||
|
|
||||||
// Need a reference to a Mongo instance
|
// Need a reference to a Mongo instance
|
||||||
String dbFactoryRef = element.getAttribute("db-factory-ref");
|
String dbFactoryRef = element.getAttribute("db-factory-ref");
|
||||||
if (!StringUtils.hasText(dbFactoryRef)) {
|
if (!StringUtils.hasText(dbFactoryRef)) {
|
||||||
@@ -345,6 +348,20 @@ public class MappingMongoConverterParser implements BeanDefinitionParser {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static String createIsNewStrategyFactoryBeanDefinition(String mappingContextRef, ParserContext context,
|
||||||
|
Element element) {
|
||||||
|
|
||||||
|
BeanDefinitionBuilder mappingContextStrategyFactoryBuilder = BeanDefinitionBuilder
|
||||||
|
.rootBeanDefinition(MappingContextIsNewStrategyFactory.class);
|
||||||
|
mappingContextStrategyFactoryBuilder.addConstructorArgReference(mappingContextRef);
|
||||||
|
|
||||||
|
BeanComponentDefinitionBuilder builder = new BeanComponentDefinitionBuilder(element, context);
|
||||||
|
context.registerBeanComponent(
|
||||||
|
builder.getComponent(mappingContextStrategyFactoryBuilder, IS_NEW_STRATEGY_FACTORY_BEAN_NAME));
|
||||||
|
|
||||||
|
return IS_NEW_STRATEGY_FACTORY_BEAN_NAME;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@link TypeFilter} that returns {@literal false} in case any of the given delegates matches.
|
* {@link TypeFilter} that returns {@literal false} in case any of the given delegates matches.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2012-2020 the original author or authors.
|
* Copyright 2012-2019 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -18,7 +18,6 @@ package org.springframework.data.mongodb.config;
|
|||||||
import static org.springframework.data.config.ParsingUtils.*;
|
import static org.springframework.data.config.ParsingUtils.*;
|
||||||
import static org.springframework.data.mongodb.config.BeanNames.*;
|
import static org.springframework.data.mongodb.config.BeanNames.*;
|
||||||
|
|
||||||
import org.springframework.beans.factory.support.AbstractBeanDefinition;
|
|
||||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||||
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
||||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||||
@@ -27,33 +26,25 @@ import org.springframework.beans.factory.xml.BeanDefinitionParser;
|
|||||||
import org.springframework.beans.factory.xml.ParserContext;
|
import org.springframework.beans.factory.xml.ParserContext;
|
||||||
import org.springframework.data.auditing.config.IsNewAwareAuditingHandlerBeanDefinitionParser;
|
import org.springframework.data.auditing.config.IsNewAwareAuditingHandlerBeanDefinitionParser;
|
||||||
import org.springframework.data.mongodb.core.mapping.MongoMappingContext;
|
import org.springframework.data.mongodb.core.mapping.MongoMappingContext;
|
||||||
import org.springframework.data.mongodb.core.mapping.event.AuditingEntityCallback;
|
import org.springframework.data.mongodb.core.mapping.event.AuditingEventListener;
|
||||||
import org.springframework.data.mongodb.core.mapping.event.ReactiveAuditingEntityCallback;
|
|
||||||
import org.springframework.lang.Nullable;
|
|
||||||
import org.springframework.util.ClassUtils;
|
|
||||||
import org.springframework.util.StringUtils;
|
import org.springframework.util.StringUtils;
|
||||||
|
|
||||||
import org.w3c.dom.Element;
|
import org.w3c.dom.Element;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@link BeanDefinitionParser} to register a {@link AuditingEntityCallback} to transparently set auditing information
|
* {@link BeanDefinitionParser} to register a {@link AuditingEventListener} to transparently set auditing information on
|
||||||
* on an entity.
|
* an entity.
|
||||||
*
|
*
|
||||||
* @author Oliver Gierke
|
* @author Oliver Gierke
|
||||||
* @author Mark Paluch
|
|
||||||
*/
|
*/
|
||||||
public class MongoAuditingBeanDefinitionParser extends AbstractSingleBeanDefinitionParser {
|
public class MongoAuditingBeanDefinitionParser extends AbstractSingleBeanDefinitionParser {
|
||||||
|
|
||||||
private static boolean PROJECT_REACTOR_AVAILABLE = ClassUtils.isPresent("reactor.core.publisher.Mono",
|
|
||||||
MongoAuditingRegistrar.class.getClassLoader());
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* (non-Javadoc)
|
* (non-Javadoc)
|
||||||
* @see org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser#getBeanClass(org.w3c.dom.Element)
|
* @see org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser#getBeanClass(org.w3c.dom.Element)
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
protected Class<?> getBeanClass(Element element) {
|
protected Class<?> getBeanClass(Element element) {
|
||||||
return AuditingEntityCallback.class;
|
return AuditingEventListener.class;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -89,24 +80,7 @@ public class MongoAuditingBeanDefinitionParser extends AbstractSingleBeanDefinit
|
|||||||
mappingContextRef);
|
mappingContextRef);
|
||||||
parser.parse(element, parserContext);
|
parser.parse(element, parserContext);
|
||||||
|
|
||||||
AbstractBeanDefinition isNewAwareAuditingHandler = getObjectFactoryBeanDefinition(parser.getResolvedBeanName(),
|
builder.addConstructorArgValue(getObjectFactoryBeanDefinition(parser.getResolvedBeanName(),
|
||||||
parserContext.extractSource(element));
|
parserContext.extractSource(element)));
|
||||||
builder.addConstructorArgValue(isNewAwareAuditingHandler);
|
|
||||||
|
|
||||||
if (PROJECT_REACTOR_AVAILABLE) {
|
|
||||||
registerReactiveAuditingEntityCallback(parserContext.getRegistry(), isNewAwareAuditingHandler,
|
|
||||||
parserContext.extractSource(element));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void registerReactiveAuditingEntityCallback(BeanDefinitionRegistry registry,
|
|
||||||
AbstractBeanDefinition isNewAwareAuditingHandler, @Nullable Object source) {
|
|
||||||
|
|
||||||
BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(ReactiveAuditingEntityCallback.class);
|
|
||||||
|
|
||||||
builder.addConstructorArgValue(isNewAwareAuditingHandler);
|
|
||||||
builder.getRawBeanDefinition().setSource(source);
|
|
||||||
|
|
||||||
registry.registerBeanDefinition(ReactiveAuditingEntityCallback.class.getName(), builder.getBeanDefinition());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2013-2020 the original author or authors.
|
* Copyright 2013-2019 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -32,23 +32,17 @@ import org.springframework.data.mapping.context.MappingContext;
|
|||||||
import org.springframework.data.mongodb.core.convert.MappingMongoConverter;
|
import org.springframework.data.mongodb.core.convert.MappingMongoConverter;
|
||||||
import org.springframework.data.mongodb.core.mapping.MongoPersistentEntity;
|
import org.springframework.data.mongodb.core.mapping.MongoPersistentEntity;
|
||||||
import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty;
|
import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty;
|
||||||
import org.springframework.data.mongodb.core.mapping.event.AuditingEntityCallback;
|
import org.springframework.data.mongodb.core.mapping.event.AuditingEventListener;
|
||||||
import org.springframework.data.mongodb.core.mapping.event.ReactiveAuditingEntityCallback;
|
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
import org.springframework.util.ClassUtils;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@link ImportBeanDefinitionRegistrar} to enable {@link EnableMongoAuditing} annotation.
|
* {@link ImportBeanDefinitionRegistrar} to enable {@link EnableMongoAuditing} annotation.
|
||||||
*
|
*
|
||||||
* @author Thomas Darimont
|
* @author Thomas Darimont
|
||||||
* @author Oliver Gierke
|
* @author Oliver Gierke
|
||||||
* @author Mark Paluch
|
|
||||||
*/
|
*/
|
||||||
class MongoAuditingRegistrar extends AuditingBeanDefinitionRegistrarSupport {
|
class MongoAuditingRegistrar extends AuditingBeanDefinitionRegistrarSupport {
|
||||||
|
|
||||||
private static boolean PROJECT_REACTOR_AVAILABLE = ClassUtils.isPresent("reactor.core.publisher.Mono",
|
|
||||||
MongoAuditingRegistrar.class.getClassLoader());
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* (non-Javadoc)
|
* (non-Javadoc)
|
||||||
* @see org.springframework.data.auditing.config.AuditingBeanDefinitionRegistrarSupport#getAnnotation()
|
* @see org.springframework.data.auditing.config.AuditingBeanDefinitionRegistrarSupport#getAnnotation()
|
||||||
@@ -110,27 +104,12 @@ class MongoAuditingRegistrar extends AuditingBeanDefinitionRegistrarSupport {
|
|||||||
Assert.notNull(registry, "BeanDefinitionRegistry must not be null!");
|
Assert.notNull(registry, "BeanDefinitionRegistry must not be null!");
|
||||||
|
|
||||||
BeanDefinitionBuilder listenerBeanDefinitionBuilder = BeanDefinitionBuilder
|
BeanDefinitionBuilder listenerBeanDefinitionBuilder = BeanDefinitionBuilder
|
||||||
.rootBeanDefinition(AuditingEntityCallback.class);
|
.rootBeanDefinition(AuditingEventListener.class);
|
||||||
listenerBeanDefinitionBuilder
|
listenerBeanDefinitionBuilder
|
||||||
.addConstructorArgValue(ParsingUtils.getObjectFactoryBeanDefinition(getAuditingHandlerBeanName(), registry));
|
.addConstructorArgValue(ParsingUtils.getObjectFactoryBeanDefinition(getAuditingHandlerBeanName(), registry));
|
||||||
|
|
||||||
registerInfrastructureBeanWithId(listenerBeanDefinitionBuilder.getBeanDefinition(),
|
registerInfrastructureBeanWithId(listenerBeanDefinitionBuilder.getBeanDefinition(),
|
||||||
AuditingEntityCallback.class.getName(), registry);
|
AuditingEventListener.class.getName(), registry);
|
||||||
|
|
||||||
if (PROJECT_REACTOR_AVAILABLE) {
|
|
||||||
registerReactiveAuditingEntityCallback(registry, auditingHandlerDefinition.getSource());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void registerReactiveAuditingEntityCallback(BeanDefinitionRegistry registry, Object source) {
|
|
||||||
|
|
||||||
BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(ReactiveAuditingEntityCallback.class);
|
|
||||||
|
|
||||||
builder.addConstructorArgValue(ParsingUtils.getObjectFactoryBeanDefinition(getAuditingHandlerBeanName(), registry));
|
|
||||||
builder.getRawBeanDefinition().setSource(source);
|
|
||||||
|
|
||||||
registerInfrastructureBeanWithId(builder.getBeanDefinition(), ReactiveAuditingEntityCallback.class.getName(),
|
|
||||||
registry);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2015-2020 the original author or authors.
|
* Copyright 2015-2019 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2016-2020 the original author or authors.
|
* Copyright 2016-2019 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -15,6 +15,7 @@
|
|||||||
*/
|
*/
|
||||||
package org.springframework.data.mongodb.config;
|
package org.springframework.data.mongodb.config;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
@@ -27,12 +28,17 @@ import org.springframework.core.convert.converter.Converter;
|
|||||||
import org.springframework.core.type.filter.AnnotationTypeFilter;
|
import org.springframework.core.type.filter.AnnotationTypeFilter;
|
||||||
import org.springframework.data.annotation.Persistent;
|
import org.springframework.data.annotation.Persistent;
|
||||||
import org.springframework.data.convert.CustomConversions;
|
import org.springframework.data.convert.CustomConversions;
|
||||||
|
import org.springframework.data.mapping.context.MappingContext;
|
||||||
|
import org.springframework.data.mapping.context.MappingContextIsNewStrategyFactory;
|
||||||
|
import org.springframework.data.mapping.context.PersistentEntities;
|
||||||
import org.springframework.data.mapping.model.CamelCaseAbbreviatingFieldNamingStrategy;
|
import org.springframework.data.mapping.model.CamelCaseAbbreviatingFieldNamingStrategy;
|
||||||
import org.springframework.data.mapping.model.FieldNamingStrategy;
|
import org.springframework.data.mapping.model.FieldNamingStrategy;
|
||||||
import org.springframework.data.mapping.model.PropertyNameFieldNamingStrategy;
|
import org.springframework.data.mapping.model.PropertyNameFieldNamingStrategy;
|
||||||
import org.springframework.data.mongodb.core.convert.MongoCustomConversions;
|
import org.springframework.data.mongodb.core.convert.MongoCustomConversions;
|
||||||
import org.springframework.data.mongodb.core.mapping.Document;
|
import org.springframework.data.mongodb.core.mapping.Document;
|
||||||
import org.springframework.data.mongodb.core.mapping.MongoMappingContext;
|
import org.springframework.data.mongodb.core.mapping.MongoMappingContext;
|
||||||
|
import org.springframework.data.support.CachingIsNewStrategyFactory;
|
||||||
|
import org.springframework.data.support.IsNewStrategyFactory;
|
||||||
import org.springframework.util.ClassUtils;
|
import org.springframework.util.ClassUtils;
|
||||||
import org.springframework.util.StringUtils;
|
import org.springframework.util.StringUtils;
|
||||||
|
|
||||||
@@ -81,11 +87,23 @@ public abstract class MongoConfigurationSupport {
|
|||||||
mappingContext.setInitialEntitySet(getInitialEntitySet());
|
mappingContext.setInitialEntitySet(getInitialEntitySet());
|
||||||
mappingContext.setSimpleTypeHolder(customConversions().getSimpleTypeHolder());
|
mappingContext.setSimpleTypeHolder(customConversions().getSimpleTypeHolder());
|
||||||
mappingContext.setFieldNamingStrategy(fieldNamingStrategy());
|
mappingContext.setFieldNamingStrategy(fieldNamingStrategy());
|
||||||
mappingContext.setAutoIndexCreation(autoIndexCreation());
|
|
||||||
|
|
||||||
return mappingContext;
|
return mappingContext;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a {@link MappingContextIsNewStrategyFactory} wrapped into a {@link CachingIsNewStrategyFactory}.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* @throws ClassNotFoundException
|
||||||
|
*/
|
||||||
|
@Bean
|
||||||
|
public IsNewStrategyFactory isNewStrategyFactory() throws ClassNotFoundException {
|
||||||
|
|
||||||
|
return new CachingIsNewStrategyFactory(new MappingContextIsNewStrategyFactory(
|
||||||
|
new PersistentEntities(Arrays.<MappingContext<?, ?>> asList(new MappingContext[] { mongoMappingContext() }))));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Register custom {@link Converter}s in a {@link CustomConversions} object if required. These
|
* Register custom {@link Converter}s in a {@link CustomConversions} object if required. These
|
||||||
* {@link CustomConversions} will be registered with the {@link #mappingMongoConverter()} and
|
* {@link CustomConversions} will be registered with the {@link #mappingMongoConverter()} and
|
||||||
@@ -172,16 +190,4 @@ public abstract class MongoConfigurationSupport {
|
|||||||
return abbreviateFieldNames() ? new CamelCaseAbbreviatingFieldNamingStrategy()
|
return abbreviateFieldNames() ? new CamelCaseAbbreviatingFieldNamingStrategy()
|
||||||
: PropertyNameFieldNamingStrategy.INSTANCE;
|
: PropertyNameFieldNamingStrategy.INSTANCE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Configure whether to automatically create indices for domain types by deriving the
|
|
||||||
* {@link org.springframework.data.mongodb.core.index.IndexDefinition} from the entity or not.
|
|
||||||
*
|
|
||||||
* @return {@literal true} by default. <br />
|
|
||||||
* <strong>INFO</strong>: As of 3.x the default will be set to {@literal false}.
|
|
||||||
* @since 2.2
|
|
||||||
*/
|
|
||||||
protected boolean autoIndexCreation() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2015-2020 the original author or authors.
|
* Copyright 2015-2019 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -17,7 +17,6 @@ package org.springframework.data.mongodb.config;
|
|||||||
|
|
||||||
import java.beans.PropertyEditorSupport;
|
import java.beans.PropertyEditorSupport;
|
||||||
import java.io.UnsupportedEncodingException;
|
import java.io.UnsupportedEncodingException;
|
||||||
import java.lang.reflect.Method;
|
|
||||||
import java.net.URLDecoder;
|
import java.net.URLDecoder;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
@@ -27,7 +26,6 @@ import java.util.regex.Matcher;
|
|||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
import org.springframework.lang.Nullable;
|
import org.springframework.lang.Nullable;
|
||||||
import org.springframework.util.ReflectionUtils;
|
|
||||||
import org.springframework.util.StringUtils;
|
import org.springframework.util.StringUtils;
|
||||||
|
|
||||||
import com.mongodb.MongoCredential;
|
import com.mongodb.MongoCredential;
|
||||||
@@ -80,23 +78,12 @@ public class MongoCredentialPropertyEditor extends PropertyEditorSupport {
|
|||||||
|
|
||||||
verifyUserNamePresent(userNameAndPassword);
|
verifyUserNamePresent(userNameAndPassword);
|
||||||
credentials.add(MongoCredential.createGSSAPICredential(userNameAndPassword[0]));
|
credentials.add(MongoCredential.createGSSAPICredential(userNameAndPassword[0]));
|
||||||
} else if ("MONGODB-CR".equals(authMechanism)) {
|
} else if (MongoCredential.MONGODB_CR_MECHANISM.equals(authMechanism)) {
|
||||||
|
|
||||||
verifyUsernameAndPasswordPresent(userNameAndPassword);
|
verifyUsernameAndPasswordPresent(userNameAndPassword);
|
||||||
verifyDatabasePresent(database);
|
verifyDatabasePresent(database);
|
||||||
|
credentials.add(MongoCredential.createMongoCRCredential(userNameAndPassword[0], database,
|
||||||
Method createCRCredentialMethod = ReflectionUtils.findMethod(MongoCredential.class,
|
|
||||||
"createMongoCRCredential", String.class, String.class, char[].class);
|
|
||||||
|
|
||||||
if (createCRCredentialMethod == null) {
|
|
||||||
throw new IllegalArgumentException("MONGODB-CR is no longer supported.");
|
|
||||||
}
|
|
||||||
|
|
||||||
MongoCredential credential = MongoCredential.class
|
|
||||||
.cast(ReflectionUtils.invokeMethod(createCRCredentialMethod, null, userNameAndPassword[0], database,
|
|
||||||
userNameAndPassword[1].toCharArray()));
|
userNameAndPassword[1].toCharArray()));
|
||||||
credentials.add(credential);
|
|
||||||
|
|
||||||
} else if (MongoCredential.MONGODB_X509_MECHANISM.equals(authMechanism)) {
|
} else if (MongoCredential.MONGODB_X509_MECHANISM.equals(authMechanism)) {
|
||||||
|
|
||||||
verifyUserNamePresent(userNameAndPassword);
|
verifyUserNamePresent(userNameAndPassword);
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2011-2020 the original author or authors.
|
* Copyright 2011-2019 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2011-2020 the original author or authors.
|
* Copyright 2011-2019 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2011-2020 the original author or authors.
|
* Copyright 2011-2019 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2011-2020 the original author or authors.
|
* Copyright 2011-2019 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -35,7 +35,6 @@ import org.w3c.dom.Element;
|
|||||||
* @author Oliver Gierke
|
* @author Oliver Gierke
|
||||||
* @author Thomas Darimont
|
* @author Thomas Darimont
|
||||||
* @author Christoph Strobl
|
* @author Christoph Strobl
|
||||||
* @author Mark Paluch
|
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("deprecation")
|
@SuppressWarnings("deprecation")
|
||||||
abstract class MongoParsingUtils {
|
abstract class MongoParsingUtils {
|
||||||
@@ -93,7 +92,6 @@ abstract class MongoParsingUtils {
|
|||||||
setPropertyValue(clientOptionsDefBuilder, optionsElement, "heartbeat-socket-timeout", "heartbeatSocketTimeout");
|
setPropertyValue(clientOptionsDefBuilder, optionsElement, "heartbeat-socket-timeout", "heartbeatSocketTimeout");
|
||||||
setPropertyValue(clientOptionsDefBuilder, optionsElement, "ssl", "ssl");
|
setPropertyValue(clientOptionsDefBuilder, optionsElement, "ssl", "ssl");
|
||||||
setPropertyReference(clientOptionsDefBuilder, optionsElement, "ssl-socket-factory-ref", "sslSocketFactory");
|
setPropertyReference(clientOptionsDefBuilder, optionsElement, "ssl-socket-factory-ref", "sslSocketFactory");
|
||||||
setPropertyReference(clientOptionsDefBuilder, optionsElement, "encryption-settings-ref", "autoEncryptionSettings");
|
|
||||||
setPropertyValue(clientOptionsDefBuilder, optionsElement, "server-selection-timeout", "serverSelectionTimeout");
|
setPropertyValue(clientOptionsDefBuilder, optionsElement, "server-selection-timeout", "serverSelectionTimeout");
|
||||||
|
|
||||||
mongoClientBuilder.addPropertyValue("mongoClientOptions", clientOptionsDefBuilder.getBeanDefinition());
|
mongoClientBuilder.addPropertyValue("mongoClientOptions", clientOptionsDefBuilder.getBeanDefinition());
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2011-2020 the original author or authors.
|
* Copyright 2011-2019 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2015-2020 the original author or authors.
|
* Copyright 2015-2019 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2011-2020 the original author or authors.
|
* Copyright 2011-2019 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2012-2020 the original author or authors.
|
* Copyright 2012-2019 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2011-2020 the original author or authors.
|
* Copyright 2011-2019 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2018-2020 the original author or authors.
|
* Copyright 2018-2019 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2015-2020 the original author or authors.
|
* Copyright 2015-2019 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -31,7 +31,6 @@ import com.mongodb.bulk.BulkWriteResult;
|
|||||||
*
|
*
|
||||||
* @author Tobias Trelle
|
* @author Tobias Trelle
|
||||||
* @author Oliver Gierke
|
* @author Oliver Gierke
|
||||||
* @author Minsu Kim
|
|
||||||
* @since 1.9
|
* @since 1.9
|
||||||
*/
|
*/
|
||||||
public interface BulkOperations {
|
public interface BulkOperations {
|
||||||
@@ -136,29 +135,6 @@ public interface BulkOperations {
|
|||||||
*/
|
*/
|
||||||
BulkOperations remove(List<Query> removes);
|
BulkOperations remove(List<Query> removes);
|
||||||
|
|
||||||
/**
|
|
||||||
* Add a single replace operation to the bulk operation.
|
|
||||||
*
|
|
||||||
* @param query Update criteria.
|
|
||||||
* @param replacement the replacement document. Must not be {@literal null}.
|
|
||||||
* @return the current {@link BulkOperations} instance with the replace added, will never be {@literal null}.
|
|
||||||
* @since 2.2
|
|
||||||
*/
|
|
||||||
default BulkOperations replaceOne(Query query, Object replacement) {
|
|
||||||
return replaceOne(query, replacement, FindAndReplaceOptions.empty());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add a single replace operation to the bulk operation.
|
|
||||||
*
|
|
||||||
* @param query Update criteria.
|
|
||||||
* @param replacement the replacement document. Must not be {@literal null}.
|
|
||||||
* @param options the {@link FindAndModifyOptions} holding additional information. Must not be {@literal null}.
|
|
||||||
* @return the current {@link BulkOperations} instance with the replace added, will never be {@literal null}.
|
|
||||||
* @since 2.2
|
|
||||||
*/
|
|
||||||
BulkOperations replaceOne(Query query, Object replacement, FindAndReplaceOptions options);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Execute all bulk operations using the default write concern.
|
* Execute all bulk operations using the default write concern.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2018-2020 the original author or authors.
|
* Copyright 2018-2019 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -20,7 +20,6 @@ import lombok.EqualsAndHashCode;
|
|||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
|
import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
|
||||||
|
|
||||||
import org.bson.BsonTimestamp;
|
|
||||||
import org.bson.BsonValue;
|
import org.bson.BsonValue;
|
||||||
import org.bson.Document;
|
import org.bson.Document;
|
||||||
import org.springframework.data.mongodb.core.convert.MongoConverter;
|
import org.springframework.data.mongodb.core.convert.MongoConverter;
|
||||||
@@ -85,19 +84,8 @@ public class ChangeStreamEvent<T> {
|
|||||||
@Nullable
|
@Nullable
|
||||||
public Instant getTimestamp() {
|
public Instant getTimestamp() {
|
||||||
|
|
||||||
return getBsonTimestamp() != null ? converter.getConversionService().convert(raw.getClusterTime(), Instant.class)
|
return raw != null && raw.getClusterTime() != null
|
||||||
: null;
|
? converter.getConversionService().convert(raw.getClusterTime(), Instant.class) : null;
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the {@link ChangeStreamDocument#getClusterTime() cluster time}.
|
|
||||||
*
|
|
||||||
* @return can be {@literal null}.
|
|
||||||
* @since 2.2
|
|
||||||
*/
|
|
||||||
@Nullable
|
|
||||||
public BsonTimestamp getBsonTimestamp() {
|
|
||||||
return raw != null ? raw.getClusterTime() : null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2018-2020 the original author or authors.
|
* Copyright 2018-2019 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -21,17 +21,12 @@ import java.time.Instant;
|
|||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
import org.bson.BsonDocument;
|
|
||||||
import org.bson.BsonTimestamp;
|
|
||||||
import org.bson.BsonValue;
|
import org.bson.BsonValue;
|
||||||
import org.bson.Document;
|
import org.bson.Document;
|
||||||
|
|
||||||
import org.springframework.data.mongodb.core.aggregation.Aggregation;
|
import org.springframework.data.mongodb.core.aggregation.Aggregation;
|
||||||
import org.springframework.data.mongodb.core.query.Collation;
|
import org.springframework.data.mongodb.core.query.Collation;
|
||||||
import org.springframework.lang.Nullable;
|
import org.springframework.lang.Nullable;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
import org.springframework.util.ClassUtils;
|
|
||||||
import org.springframework.util.ObjectUtils;
|
|
||||||
|
|
||||||
import com.mongodb.client.model.changestream.ChangeStreamDocument;
|
import com.mongodb.client.model.changestream.ChangeStreamDocument;
|
||||||
import com.mongodb.client.model.changestream.FullDocument;
|
import com.mongodb.client.model.changestream.FullDocument;
|
||||||
@@ -52,8 +47,7 @@ public class ChangeStreamOptions {
|
|||||||
private @Nullable BsonValue resumeToken;
|
private @Nullable BsonValue resumeToken;
|
||||||
private @Nullable FullDocument fullDocumentLookup;
|
private @Nullable FullDocument fullDocumentLookup;
|
||||||
private @Nullable Collation collation;
|
private @Nullable Collation collation;
|
||||||
private @Nullable Object resumeTimestamp;
|
private @Nullable Instant resumeTimestamp;
|
||||||
private Resume resume = Resume.UNDEFINED;
|
|
||||||
|
|
||||||
protected ChangeStreamOptions() {}
|
protected ChangeStreamOptions() {}
|
||||||
|
|
||||||
@@ -89,31 +83,7 @@ public class ChangeStreamOptions {
|
|||||||
* @return {@link Optional#empty()} if not set.
|
* @return {@link Optional#empty()} if not set.
|
||||||
*/
|
*/
|
||||||
public Optional<Instant> getResumeTimestamp() {
|
public Optional<Instant> getResumeTimestamp() {
|
||||||
return Optional.ofNullable(resumeTimestamp).map(timestamp -> asTimestampOfType(timestamp, Instant.class));
|
return Optional.ofNullable(resumeTimestamp);
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return {@link Optional#empty()} if not set.
|
|
||||||
* @since 2.2
|
|
||||||
*/
|
|
||||||
public Optional<BsonTimestamp> getResumeBsonTimestamp() {
|
|
||||||
return Optional.ofNullable(resumeTimestamp).map(timestamp -> asTimestampOfType(timestamp, BsonTimestamp.class));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return {@literal true} if the change stream should be started after the {@link #getResumeToken() token}.
|
|
||||||
* @since 2.2
|
|
||||||
*/
|
|
||||||
public boolean isStartAfter() {
|
|
||||||
return Resume.START_AFTER.equals(resume);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return {@literal true} if the change stream should be resumed after the {@link #getResumeToken() token}.
|
|
||||||
* @since 2.2
|
|
||||||
*/
|
|
||||||
public boolean isResumeAfter() {
|
|
||||||
return Resume.RESUME_AFTER.equals(resume);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -133,48 +103,6 @@ public class ChangeStreamOptions {
|
|||||||
return new ChangeStreamOptionsBuilder();
|
return new ChangeStreamOptionsBuilder();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static <T> T asTimestampOfType(Object timestamp, Class<T> targetType) {
|
|
||||||
return targetType.cast(doGetTimestamp(timestamp, targetType));
|
|
||||||
}
|
|
||||||
|
|
||||||
private static <T> Object doGetTimestamp(Object timestamp, Class<T> targetType) {
|
|
||||||
|
|
||||||
if (ClassUtils.isAssignableValue(targetType, timestamp)) {
|
|
||||||
return timestamp;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (timestamp instanceof Instant) {
|
|
||||||
return new BsonTimestamp((int) ((Instant) timestamp).getEpochSecond(), 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (timestamp instanceof BsonTimestamp) {
|
|
||||||
return Instant.ofEpochSecond(((BsonTimestamp) timestamp).getTime());
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new IllegalArgumentException(
|
|
||||||
"o_O that should actually not happen. The timestamp should be an Instant or a BsonTimestamp but was "
|
|
||||||
+ ObjectUtils.nullSafeClassName(timestamp));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author Christoph Strobl
|
|
||||||
* @since 2.2
|
|
||||||
*/
|
|
||||||
enum Resume {
|
|
||||||
|
|
||||||
UNDEFINED,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @see com.mongodb.client.ChangeStreamIterable#startAfter(BsonDocument)
|
|
||||||
*/
|
|
||||||
START_AFTER,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @see com.mongodb.client.ChangeStreamIterable#resumeAfter(BsonDocument)
|
|
||||||
*/
|
|
||||||
RESUME_AFTER
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Builder for creating {@link ChangeStreamOptions}.
|
* Builder for creating {@link ChangeStreamOptions}.
|
||||||
*
|
*
|
||||||
@@ -187,8 +115,7 @@ public class ChangeStreamOptions {
|
|||||||
private @Nullable BsonValue resumeToken;
|
private @Nullable BsonValue resumeToken;
|
||||||
private @Nullable FullDocument fullDocumentLookup;
|
private @Nullable FullDocument fullDocumentLookup;
|
||||||
private @Nullable Collation collation;
|
private @Nullable Collation collation;
|
||||||
private @Nullable Object resumeTimestamp;
|
private @Nullable Instant resumeTimestamp;
|
||||||
private Resume resume = Resume.UNDEFINED;
|
|
||||||
|
|
||||||
private ChangeStreamOptionsBuilder() {}
|
private ChangeStreamOptionsBuilder() {}
|
||||||
|
|
||||||
@@ -256,11 +183,6 @@ public class ChangeStreamOptions {
|
|||||||
Assert.notNull(resumeToken, "ResumeToken must not be null!");
|
Assert.notNull(resumeToken, "ResumeToken must not be null!");
|
||||||
|
|
||||||
this.resumeToken = resumeToken;
|
this.resumeToken = resumeToken;
|
||||||
|
|
||||||
if (this.resume == Resume.UNDEFINED) {
|
|
||||||
this.resume = Resume.RESUME_AFTER;
|
|
||||||
}
|
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -302,51 +224,6 @@ public class ChangeStreamOptions {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the cluster time to resume from.
|
|
||||||
*
|
|
||||||
* @param resumeTimestamp must not be {@literal null}.
|
|
||||||
* @return this.
|
|
||||||
* @since 2.2
|
|
||||||
*/
|
|
||||||
public ChangeStreamOptionsBuilder resumeAt(BsonTimestamp resumeTimestamp) {
|
|
||||||
|
|
||||||
Assert.notNull(resumeTimestamp, "ResumeTimestamp must not be null!");
|
|
||||||
|
|
||||||
this.resumeTimestamp = resumeTimestamp;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the resume token after which to continue emitting notifications.
|
|
||||||
*
|
|
||||||
* @param resumeToken must not be {@literal null}.
|
|
||||||
* @return this.
|
|
||||||
* @since 2.2
|
|
||||||
*/
|
|
||||||
public ChangeStreamOptionsBuilder resumeAfter(BsonValue resumeToken) {
|
|
||||||
|
|
||||||
resumeToken(resumeToken);
|
|
||||||
this.resume = Resume.RESUME_AFTER;
|
|
||||||
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the resume token after which to start emitting notifications.
|
|
||||||
*
|
|
||||||
* @param resumeToken must not be {@literal null}.
|
|
||||||
* @return this.
|
|
||||||
* @since 2.2
|
|
||||||
*/
|
|
||||||
public ChangeStreamOptionsBuilder startAfter(BsonValue resumeToken) {
|
|
||||||
|
|
||||||
resumeToken(resumeToken);
|
|
||||||
this.resume = Resume.START_AFTER;
|
|
||||||
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the built {@link ChangeStreamOptions}
|
* @return the built {@link ChangeStreamOptions}
|
||||||
*/
|
*/
|
||||||
@@ -354,12 +231,11 @@ public class ChangeStreamOptions {
|
|||||||
|
|
||||||
ChangeStreamOptions options = new ChangeStreamOptions();
|
ChangeStreamOptions options = new ChangeStreamOptions();
|
||||||
|
|
||||||
options.filter = this.filter;
|
options.filter = filter;
|
||||||
options.resumeToken = this.resumeToken;
|
options.resumeToken = resumeToken;
|
||||||
options.fullDocumentLookup = this.fullDocumentLookup;
|
options.fullDocumentLookup = fullDocumentLookup;
|
||||||
options.collation = this.collation;
|
options.collation = collation;
|
||||||
options.resumeTimestamp = this.resumeTimestamp;
|
options.resumeTimestamp = resumeTimestamp;
|
||||||
options.resume = this.resume;
|
|
||||||
|
|
||||||
return options;
|
return options;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2010-2020 the original author or authors.
|
* Copyright 2010-2019 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2010-2020 the original author or authors.
|
* Copyright 2010-2019 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|||||||
@@ -1,227 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2019-2020 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.core;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
import org.bson.Document;
|
|
||||||
|
|
||||||
import org.springframework.data.geo.Point;
|
|
||||||
import org.springframework.lang.Nullable;
|
|
||||||
import org.springframework.util.ObjectUtils;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Value object representing a count query. Count queries using {@code $near} or {@code $nearSphere} require a rewrite
|
|
||||||
* to {@code $geoWithin}.
|
|
||||||
*
|
|
||||||
* @author Christoph Strobl
|
|
||||||
* @author Mark Paluch
|
|
||||||
* @since 3.0
|
|
||||||
*/
|
|
||||||
class CountQuery {
|
|
||||||
|
|
||||||
private Document source;
|
|
||||||
|
|
||||||
private CountQuery(Document source) {
|
|
||||||
this.source = source;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static CountQuery of(Document source) {
|
|
||||||
return new CountQuery(source);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the query {@link Document} that can be used with {@code countDocuments()}. Potentially rewrites the query
|
|
||||||
* to be usable with {@code countDocuments()}.
|
|
||||||
*
|
|
||||||
* @return the query {@link Document} that can be used with {@code countDocuments()}.
|
|
||||||
*/
|
|
||||||
public Document toQueryDocument() {
|
|
||||||
|
|
||||||
if (!requiresRewrite(source)) {
|
|
||||||
return source;
|
|
||||||
}
|
|
||||||
|
|
||||||
Document target = new Document();
|
|
||||||
|
|
||||||
for (Map.Entry<String, Object> entry : source.entrySet()) {
|
|
||||||
|
|
||||||
if (entry.getValue() instanceof Document && requiresRewrite(entry.getValue())) {
|
|
||||||
|
|
||||||
Document theValue = (Document) entry.getValue();
|
|
||||||
target.putAll(createGeoWithin(entry.getKey(), theValue, source.get("$and")));
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (entry.getValue() instanceof Collection && requiresRewrite(entry.getValue())) {
|
|
||||||
|
|
||||||
Collection<?> source = (Collection<?>) entry.getValue();
|
|
||||||
|
|
||||||
target.put(entry.getKey(), rewriteCollection(source));
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ("$and".equals(entry.getKey()) && target.containsKey("$and")) {
|
|
||||||
// Expect $and to be processed with Document and createGeoWithin.
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
target.put(entry.getKey(), entry.getValue());
|
|
||||||
}
|
|
||||||
|
|
||||||
return target;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param valueToInspect
|
|
||||||
* @return {@code true} if the enclosing element needs to be rewritten.
|
|
||||||
*/
|
|
||||||
private boolean requiresRewrite(Object valueToInspect) {
|
|
||||||
|
|
||||||
if (valueToInspect instanceof Document) {
|
|
||||||
return requiresRewrite((Document) valueToInspect);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (valueToInspect instanceof Collection) {
|
|
||||||
return requiresRewrite((Collection) valueToInspect);
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean requiresRewrite(Collection<?> collection) {
|
|
||||||
|
|
||||||
for (Object o : collection) {
|
|
||||||
if (o instanceof Document && requiresRewrite((Document) o)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean requiresRewrite(Document document) {
|
|
||||||
|
|
||||||
if (containsNear(document)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (Object entry : document.values()) {
|
|
||||||
|
|
||||||
if (requiresRewrite(entry)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Collection<Object> rewriteCollection(Collection<?> source) {
|
|
||||||
|
|
||||||
Collection<Object> rewrittenCollection = new ArrayList<>(source.size());
|
|
||||||
|
|
||||||
for (Object item : source) {
|
|
||||||
if (item instanceof Document && requiresRewrite(item)) {
|
|
||||||
rewrittenCollection.add(CountQuery.of((Document) item).toQueryDocument());
|
|
||||||
} else {
|
|
||||||
rewrittenCollection.add(item);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return rewrittenCollection;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Rewrite the near query for field {@code key} to {@code $geoWithin}.
|
|
||||||
*
|
|
||||||
* @param key the queried field.
|
|
||||||
* @param source source {@link Document}.
|
|
||||||
* @param $and potentially existing {@code $and} condition.
|
|
||||||
* @return the rewritten query {@link Document}.
|
|
||||||
*/
|
|
||||||
private static Document createGeoWithin(String key, Document source, @Nullable Object $and) {
|
|
||||||
|
|
||||||
boolean spheric = source.containsKey("$nearSphere");
|
|
||||||
Object $near = spheric ? source.get("$nearSphere") : source.get("$near");
|
|
||||||
|
|
||||||
Number maxDistance = source.containsKey("$maxDistance") ? (Number) source.get("$maxDistance") : Double.MAX_VALUE;
|
|
||||||
List<Object> $centerMax = Arrays.asList(toCenterCoordinates($near), maxDistance);
|
|
||||||
Document $geoWithinMax = new Document("$geoWithin",
|
|
||||||
new Document(spheric ? "$centerSphere" : "$center", $centerMax));
|
|
||||||
|
|
||||||
if (!containsNearWithMinDistance(source)) {
|
|
||||||
return new Document(key, $geoWithinMax);
|
|
||||||
}
|
|
||||||
|
|
||||||
Number minDistance = (Number) source.get("$minDistance");
|
|
||||||
List<Object> $centerMin = Arrays.asList(toCenterCoordinates($near), minDistance);
|
|
||||||
Document $geoWithinMin = new Document("$geoWithin",
|
|
||||||
new Document(spheric ? "$centerSphere" : "$center", $centerMin));
|
|
||||||
|
|
||||||
List<Document> criteria = new ArrayList<>();
|
|
||||||
|
|
||||||
if ($and != null) {
|
|
||||||
if ($and instanceof Collection) {
|
|
||||||
criteria.addAll((Collection) $and);
|
|
||||||
} else {
|
|
||||||
throw new IllegalArgumentException(
|
|
||||||
"Cannot rewrite query as it contains an '$and' element that is not a Collection!: Offending element: "
|
|
||||||
+ $and);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
criteria.add(new Document("$nor", Collections.singletonList(new Document(key, $geoWithinMin))));
|
|
||||||
criteria.add(new Document(key, $geoWithinMax));
|
|
||||||
return new Document("$and", criteria);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static boolean containsNear(Document source) {
|
|
||||||
return source.containsKey("$near") || source.containsKey("$nearSphere");
|
|
||||||
}
|
|
||||||
|
|
||||||
private static boolean containsNearWithMinDistance(Document source) {
|
|
||||||
|
|
||||||
if (!containsNear(source)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return source.containsKey("$minDistance");
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Object toCenterCoordinates(Object value) {
|
|
||||||
|
|
||||||
if (ObjectUtils.isArray(value)) {
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (value instanceof Point) {
|
|
||||||
return Arrays.asList(((Point) value).getX(), ((Point) value).getY());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (value instanceof Document && ((Document) value).containsKey("x")) {
|
|
||||||
|
|
||||||
Document point = (Document) value;
|
|
||||||
return Arrays.asList(point.get("x"), point.get("y"));
|
|
||||||
}
|
|
||||||
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2002-2020 the original author or authors.
|
* Copyright 2002-2019 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -15,15 +15,9 @@
|
|||||||
*/
|
*/
|
||||||
package org.springframework.data.mongodb.core;
|
package org.springframework.data.mongodb.core;
|
||||||
|
|
||||||
import java.util.function.Function;
|
|
||||||
|
|
||||||
import org.bson.Document;
|
import org.bson.Document;
|
||||||
import org.springframework.lang.Nullable;
|
|
||||||
import org.springframework.util.Assert;
|
|
||||||
|
|
||||||
import com.mongodb.ReadPreference;
|
|
||||||
import com.mongodb.client.FindIterable;
|
import com.mongodb.client.FindIterable;
|
||||||
import com.mongodb.client.MongoCollection;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Simple callback interface to allow customization of a {@link FindIterable}.
|
* Simple callback interface to allow customization of a {@link FindIterable}.
|
||||||
@@ -31,14 +25,7 @@ import com.mongodb.client.MongoCollection;
|
|||||||
* @author Oliver Gierke
|
* @author Oliver Gierke
|
||||||
* @author Christoph Strobl
|
* @author Christoph Strobl
|
||||||
*/
|
*/
|
||||||
public interface CursorPreparer extends ReadPreferenceAware {
|
public interface CursorPreparer {
|
||||||
|
|
||||||
/**
|
|
||||||
* Default {@link CursorPreparer} just passing on the given {@link FindIterable}.
|
|
||||||
*
|
|
||||||
* @since 2.2
|
|
||||||
*/
|
|
||||||
CursorPreparer NO_OP_PREPARER = (iterable -> iterable);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Prepare the given cursor (apply limits, skips and so on). Returns the prepared cursor.
|
* Prepare the given cursor (apply limits, skips and so on). Returns the prepared cursor.
|
||||||
@@ -46,37 +33,4 @@ public interface CursorPreparer extends ReadPreferenceAware {
|
|||||||
* @param cursor
|
* @param cursor
|
||||||
*/
|
*/
|
||||||
FindIterable<Document> prepare(FindIterable<Document> cursor);
|
FindIterable<Document> prepare(FindIterable<Document> cursor);
|
||||||
|
|
||||||
/**
|
|
||||||
* Apply query specific settings to {@link MongoCollection} and initate a find operation returning a
|
|
||||||
* {@link FindIterable} via the given {@link Function find} function.
|
|
||||||
*
|
|
||||||
* @param collection must not be {@literal null}.
|
|
||||||
* @param find must not be {@literal null}.
|
|
||||||
* @return
|
|
||||||
* @throws IllegalArgumentException if one of the required arguments is {@literal null}.
|
|
||||||
* @since 2.2
|
|
||||||
*/
|
|
||||||
default FindIterable<Document> initiateFind(MongoCollection<Document> collection,
|
|
||||||
Function<MongoCollection<Document>, FindIterable<Document>> find) {
|
|
||||||
|
|
||||||
Assert.notNull(collection, "Collection must not be null!");
|
|
||||||
Assert.notNull(find, "Find function must not be null!");
|
|
||||||
|
|
||||||
if (hasReadPreference()) {
|
|
||||||
collection = collection.withReadPreference(getReadPreference());
|
|
||||||
}
|
|
||||||
|
|
||||||
return prepare(find.apply(collection));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return the {@link ReadPreference} to apply or {@literal null} if none defined.
|
|
||||||
* @since 2.2
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
@Nullable
|
|
||||||
default ReadPreference getReadPreference() {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2010-2020 the original author or authors.
|
* Copyright 2010-2019 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2015-2020 the original author or authors.
|
* Copyright 2015-2019 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -26,31 +26,30 @@ import java.util.stream.Collectors;
|
|||||||
|
|
||||||
import org.bson.Document;
|
import org.bson.Document;
|
||||||
import org.bson.conversions.Bson;
|
import org.bson.conversions.Bson;
|
||||||
import org.springframework.context.ApplicationEventPublisher;
|
import org.springframework.dao.DataAccessException;
|
||||||
import org.springframework.dao.support.PersistenceExceptionTranslator;
|
import org.springframework.dao.support.PersistenceExceptionTranslator;
|
||||||
import org.springframework.data.mapping.callback.EntityCallbacks;
|
|
||||||
import org.springframework.data.mongodb.core.convert.QueryMapper;
|
import org.springframework.data.mongodb.core.convert.QueryMapper;
|
||||||
import org.springframework.data.mongodb.core.convert.UpdateMapper;
|
import org.springframework.data.mongodb.core.convert.UpdateMapper;
|
||||||
import org.springframework.data.mongodb.core.mapping.MongoPersistentEntity;
|
import org.springframework.data.mongodb.core.mapping.MongoPersistentEntity;
|
||||||
import org.springframework.data.mongodb.core.mapping.event.AfterSaveEvent;
|
|
||||||
import org.springframework.data.mongodb.core.mapping.event.BeforeConvertCallback;
|
|
||||||
import org.springframework.data.mongodb.core.mapping.event.BeforeConvertEvent;
|
|
||||||
import org.springframework.data.mongodb.core.mapping.event.BeforeSaveCallback;
|
|
||||||
import org.springframework.data.mongodb.core.mapping.event.BeforeSaveEvent;
|
|
||||||
import org.springframework.data.mongodb.core.mapping.event.MongoMappingEvent;
|
|
||||||
import org.springframework.data.mongodb.core.query.Collation;
|
import org.springframework.data.mongodb.core.query.Collation;
|
||||||
import org.springframework.data.mongodb.core.query.Query;
|
import org.springframework.data.mongodb.core.query.Query;
|
||||||
import org.springframework.data.mongodb.core.query.Update;
|
import org.springframework.data.mongodb.core.query.Update;
|
||||||
import org.springframework.data.mongodb.core.query.UpdateDefinition;
|
|
||||||
import org.springframework.data.mongodb.core.query.UpdateDefinition.ArrayFilter;
|
|
||||||
import org.springframework.data.util.Pair;
|
import org.springframework.data.util.Pair;
|
||||||
import org.springframework.lang.Nullable;
|
import org.springframework.lang.Nullable;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
|
|
||||||
|
import com.mongodb.BulkWriteException;
|
||||||
import com.mongodb.WriteConcern;
|
import com.mongodb.WriteConcern;
|
||||||
import com.mongodb.bulk.BulkWriteResult;
|
|
||||||
import com.mongodb.client.MongoCollection;
|
import com.mongodb.client.MongoCollection;
|
||||||
import com.mongodb.client.model.*;
|
import com.mongodb.client.model.BulkWriteOptions;
|
||||||
|
import com.mongodb.client.model.DeleteManyModel;
|
||||||
|
import com.mongodb.client.model.DeleteOneModel;
|
||||||
|
import com.mongodb.client.model.DeleteOptions;
|
||||||
|
import com.mongodb.client.model.InsertOneModel;
|
||||||
|
import com.mongodb.client.model.UpdateManyModel;
|
||||||
|
import com.mongodb.client.model.UpdateOneModel;
|
||||||
|
import com.mongodb.client.model.UpdateOptions;
|
||||||
|
import com.mongodb.client.model.WriteModel;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Default implementation for {@link BulkOperations}.
|
* Default implementation for {@link BulkOperations}.
|
||||||
@@ -59,8 +58,6 @@ import com.mongodb.client.model.*;
|
|||||||
* @author Oliver Gierke
|
* @author Oliver Gierke
|
||||||
* @author Christoph Strobl
|
* @author Christoph Strobl
|
||||||
* @author Mark Paluch
|
* @author Mark Paluch
|
||||||
* @author Minsu Kim
|
|
||||||
* @author Jens Schauder
|
|
||||||
* @author Michail Nikolaev
|
* @author Michail Nikolaev
|
||||||
* @since 1.9
|
* @since 1.9
|
||||||
*/
|
*/
|
||||||
@@ -69,7 +66,7 @@ class DefaultBulkOperations implements BulkOperations {
|
|||||||
private final MongoOperations mongoOperations;
|
private final MongoOperations mongoOperations;
|
||||||
private final String collectionName;
|
private final String collectionName;
|
||||||
private final BulkOperationContext bulkOperationContext;
|
private final BulkOperationContext bulkOperationContext;
|
||||||
private final List<SourceAwareWriteModelHolder> models = new ArrayList<>();
|
private final List<WriteModel<Document>> models = new ArrayList<>();
|
||||||
|
|
||||||
private PersistenceExceptionTranslator exceptionTranslator;
|
private PersistenceExceptionTranslator exceptionTranslator;
|
||||||
private @Nullable WriteConcern defaultWriteConcern;
|
private @Nullable WriteConcern defaultWriteConcern;
|
||||||
@@ -126,9 +123,16 @@ class DefaultBulkOperations implements BulkOperations {
|
|||||||
|
|
||||||
Assert.notNull(document, "Document must not be null!");
|
Assert.notNull(document, "Document must not be null!");
|
||||||
|
|
||||||
maybeEmitEvent(new BeforeConvertEvent<>(document, collectionName));
|
if (document instanceof Document) {
|
||||||
Object source = maybeInvokeBeforeConvertCallback(document);
|
|
||||||
addModel(source, new InsertOneModel<>(getMappedObject(source)));
|
models.add(new InsertOneModel<>((Document) document));
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
Document sink = new Document();
|
||||||
|
mongoOperations.getConverter().write(document, sink);
|
||||||
|
|
||||||
|
models.add(new InsertOneModel<>(sink));
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
@@ -242,7 +246,7 @@ class DefaultBulkOperations implements BulkOperations {
|
|||||||
DeleteOptions deleteOptions = new DeleteOptions();
|
DeleteOptions deleteOptions = new DeleteOptions();
|
||||||
query.getCollation().map(Collation::toMongoCollation).ifPresent(deleteOptions::collation);
|
query.getCollation().map(Collation::toMongoCollation).ifPresent(deleteOptions::collation);
|
||||||
|
|
||||||
addModel(query, new DeleteManyModel<>(query.getQueryObject(), deleteOptions));
|
models.add(new DeleteManyModel<>(query.getQueryObject(), deleteOptions));
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
@@ -263,29 +267,6 @@ class DefaultBulkOperations implements BulkOperations {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* (non-Javadoc)
|
|
||||||
* @see org.springframework.data.mongodb.core.BulkOperations#replaceOne(org.springframework.data.mongodb.core.query.Query, java.lang.Object, org.springframework.data.mongodb.core.FindAndReplaceOptions)
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public BulkOperations replaceOne(Query query, Object replacement, FindAndReplaceOptions options) {
|
|
||||||
|
|
||||||
Assert.notNull(query, "Query must not be null!");
|
|
||||||
Assert.notNull(replacement, "Replacement must not be null!");
|
|
||||||
Assert.notNull(options, "Options must not be null!");
|
|
||||||
|
|
||||||
ReplaceOptions replaceOptions = new ReplaceOptions();
|
|
||||||
replaceOptions.upsert(options.isUpsert());
|
|
||||||
query.getCollation().map(Collation::toMongoCollation).ifPresent(replaceOptions::collation);
|
|
||||||
|
|
||||||
maybeEmitEvent(new BeforeConvertEvent<>(replacement, collectionName));
|
|
||||||
Object source = maybeInvokeBeforeConvertCallback(replacement);
|
|
||||||
addModel(source,
|
|
||||||
new ReplaceOneModel<>(getMappedQuery(query.getQueryObject()), getMappedObject(source), replaceOptions));
|
|
||||||
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* (non-Javadoc)
|
* (non-Javadoc)
|
||||||
* @see org.springframework.data.mongodb.core.BulkOperations#executeBulk()
|
* @see org.springframework.data.mongodb.core.BulkOperations#executeBulk()
|
||||||
@@ -295,46 +276,16 @@ class DefaultBulkOperations implements BulkOperations {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
||||||
com.mongodb.bulk.BulkWriteResult result = mongoOperations.execute(collectionName, this::bulkWriteTo);
|
return mongoOperations.execute(collectionName, collection -> {
|
||||||
|
|
||||||
Assert.state(result != null, "Result must not be null.");
|
|
||||||
|
|
||||||
models.forEach(this::maybeEmitAfterSaveEvent);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
} finally {
|
|
||||||
this.bulkOptions = getBulkWriteOptions(bulkOperationContext.getBulkMode());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private BulkWriteResult bulkWriteTo(MongoCollection<Document> collection) {
|
|
||||||
|
|
||||||
if (defaultWriteConcern != null) {
|
if (defaultWriteConcern != null) {
|
||||||
collection = collection.withWriteConcern(defaultWriteConcern);
|
collection = collection.withWriteConcern(defaultWriteConcern);
|
||||||
}
|
}
|
||||||
|
return collection.bulkWrite(models.stream().map(this::mapWriteModel).collect(Collectors.toList()), bulkOptions);
|
||||||
return collection.bulkWrite( //
|
});
|
||||||
models.stream() //
|
} finally {
|
||||||
.map(this::extractAndMapWriteModel) //
|
this.bulkOptions = getBulkWriteOptions(bulkOperationContext.getBulkMode());
|
||||||
.collect(Collectors.toList()), //
|
|
||||||
bulkOptions);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private WriteModel<Document> extractAndMapWriteModel(SourceAwareWriteModelHolder it) {
|
|
||||||
|
|
||||||
maybeEmitBeforeSaveEvent(it);
|
|
||||||
|
|
||||||
if (it.getModel() instanceof InsertOneModel) {
|
|
||||||
|
|
||||||
Document target = ((InsertOneModel<Document>) it.getModel()).getDocument();
|
|
||||||
maybeInvokeBeforeSaveCallback(it.getSource(), target);
|
|
||||||
} else if (it.getModel() instanceof ReplaceOneModel) {
|
|
||||||
|
|
||||||
Document target = ((ReplaceOneModel<Document>) it.getModel()).getReplacement();
|
|
||||||
maybeInvokeBeforeSaveCallback(it.getSource(), target);
|
|
||||||
}
|
|
||||||
|
|
||||||
return mapWriteModel(it.getModel());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -351,12 +302,14 @@ class DefaultBulkOperations implements BulkOperations {
|
|||||||
Assert.notNull(query, "Query must not be null!");
|
Assert.notNull(query, "Query must not be null!");
|
||||||
Assert.notNull(update, "Update must not be null!");
|
Assert.notNull(update, "Update must not be null!");
|
||||||
|
|
||||||
UpdateOptions options = computeUpdateOptions(query, update, upsert);
|
UpdateOptions options = new UpdateOptions();
|
||||||
|
options.upsert(upsert);
|
||||||
|
query.getCollation().map(Collation::toMongoCollation).ifPresent(options::collation);
|
||||||
|
|
||||||
if (multi) {
|
if (multi) {
|
||||||
addModel(update, new UpdateManyModel<>(query.getQueryObject(), update.getUpdateObject(), options));
|
models.add(new UpdateManyModel<>(query.getQueryObject(), update.getUpdateObject(), options));
|
||||||
} else {
|
} else {
|
||||||
addModel(update, new UpdateOneModel<>(query.getQueryObject(), update.getUpdateObject(), options));
|
models.add(new UpdateOneModel<>(query.getQueryObject(), update.getUpdateObject(), options));
|
||||||
}
|
}
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
@@ -405,76 +358,6 @@ class DefaultBulkOperations implements BulkOperations {
|
|||||||
return bulkOperationContext.getQueryMapper().getMappedObject(query, bulkOperationContext.getEntity());
|
return bulkOperationContext.getQueryMapper().getMappedObject(query, bulkOperationContext.getEntity());
|
||||||
}
|
}
|
||||||
|
|
||||||
private Document getMappedObject(Object source) {
|
|
||||||
|
|
||||||
if (source instanceof Document) {
|
|
||||||
return (Document) source;
|
|
||||||
}
|
|
||||||
|
|
||||||
Document sink = new Document();
|
|
||||||
|
|
||||||
mongoOperations.getConverter().write(source, sink);
|
|
||||||
return sink;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void addModel(Object source, WriteModel<Document> model) {
|
|
||||||
models.add(new SourceAwareWriteModelHolder(source, model));
|
|
||||||
}
|
|
||||||
|
|
||||||
private void maybeEmitBeforeSaveEvent(SourceAwareWriteModelHolder it) {
|
|
||||||
|
|
||||||
if (it.getModel() instanceof InsertOneModel) {
|
|
||||||
|
|
||||||
Document target = ((InsertOneModel<Document>) it.getModel()).getDocument();
|
|
||||||
maybeEmitEvent(new BeforeSaveEvent<>(it.getSource(), target, collectionName));
|
|
||||||
} else if (it.getModel() instanceof ReplaceOneModel) {
|
|
||||||
|
|
||||||
Document target = ((ReplaceOneModel<Document>) it.getModel()).getReplacement();
|
|
||||||
maybeEmitEvent(new BeforeSaveEvent<>(it.getSource(), target, collectionName));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void maybeEmitAfterSaveEvent(SourceAwareWriteModelHolder it) {
|
|
||||||
|
|
||||||
if (it.getModel() instanceof InsertOneModel) {
|
|
||||||
|
|
||||||
Document target = ((InsertOneModel<Document>) it.getModel()).getDocument();
|
|
||||||
maybeEmitEvent(new AfterSaveEvent<>(it.getSource(), target, collectionName));
|
|
||||||
} else if (it.getModel() instanceof ReplaceOneModel) {
|
|
||||||
|
|
||||||
Document target = ((ReplaceOneModel<Document>) it.getModel()).getReplacement();
|
|
||||||
maybeEmitEvent(new AfterSaveEvent<>(it.getSource(), target, collectionName));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private <E extends MongoMappingEvent<T>, T> E maybeEmitEvent(E event) {
|
|
||||||
|
|
||||||
if (null != bulkOperationContext.getEventPublisher()) {
|
|
||||||
bulkOperationContext.getEventPublisher().publishEvent(event);
|
|
||||||
}
|
|
||||||
|
|
||||||
return event;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Object maybeInvokeBeforeConvertCallback(Object value) {
|
|
||||||
|
|
||||||
if (bulkOperationContext.getEntityCallbacks() == null) {
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
return bulkOperationContext.getEntityCallbacks().callback(BeforeConvertCallback.class, value, collectionName);
|
|
||||||
}
|
|
||||||
|
|
||||||
private Object maybeInvokeBeforeSaveCallback(Object value, Document mappedDocument) {
|
|
||||||
|
|
||||||
if (bulkOperationContext.getEntityCallbacks() == null) {
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
return bulkOperationContext.getEntityCallbacks().callback(BeforeSaveCallback.class, value, mappedDocument,
|
|
||||||
collectionName);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static BulkWriteOptions getBulkWriteOptions(BulkMode bulkMode) {
|
private static BulkWriteOptions getBulkWriteOptions(BulkMode bulkMode) {
|
||||||
|
|
||||||
BulkWriteOptions options = new BulkWriteOptions();
|
BulkWriteOptions options = new BulkWriteOptions();
|
||||||
@@ -489,29 +372,6 @@ class DefaultBulkOperations implements BulkOperations {
|
|||||||
throw new IllegalStateException("BulkMode was null!");
|
throw new IllegalStateException("BulkMode was null!");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @param filterQuery The {@link Query} to read a potential {@link Collation} from. Must not be {@literal null}.
|
|
||||||
* @param update The {@link Update} to apply
|
|
||||||
* @param upsert flag to indicate if document should be upserted.
|
|
||||||
* @return new instance of {@link UpdateOptions}.
|
|
||||||
*/
|
|
||||||
private static UpdateOptions computeUpdateOptions(Query filterQuery, UpdateDefinition update, boolean upsert) {
|
|
||||||
|
|
||||||
UpdateOptions options = new UpdateOptions();
|
|
||||||
options.upsert(upsert);
|
|
||||||
|
|
||||||
if (update.hasArrayFilters()) {
|
|
||||||
List<Document> list = new ArrayList<>(update.getArrayFilters().size());
|
|
||||||
for (ArrayFilter arrayFilter : update.getArrayFilters()) {
|
|
||||||
list.add(arrayFilter.asDocument());
|
|
||||||
}
|
|
||||||
options.arrayFilters(list);
|
|
||||||
}
|
|
||||||
|
|
||||||
filterQuery.getCollation().map(Collation::toMongoCollation).ifPresent(options::collation);
|
|
||||||
return options;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@link BulkOperationContext} holds information about
|
* {@link BulkOperationContext} holds information about
|
||||||
* {@link org.springframework.data.mongodb.core.BulkOperations.BulkMode} the entity in use as well as references to
|
* {@link org.springframework.data.mongodb.core.BulkOperations.BulkMode} the entity in use as well as references to
|
||||||
@@ -527,20 +387,5 @@ class DefaultBulkOperations implements BulkOperations {
|
|||||||
@NonNull Optional<? extends MongoPersistentEntity<?>> entity;
|
@NonNull Optional<? extends MongoPersistentEntity<?>> entity;
|
||||||
@NonNull QueryMapper queryMapper;
|
@NonNull QueryMapper queryMapper;
|
||||||
@NonNull UpdateMapper updateMapper;
|
@NonNull UpdateMapper updateMapper;
|
||||||
ApplicationEventPublisher eventPublisher;
|
|
||||||
EntityCallbacks entityCallbacks;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Value object chaining together an actual source with its {@link WriteModel} representation.
|
|
||||||
*
|
|
||||||
* @since 2.2
|
|
||||||
* @author Christoph Strobl
|
|
||||||
*/
|
|
||||||
@Value
|
|
||||||
private static class SourceAwareWriteModelHolder {
|
|
||||||
|
|
||||||
Object source;
|
|
||||||
WriteModel<Document> model;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2011-2020 the original author or authors.
|
* Copyright 2011-2019 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -120,15 +120,19 @@ public class DefaultIndexOperations implements IndexOperations {
|
|||||||
|
|
||||||
return execute(collection -> {
|
return execute(collection -> {
|
||||||
|
|
||||||
MongoPersistentEntity<?> entity = lookupPersistentEntity(type, collectionName);
|
Document indexOptions = indexDefinition.getIndexOptions();
|
||||||
|
|
||||||
IndexOptions indexOptions = IndexConverters.indexDefinitionToIndexOptionsConverter().convert(indexDefinition);
|
IndexOptions ops = IndexConverters.indexDefinitionToIndexOptionsConverter().convert(indexDefinition);
|
||||||
|
|
||||||
indexOptions = addPartialFilterIfPresent(indexOptions, indexDefinition.getIndexOptions(), entity);
|
if (indexOptions.containsKey(PARTIAL_FILTER_EXPRESSION_KEY)) {
|
||||||
indexOptions = addDefaultCollationIfRequired(indexOptions, entity);
|
|
||||||
|
|
||||||
Document mappedKeys = mapper.getMappedSort(indexDefinition.getIndexKeys(), entity);
|
Assert.isInstanceOf(Document.class, indexOptions.get(PARTIAL_FILTER_EXPRESSION_KEY));
|
||||||
return collection.createIndex(mappedKeys, indexOptions);
|
|
||||||
|
ops.partialFilterExpression(mapper.getMappedObject((Document) indexOptions.get(PARTIAL_FILTER_EXPRESSION_KEY),
|
||||||
|
lookupPersistentEntity(type, collectionName)));
|
||||||
|
}
|
||||||
|
|
||||||
|
return collection.createIndex(indexDefinition.getIndexKeys(), ops);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -188,7 +192,7 @@ public class DefaultIndexOperations implements IndexOperations {
|
|||||||
|
|
||||||
private List<IndexInfo> getIndexData(MongoCursor<Document> cursor) {
|
private List<IndexInfo> getIndexData(MongoCursor<Document> cursor) {
|
||||||
|
|
||||||
List<IndexInfo> indexInfoList = new ArrayList<>();
|
List<IndexInfo> indexInfoList = new ArrayList<IndexInfo>();
|
||||||
|
|
||||||
while (cursor.hasNext()) {
|
while (cursor.hasNext()) {
|
||||||
|
|
||||||
@@ -213,25 +217,4 @@ public class DefaultIndexOperations implements IndexOperations {
|
|||||||
|
|
||||||
return mongoOperations.execute(collectionName, callback);
|
return mongoOperations.execute(collectionName, callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
private IndexOptions addPartialFilterIfPresent(IndexOptions ops, Document sourceOptions,
|
|
||||||
@Nullable MongoPersistentEntity<?> entity) {
|
|
||||||
|
|
||||||
if (!sourceOptions.containsKey(PARTIAL_FILTER_EXPRESSION_KEY)) {
|
|
||||||
return ops;
|
|
||||||
}
|
|
||||||
|
|
||||||
Assert.isInstanceOf(Document.class, sourceOptions.get(PARTIAL_FILTER_EXPRESSION_KEY));
|
|
||||||
return ops.partialFilterExpression(
|
|
||||||
mapper.getMappedSort((Document) sourceOptions.get(PARTIAL_FILTER_EXPRESSION_KEY), entity));
|
|
||||||
}
|
|
||||||
|
|
||||||
private static IndexOptions addDefaultCollationIfRequired(IndexOptions ops, MongoPersistentEntity<?> entity) {
|
|
||||||
|
|
||||||
if (ops.getCollation() != null || entity == null || !entity.hasCollation()) {
|
|
||||||
return ops;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ops.collation(entity.getCollation().toMongoCollation());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2016-2020 the original author or authors.
|
* Copyright 2016-2019 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2016-2020 the original author or authors.
|
* Copyright 2016-2019 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -94,16 +94,23 @@ public class DefaultReactiveIndexOperations implements ReactiveIndexOperations {
|
|||||||
|
|
||||||
return mongoOperations.execute(collectionName, collection -> {
|
return mongoOperations.execute(collectionName, collection -> {
|
||||||
|
|
||||||
|
Document indexOptions = indexDefinition.getIndexOptions();
|
||||||
|
|
||||||
|
IndexOptions ops = IndexConverters.indexDefinitionToIndexOptionsConverter().convert(indexDefinition);
|
||||||
|
|
||||||
|
if (indexOptions.containsKey(PARTIAL_FILTER_EXPRESSION_KEY)) {
|
||||||
|
|
||||||
|
Assert.isInstanceOf(Document.class, indexOptions.get(PARTIAL_FILTER_EXPRESSION_KEY));
|
||||||
|
|
||||||
MongoPersistentEntity<?> entity = type
|
MongoPersistentEntity<?> entity = type
|
||||||
.map(val -> (MongoPersistentEntity) queryMapper.getMappingContext().getRequiredPersistentEntity(val))
|
.map(val -> (MongoPersistentEntity) queryMapper.getMappingContext().getRequiredPersistentEntity(val))
|
||||||
.orElseGet(() -> lookupPersistentEntity(collectionName));
|
.orElseGet(() -> lookupPersistentEntity(collectionName));
|
||||||
|
|
||||||
IndexOptions indexOptions = IndexConverters.indexDefinitionToIndexOptionsConverter().convert(indexDefinition);
|
ops = ops.partialFilterExpression(
|
||||||
|
queryMapper.getMappedObject(indexOptions.get(PARTIAL_FILTER_EXPRESSION_KEY, Document.class), entity));
|
||||||
|
}
|
||||||
|
|
||||||
indexOptions = addPartialFilterIfPresent(indexOptions, indexDefinition.getIndexOptions(), entity);
|
return collection.createIndex(indexDefinition.getIndexKeys(), ops);
|
||||||
indexOptions = addDefaultCollationIfRequired(indexOptions, entity);
|
|
||||||
|
|
||||||
return collection.createIndex(indexDefinition.getIndexKeys(), indexOptions);
|
|
||||||
|
|
||||||
}).next();
|
}).next();
|
||||||
}
|
}
|
||||||
@@ -119,24 +126,21 @@ public class DefaultReactiveIndexOperations implements ReactiveIndexOperations {
|
|||||||
.orElse(null);
|
.orElse(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/* (non-Javadoc)
|
||||||
* (non-Javadoc)
|
|
||||||
* @see org.springframework.data.mongodb.core.index.ReactiveIndexOperations#dropIndex(java.lang.String)
|
* @see org.springframework.data.mongodb.core.index.ReactiveIndexOperations#dropIndex(java.lang.String)
|
||||||
*/
|
*/
|
||||||
public Mono<Void> dropIndex(final String name) {
|
public Mono<Void> dropIndex(final String name) {
|
||||||
return mongoOperations.execute(collectionName, collection -> collection.dropIndex(name)).then();
|
return mongoOperations.execute(collectionName, collection -> collection.dropIndex(name)).then();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/* (non-Javadoc)
|
||||||
* (non-Javadoc)
|
|
||||||
* @see org.springframework.data.mongodb.core.index.ReactiveIndexOperations#dropAllIndexes()
|
* @see org.springframework.data.mongodb.core.index.ReactiveIndexOperations#dropAllIndexes()
|
||||||
*/
|
*/
|
||||||
public Mono<Void> dropAllIndexes() {
|
public Mono<Void> dropAllIndexes() {
|
||||||
return dropIndex("*");
|
return dropIndex("*");
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/* (non-Javadoc)
|
||||||
* (non-Javadoc)
|
|
||||||
* @see org.springframework.data.mongodb.core.index.ReactiveIndexOperations#getIndexInfo()
|
* @see org.springframework.data.mongodb.core.index.ReactiveIndexOperations#getIndexInfo()
|
||||||
*/
|
*/
|
||||||
public Flux<IndexInfo> getIndexInfo() {
|
public Flux<IndexInfo> getIndexInfo() {
|
||||||
@@ -144,25 +148,4 @@ public class DefaultReactiveIndexOperations implements ReactiveIndexOperations {
|
|||||||
return mongoOperations.execute(collectionName, collection -> collection.listIndexes(Document.class)) //
|
return mongoOperations.execute(collectionName, collection -> collection.listIndexes(Document.class)) //
|
||||||
.map(IndexConverters.documentToIndexInfoConverter()::convert);
|
.map(IndexConverters.documentToIndexInfoConverter()::convert);
|
||||||
}
|
}
|
||||||
|
|
||||||
private IndexOptions addPartialFilterIfPresent(IndexOptions ops, Document sourceOptions,
|
|
||||||
@Nullable MongoPersistentEntity<?> entity) {
|
|
||||||
|
|
||||||
if (!sourceOptions.containsKey(PARTIAL_FILTER_EXPRESSION_KEY)) {
|
|
||||||
return ops;
|
|
||||||
}
|
|
||||||
|
|
||||||
Assert.isInstanceOf(Document.class, sourceOptions.get(PARTIAL_FILTER_EXPRESSION_KEY));
|
|
||||||
return ops.partialFilterExpression(
|
|
||||||
queryMapper.getMappedObject((Document) sourceOptions.get(PARTIAL_FILTER_EXPRESSION_KEY), entity));
|
|
||||||
}
|
|
||||||
|
|
||||||
private static IndexOptions addDefaultCollationIfRequired(IndexOptions ops, MongoPersistentEntity<?> entity) {
|
|
||||||
|
|
||||||
if (ops.getCollation() != null || entity == null || !entity.hasCollation()) {
|
|
||||||
return ops;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ops.collation(entity.getCollation().toMongoCollation());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2014-2020 the original author or authors.
|
* Copyright 2014-2019 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -42,15 +42,13 @@ import com.mongodb.MongoException;
|
|||||||
import com.mongodb.client.MongoDatabase;
|
import com.mongodb.client.MongoDatabase;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Default implementation of {@link ScriptOperations} capable of saving and executing {@link ExecutableMongoScript}.
|
* Default implementation of {@link ScriptOperations} capable of saving and executing {@link ServerSideJavaScript}.
|
||||||
*
|
*
|
||||||
* @author Christoph Strobl
|
* @author Christoph Strobl
|
||||||
* @author Oliver Gierke
|
* @author Oliver Gierke
|
||||||
* @author Mark Paluch
|
* @author Mark Paluch
|
||||||
* @since 1.7
|
* @since 1.7
|
||||||
* @deprecated since 2.2. The {@code eval} command has been removed in MongoDB Server 4.2.0.
|
|
||||||
*/
|
*/
|
||||||
@Deprecated
|
|
||||||
class DefaultScriptOperations implements ScriptOperations {
|
class DefaultScriptOperations implements ScriptOperations {
|
||||||
|
|
||||||
private static final String SCRIPT_COLLECTION_NAME = "system.js";
|
private static final String SCRIPT_COLLECTION_NAME = "system.js";
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2015-2020 the original author or authors.
|
* Copyright 2015-2019 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2010-2020 the original author or authors.
|
* Copyright 2010-2019 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2018-2020 the original author or authors.
|
* Copyright 2018-2019 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -21,14 +21,12 @@ import lombok.RequiredArgsConstructor;
|
|||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Optional;
|
|
||||||
|
|
||||||
import org.bson.Document;
|
import org.bson.Document;
|
||||||
import org.springframework.core.convert.ConversionService;
|
import org.springframework.core.convert.ConversionService;
|
||||||
import org.springframework.dao.InvalidDataAccessApiUsageException;
|
import org.springframework.dao.InvalidDataAccessApiUsageException;
|
||||||
import org.springframework.data.mapping.IdentifierAccessor;
|
import org.springframework.data.mapping.IdentifierAccessor;
|
||||||
import org.springframework.data.mapping.MappingException;
|
import org.springframework.data.mapping.MappingException;
|
||||||
import org.springframework.data.mapping.PersistentEntity;
|
|
||||||
import org.springframework.data.mapping.PersistentPropertyAccessor;
|
import org.springframework.data.mapping.PersistentPropertyAccessor;
|
||||||
import org.springframework.data.mapping.context.MappingContext;
|
import org.springframework.data.mapping.context.MappingContext;
|
||||||
import org.springframework.data.mapping.model.ConvertingPropertyAccessor;
|
import org.springframework.data.mapping.model.ConvertingPropertyAccessor;
|
||||||
@@ -36,15 +34,15 @@ import org.springframework.data.mongodb.core.convert.MongoWriter;
|
|||||||
import org.springframework.data.mongodb.core.mapping.MongoPersistentEntity;
|
import org.springframework.data.mongodb.core.mapping.MongoPersistentEntity;
|
||||||
import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty;
|
import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty;
|
||||||
import org.springframework.data.mongodb.core.mapping.MongoSimpleTypes;
|
import org.springframework.data.mongodb.core.mapping.MongoSimpleTypes;
|
||||||
import org.springframework.data.mongodb.core.query.Collation;
|
|
||||||
import org.springframework.data.mongodb.core.query.Criteria;
|
import org.springframework.data.mongodb.core.query.Criteria;
|
||||||
import org.springframework.data.mongodb.core.query.Query;
|
import org.springframework.data.mongodb.core.query.Query;
|
||||||
import org.springframework.lang.Nullable;
|
import org.springframework.lang.Nullable;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
import org.springframework.util.ClassUtils;
|
|
||||||
import org.springframework.util.LinkedMultiValueMap;
|
import org.springframework.util.LinkedMultiValueMap;
|
||||||
import org.springframework.util.MultiValueMap;
|
import org.springframework.util.MultiValueMap;
|
||||||
|
|
||||||
|
import com.mongodb.util.JSONParseException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Common operations performed on an entity in the context of it's mapping metadata.
|
* Common operations performed on an entity in the context of it's mapping metadata.
|
||||||
*
|
*
|
||||||
@@ -153,57 +151,13 @@ class EntityOperations {
|
|||||||
return ID_FIELD;
|
return ID_FIELD;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the name used for {@code $geoNear.distanceField} avoiding clashes with potentially existing properties.
|
|
||||||
*
|
|
||||||
* @param domainType must not be {@literal null}.
|
|
||||||
* @return the name of the distanceField to use. {@literal dis} by default.
|
|
||||||
* @since 2.2
|
|
||||||
*/
|
|
||||||
public String nearQueryDistanceFieldName(Class<?> domainType) {
|
|
||||||
|
|
||||||
MongoPersistentEntity<?> persistentEntity = context.getPersistentEntity(domainType);
|
|
||||||
if (persistentEntity == null || persistentEntity.getPersistentProperty("dis") == null) {
|
|
||||||
return "dis";
|
|
||||||
}
|
|
||||||
|
|
||||||
String distanceFieldName = "calculated-distance";
|
|
||||||
int counter = 0;
|
|
||||||
while (persistentEntity.getPersistentProperty(distanceFieldName) != null) {
|
|
||||||
distanceFieldName += "-" + (counter++);
|
|
||||||
}
|
|
||||||
|
|
||||||
return distanceFieldName;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Document parse(String source) {
|
private static Document parse(String source) {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return Document.parse(source);
|
return Document.parse(source);
|
||||||
} catch (org.bson.json.JsonParseException o_O) {
|
} catch (JSONParseException | org.bson.json.JsonParseException o_O) {
|
||||||
throw new MappingException("Could not parse given String to save into a JSON document!", o_O);
|
|
||||||
} catch (RuntimeException o_O) {
|
|
||||||
|
|
||||||
// legacy 3.x exception
|
|
||||||
if (ClassUtils.matchesTypeName(o_O.getClass(), "JSONParseException")) {
|
|
||||||
throw new MappingException("Could not parse given String to save into a JSON document!", o_O);
|
throw new MappingException("Could not parse given String to save into a JSON document!", o_O);
|
||||||
}
|
}
|
||||||
throw o_O;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public <T> TypedOperations<T> forType(@Nullable Class<T> entityClass) {
|
|
||||||
|
|
||||||
if (entityClass != null) {
|
|
||||||
|
|
||||||
MongoPersistentEntity<?> entity = context.getPersistentEntity(entityClass);
|
|
||||||
|
|
||||||
if (entity != null) {
|
|
||||||
return new TypedEntityOperations(entity);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
return UntypedOperations.instance();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -235,16 +189,6 @@ class EntityOperations {
|
|||||||
*/
|
*/
|
||||||
Query getByIdQuery();
|
Query getByIdQuery();
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the {@link Query} to remove an entity by its {@literal id} and if applicable {@literal version}.
|
|
||||||
*
|
|
||||||
* @return the {@link Query} to use for removing the entity. Never {@literal null}.
|
|
||||||
* @since 2.2
|
|
||||||
*/
|
|
||||||
default Query getRemoveByQuery() {
|
|
||||||
return isVersionedEntity() ? getQueryForVersion() : getByIdQuery();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the {@link Query} to find the entity in its current version.
|
* Returns the {@link Query} to find the entity in its current version.
|
||||||
*
|
*
|
||||||
@@ -275,11 +219,9 @@ class EntityOperations {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the value of the version if the entity {@link #isVersionedEntity() has a version property}.
|
* Returns the value of the version if the entity has a version property, {@literal null} otherwise.
|
||||||
*
|
*
|
||||||
* @return the entity version. Can be {@literal null}.
|
* @return
|
||||||
* @throws IllegalStateException if the entity does not define a {@literal version} property. Make sure to check
|
|
||||||
* {@link #isVersionedEntity()}.
|
|
||||||
*/
|
*/
|
||||||
@Nullable
|
@Nullable
|
||||||
Object getVersion();
|
Object getVersion();
|
||||||
@@ -335,8 +277,8 @@ class EntityOperations {
|
|||||||
/**
|
/**
|
||||||
* Returns the current version value if the entity has a version property.
|
* Returns the current version value if the entity has a version property.
|
||||||
*
|
*
|
||||||
* @return the current version or {@literal null} in case it's uninitialized.
|
* @return the current version or {@literal null} in case it's uninitialized or the entity doesn't expose a version
|
||||||
* @throws IllegalStateException if the entity does not define a {@literal version} property.
|
* property.
|
||||||
*/
|
*/
|
||||||
@Nullable
|
@Nullable
|
||||||
Number getVersion();
|
Number getVersion();
|
||||||
@@ -538,10 +480,10 @@ class EntityOperations {
|
|||||||
public Query getQueryForVersion() {
|
public Query getQueryForVersion() {
|
||||||
|
|
||||||
MongoPersistentProperty idProperty = entity.getRequiredIdProperty();
|
MongoPersistentProperty idProperty = entity.getRequiredIdProperty();
|
||||||
MongoPersistentProperty versionProperty = entity.getRequiredVersionProperty();
|
MongoPersistentProperty property = entity.getRequiredVersionProperty();
|
||||||
|
|
||||||
return new Query(Criteria.where(idProperty.getName()).is(getId())//
|
return new Query(Criteria.where(idProperty.getName()).is(getId())//
|
||||||
.and(versionProperty.getName()).is(getVersion()));
|
.and(property.getName()).is(getVersion()));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -725,102 +667,4 @@ class EntityOperations {
|
|||||||
return propertyAccessor.getBean();
|
return propertyAccessor.getBean();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Type-specific operations abstraction.
|
|
||||||
*
|
|
||||||
* @author Mark Paluch
|
|
||||||
* @param <T>
|
|
||||||
* @since 2.2
|
|
||||||
*/
|
|
||||||
interface TypedOperations<T> {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the optional {@link Collation} for the underlying entity.
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
Optional<Collation> getCollation();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the optional {@link Collation} from the given {@link Query} and fall back to the collation configured for
|
|
||||||
* the underlying entity.
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
Optional<Collation> getCollation(Query query);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@link TypedOperations} for generic entities that are not represented with {@link PersistentEntity} (e.g. custom
|
|
||||||
* conversions).
|
|
||||||
*/
|
|
||||||
@RequiredArgsConstructor
|
|
||||||
enum UntypedOperations implements TypedOperations<Object> {
|
|
||||||
|
|
||||||
INSTANCE;
|
|
||||||
|
|
||||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
|
||||||
public static <T> TypedOperations<T> instance() {
|
|
||||||
return (TypedOperations) INSTANCE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* (non-Javadoc)
|
|
||||||
* @see org.springframework.data.mongodb.core.EntityOperations.TypedOperations#getCollation()
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public Optional<Collation> getCollation() {
|
|
||||||
return Optional.empty();
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* (non-Javadoc)
|
|
||||||
* @see org.springframework.data.mongodb.core.EntityOperations.TypedOperations#getCollation(org.springframework.data.mongodb.core.query.Query)
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public Optional<Collation> getCollation(Query query) {
|
|
||||||
|
|
||||||
if (query == null) {
|
|
||||||
return Optional.empty();
|
|
||||||
}
|
|
||||||
|
|
||||||
return query.getCollation();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@link TypedOperations} backed by {@link MongoPersistentEntity}.
|
|
||||||
*
|
|
||||||
* @param <T>
|
|
||||||
*/
|
|
||||||
@RequiredArgsConstructor
|
|
||||||
static class TypedEntityOperations<T> implements TypedOperations<T> {
|
|
||||||
|
|
||||||
private final @NonNull MongoPersistentEntity<T> entity;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* (non-Javadoc)
|
|
||||||
* @see org.springframework.data.mongodb.core.EntityOperations.TypedOperations#getCollation()
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public Optional<Collation> getCollation() {
|
|
||||||
return Optional.ofNullable(entity.getCollation());
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* (non-Javadoc)
|
|
||||||
* @see org.springframework.data.mongodb.core.EntityOperations.TypedOperations#getCollation(org.springframework.data.mongodb.core.query.Query)
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public Optional<Collation> getCollation(Query query) {
|
|
||||||
|
|
||||||
if (query.getCollation().isPresent()) {
|
|
||||||
return query.getCollation();
|
|
||||||
}
|
|
||||||
|
|
||||||
return Optional.ofNullable(entity.getCollation());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2017-2020 the original author or authors.
|
* Copyright 2017-2019 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2017-2020 the original author or authors.
|
* Copyright 2017-2019 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2017-2020 the original author or authors.
|
* Copyright 2017-2019 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2017-2020 the original author or authors.
|
* Copyright 2017-2019 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -15,7 +15,6 @@
|
|||||||
*/
|
*/
|
||||||
package org.springframework.data.mongodb.core;
|
package org.springframework.data.mongodb.core;
|
||||||
|
|
||||||
import com.mongodb.ReadPreference;
|
|
||||||
import lombok.AccessLevel;
|
import lombok.AccessLevel;
|
||||||
import lombok.NonNull;
|
import lombok.NonNull;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
@@ -268,11 +267,6 @@ class ExecutableFindOperationSupport implements ExecutableFindOperation {
|
|||||||
this.limit = Optional.of(limit);
|
this.limit = Optional.of(limit);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public ReadPreference getReadPreference() {
|
|
||||||
return delegate.getReadPreference();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2017-2020 the original author or authors.
|
* Copyright 2017-2019 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2017-2020 the original author or authors.
|
* Copyright 2017-2019 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2018-2020 the original author or authors.
|
* Copyright 2018-2019 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2018-2020 the original author or authors.
|
* Copyright 2018-2019 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2017-2020 the original author or authors.
|
* Copyright 2017-2019 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2017-2020 the original author or authors.
|
* Copyright 2017-2019 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2017-2020 the original author or authors.
|
* Copyright 2017-2019 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -17,10 +17,8 @@ package org.springframework.data.mongodb.core;
|
|||||||
|
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
import org.springframework.data.mongodb.core.aggregation.AggregationUpdate;
|
|
||||||
import org.springframework.data.mongodb.core.query.Query;
|
import org.springframework.data.mongodb.core.query.Query;
|
||||||
import org.springframework.data.mongodb.core.query.Update;
|
import org.springframework.data.mongodb.core.query.Update;
|
||||||
import org.springframework.data.mongodb.core.query.UpdateDefinition;
|
|
||||||
import org.springframework.lang.Nullable;
|
import org.springframework.lang.Nullable;
|
||||||
|
|
||||||
import com.mongodb.client.result.UpdateResult;
|
import com.mongodb.client.result.UpdateResult;
|
||||||
@@ -153,16 +151,13 @@ public interface ExecutableUpdateOperation {
|
|||||||
interface UpdateWithUpdate<T> {
|
interface UpdateWithUpdate<T> {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the {@link UpdateDefinition} to be applied.
|
* Set the {@link Update} to be applied.
|
||||||
*
|
*
|
||||||
* @param update must not be {@literal null}.
|
* @param update must not be {@literal null}.
|
||||||
* @return new instance of {@link TerminatingUpdate}.
|
* @return new instance of {@link TerminatingUpdate}.
|
||||||
* @throws IllegalArgumentException if update is {@literal null}.
|
* @throws IllegalArgumentException if update is {@literal null}.
|
||||||
* @since 3.0
|
|
||||||
* @see Update
|
|
||||||
* @see AggregationUpdate
|
|
||||||
*/
|
*/
|
||||||
TerminatingUpdate<T> apply(UpdateDefinition update);
|
TerminatingUpdate<T> apply(Update update);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Specify {@code replacement} object.
|
* Specify {@code replacement} object.
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user