Compare commits
295 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ede2f5eeda | ||
|
|
49feb3d55e | ||
|
|
3e41264aeb | ||
|
|
dd5b1f7989 | ||
|
|
f4adc29c60 | ||
|
|
85807975e9 | ||
|
|
f6f9bba2ff | ||
|
|
32b992b918 | ||
|
|
91c69eed10 | ||
|
|
314156a4cd | ||
|
|
1f5e2c714d | ||
|
|
949b1e596e | ||
|
|
46d4206297 | ||
|
|
86db5f8265 | ||
|
|
5aa4eb058d | ||
|
|
71a077a599 | ||
|
|
25840d61fc | ||
|
|
553912a380 | ||
|
|
b418fa16e5 | ||
|
|
2f627cc02d | ||
|
|
ba1b769c1a | ||
|
|
47747aca8d | ||
|
|
ce8a97b1e5 | ||
|
|
a567cb1f7b | ||
|
|
b42081f05b | ||
|
|
9380cfea08 | ||
|
|
3466281a8b | ||
|
|
26e8b3a8ec | ||
|
|
b0814d334f | ||
|
|
33624fcc6a | ||
|
|
7e63897b87 | ||
|
|
2c446f5693 | ||
|
|
e05dffec18 | ||
|
|
47dd74b8d6 | ||
|
|
c7e4673e29 | ||
|
|
9d694dbdd5 | ||
|
|
74179a9af9 | ||
|
|
c1c5e3bdbb | ||
|
|
24978577cc | ||
|
|
c43ae822be | ||
|
|
881a69864f | ||
|
|
dc054a793f | ||
|
|
f048fb6800 | ||
|
|
20fdb0e63c | ||
|
|
7e3ff86d36 | ||
|
|
54c9933535 | ||
|
|
1f07a3eb29 | ||
|
|
76f4328498 | ||
|
|
c572ca4e3b | ||
|
|
f1d214b87d | ||
|
|
f4854a15f9 | ||
|
|
b491d6ce81 | ||
|
|
0b482f8dcf | ||
|
|
9f1b27c305 | ||
|
|
b6e69606b1 | ||
|
|
0429ea69fa | ||
|
|
383b7031dd | ||
|
|
e8f0ed8d59 | ||
|
|
f90d30472b | ||
|
|
cec1c8305a | ||
|
|
cd714b1ba8 | ||
|
|
0a83eec8b2 | ||
|
|
3a28fb18f6 | ||
|
|
6e65d2fd1d | ||
|
|
8d63c10e07 | ||
|
|
aee5f71229 | ||
|
|
5cc044b72c | ||
|
|
45243468ec | ||
|
|
5a162bdbaf | ||
|
|
1d15eaf42e | ||
|
|
0076e294ae | ||
|
|
cd8603caa3 | ||
|
|
aac1c3406b | ||
|
|
3a16cc80c5 | ||
|
|
c2ba361d24 | ||
|
|
eb5a331822 | ||
|
|
3100e0db01 | ||
|
|
4efaed4741 | ||
|
|
00bbf439c0 | ||
|
|
87476f9a91 | ||
|
|
7bcf686b40 | ||
|
|
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 |
1
.github/PULL_REQUEST_TEMPLATE.md
vendored
1
.github/PULL_REQUEST_TEMPLATE.md
vendored
@@ -6,6 +6,7 @@ Make sure that:
|
|||||||
-->
|
-->
|
||||||
|
|
||||||
- [ ] You have read the [Spring Data contribution guidelines](https://github.com/spring-projects/spring-data-build/blob/master/CONTRIBUTING.adoc).
|
- [ ] You have read the [Spring Data contribution guidelines](https://github.com/spring-projects/spring-data-build/blob/master/CONTRIBUTING.adoc).
|
||||||
|
- [ ] There is a ticket in the bug tracker for the project in our [JIRA](https://jira.spring.io/browse/DATAMONGO).
|
||||||
- [ ] You use the code formatters provided [here](https://github.com/spring-projects/spring-data-build/tree/master/etc/ide) and have them applied to your changes. Don’t submit any formatting related changes.
|
- [ ] You use the code formatters provided [here](https://github.com/spring-projects/spring-data-build/tree/master/etc/ide) and have them applied to your changes. Don’t submit any formatting related changes.
|
||||||
- [ ] You submit test cases (unit or integration tests) that back your changes.
|
- [ ] You submit test cases (unit or integration tests) that back your changes.
|
||||||
- [ ] You added yourself as author in the headers of the classes you touched. Amend the date range in the Apache license header if needed. For new types, add the license header (copy from another file and set the current year only).
|
- [ ] You added yourself as author in the headers of the classes you touched. Amend the date range in the Apache license header if needed. For new types, add the license header (copy from another file and set the current year only).
|
||||||
|
|||||||
47
.github/workflows/project.yml
vendored
47
.github/workflows/project.yml
vendored
@@ -1,47 +0,0 @@
|
|||||||
# GitHub Actions to automate GitHub issues for Spring Data Project Management
|
|
||||||
|
|
||||||
name: Spring Data GitHub Issues
|
|
||||||
|
|
||||||
on:
|
|
||||||
issues:
|
|
||||||
types: [opened, edited, reopened]
|
|
||||||
issue_comment:
|
|
||||||
types: [created]
|
|
||||||
pull_request_target:
|
|
||||||
types: [opened, edited, reopened]
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
Inbox:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
if: github.repository_owner == 'spring-projects' && (github.event.action == 'opened' || github.event.action == 'reopened') && github.event.pull_request == null
|
|
||||||
steps:
|
|
||||||
- name: Create or Update Issue Card
|
|
||||||
uses: peter-evans/create-or-update-project-card@v1.1.2
|
|
||||||
with:
|
|
||||||
project-name: 'Spring Data'
|
|
||||||
column-name: 'Inbox'
|
|
||||||
project-location: 'spring-projects'
|
|
||||||
token: ${{ secrets.GH_ISSUES_TOKEN_SPRING_DATA }}
|
|
||||||
Pull-Request:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
if: github.repository_owner == 'spring-projects' && (github.event.action == 'opened' || github.event.action == 'reopened') && github.event.pull_request != null
|
|
||||||
steps:
|
|
||||||
- name: Create or Update Pull Request Card
|
|
||||||
uses: peter-evans/create-or-update-project-card@v1.1.2
|
|
||||||
with:
|
|
||||||
project-name: 'Spring Data'
|
|
||||||
column-name: 'Review pending'
|
|
||||||
project-location: 'spring-projects'
|
|
||||||
issue-number: ${{ github.event.pull_request.number }}
|
|
||||||
token: ${{ secrets.GH_ISSUES_TOKEN_SPRING_DATA }}
|
|
||||||
Feedback-Provided:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
if: github.repository_owner == 'spring-projects' && github.event_name == 'issue_comment' && github.event.action == 'created' && github.actor != 'spring-projects-issues' && github.event.pull_request == null && github.event.issue.state == 'open' && contains(toJSON(github.event.issue.labels), 'waiting-for-feedback')
|
|
||||||
steps:
|
|
||||||
- name: Update Project Card
|
|
||||||
uses: peter-evans/create-or-update-project-card@v1.1.2
|
|
||||||
with:
|
|
||||||
project-name: 'Spring Data'
|
|
||||||
column-name: 'Feedback provided'
|
|
||||||
project-location: 'spring-projects'
|
|
||||||
token: ${{ secrets.GH_ISSUES_TOKEN_SPRING_DATA }}
|
|
||||||
3
.mvn/wrapper/maven-wrapper.properties
vendored
3
.mvn/wrapper/maven-wrapper.properties
vendored
@@ -1,2 +1 @@
|
|||||||
#Mon Oct 11 14:30:24 CEST 2021
|
distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.5.4/apache-maven-3.5.4-bin.zip
|
||||||
distributionUrl=https\://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.8.3/apache-maven-3.8.3-bin.zip
|
|
||||||
2
CI.adoc
2
CI.adoc
@@ -1,6 +1,6 @@
|
|||||||
= Continuous Integration
|
= Continuous Integration
|
||||||
|
|
||||||
image:https://jenkins.spring.io/buildStatus/icon?job=spring-data-mongodb%2Fmain&subject=Moore%20(main)[link=https://jenkins.spring.io/view/SpringData/job/spring-data-mongodb/]
|
image:https://jenkins.spring.io/buildStatus/icon?job=spring-data-mongodb%2Fmaster&subject=Moore%20(master)[link=https://jenkins.spring.io/view/SpringData/job/spring-data-mongodb/]
|
||||||
image:https://jenkins.spring.io/buildStatus/icon?job=spring-data-mongodb%2F2.1.x&subject=Lovelace%20(2.1.x)[link=https://jenkins.spring.io/view/SpringData/job/spring-data-mongodb/]
|
image:https://jenkins.spring.io/buildStatus/icon?job=spring-data-mongodb%2F2.1.x&subject=Lovelace%20(2.1.x)[link=https://jenkins.spring.io/view/SpringData/job/spring-data-mongodb/]
|
||||||
image:https://jenkins.spring.io/buildStatus/icon?job=spring-data-mongodb%2F1.10.x&subject=Ingalls%20(1.10.x)[link=https://jenkins.spring.io/view/SpringData/job/spring-data-mongodb/]
|
image:https://jenkins.spring.io/buildStatus/icon?job=spring-data-mongodb%2F1.10.x&subject=Ingalls%20(1.10.x)[link=https://jenkins.spring.io/view/SpringData/job/spring-data-mongodb/]
|
||||||
|
|
||||||
|
|||||||
27
CODE_OF_CONDUCT.adoc
Normal file
27
CODE_OF_CONDUCT.adoc
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
= Contributor Code of Conduct
|
||||||
|
|
||||||
|
As contributors and maintainers of this project, and in the interest of fostering an open and welcoming community, we pledge to respect all people who contribute through reporting issues, posting feature requests, updating documentation, submitting pull requests or patches, and other activities.
|
||||||
|
|
||||||
|
We are committed to making participation in this project a harassment-free experience for everyone, regardless of level of experience, gender, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, ethnicity, age, religion, or nationality.
|
||||||
|
|
||||||
|
Examples of unacceptable behavior by participants include:
|
||||||
|
|
||||||
|
* The use of sexualized language or imagery
|
||||||
|
* Personal attacks
|
||||||
|
* Trolling or insulting/derogatory comments
|
||||||
|
* Public or private harassment
|
||||||
|
* Publishing other's private information, such as physical or electronic addresses,
|
||||||
|
without explicit permission
|
||||||
|
* Other unethical or unprofessional conduct
|
||||||
|
|
||||||
|
Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.
|
||||||
|
|
||||||
|
By adopting this Code of Conduct, project maintainers commit themselves to fairly and consistently applying these principles to every aspect of managing this project. Project maintainers who do not follow or enforce the Code of Conduct may be permanently removed from the project team.
|
||||||
|
|
||||||
|
This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community.
|
||||||
|
|
||||||
|
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting a project maintainer at spring-code-of-conduct@pivotal.io.
|
||||||
|
All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances.
|
||||||
|
Maintainers are obligated to maintain confidentiality with regard to the reporter of an incident.
|
||||||
|
|
||||||
|
This Code of Conduct is adapted from the https://contributor-covenant.org[Contributor Covenant], version 1.3.0, available at https://contributor-covenant.org/version/1/3/0/[contributor-covenant.org/version/1/3/0/].
|
||||||
@@ -1,3 +1,3 @@
|
|||||||
= Spring Data contribution guidelines
|
= Spring Data contribution guidelines
|
||||||
|
|
||||||
You find the contribution guidelines for Spring Data projects https://github.com/spring-projects/spring-data-build/blob/main/CONTRIBUTING.adoc[here].
|
You find the contribution guidelines for Spring Data projects https://github.com/spring-projects/spring-data-build/blob/master/CONTRIBUTING.adoc[here].
|
||||||
|
|||||||
268
Jenkinsfile
vendored
268
Jenkinsfile
vendored
@@ -1,169 +1,123 @@
|
|||||||
pipeline {
|
pipeline {
|
||||||
agent none
|
agent none
|
||||||
|
|
||||||
triggers {
|
triggers {
|
||||||
pollSCM 'H/10 * * * *'
|
pollSCM 'H/10 * * * *'
|
||||||
upstream(upstreamProjects: "spring-data-commons/main", threshold: hudson.model.Result.SUCCESS)
|
upstream(upstreamProjects: "spring-data-commons/2.1.x", threshold: hudson.model.Result.SUCCESS)
|
||||||
}
|
}
|
||||||
|
|
||||||
options {
|
options {
|
||||||
disableConcurrentBuilds()
|
disableConcurrentBuilds()
|
||||||
buildDiscarder(logRotator(numToKeepStr: '14'))
|
buildDiscarder(logRotator(numToKeepStr: '14'))
|
||||||
}
|
}
|
||||||
|
|
||||||
stages {
|
stages {
|
||||||
stage("Docker images") {
|
stage("Test") {
|
||||||
parallel {
|
when {
|
||||||
stage('Publish JDK 17 + MongoDB 4.4') {
|
anyOf {
|
||||||
when {
|
branch '2.1.x'
|
||||||
changeset "ci/openjdk17-mongodb-4.4/**"
|
not { triggeredBy 'UpstreamCause' }
|
||||||
}
|
}
|
||||||
agent { label 'data' }
|
}
|
||||||
options { timeout(time: 30, unit: 'MINUTES') }
|
parallel {
|
||||||
|
stage("test: baseline") {
|
||||||
steps {
|
agent {
|
||||||
script {
|
docker {
|
||||||
def image = docker.build("springci/spring-data-openjdk17-with-mongodb-4.4.4", "ci/openjdk17-mongodb-4.4/")
|
image 'springci/spring-data-openjdk8-with-mongodb-4.0:latest'
|
||||||
docker.withRegistry('', 'hub.docker.com-springbuildmaster') {
|
label 'data'
|
||||||
image.push()
|
args '-v $HOME:/tmp/jenkins-home'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
options { timeout(time: 30, unit: 'MINUTES') }
|
||||||
}
|
steps {
|
||||||
stage('Publish JDK 17 + MongoDB 5.0') {
|
sh 'rm -rf ?'
|
||||||
when {
|
sh 'mkdir -p /tmp/mongodb/db /tmp/mongodb/log'
|
||||||
changeset "ci/openjdk17-mongodb-5.0/**"
|
sh 'mongod --dbpath /tmp/mongodb/db --replSet rs0 --fork --logpath /tmp/mongodb/log/mongod.log &'
|
||||||
}
|
sh 'sleep 10'
|
||||||
agent { label 'data' }
|
sh 'mongo --eval "rs.initiate({_id: \'rs0\', members:[{_id: 0, host: \'127.0.0.1:27017\'}]});"'
|
||||||
options { timeout(time: 30, unit: 'MINUTES') }
|
sh 'sleep 15'
|
||||||
|
sh 'MAVEN_OPTS="-Duser.name=jenkins -Duser.home=/tmp/jenkins-home" ./mvnw clean dependency:list test -Dsort -U -B'
|
||||||
steps {
|
}
|
||||||
script {
|
|
||||||
def image = docker.build("springci/spring-data-openjdk17-with-mongodb-5.0.3", "ci/openjdk17-mongodb-5.0/")
|
|
||||||
docker.withRegistry('', 'hub.docker.com-springbuildmaster') {
|
|
||||||
image.push()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
stage("test: baseline Mongo 5.0 (jdk17)") {
|
}
|
||||||
when {
|
}
|
||||||
beforeAgent(true)
|
|
||||||
anyOf {
|
|
||||||
branch(pattern: "main|(\\d\\.\\d\\.x)", comparator: "REGEXP")
|
|
||||||
not { triggeredBy 'UpstreamCause' }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
agent {
|
|
||||||
label 'data'
|
|
||||||
}
|
|
||||||
options { timeout(time: 30, unit: 'MINUTES') }
|
|
||||||
environment {
|
|
||||||
ARTIFACTORY = credentials('02bd1690-b54f-4c9f-819d-a77cb7a9822c')
|
|
||||||
}
|
|
||||||
steps {
|
|
||||||
script {
|
|
||||||
docker.withRegistry('', 'hub.docker.com-springbuildmaster') {
|
|
||||||
docker.image('springci/spring-data-openjdk17-with-mongodb-5.0.3:latest').inside('-v $HOME:/tmp/jenkins-home') {
|
|
||||||
sh 'mkdir -p /tmp/mongodb/db /tmp/mongodb/log'
|
|
||||||
sh 'mongod --setParameter transactionLifetimeLimitSeconds=90 --setParameter maxTransactionLockRequestTimeoutMillis=10000 --dbpath /tmp/mongodb/db --replSet rs0 --fork --logpath /tmp/mongodb/log/mongod.log &'
|
|
||||||
sh 'sleep 10'
|
|
||||||
sh 'mongo --eval "rs.initiate({_id: \'rs0\', members:[{_id: 0, host: \'127.0.0.1:27017\'}]});"'
|
|
||||||
sh 'sleep 15'
|
|
||||||
sh 'MAVEN_OPTS="-Duser.name=jenkins -Duser.home=/tmp/jenkins-home" ./mvnw -s settings.xml clean dependency:list test -Duser.name=jenkins -Dsort -U -B'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
stage("Test other configurations") {
|
stage('Release to artifactory') {
|
||||||
when {
|
when {
|
||||||
beforeAgent(true)
|
branch 'issue/*'
|
||||||
allOf {
|
not { triggeredBy 'UpstreamCause' }
|
||||||
branch(pattern: "main|(\\d\\.\\d\\.x)", comparator: "REGEXP")
|
}
|
||||||
not { triggeredBy 'UpstreamCause' }
|
agent {
|
||||||
}
|
docker {
|
||||||
}
|
image 'adoptopenjdk/openjdk8:latest'
|
||||||
parallel {
|
label 'data'
|
||||||
stage("test: baseline MongoDB 4.4 (jdk17)") {
|
args '-v $HOME:/tmp/jenkins-home'
|
||||||
agent {
|
}
|
||||||
label 'data'
|
}
|
||||||
}
|
options { timeout(time: 20, unit: 'MINUTES') }
|
||||||
options { timeout(time: 30, unit: 'MINUTES') }
|
|
||||||
environment {
|
|
||||||
ARTIFACTORY = credentials('02bd1690-b54f-4c9f-819d-a77cb7a9822c')
|
|
||||||
}
|
|
||||||
steps {
|
|
||||||
script {
|
|
||||||
docker.withRegistry('', 'hub.docker.com-springbuildmaster') {
|
|
||||||
docker.image('springci/spring-data-openjdk17-with-mongodb-4.4.4:latest').inside('-v $HOME:/tmp/jenkins-home') {
|
|
||||||
sh 'mkdir -p /tmp/mongodb/db /tmp/mongodb/log'
|
|
||||||
sh 'mongod --setParameter transactionLifetimeLimitSeconds=90 --setParameter maxTransactionLockRequestTimeoutMillis=10000 --dbpath /tmp/mongodb/db --replSet rs0 --fork --logpath /tmp/mongodb/log/mongod.log &'
|
|
||||||
sh 'sleep 10'
|
|
||||||
sh 'mongo --eval "rs.initiate({_id: \'rs0\', members:[{_id: 0, host: \'127.0.0.1:27017\'}]});"'
|
|
||||||
sh 'sleep 15'
|
|
||||||
sh 'MAVEN_OPTS="-Duser.name=jenkins -Duser.home=/tmp/jenkins-home" ./mvnw -s settings.xml clean dependency:list test -Duser.name=jenkins -Dsort -U -B'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
stage('Release to artifactory') {
|
environment {
|
||||||
when {
|
ARTIFACTORY = credentials('02bd1690-b54f-4c9f-819d-a77cb7a9822c')
|
||||||
beforeAgent(true)
|
}
|
||||||
anyOf {
|
|
||||||
branch(pattern: "main|(\\d\\.\\d\\.x)", comparator: "REGEXP")
|
|
||||||
not { triggeredBy 'UpstreamCause' }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
agent {
|
|
||||||
label 'data'
|
|
||||||
}
|
|
||||||
options { timeout(time: 20, unit: 'MINUTES') }
|
|
||||||
|
|
||||||
environment {
|
steps {
|
||||||
ARTIFACTORY = credentials('02bd1690-b54f-4c9f-819d-a77cb7a9822c')
|
sh 'rm -rf ?'
|
||||||
}
|
sh 'MAVEN_OPTS="-Duser.name=jenkins -Duser.home=/tmp/jenkins-home" ./mvnw -Pci,artifactory ' +
|
||||||
|
'-Dartifactory.server=https://repo.spring.io ' +
|
||||||
|
"-Dartifactory.username=${ARTIFACTORY_USR} " +
|
||||||
|
"-Dartifactory.password=${ARTIFACTORY_PSW} " +
|
||||||
|
"-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'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
steps {
|
stage('Release to artifactory with docs') {
|
||||||
script {
|
when {
|
||||||
docker.withRegistry('', 'hub.docker.com-springbuildmaster') {
|
branch '2.1.x'
|
||||||
docker.image('openjdk:17-bullseye').inside('-v $HOME:/tmp/jenkins-home') {
|
}
|
||||||
sh 'MAVEN_OPTS="-Duser.name=jenkins -Duser.home=/tmp/jenkins-home" ./mvnw -s settings.xml -Pci,artifactory ' +
|
agent {
|
||||||
'-Dartifactory.server=https://repo.spring.io ' +
|
docker {
|
||||||
"-Dartifactory.username=${ARTIFACTORY_USR} " +
|
image 'adoptopenjdk/openjdk8:latest'
|
||||||
"-Dartifactory.password=${ARTIFACTORY_PSW} " +
|
label 'data'
|
||||||
"-Dartifactory.staging-repository=libs-snapshot-local " +
|
args '-v $HOME:/tmp/jenkins-home'
|
||||||
"-Dartifactory.build-name=spring-data-mongodb " +
|
}
|
||||||
"-Dartifactory.build-number=${BUILD_NUMBER} " +
|
}
|
||||||
'-Dmaven.test.skip=true clean deploy -U -B'
|
options { timeout(time: 20, unit: 'MINUTES') }
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
post {
|
environment {
|
||||||
changed {
|
ARTIFACTORY = credentials('02bd1690-b54f-4c9f-819d-a77cb7a9822c')
|
||||||
script {
|
}
|
||||||
slackSend(
|
|
||||||
color: (currentBuild.currentResult == 'SUCCESS') ? 'good' : 'danger',
|
steps {
|
||||||
channel: '#spring-data-dev',
|
sh 'rm -rf ?'
|
||||||
message: "${currentBuild.fullDisplayName} - `${currentBuild.currentResult}`\n${env.BUILD_URL}")
|
sh 'MAVEN_OPTS="-Duser.name=jenkins -Duser.home=/tmp/jenkins-home" ./mvnw -Pci,artifactory ' +
|
||||||
emailext(
|
'-Dartifactory.server=https://repo.spring.io ' +
|
||||||
subject: "[${currentBuild.fullDisplayName}] ${currentBuild.currentResult}",
|
"-Dartifactory.username=${ARTIFACTORY_USR} " +
|
||||||
mimeType: 'text/html',
|
"-Dartifactory.password=${ARTIFACTORY_PSW} " +
|
||||||
recipientProviders: [[$class: 'CulpritsRecipientProvider'], [$class: 'RequesterRecipientProvider']],
|
"-Dartifactory.staging-repository=libs-snapshot-local " +
|
||||||
body: "<a href=\"${env.BUILD_URL}\">${currentBuild.fullDisplayName} is reported as ${currentBuild.currentResult}</a>")
|
"-Dartifactory.build-name=spring-data-mongodb-2.1 " +
|
||||||
}
|
"-Dartifactory.build-number=${BUILD_NUMBER} " +
|
||||||
}
|
'-Dmaven.test.skip=true clean deploy -U -B'
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
post {
|
||||||
|
changed {
|
||||||
|
script {
|
||||||
|
slackSend(
|
||||||
|
color: (currentBuild.currentResult == 'SUCCESS') ? 'good' : 'danger',
|
||||||
|
channel: '#spring-data-dev',
|
||||||
|
message: "${currentBuild.fullDisplayName} - `${currentBuild.currentResult}`\n${env.BUILD_URL}")
|
||||||
|
emailext(
|
||||||
|
subject: "[${currentBuild.fullDisplayName}] ${currentBuild.currentResult}",
|
||||||
|
mimeType: 'text/html',
|
||||||
|
recipientProviders: [[$class: 'CulpritsRecipientProvider'], [$class: 'RequesterRecipientProvider']],
|
||||||
|
body: "<a href=\"${env.BUILD_URL}\">${currentBuild.fullDisplayName} is reported as ${currentBuild.currentResult}</a>")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
202
LICENSE.txt
202
LICENSE.txt
@@ -1,202 +0,0 @@
|
|||||||
|
|
||||||
Apache License
|
|
||||||
Version 2.0, January 2004
|
|
||||||
https://www.apache.org/licenses/
|
|
||||||
|
|
||||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
|
||||||
|
|
||||||
1. Definitions.
|
|
||||||
|
|
||||||
"License" shall mean the terms and conditions for use, reproduction,
|
|
||||||
and distribution as defined by Sections 1 through 9 of this document.
|
|
||||||
|
|
||||||
"Licensor" shall mean the copyright owner or entity authorized by
|
|
||||||
the copyright owner that is granting the License.
|
|
||||||
|
|
||||||
"Legal Entity" shall mean the union of the acting entity and all
|
|
||||||
other entities that control, are controlled by, or are under common
|
|
||||||
control with that entity. For the purposes of this definition,
|
|
||||||
"control" means (i) the power, direct or indirect, to cause the
|
|
||||||
direction or management of such entity, whether by contract or
|
|
||||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
|
||||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
|
||||||
|
|
||||||
"You" (or "Your") shall mean an individual or Legal Entity
|
|
||||||
exercising permissions granted by this License.
|
|
||||||
|
|
||||||
"Source" form shall mean the preferred form for making modifications,
|
|
||||||
including but not limited to software source code, documentation
|
|
||||||
source, and configuration files.
|
|
||||||
|
|
||||||
"Object" form shall mean any form resulting from mechanical
|
|
||||||
transformation or translation of a Source form, including but
|
|
||||||
not limited to compiled object code, generated documentation,
|
|
||||||
and conversions to other media types.
|
|
||||||
|
|
||||||
"Work" shall mean the work of authorship, whether in Source or
|
|
||||||
Object form, made available under the License, as indicated by a
|
|
||||||
copyright notice that is included in or attached to the work
|
|
||||||
(an example is provided in the Appendix below).
|
|
||||||
|
|
||||||
"Derivative Works" shall mean any work, whether in Source or Object
|
|
||||||
form, that is based on (or derived from) the Work and for which the
|
|
||||||
editorial revisions, annotations, elaborations, or other modifications
|
|
||||||
represent, as a whole, an original work of authorship. For the purposes
|
|
||||||
of this License, Derivative Works shall not include works that remain
|
|
||||||
separable from, or merely link (or bind by name) to the interfaces of,
|
|
||||||
the Work and Derivative Works thereof.
|
|
||||||
|
|
||||||
"Contribution" shall mean any work of authorship, including
|
|
||||||
the original version of the Work and any modifications or additions
|
|
||||||
to that Work or Derivative Works thereof, that is intentionally
|
|
||||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
|
||||||
or by an individual or Legal Entity authorized to submit on behalf of
|
|
||||||
the copyright owner. For the purposes of this definition, "submitted"
|
|
||||||
means any form of electronic, verbal, or written communication sent
|
|
||||||
to the Licensor or its representatives, including but not limited to
|
|
||||||
communication on electronic mailing lists, source code control systems,
|
|
||||||
and issue tracking systems that are managed by, or on behalf of, the
|
|
||||||
Licensor for the purpose of discussing and improving the Work, but
|
|
||||||
excluding communication that is conspicuously marked or otherwise
|
|
||||||
designated in writing by the copyright owner as "Not a Contribution."
|
|
||||||
|
|
||||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
|
||||||
on behalf of whom a Contribution has been received by Licensor and
|
|
||||||
subsequently incorporated within the Work.
|
|
||||||
|
|
||||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
|
||||||
this License, each Contributor hereby grants to You a perpetual,
|
|
||||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
||||||
copyright license to reproduce, prepare Derivative Works of,
|
|
||||||
publicly display, publicly perform, sublicense, and distribute the
|
|
||||||
Work and such Derivative Works in Source or Object form.
|
|
||||||
|
|
||||||
3. Grant of Patent License. Subject to the terms and conditions of
|
|
||||||
this License, each Contributor hereby grants to You a perpetual,
|
|
||||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
||||||
(except as stated in this section) patent license to make, have made,
|
|
||||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
|
||||||
where such license applies only to those patent claims licensable
|
|
||||||
by such Contributor that are necessarily infringed by their
|
|
||||||
Contribution(s) alone or by combination of their Contribution(s)
|
|
||||||
with the Work to which such Contribution(s) was submitted. If You
|
|
||||||
institute patent litigation against any entity (including a
|
|
||||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
|
||||||
or a Contribution incorporated within the Work constitutes direct
|
|
||||||
or contributory patent infringement, then any patent licenses
|
|
||||||
granted to You under this License for that Work shall terminate
|
|
||||||
as of the date such litigation is filed.
|
|
||||||
|
|
||||||
4. Redistribution. You may reproduce and distribute copies of the
|
|
||||||
Work or Derivative Works thereof in any medium, with or without
|
|
||||||
modifications, and in Source or Object form, provided that You
|
|
||||||
meet the following conditions:
|
|
||||||
|
|
||||||
(a) You must give any other recipients of the Work or
|
|
||||||
Derivative Works a copy of this License; and
|
|
||||||
|
|
||||||
(b) You must cause any modified files to carry prominent notices
|
|
||||||
stating that You changed the files; and
|
|
||||||
|
|
||||||
(c) You must retain, in the Source form of any Derivative Works
|
|
||||||
that You distribute, all copyright, patent, trademark, and
|
|
||||||
attribution notices from the Source form of the Work,
|
|
||||||
excluding those notices that do not pertain to any part of
|
|
||||||
the Derivative Works; and
|
|
||||||
|
|
||||||
(d) If the Work includes a "NOTICE" text file as part of its
|
|
||||||
distribution, then any Derivative Works that You distribute must
|
|
||||||
include a readable copy of the attribution notices contained
|
|
||||||
within such NOTICE file, excluding those notices that do not
|
|
||||||
pertain to any part of the Derivative Works, in at least one
|
|
||||||
of the following places: within a NOTICE text file distributed
|
|
||||||
as part of the Derivative Works; within the Source form or
|
|
||||||
documentation, if provided along with the Derivative Works; or,
|
|
||||||
within a display generated by the Derivative Works, if and
|
|
||||||
wherever such third-party notices normally appear. The contents
|
|
||||||
of the NOTICE file are for informational purposes only and
|
|
||||||
do not modify the License. You may add Your own attribution
|
|
||||||
notices within Derivative Works that You distribute, alongside
|
|
||||||
or as an addendum to the NOTICE text from the Work, provided
|
|
||||||
that such additional attribution notices cannot be construed
|
|
||||||
as modifying the License.
|
|
||||||
|
|
||||||
You may add Your own copyright statement to Your modifications and
|
|
||||||
may provide additional or different license terms and conditions
|
|
||||||
for use, reproduction, or distribution of Your modifications, or
|
|
||||||
for any such Derivative Works as a whole, provided Your use,
|
|
||||||
reproduction, and distribution of the Work otherwise complies with
|
|
||||||
the conditions stated in this License.
|
|
||||||
|
|
||||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
|
||||||
any Contribution intentionally submitted for inclusion in the Work
|
|
||||||
by You to the Licensor shall be under the terms and conditions of
|
|
||||||
this License, without any additional terms or conditions.
|
|
||||||
Notwithstanding the above, nothing herein shall supersede or modify
|
|
||||||
the terms of any separate license agreement you may have executed
|
|
||||||
with Licensor regarding such Contributions.
|
|
||||||
|
|
||||||
6. Trademarks. This License does not grant permission to use the trade
|
|
||||||
names, trademarks, service marks, or product names of the Licensor,
|
|
||||||
except as required for reasonable and customary use in describing the
|
|
||||||
origin of the Work and reproducing the content of the NOTICE file.
|
|
||||||
|
|
||||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
|
||||||
agreed to in writing, Licensor provides the Work (and each
|
|
||||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
|
||||||
implied, including, without limitation, any warranties or conditions
|
|
||||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
|
||||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
|
||||||
appropriateness of using or redistributing the Work and assume any
|
|
||||||
risks associated with Your exercise of permissions under this License.
|
|
||||||
|
|
||||||
8. Limitation of Liability. In no event and under no legal theory,
|
|
||||||
whether in tort (including negligence), contract, or otherwise,
|
|
||||||
unless required by applicable law (such as deliberate and grossly
|
|
||||||
negligent acts) or agreed to in writing, shall any Contributor be
|
|
||||||
liable to You for damages, including any direct, indirect, special,
|
|
||||||
incidental, or consequential damages of any character arising as a
|
|
||||||
result of this License or out of the use or inability to use the
|
|
||||||
Work (including but not limited to damages for loss of goodwill,
|
|
||||||
work stoppage, computer failure or malfunction, or any and all
|
|
||||||
other commercial damages or losses), even if such Contributor
|
|
||||||
has been advised of the possibility of such damages.
|
|
||||||
|
|
||||||
9. Accepting Warranty or Additional Liability. While redistributing
|
|
||||||
the Work or Derivative Works thereof, You may choose to offer,
|
|
||||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
|
||||||
or other liability obligations and/or rights consistent with this
|
|
||||||
License. However, in accepting such obligations, You may act only
|
|
||||||
on Your own behalf and on Your sole responsibility, not on behalf
|
|
||||||
of any other Contributor, and only if You agree to indemnify,
|
|
||||||
defend, and hold each Contributor harmless for any liability
|
|
||||||
incurred by, or claims asserted against, such Contributor by reason
|
|
||||||
of your accepting any such warranty or additional liability.
|
|
||||||
|
|
||||||
END OF TERMS AND CONDITIONS
|
|
||||||
|
|
||||||
APPENDIX: How to apply the Apache License to your work.
|
|
||||||
|
|
||||||
To apply the Apache License to your work, attach the following
|
|
||||||
boilerplate notice, with the fields enclosed by brackets "{}"
|
|
||||||
replaced with your own identifying information. (Don't include
|
|
||||||
the brackets!) The text should be enclosed in the appropriate
|
|
||||||
comment syntax for the file format. We also recommend that a
|
|
||||||
file or class name and description of purpose be included on the
|
|
||||||
same "printed page" as the copyright notice for easier
|
|
||||||
identification within third-party archives.
|
|
||||||
|
|
||||||
Copyright {yyyy} {name of copyright owner}
|
|
||||||
|
|
||||||
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.
|
|
||||||
274
README.adoc
274
README.adoc
@@ -1,6 +1,6 @@
|
|||||||
image:https://spring.io/badges/spring-data-mongodb/ga.svg[Spring Data MongoDB,link=https://projects.spring.io/spring-data-mongodb#quick-start] image:https://spring.io/badges/spring-data-mongodb/snapshot.svg[Spring Data MongoDB,link=https://projects.spring.io/spring-data-mongodb#quick-start]
|
image:https://spring.io/badges/spring-data-mongodb/ga.svg[Spring Data MongoDB,link=https://projects.spring.io/spring-data-mongodb#quick-start] image:https://spring.io/badges/spring-data-mongodb/snapshot.svg[Spring Data MongoDB,link=https://projects.spring.io/spring-data-mongodb#quick-start]
|
||||||
|
|
||||||
= Spring Data MongoDB image:https://jenkins.spring.io/buildStatus/icon?job=spring-data-mongodb%2Fmain&subject=Build[link=https://jenkins.spring.io/view/SpringData/job/spring-data-mongodb/] https://gitter.im/spring-projects/spring-data[image:https://badges.gitter.im/spring-projects/spring-data.svg[Gitter]]
|
= Spring Data MongoDB image:https://jenkins.spring.io/buildStatus/icon?job=spring-data-mongodb%2Fmaster&subject=Build[link=https://jenkins.spring.io/view/SpringData/job/spring-data-mongodb/] https://gitter.im/spring-projects/spring-data[image:https://badges.gitter.im/spring-projects/spring-data.svg[Gitter]]
|
||||||
|
|
||||||
The primary goal of the https://projects.spring.io/spring-data[Spring Data] project is to make it easier to build Spring-powered applications that use new data access technologies such as non-relational databases, map-reduce frameworks, and cloud based data services.
|
The primary goal of the https://projects.spring.io/spring-data[Spring Data] project is to make it easier to build Spring-powered applications that use new data access technologies such as non-relational databases, map-reduce frameworks, and cloud based data services.
|
||||||
|
|
||||||
@@ -8,12 +8,10 @@ The Spring Data MongoDB project aims to provide a familiar and consistent Spring
|
|||||||
The Spring Data MongoDB project provides integration with the MongoDB document database.
|
The Spring Data MongoDB project provides integration with the MongoDB document database.
|
||||||
Key functional areas of Spring Data MongoDB are a POJO centric model for interacting with a MongoDB `+Document+` and easily writing a repository style data access layer.
|
Key functional areas of Spring Data MongoDB are a POJO centric model for interacting with a MongoDB `+Document+` and easily writing a repository style data access layer.
|
||||||
|
|
||||||
[[code-of-conduct]]
|
|
||||||
== Code of Conduct
|
== Code of Conduct
|
||||||
|
|
||||||
This project is governed by the https://github.com/spring-projects/.github/blob/e3cc2ff230d8f1dca06535aa6b5a4a23815861d4/CODE_OF_CONDUCT.md[Spring Code of Conduct]. By participating, you are expected to uphold this code of conduct. Please report unacceptable behavior to spring-code-of-conduct@pivotal.io.
|
This project is governed by the link:CODE_OF_CONDUCT.adoc[Spring Code of Conduct]. By participating, you are expected to uphold this code of conduct. Please report unacceptable behavior to spring-code-of-conduct@pivotal.io.
|
||||||
|
|
||||||
[[getting-started]]
|
|
||||||
== Getting Started
|
== Getting Started
|
||||||
|
|
||||||
Here is a quick teaser of an application using Spring Data Repositories in Java:
|
Here is a quick teaser of an application using Spring Data Repositories in Java:
|
||||||
@@ -52,7 +50,12 @@ public class MyService {
|
|||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
@EnableMongoRepositories
|
@EnableMongoRepositories
|
||||||
class ApplicationConfig extends AbstractMongoClientConfiguration {
|
class ApplicationConfig extends AbstractMongoConfiguration {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MongoClient mongoClient() {
|
||||||
|
return new MongoClient();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected String getDatabaseName() {
|
protected String getDatabaseName() {
|
||||||
@@ -61,7 +64,6 @@ class ApplicationConfig extends AbstractMongoClientConfiguration {
|
|||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
[[maven-configuration]]
|
|
||||||
=== Maven configuration
|
=== Maven configuration
|
||||||
|
|
||||||
Add the Maven dependency:
|
Add the Maven dependency:
|
||||||
@@ -71,166 +73,27 @@ Add the Maven dependency:
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework.data</groupId>
|
<groupId>org.springframework.data</groupId>
|
||||||
<artifactId>spring-data-mongodb</artifactId>
|
<artifactId>spring-data-mongodb</artifactId>
|
||||||
<version>${version}</version>
|
<version>${version}.RELEASE</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
----
|
----
|
||||||
|
|
||||||
If you'd rather like the latest snapshots of the upcoming major version, use our Maven snapshot repository
|
If you'd rather like the latest snapshots of the upcoming major version, use our Maven snapshot repository and declare the appropriate dependency version.
|
||||||
and declare the appropriate dependency version.
|
|
||||||
|
|
||||||
[source,xml]
|
[source,xml]
|
||||||
----
|
----
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework.data</groupId>
|
<groupId>org.springframework.data</groupId>
|
||||||
<artifactId>spring-data-mongodb</artifactId>
|
<artifactId>spring-data-mongodb</artifactId>
|
||||||
<version>${version}-SNAPSHOT</version>
|
<version>${version}.BUILD-SNAPSHOT</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<repository>
|
<repository>
|
||||||
<id>spring-snapshot</id>
|
<id>spring-libs-snapshot</id>
|
||||||
<name>Spring Snapshot Repository</name>
|
<name>Spring Snapshot Repository</name>
|
||||||
<url>https://repo.spring.io/snapshot</url>
|
<url>https://repo.spring.io/libs-snapshot</url>
|
||||||
</repository>
|
</repository>
|
||||||
----
|
----
|
||||||
|
|
||||||
== Upgrading from 2.x
|
|
||||||
|
|
||||||
The 4.0 MongoDB Java Driver does no longer support certain features that have already been deprecated in one of the last minor versions.
|
|
||||||
Some of the changes affect the initial setup configuration as well as compile/runtime features. We summarized the most typical changes one might encounter.
|
|
||||||
|
|
||||||
=== XML Namespace
|
|
||||||
|
|
||||||
.Changed XML Namespace Elements and Attributes:
|
|
||||||
|===
|
|
||||||
| Element / Attribute | 2.x | 3.x
|
|
||||||
|
|
||||||
| `<mongo:mongo-client />`
|
|
||||||
| Used to create a `com.mongodb.MongoClient`
|
|
||||||
| Now exposes a `com.mongodb.client.MongoClient`
|
|
||||||
|
|
||||||
| `<mongo:mongo-client replica-set="..." />`
|
|
||||||
| Was a comma delimited list of replica set members (host/port)
|
|
||||||
| Now defines the replica set name. +
|
|
||||||
Use `<mongo:client-settings cluster-hosts="..." />` instead
|
|
||||||
|
|
||||||
| `<mongo:db-factory writeConcern="..." />`
|
|
||||||
| NONE, NORMAL, SAFE, FSYNC_SAFE, REPLICAS_SAFE, MAJORITY
|
|
||||||
| W1, W2, W3, UNAKNOWLEDGED, AKNOWLEDGED, JOURNALED, MAJORITY
|
|
||||||
|===
|
|
||||||
|
|
||||||
.Removed XML Namespace Elements and Attributes:
|
|
||||||
|===
|
|
||||||
| Element / Attribute | Replacement in 3.x | Comment
|
|
||||||
|
|
||||||
| `<mongo:db-factory mongo-ref="..." />`
|
|
||||||
| `<mongo:db-factory mongo-client-ref="..." />`
|
|
||||||
| Referencing a `com.mongodb.client.MongoClient`.
|
|
||||||
|
|
||||||
| `<mongo:mongo-client credentials="..." />`
|
|
||||||
| `<mongo:mongo-client credential="..." />`
|
|
||||||
| Single authentication data instead of list.
|
|
||||||
|
|
||||||
| `<mongo:client-options />`
|
|
||||||
| `<mongo:client-settings />`
|
|
||||||
| See `com.mongodb.MongoClientSettings` for details.
|
|
||||||
|===
|
|
||||||
|
|
||||||
.New XML Namespace Elements and Attributes:
|
|
||||||
|===
|
|
||||||
| Element | Comment
|
|
||||||
|
|
||||||
| `<mongo:db-factory mongo-client-ref="..." />`
|
|
||||||
| Replacement for `<mongo:db-factory mongo-ref="..." />`
|
|
||||||
|
|
||||||
| `<mongo:db-factory connection-string="..." />`
|
|
||||||
| Replacement for `uri` and `client-uri`.
|
|
||||||
|
|
||||||
| `<mongo:mongo-client connection-string="..." />`
|
|
||||||
| Replacement for `uri` and `client-uri`.
|
|
||||||
|
|
||||||
| `<mongo:client-settings />`
|
|
||||||
| Namespace element for `com.mongodb.MongoClientSettings`.
|
|
||||||
|
|
||||||
|===
|
|
||||||
|
|
||||||
=== Java Configuration
|
|
||||||
|
|
||||||
.Java API changes
|
|
||||||
|===
|
|
||||||
| Type | Comment
|
|
||||||
|
|
||||||
| `MongoClientFactoryBean`
|
|
||||||
| Creates `com.mongodb.client.MongoClient` instead of `com.mongodb.MongoClient` +
|
|
||||||
Uses `MongoClientSettings` instead of `MongoClientOptions`.
|
|
||||||
|
|
||||||
| `MongoDataIntegrityViolationException`
|
|
||||||
| Uses `WriteConcernResult` instead of `WriteResult`.
|
|
||||||
|
|
||||||
| `BulkOperationException`
|
|
||||||
| Uses `MongoBulkWriteException` and `com.mongodb.bulk.BulkWriteError` instead of `BulkWriteException` and `com.mongodb.BulkWriteError`
|
|
||||||
|
|
||||||
| `ReactiveMongoClientFactoryBean`
|
|
||||||
| Uses `com.mongodb.MongoClientSettings` instead of `com.mongodb.async.client.MongoClientSettings`
|
|
||||||
|
|
||||||
| `ReactiveMongoClientSettingsFactoryBean`
|
|
||||||
| Now produces `com.mongodb.MongoClientSettings` instead of `com.mongodb.async.client.MongoClientSettings`
|
|
||||||
|===
|
|
||||||
|
|
||||||
.Removed Java API:
|
|
||||||
|===
|
|
||||||
| 2.x | Replacement in 3.x | Comment
|
|
||||||
|
|
||||||
| `MongoClientOptionsFactoryBean`
|
|
||||||
| `MongoClientSettingsFactoryBean`
|
|
||||||
| Creating a `com.mongodb.MongoClientSettings`.
|
|
||||||
|
|
||||||
| `AbstractMongoConfiguration`
|
|
||||||
| `AbstractMongoClientConfiguration` +
|
|
||||||
(Available since 2.1)
|
|
||||||
| Using `com.mongodb.client.MongoClient`.
|
|
||||||
|
|
||||||
| `MongoDbFactory#getLegacyDb()`
|
|
||||||
| -
|
|
||||||
| -
|
|
||||||
|
|
||||||
| `SimpleMongoDbFactory`
|
|
||||||
| `SimpleMongoClientDbFactory` +
|
|
||||||
(Available since 2.1)
|
|
||||||
|
|
|
||||||
|
|
||||||
| `MapReduceOptions#getOutputType()`
|
|
||||||
| `MapReduceOptions#getMapReduceAction()`
|
|
||||||
| Returns `MapReduceAction` instead of `MapReduceCommand.OutputType`.
|
|
||||||
|
|
||||||
| `Meta\|Query` maxScan & snapshot
|
|
||||||
|
|
|
||||||
|
|
|
||||||
|===
|
|
||||||
|
|
||||||
=== Other Changes
|
|
||||||
|
|
||||||
==== UUID Types
|
|
||||||
|
|
||||||
The MongoDB UUID representation can now be configured with different formats.
|
|
||||||
This has to be done via `MongoClientSettings` as shown in the snippet below.
|
|
||||||
|
|
||||||
.UUID Codec Configuration
|
|
||||||
====
|
|
||||||
[source,java]
|
|
||||||
----
|
|
||||||
static class Config extends AbstractMongoClientConfiguration {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void configureClientSettings(MongoClientSettings.Builder builder) {
|
|
||||||
builder.uuidRepresentation(UuidRepresentation.STANDARD);
|
|
||||||
}
|
|
||||||
|
|
||||||
// ...
|
|
||||||
}
|
|
||||||
----
|
|
||||||
====
|
|
||||||
|
|
||||||
[[getting-help]]
|
|
||||||
== Getting Help
|
== Getting Help
|
||||||
|
|
||||||
Having trouble with Spring Data? We’d love to help!
|
Having trouble with Spring Data? We’d love to help!
|
||||||
@@ -242,99 +105,23 @@ If you are just starting out with Spring, try one of the https://spring.io/guide
|
|||||||
* If you are upgrading, check out the https://docs.spring.io/spring-data/mongodb/docs/current/changelog.txt[changelog] for "`new and noteworthy`" features.
|
* If you are upgrading, check out the https://docs.spring.io/spring-data/mongodb/docs/current/changelog.txt[changelog] for "`new and noteworthy`" features.
|
||||||
* Ask a question - we monitor https://stackoverflow.com[stackoverflow.com] for questions tagged with https://stackoverflow.com/tags/spring-data[`spring-data-mongodb`].
|
* Ask a question - we monitor https://stackoverflow.com[stackoverflow.com] for questions tagged with https://stackoverflow.com/tags/spring-data[`spring-data-mongodb`].
|
||||||
You can also chat with the community on https://gitter.im/spring-projects/spring-data[Gitter].
|
You can also chat with the community on https://gitter.im/spring-projects/spring-data[Gitter].
|
||||||
* Report bugs with Spring Data MongoDB at https://github.com/spring-projects/spring-data-mongodb/issues[github.com/spring-projects/spring-data-mongodb/issues].
|
* Report bugs with Spring Data MongoDB at https://jira.spring.io/browse/DATAMONGO[jira.spring.io/browse/DATAMONGO].
|
||||||
|
|
||||||
[[reporting-issues]]
|
|
||||||
== Reporting Issues
|
== Reporting Issues
|
||||||
|
|
||||||
Spring Data uses Github as issue tracking system to record bugs and feature requests.
|
Spring Data uses JIRA as issue tracking system to record bugs and feature requests. If you want to raise an issue, please follow the recommendations below:
|
||||||
If you want to raise an issue, please follow the recommendations below:
|
|
||||||
|
|
||||||
* Before you log a bug, please search the https://github.com/spring-projects/spring-data-mongodb/issues[issue tracker] to see if someone has already reported the problem.
|
* Before you log a bug, please search the
|
||||||
* If the issue does not already exist, https://github.com/spring-projects/spring-data-mongodb/issues/new[create a new issue].
|
https://jira.spring.io/browse/DATAMONGO[issue tracker] to see if someone has already reported the problem.
|
||||||
* Please provide as much information as possible with the issue report, we like to know the version of Spring Data that you are using, the JVM version, Stacktrace, etc.
|
* If the issue doesn’t already exist, https://jira.spring.io/browse/DATAMONGO[create a new issue].
|
||||||
* If you need to paste code, or include a stack trace use https://guides.github.com/features/mastering-markdown/[Markdown] code fences +++```+++.
|
* Please provide as much information as possible with the issue report, we like to know the version of Spring Data that you are using and JVM version.
|
||||||
|
* If you need to paste code, or include a stack trace use JIRA `{code}…{code}` escapes before and after your text.
|
||||||
|
* If possible try to create a test-case or project that replicates the issue. Attach a link to your code or a compressed file containing your code.
|
||||||
|
|
||||||
[[guides]]
|
|
||||||
== Guides
|
|
||||||
|
|
||||||
The https://spring.io/[spring.io] site contains several guides that show how to use Spring Data step-by-step:
|
|
||||||
|
|
||||||
* https://spring.io/guides/gs/accessing-data-mongodb/[Accessing Data with MongoDB] is a very basic guide that shows you how to create a simple application and how to access data using repositories.
|
|
||||||
* https://spring.io/guides/gs/accessing-mongodb-data-rest/[Accessing MongoDB Data with REST] is a guide to creating a REST web service exposing data stored in MongoDB through repositories.
|
|
||||||
|
|
||||||
[[examples]]
|
|
||||||
== Examples
|
|
||||||
|
|
||||||
* https://github.com/spring-projects/spring-data-examples/[Spring Data Examples] contains example projects that explain specific features in more detail.
|
|
||||||
|
|
||||||
[[building-from-source]]
|
|
||||||
== Building from Source
|
== Building from Source
|
||||||
|
|
||||||
You do not need to build from source to use Spring Data. Binaries are available in https://repo.spring.io[repo.spring.io]
|
You don’t need to build from source to use Spring Data (binaries in https://repo.spring.io[repo.spring.io]), but if you want to try out the latest and greatest, Spring Data can be easily built with the https://github.com/takari/maven-wrapper[maven wrapper].
|
||||||
and accessible from Maven using the Maven configuration noted <<maven-configuration,above>>.
|
You also need JDK 1.8.
|
||||||
|
|
||||||
NOTE: Configuration for Gradle is similar to Maven.
|
|
||||||
|
|
||||||
The best way to get started is by creating a Spring Boot project using MongoDB on https://start.spring.io[start.spring.io].
|
|
||||||
Follow this https://start.spring.io/#type=maven-project&language=java&platformVersion=2.5.4&packaging=jar&jvmVersion=1.8&groupId=com.example&artifactId=demo&name=demo&description=Demo%20project%20for%20Spring%20Boot&packageName=com.example.demo&dependencies=data-mongodb[link]
|
|
||||||
to build an imperative application and this https://start.spring.io/#type=maven-project&language=java&platformVersion=2.5.4&packaging=jar&jvmVersion=1.8&groupId=com.example&artifactId=demo&name=demo&description=Demo%20project%20for%20Spring%20Boot&packageName=com.example.demo&dependencies=data-mongodb-reactive[link]
|
|
||||||
to build a reactive one.
|
|
||||||
|
|
||||||
However, if you want to try out the latest and greatest, Spring Data MongoDB can be easily built with the https://github.com/takari/maven-wrapper[Maven wrapper]
|
|
||||||
and minimally, JDK 8 (https://www.oracle.com/java/technologies/downloads/[JDK downloads]).
|
|
||||||
|
|
||||||
In order to build Spring Data MongoDB, you will need to https://www.mongodb.com/try/download/community[download]
|
|
||||||
and https://docs.mongodb.com/manual/installation/[install a MongoDB distribution].
|
|
||||||
|
|
||||||
Once you have installed MongoDB, you need to start a MongoDB server. It is convenient to set an environment variable to
|
|
||||||
your MongoDB installation directory (e.g. `MONGODB_HOME`).
|
|
||||||
|
|
||||||
To run the full test suite, a https://docs.mongodb.com/manual/tutorial/deploy-replica-set/[MongoDB Replica Set]
|
|
||||||
is required.
|
|
||||||
|
|
||||||
To run the MongoDB server enter the following command from a command-line:
|
|
||||||
|
|
||||||
[source,bash]
|
|
||||||
----
|
|
||||||
$ $MONGODB_HOME/bin/mongod --dbpath $MONGODB_HOME/runtime/data --ipv6 --port 27017 --replSet rs0
|
|
||||||
...
|
|
||||||
"msg":"Successfully connected to host"
|
|
||||||
----
|
|
||||||
|
|
||||||
Once the MongoDB server starts up, you should see the message (`msg`), "_Successfully connected to host_".
|
|
||||||
|
|
||||||
Notice the `--dbpath` option to the `mongod` command. You can set this to anything you like, but in this case, we set
|
|
||||||
the absolute path to a sub-directory (`runtime/data/`) under the MongoDB installation directory (in `$MONGODB_HOME`).
|
|
||||||
|
|
||||||
You need to initialize the MongoDB replica set only once on the first time the MongoDB server is started.
|
|
||||||
To initialize the replica set, start a mongo client:
|
|
||||||
|
|
||||||
[source,bash]
|
|
||||||
----
|
|
||||||
$ $MONGODB_HOME/bin/mongo
|
|
||||||
MongoDB server version: 5.0.0
|
|
||||||
...
|
|
||||||
----
|
|
||||||
|
|
||||||
Then enter the following command:
|
|
||||||
|
|
||||||
[source,bash]
|
|
||||||
----
|
|
||||||
mongo> rs.initiate({ _id: 'rs0', members: [ { _id: 0, host: '127.0.0.1:27017' } ] })
|
|
||||||
----
|
|
||||||
|
|
||||||
Finally, on UNIX-based system (for example, Linux or Mac OS X) you may need to adjust the `ulimit`.
|
|
||||||
In case you need to, you can adjust the `ulimit` with the following command (32768 is just a recommendation):
|
|
||||||
|
|
||||||
[source,bash]
|
|
||||||
----
|
|
||||||
$ ulimit -n 32768
|
|
||||||
----
|
|
||||||
|
|
||||||
You can use `ulimit -a` again to verify the `ulimit` for "_open files_" was set appropriately.
|
|
||||||
|
|
||||||
Now you are ready to build Spring Data MongoDB. Simply enter the following `mvnw` (Maven Wrapper) command:
|
|
||||||
|
|
||||||
[source,bash]
|
[source,bash]
|
||||||
----
|
----
|
||||||
@@ -343,8 +130,7 @@ Now you are ready to build Spring Data MongoDB. Simply enter the following `mvnw
|
|||||||
|
|
||||||
If you want to build with the regular `mvn` command, you will need https://maven.apache.org/run-maven/index.html[Maven v3.5.0 or above].
|
If you want to build with the regular `mvn` command, you will need https://maven.apache.org/run-maven/index.html[Maven v3.5.0 or above].
|
||||||
|
|
||||||
_Also see link:CONTRIBUTING.adoc[CONTRIBUTING.adoc] if you wish to submit pull requests, and in particular, please sign
|
_Also see link:CONTRIBUTING.adoc[CONTRIBUTING.adoc] if you wish to submit pull requests, and in particular please sign the https://cla.pivotal.io/sign/spring[Contributor’s Agreement] before your first non-trivial change._
|
||||||
the https://cla.pivotal.io/sign/spring[Contributor’s Agreement] before your first non-trivial change._
|
|
||||||
|
|
||||||
=== Building reference documentation
|
=== Building reference documentation
|
||||||
|
|
||||||
@@ -357,7 +143,17 @@ Building the documentation builds also the project without running tests.
|
|||||||
|
|
||||||
The generated documentation is available from `target/site/reference/html/index.html`.
|
The generated documentation is available from `target/site/reference/html/index.html`.
|
||||||
|
|
||||||
[[license]]
|
== Guides
|
||||||
|
|
||||||
|
The https://spring.io/[spring.io] site contains several guides that show how to use Spring Data step-by-step:
|
||||||
|
|
||||||
|
* https://spring.io/guides/gs/accessing-data-mongodb/[Accessing Data with MongoDB] is a very basic guide that shows you how to create a simple application and how to access data using repositories.
|
||||||
|
* https://spring.io/guides/gs/accessing-mongodb-data-rest/[Accessing MongoDB Data with REST] is a guide to creating a REST web service exposing data stored in MongoDB through repositories.
|
||||||
|
|
||||||
|
== Examples
|
||||||
|
|
||||||
|
* https://github.com/spring-projects/spring-data-examples/[Spring Data Examples] contains example projects that explain specific features in more detail.
|
||||||
|
|
||||||
== License
|
== License
|
||||||
|
|
||||||
Spring Data MongoDB is Open Source software released under the https://www.apache.org/licenses/LICENSE-2.0.html[Apache 2.0 license].
|
Spring Data MongoDB is Open Source software released under the https://www.apache.org/licenses/LICENSE-2.0.html[Apache 2.0 license].
|
||||||
|
|||||||
@@ -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,18 +0,0 @@
|
|||||||
FROM openjdk:17-bullseye
|
|
||||||
|
|
||||||
ENV TZ=Etc/UTC
|
|
||||||
ENV DEBIAN_FRONTEND=noninteractive
|
|
||||||
|
|
||||||
RUN set -eux; \
|
|
||||||
sed -i -e 's/archive.ubuntu.com/mirror.one.com/g' /etc/apt/sources.list; \
|
|
||||||
sed -i -e 's/security.ubuntu.com/mirror.one.com/g' /etc/apt/sources.list; \
|
|
||||||
sed -i -e 's/http/https/g' /etc/apt/sources.list ; \
|
|
||||||
apt-get update && apt-get install -y apt-transport-https apt-utils gnupg2 ; \
|
|
||||||
apt-key adv --keyserver hkps://keyserver.ubuntu.com:443 --recv 656408E390CFB1F5 ; \
|
|
||||||
echo "deb [ arch=amd64 ] https://repo.mongodb.org/apt/ubuntu bionic/mongodb-org/4.4 multiverse" | tee /etc/apt/sources.list.d/mongodb-org-4.4.list; \
|
|
||||||
echo ${TZ} > /etc/timezone;
|
|
||||||
|
|
||||||
RUN apt-get update ; \
|
|
||||||
apt-get install -y mongodb-org=4.4.4 mongodb-org-server=4.4.4 mongodb-org-shell=4.4.4 mongodb-org-mongos=4.4.4 mongodb-org-tools=4.4.4 ; \
|
|
||||||
apt-get clean; \
|
|
||||||
rm -rf /var/lib/apt/lists/*;
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
FROM openjdk:17-bullseye
|
|
||||||
|
|
||||||
ENV TZ=Etc/UTC
|
|
||||||
ENV DEBIAN_FRONTEND=noninteractive
|
|
||||||
|
|
||||||
RUN set -eux; \
|
|
||||||
sed -i -e 's/archive.ubuntu.com/mirror.one.com/g' /etc/apt/sources.list; \
|
|
||||||
sed -i -e 's/security.ubuntu.com/mirror.one.com/g' /etc/apt/sources.list; \
|
|
||||||
sed -i -e 's/http/https/g' /etc/apt/sources.list ; \
|
|
||||||
apt-get update && apt-get install -y apt-transport-https apt-utils gnupg2 wget ; \
|
|
||||||
# MongoDB 5.0 release signing key
|
|
||||||
apt-key adv --keyserver hkps://keyserver.ubuntu.com:443 --recv B00A0BD1E2C63C11 ; \
|
|
||||||
# Needed when MongoDB creates a 5.0 folder.
|
|
||||||
echo "deb [ arch=amd64 ] https://repo.mongodb.org/apt/ubuntu bionic/mongodb-org/5.0 multiverse" | tee /etc/apt/sources.list.d/mongodb-org-5.0.list; \
|
|
||||||
echo ${TZ} > /etc/timezone;
|
|
||||||
|
|
||||||
RUN apt-get update; \
|
|
||||||
apt-get install -y mongodb-org=5.0.3 mongodb-org-server=5.0.3 mongodb-org-shell=5.0.3 mongodb-org-mongos=5.0.3 mongodb-org-tools=5.0.3; \
|
|
||||||
apt-get clean; \
|
|
||||||
rm -rf /var/lib/apt/lists/*;
|
|
||||||
|
|
||||||
14
ci/openjdk8-mongodb-4.0/Dockerfile
Normal file
14
ci/openjdk8-mongodb-4.0/Dockerfile
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
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 9DA31620334BD75D9DCB49F368818C72E52529D4
|
||||||
|
|
||||||
|
RUN echo "deb [ arch=amd64 ] https://repo.mongodb.org/apt/ubuntu bionic/mongodb-org/4.0 multiverse" | tee /etc/apt/sources.list.d/mongodb-org-4.0.list
|
||||||
|
|
||||||
|
RUN apt-get update
|
||||||
|
|
||||||
|
RUN apt-get install -y mongodb-org=4.0.9 mongodb-org-server=4.0.9 mongodb-org-shell=4.0.9 mongodb-org-mongos=4.0.9 mongodb-org-tools=4.0.9
|
||||||
|
|
||||||
|
RUN apt-get clean \
|
||||||
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
14
ci/openjdk8-mongodb-4.1/Dockerfile
Normal file
14
ci/openjdk8-mongodb-4.1/Dockerfile
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
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 4B7C549A058F8B6B
|
||||||
|
|
||||||
|
RUN echo "deb [ arch=amd64 ] https://repo.mongodb.org/apt/ubuntu bionic/mongodb-org/4.1 multiverse" | tee /etc/apt/sources.list.d/mongodb-org-4.1.list
|
||||||
|
|
||||||
|
RUN apt-get update
|
||||||
|
|
||||||
|
RUN apt-get install -y mongodb-org-unstable=4.1.13 mongodb-org-unstable-server=4.1.13 mongodb-org-unstable-shell=4.1.13 mongodb-org-unstable-mongos=4.1.13 mongodb-org-unstable-tools=4.1.13
|
||||||
|
|
||||||
|
RUN apt-get clean \
|
||||||
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
49
pom.xml
49
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>4.0.0-M1</version>
|
<version>2.1.22.BUILD-SNAPSHOT</version>
|
||||||
<packaging>pom</packaging>
|
<packaging>pom</packaging>
|
||||||
|
|
||||||
<name>Spring Data MongoDB</name>
|
<name>Spring Data MongoDB</name>
|
||||||
@@ -15,21 +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>3.0.0-M1</version>
|
<version>2.1.22.BUILD-SNAPSHOT</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>
|
||||||
<source.level>16</source.level>
|
|
||||||
<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>3.0.0-M1</springdata.commons>
|
<springdata.commons>2.1.22.BUILD-SNAPSHOT</springdata.commons>
|
||||||
<mongo>4.4.1</mongo>
|
<mongo>3.8.2</mongo>
|
||||||
<mongo.reactivestreams>${mongo}</mongo.reactivestreams>
|
<mongo.reactivestreams>1.9.2</mongo.reactivestreams>
|
||||||
<jmh.version>1.19</jmh.version>
|
<jmh.version>1.19</jmh.version>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
@@ -118,35 +118,45 @@
|
|||||||
<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>
|
||||||
<!-- MongoDB -->
|
<!-- MongoDB -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.mongodb</groupId>
|
<groupId>org.mongodb</groupId>
|
||||||
<artifactId>mongodb-driver-core</artifactId>
|
<artifactId>mongo-java-driver</artifactId>
|
||||||
<version>${mongo}</version>
|
<version>${mongo}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<repositories>
|
<repositories>
|
||||||
<repository>
|
<repository>
|
||||||
<id>spring-libs-milestone</id>
|
<id>spring-libs-snapshot</id>
|
||||||
<url>https://repo.spring.io/libs-milestone</url>
|
<url>https://repo.spring.io/libs-snapshot</url>
|
||||||
</repository>
|
|
||||||
<repository>
|
|
||||||
<id>sonatype-libs-snapshot</id>
|
|
||||||
<url>https://oss.sonatype.org/content/repositories/snapshots</url>
|
|
||||||
<releases>
|
|
||||||
<enabled>false</enabled>
|
|
||||||
</releases>
|
|
||||||
<snapshots>
|
|
||||||
<enabled>true</enabled>
|
|
||||||
</snapshots>
|
|
||||||
</repository>
|
</repository>
|
||||||
</repositories>
|
</repositories>
|
||||||
|
|
||||||
@@ -159,6 +169,7 @@
|
|||||||
<id>spring-libs-milestone</id>
|
<id>spring-libs-milestone</id>
|
||||||
<url>https://repo.spring.io/libs-milestone</url>
|
<url>https://repo.spring.io/libs-milestone</url>
|
||||||
</pluginRepository>
|
</pluginRepository>
|
||||||
|
|
||||||
</pluginRepositories>
|
</pluginRepositories>
|
||||||
|
|
||||||
</project>
|
</project>
|
||||||
|
|||||||
29
settings.xml
29
settings.xml
@@ -1,29 +0,0 @@
|
|||||||
<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"
|
|
||||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
|
||||||
xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0
|
|
||||||
https://maven.apache.org/xsd/settings-1.0.0.xsd">
|
|
||||||
|
|
||||||
<servers>
|
|
||||||
<server>
|
|
||||||
<id>spring-plugins-release</id>
|
|
||||||
<username>${env.ARTIFACTORY_USR}</username>
|
|
||||||
<password>${env.ARTIFACTORY_PSW}</password>
|
|
||||||
</server>
|
|
||||||
<server>
|
|
||||||
<id>spring-libs-snapshot</id>
|
|
||||||
<username>${env.ARTIFACTORY_USR}</username>
|
|
||||||
<password>${env.ARTIFACTORY_PSW}</password>
|
|
||||||
</server>
|
|
||||||
<server>
|
|
||||||
<id>spring-libs-milestone</id>
|
|
||||||
<username>${env.ARTIFACTORY_USR}</username>
|
|
||||||
<password>${env.ARTIFACTORY_PSW}</password>
|
|
||||||
</server>
|
|
||||||
<server>
|
|
||||||
<id>spring-libs-release</id>
|
|
||||||
<username>${env.ARTIFACTORY_USR}</username>
|
|
||||||
<password>${env.ARTIFACTORY_PSW}</password>
|
|
||||||
</server>
|
|
||||||
</servers>
|
|
||||||
|
|
||||||
</settings>
|
|
||||||
@@ -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>4.0.0-M1</version>
|
<version>2.1.22.BUILD-SNAPSHOT</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-2021 the original author or authors.
|
* Copyright 2017-2020 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-2021 the original author or authors.
|
* Copyright 2017-2020 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-2021 the original author or authors.
|
* Copyright 2017-2020 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-2021 the original author or authors.
|
* Copyright 2017-2020 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-2021 the original author or authors.
|
* Copyright 2017-2020 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-2021 the original author or authors.
|
* Copyright 2017-2020 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-2021 the original author or authors.
|
* Copyright 2017-2020 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.22.BUILD-SNAPSHOT</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.22.BUILD-SNAPSHOT</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-2021 the original author or authors.
|
* Copyright 2011-2020 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-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.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 2021 the original author or authors.
|
* Copyright 2011-2020 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,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.core.timeseries;
|
package org.springframework.data.mongodb.crossstore;
|
||||||
|
|
||||||
|
import java.lang.annotation.ElementType;
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
import java.lang.annotation.Target;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The Granularity of time series data that is closest to the time span between incoming measurements.
|
* @author Thomas Risberg
|
||||||
*
|
* @deprecated will be removed without replacement.
|
||||||
* @author Christoph Strobl
|
|
||||||
* @since 3.3
|
|
||||||
*/
|
*/
|
||||||
public interface GranularityDefinition {
|
@Deprecated
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
String name();
|
@Target({ ElementType.FIELD })
|
||||||
|
public @interface RelatedDocument {
|
||||||
}
|
}
|
||||||
@@ -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-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.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-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.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-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.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-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.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>4.0.0-M1</version>
|
<version>2.1.22.BUILD-SNAPSHOT</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>4.0.0-M1</version>
|
<version>2.1.22.BUILD-SNAPSHOT</version>
|
||||||
<relativePath>../pom.xml</relativePath>
|
<relativePath>../pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
@@ -65,12 +65,6 @@
|
|||||||
<artifactId>querydsl-mongodb</artifactId>
|
<artifactId>querydsl-mongodb</artifactId>
|
||||||
<version>${querydsl}</version>
|
<version>${querydsl}</version>
|
||||||
<optional>true</optional>
|
<optional>true</optional>
|
||||||
<exclusions>
|
|
||||||
<exclusion>
|
|
||||||
<groupId>org.mongodb</groupId>
|
|
||||||
<artifactId>mongo-java-driver</artifactId>
|
|
||||||
</exclusion>
|
|
||||||
</exclusions>
|
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
@@ -87,31 +81,33 @@
|
|||||||
<optional>true</optional>
|
<optional>true</optional>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>com.google.code.findbugs</groupId>
|
|
||||||
<artifactId>jsr305</artifactId>
|
|
||||||
<version>3.0.2</version>
|
|
||||||
<optional>true</optional>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<!-- reactive -->
|
<!-- reactive -->
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.mongodb</groupId>
|
<groupId>org.mongodb</groupId>
|
||||||
<artifactId>mongodb-driver-sync</artifactId>
|
|
||||||
<version>${mongo}</version>
|
|
||||||
<optional>true</optional>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.mongodb</groupId>
|
|
||||||
<artifactId>mongodb-driver-reactivestreams</artifactId>
|
<artifactId>mongodb-driver-reactivestreams</artifactId>
|
||||||
<version>${mongo.reactivestreams}</version>
|
<version>${mongo.reactivestreams}</version>
|
||||||
<optional>true</optional>
|
<optional>true</optional>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.projectreactor</groupId>
|
<groupId>org.mongodb</groupId>
|
||||||
|
<artifactId>mongodb-driver-async</artifactId>
|
||||||
|
<version>${mongo}</version>
|
||||||
|
<optional>true</optional>
|
||||||
|
<exclusions>
|
||||||
|
<exclusion>
|
||||||
|
<groupId>org.mongodb</groupId>
|
||||||
|
<artifactId>mongodb-driver-core</artifactId>
|
||||||
|
</exclusion>
|
||||||
|
<exclusion>
|
||||||
|
<groupId>org.mongodb</groupId>
|
||||||
|
<artifactId>bson</artifactId>
|
||||||
|
</exclusion>
|
||||||
|
</exclusions>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.projectreactor</groupId>
|
||||||
<artifactId>reactor-core</artifactId>
|
<artifactId>reactor-core</artifactId>
|
||||||
<optional>true</optional>
|
<optional>true</optional>
|
||||||
</dependency>
|
</dependency>
|
||||||
@@ -123,14 +119,34 @@
|
|||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.reactivex.rxjava3</groupId>
|
<groupId>io.reactivex</groupId>
|
||||||
<artifactId>rxjava</artifactId>
|
<artifactId>rxjava</artifactId>
|
||||||
<version>${rxjava3}</version>
|
<version>${rxjava}</version>
|
||||||
|
<optional>true</optional>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.reactivex</groupId>
|
||||||
|
<artifactId>rxjava-reactive-streams</artifactId>
|
||||||
|
<version>${rxjava-reactive-streams}</version>
|
||||||
|
<optional>true</optional>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.reactivex.rxjava2</groupId>
|
||||||
|
<artifactId>rxjava</artifactId>
|
||||||
|
<version>${rxjava2}</version>
|
||||||
<optional>true</optional>
|
<optional>true</optional>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<!-- CDI -->
|
<!-- CDI -->
|
||||||
<!-- Dependency order required to build against CDI 1.0 and test with CDI 2.0 -->
|
<!-- Dependency order required to build against CDI 1.0 and test with CDI 2.0 -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.geronimo.specs</groupId>
|
||||||
|
<artifactId>geronimo-jcdi_2.0_spec</artifactId>
|
||||||
|
<version>1.0.1</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>javax.interceptor</groupId>
|
<groupId>javax.interceptor</groupId>
|
||||||
@@ -140,48 +156,31 @@
|
|||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>jakarta.enterprise</groupId>
|
<groupId>javax.enterprise</groupId>
|
||||||
<artifactId>jakarta.enterprise.cdi-api</artifactId>
|
<artifactId>cdi-api</artifactId>
|
||||||
<version>${cdi}</version>
|
<version>${cdi}</version>
|
||||||
<scope>provided</scope>
|
<scope>provided</scope>
|
||||||
<optional>true</optional>
|
<optional>true</optional>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>jakarta.annotation</groupId>
|
<groupId>javax.annotation</groupId>
|
||||||
<artifactId>jakarta.annotation-api</artifactId>
|
<artifactId>javax.annotation-api</artifactId>
|
||||||
<version>${jakarta-annotation-api}</version>
|
<version>${javax-annotation-api}</version>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.apache.openwebbeans</groupId>
|
<groupId>org.apache.openwebbeans</groupId>
|
||||||
<artifactId>openwebbeans-se</artifactId>
|
<artifactId>openwebbeans-se</artifactId>
|
||||||
<classifier>jakarta</classifier>
|
|
||||||
<version>${webbeans}</version>
|
|
||||||
<scope>test</scope>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.apache.openwebbeans</groupId>
|
|
||||||
<artifactId>openwebbeans-spi</artifactId>
|
|
||||||
<classifier>jakarta</classifier>
|
|
||||||
<version>${webbeans}</version>
|
|
||||||
<scope>test</scope>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.apache.openwebbeans</groupId>
|
|
||||||
<artifactId>openwebbeans-impl</artifactId>
|
|
||||||
<classifier>jakarta</classifier>
|
|
||||||
<version>${webbeans}</version>
|
<version>${webbeans}</version>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<!-- JSR 303 Validation -->
|
<!-- JSR 303 Validation -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>jakarta.validation</groupId>
|
<groupId>javax.validation</groupId>
|
||||||
<artifactId>jakarta.validation-api</artifactId>
|
<artifactId>validation-api</artifactId>
|
||||||
<version>${validation}</version>
|
<version>${validation}</version>
|
||||||
<optional>true</optional>
|
<optional>true</optional>
|
||||||
</dependency>
|
</dependency>
|
||||||
@@ -196,30 +195,21 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.hibernate</groupId>
|
<groupId>org.hibernate</groupId>
|
||||||
<artifactId>hibernate-validator</artifactId>
|
<artifactId>hibernate-validator</artifactId>
|
||||||
<version>7.0.1.Final</version>
|
<version>5.2.4.Final</version>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>jakarta.el</groupId>
|
<groupId>joda-time</groupId>
|
||||||
<artifactId>jakarta.el-api</artifactId>
|
<artifactId>joda-time</artifactId>
|
||||||
<version>4.0.0</version>
|
<version>${jodatime}</version>
|
||||||
<scope>provided</scope>
|
<scope>test</scope>
|
||||||
<optional>true</optional>
|
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.glassfish</groupId>
|
<groupId>org.threeten</groupId>
|
||||||
<artifactId>jakarta.el</artifactId>
|
<artifactId>threetenbp</artifactId>
|
||||||
<version>4.0.2</version>
|
<version>${threetenbp}</version>
|
||||||
<scope>provided</scope>
|
|
||||||
<optional>true</optional>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>jakarta.enterprise</groupId>
|
|
||||||
<artifactId>jakarta.enterprise.cdi-api</artifactId>
|
|
||||||
<scope>provided</scope>
|
|
||||||
<optional>true</optional>
|
<optional>true</optional>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
@@ -229,6 +219,13 @@
|
|||||||
<optional>true</optional>
|
<optional>true</optional>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.slf4j</groupId>
|
||||||
|
<artifactId>jul-to-slf4j</artifactId>
|
||||||
|
<version>${slf4j}</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>nl.jqno.equalsverifier</groupId>
|
<groupId>nl.jqno.equalsverifier</groupId>
|
||||||
<artifactId>equalsverifier</artifactId>
|
<artifactId>equalsverifier</artifactId>
|
||||||
@@ -257,16 +254,9 @@
|
|||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.junit-pioneer</groupId>
|
<groupId>javax.transaction</groupId>
|
||||||
<artifactId>junit-pioneer</artifactId>
|
<artifactId>jta</artifactId>
|
||||||
<version>0.5.3</version>
|
<version>1.1</version>
|
||||||
<scope>test</scope>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>jakarta.transaction</groupId>
|
|
||||||
<artifactId>jakarta.transaction-api</artifactId>
|
|
||||||
<version>2.0.0</version>
|
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
@@ -274,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>
|
||||||
@@ -302,15 +287,6 @@
|
|||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<!-- jMolecules -->
|
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.jmolecules</groupId>
|
|
||||||
<artifactId>jmolecules-ddd</artifactId>
|
|
||||||
<version>${jmolecules}</version>
|
|
||||||
<scope>test</scope>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
@@ -346,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>
|
||||||
@@ -359,6 +334,12 @@
|
|||||||
<java.util.logging.config.file>src/test/resources/logging.properties</java.util.logging.config.file>
|
<java.util.logging.config.file>src/test/resources/logging.properties</java.util.logging.config.file>
|
||||||
<reactor.trace.cancel>true</reactor.trace.cancel>
|
<reactor.trace.cancel>true</reactor.trace.cancel>
|
||||||
</systemPropertyVariables>
|
</systemPropertyVariables>
|
||||||
|
<properties>
|
||||||
|
<property>
|
||||||
|
<name>listener</name>
|
||||||
|
<value>org.springframework.data.mongodb.test.util.CleanMongoDBJunitRunListener</value>
|
||||||
|
</property>
|
||||||
|
</properties>
|
||||||
</configuration>
|
</configuration>
|
||||||
</plugin>
|
</plugin>
|
||||||
|
|
||||||
|
|||||||
@@ -1,144 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2021 the original author or authors.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* https://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package org.springframework.data.mongodb;
|
|
||||||
|
|
||||||
import java.util.Arrays;
|
|
||||||
|
|
||||||
import org.bson.Document;
|
|
||||||
import org.bson.codecs.DocumentCodec;
|
|
||||||
import org.bson.codecs.configuration.CodecRegistry;
|
|
||||||
import org.springframework.data.mongodb.util.json.ParameterBindingDocumentCodec;
|
|
||||||
import org.springframework.data.util.Lazy;
|
|
||||||
import org.springframework.lang.Nullable;
|
|
||||||
import org.springframework.util.ObjectUtils;
|
|
||||||
import org.springframework.util.StringUtils;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A {@link MongoExpression} using the {@link ParameterBindingDocumentCodec} for parsing a raw ({@literal json})
|
|
||||||
* expression. The expression will be wrapped within <code>{ ... }</code> if necessary. The actual parsing and parameter
|
|
||||||
* binding of placeholders like {@code ?0} is delayed upon first call on the the target {@link Document} via
|
|
||||||
* {@link #toDocument()}.
|
|
||||||
* <br />
|
|
||||||
*
|
|
||||||
* <pre class="code">
|
|
||||||
* $toUpper : $name -> { '$toUpper' : '$name' }
|
|
||||||
*
|
|
||||||
* { '$toUpper' : '$name' } -> { '$toUpper' : '$name' }
|
|
||||||
*
|
|
||||||
* { '$toUpper' : '?0' }, "$name" -> { '$toUpper' : '$name' }
|
|
||||||
* </pre>
|
|
||||||
*
|
|
||||||
* Some types might require a special {@link org.bson.codecs.Codec}. If so, make sure to provide a {@link CodecRegistry}
|
|
||||||
* containing the required {@link org.bson.codecs.Codec codec} via {@link #withCodecRegistry(CodecRegistry)}.
|
|
||||||
*
|
|
||||||
* @author Christoph Strobl
|
|
||||||
* @since 3.2
|
|
||||||
*/
|
|
||||||
public class BindableMongoExpression implements MongoExpression {
|
|
||||||
|
|
||||||
private final String expressionString;
|
|
||||||
|
|
||||||
private final @Nullable CodecRegistryProvider codecRegistryProvider;
|
|
||||||
|
|
||||||
private final @Nullable Object[] args;
|
|
||||||
|
|
||||||
private final Lazy<Document> target;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new instance of {@link BindableMongoExpression}.
|
|
||||||
*
|
|
||||||
* @param expression must not be {@literal null}.
|
|
||||||
* @param args can be {@literal null}.
|
|
||||||
*/
|
|
||||||
public BindableMongoExpression(String expression, @Nullable Object[] args) {
|
|
||||||
this(expression, null, args);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new instance of {@link BindableMongoExpression}.
|
|
||||||
*
|
|
||||||
* @param expression must not be {@literal null}.
|
|
||||||
* @param codecRegistryProvider can be {@literal null}.
|
|
||||||
* @param args can be {@literal null}.
|
|
||||||
*/
|
|
||||||
public BindableMongoExpression(String expression, @Nullable CodecRegistryProvider codecRegistryProvider,
|
|
||||||
@Nullable Object[] args) {
|
|
||||||
|
|
||||||
this.expressionString = expression;
|
|
||||||
this.codecRegistryProvider = codecRegistryProvider;
|
|
||||||
this.args = args;
|
|
||||||
this.target = Lazy.of(this::parse);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Provide the {@link CodecRegistry} used to convert expressions.
|
|
||||||
*
|
|
||||||
* @param codecRegistry must not be {@literal null}.
|
|
||||||
* @return new instance of {@link BindableMongoExpression}.
|
|
||||||
*/
|
|
||||||
public BindableMongoExpression withCodecRegistry(CodecRegistry codecRegistry) {
|
|
||||||
return new BindableMongoExpression(expressionString, () -> codecRegistry, args);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Provide the arguments to bind to the placeholders via their index.
|
|
||||||
*
|
|
||||||
* @param args must not be {@literal null}.
|
|
||||||
* @return new instance of {@link BindableMongoExpression}.
|
|
||||||
*/
|
|
||||||
public BindableMongoExpression bind(Object... args) {
|
|
||||||
return new BindableMongoExpression(expressionString, codecRegistryProvider, args);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Document toDocument() {
|
|
||||||
return target.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return "BindableMongoExpression{" + "expressionString='" + expressionString + '\'' + ", args="
|
|
||||||
+ Arrays.toString(args) + '}';
|
|
||||||
}
|
|
||||||
|
|
||||||
private Document parse() {
|
|
||||||
|
|
||||||
String expression = wrapJsonIfNecessary(expressionString);
|
|
||||||
|
|
||||||
if (ObjectUtils.isEmpty(args)) {
|
|
||||||
|
|
||||||
if (codecRegistryProvider == null) {
|
|
||||||
return Document.parse(expression);
|
|
||||||
}
|
|
||||||
|
|
||||||
return Document.parse(expression, codecRegistryProvider.getCodecFor(Document.class)
|
|
||||||
.orElseGet(() -> new DocumentCodec(codecRegistryProvider.getCodecRegistry())));
|
|
||||||
}
|
|
||||||
|
|
||||||
ParameterBindingDocumentCodec codec = codecRegistryProvider == null ? new ParameterBindingDocumentCodec()
|
|
||||||
: new ParameterBindingDocumentCodec(codecRegistryProvider.getCodecRegistry());
|
|
||||||
return codec.decode(expression, args);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static String wrapJsonIfNecessary(String json) {
|
|
||||||
|
|
||||||
if (StringUtils.hasText(json) && (json.startsWith("{") && json.endsWith("}"))) {
|
|
||||||
return json;
|
|
||||||
}
|
|
||||||
|
|
||||||
return "{" + json + "}";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2015-2021 the original author or authors.
|
* Copyright 2015-2020 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.
|
||||||
@@ -19,9 +19,9 @@ import java.util.List;
|
|||||||
|
|
||||||
import org.springframework.dao.DataAccessException;
|
import org.springframework.dao.DataAccessException;
|
||||||
|
|
||||||
import com.mongodb.MongoBulkWriteException;
|
import com.mongodb.BulkWriteError;
|
||||||
import com.mongodb.bulk.BulkWriteError;
|
import com.mongodb.BulkWriteException;
|
||||||
import com.mongodb.bulk.BulkWriteResult;
|
import com.mongodb.BulkWriteResult;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Is thrown when errors occur during bulk operations.
|
* Is thrown when errors occur during bulk operations.
|
||||||
@@ -38,12 +38,12 @@ public class BulkOperationException extends DataAccessException {
|
|||||||
private final BulkWriteResult result;
|
private final BulkWriteResult result;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new {@link BulkOperationException} with the given message and source {@link MongoBulkWriteException}.
|
* Creates a new {@link BulkOperationException} with the given message and source {@link BulkWriteException}.
|
||||||
*
|
*
|
||||||
* @param message must not be {@literal null}.
|
* @param message must not be {@literal null}.
|
||||||
* @param source must not be {@literal null}.
|
* @param source must not be {@literal null}.
|
||||||
*/
|
*/
|
||||||
public BulkOperationException(String message, MongoBulkWriteException source) {
|
public BulkOperationException(String message, BulkWriteException source) {
|
||||||
|
|
||||||
super(message, source);
|
super(message, source);
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,69 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-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.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-2021 the original author or authors.
|
* Copyright 2018-2020 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-2021 the original author or authors.
|
* Copyright 2017-2020 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-2021 the original author or authors.
|
* Copyright 2010-2020 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-2021 the original author or authors.
|
* Copyright 2013-2020 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.
|
||||||
@@ -25,10 +25,8 @@ public class LazyLoadingException extends UncategorizedDataAccessException {
|
|||||||
private static final long serialVersionUID = -7089224903873220037L;
|
private static final long serialVersionUID = -7089224903873220037L;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor for LazyLoadingException.
|
* @param msg
|
||||||
*
|
* @param cause
|
||||||
* @param msg the detail message.
|
|
||||||
* @param cause the exception thrown by underlying data access API.
|
|
||||||
*/
|
*/
|
||||||
public LazyLoadingException(String msg, Throwable cause) {
|
public LazyLoadingException(String msg, Throwable cause) {
|
||||||
super(msg, cause);
|
super(msg, cause);
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2011-2021 the original author or authors.
|
* Copyright 2011-2020 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,8 +20,8 @@ import org.springframework.util.StringUtils;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper class featuring helper methods for working with MongoDb collections.
|
* Helper class featuring helper methods for working with MongoDb collections.
|
||||||
* <br />
|
* <p/>
|
||||||
* <br />
|
* <p/>
|
||||||
* Mainly intended for internal use within the framework.
|
* Mainly intended for internal use within the framework.
|
||||||
*
|
*
|
||||||
* @author Thomas Risberg
|
* @author Thomas Risberg
|
||||||
|
|||||||
@@ -1,112 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2011-2021 the original author or authors.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* https://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package org.springframework.data.mongodb;
|
|
||||||
|
|
||||||
import org.bson.codecs.configuration.CodecRegistry;
|
|
||||||
import org.springframework.dao.DataAccessException;
|
|
||||||
import org.springframework.dao.support.PersistenceExceptionTranslator;
|
|
||||||
import org.springframework.data.mongodb.core.MongoExceptionTranslator;
|
|
||||||
|
|
||||||
import com.mongodb.ClientSessionOptions;
|
|
||||||
import com.mongodb.client.ClientSession;
|
|
||||||
import com.mongodb.client.MongoDatabase;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Interface for factories creating {@link MongoDatabase} instances.
|
|
||||||
*
|
|
||||||
* @author Mark Pollack
|
|
||||||
* @author Thomas Darimont
|
|
||||||
* @author Christoph Strobl
|
|
||||||
* @since 3.0
|
|
||||||
*/
|
|
||||||
public interface MongoDatabaseFactory extends CodecRegistryProvider, MongoSessionProvider {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Obtain a {@link MongoDatabase} from the underlying factory.
|
|
||||||
*
|
|
||||||
* @return never {@literal null}.
|
|
||||||
* @throws DataAccessException
|
|
||||||
*/
|
|
||||||
MongoDatabase getMongoDatabase() throws DataAccessException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Obtain a {@link MongoDatabase} instance to access the database with the given name.
|
|
||||||
*
|
|
||||||
* @param dbName must not be {@literal null}.
|
|
||||||
* @return never {@literal null}.
|
|
||||||
* @throws DataAccessException
|
|
||||||
*/
|
|
||||||
MongoDatabase getMongoDatabase(String dbName) throws DataAccessException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Exposes a shared {@link MongoExceptionTranslator}.
|
|
||||||
*
|
|
||||||
* @return will never be {@literal null}.
|
|
||||||
*/
|
|
||||||
PersistenceExceptionTranslator getExceptionTranslator();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the underlying {@link CodecRegistry} used by the MongoDB Java driver.
|
|
||||||
*
|
|
||||||
* @return never {@literal null}.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
default CodecRegistry getCodecRegistry() {
|
|
||||||
return getMongoDatabase().getCodecRegistry();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Obtain a {@link ClientSession} for given ClientSessionOptions.
|
|
||||||
*
|
|
||||||
* @param options must not be {@literal null}.
|
|
||||||
* @return never {@literal null}.
|
|
||||||
* @since 2.1
|
|
||||||
*/
|
|
||||||
ClientSession getSession(ClientSessionOptions options);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Obtain a {@link ClientSession} bound instance of {@link MongoDatabaseFactory} returning {@link MongoDatabase}
|
|
||||||
* instances that are aware and bound to a new session with given {@link ClientSessionOptions options}.
|
|
||||||
*
|
|
||||||
* @param options must not be {@literal null}.
|
|
||||||
* @return never {@literal null}.
|
|
||||||
* @since 2.1
|
|
||||||
*/
|
|
||||||
default MongoDatabaseFactory withSession(ClientSessionOptions options) {
|
|
||||||
return withSession(getSession(options));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Obtain a {@link ClientSession} bound instance of {@link MongoDatabaseFactory} returning {@link MongoDatabase}
|
|
||||||
* instances that are aware and bound to the given session.
|
|
||||||
*
|
|
||||||
* @param session must not be {@literal null}.
|
|
||||||
* @return never {@literal null}.
|
|
||||||
* @since 2.1
|
|
||||||
*/
|
|
||||||
MongoDatabaseFactory withSession(ClientSession session);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns if the given {@link MongoDatabaseFactory} is bound to a {@link ClientSession} that has an
|
|
||||||
* {@link ClientSession#hasActiveTransaction() active transaction}.
|
|
||||||
*
|
|
||||||
* @return {@literal true} if there's an active transaction, {@literal false} otherwise.
|
|
||||||
* @since 2.1.3
|
|
||||||
*/
|
|
||||||
default boolean isTransactionActive() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2018-2021 the original author or authors.
|
* Copyright 2018-2020 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.
|
||||||
@@ -27,10 +27,10 @@ import com.mongodb.client.ClientSession;
|
|||||||
import com.mongodb.client.MongoDatabase;
|
import com.mongodb.client.MongoDatabase;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper class for managing a {@link MongoDatabase} instances via {@link MongoDatabaseFactory}. Used for obtaining
|
* Helper class for managing a {@link MongoDatabase} instances via {@link MongoDbFactory}. Used for obtaining
|
||||||
* {@link ClientSession session bound} resources, such as {@link MongoDatabase} and
|
* {@link ClientSession session bound} resources, such as {@link MongoDatabase} and
|
||||||
* {@link com.mongodb.client.MongoCollection} suitable for transactional usage.
|
* {@link com.mongodb.client.MongoCollection} suitable for transactional usage.
|
||||||
* <br />
|
* <p />
|
||||||
* <strong>Note:</strong> Intended for internal usage only.
|
* <strong>Note:</strong> Intended for internal usage only.
|
||||||
*
|
*
|
||||||
* @author Christoph Strobl
|
* @author Christoph Strobl
|
||||||
@@ -41,95 +41,93 @@ import com.mongodb.client.MongoDatabase;
|
|||||||
public class MongoDatabaseUtils {
|
public class MongoDatabaseUtils {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Obtain the default {@link MongoDatabase database} form the given {@link MongoDatabaseFactory factory} using
|
* Obtain the default {@link MongoDatabase database} form the given {@link MongoDbFactory factory} using
|
||||||
* {@link SessionSynchronization#ON_ACTUAL_TRANSACTION native session synchronization}.
|
* {@link SessionSynchronization#ON_ACTUAL_TRANSACTION native session synchronization}.
|
||||||
* <br />
|
* <p />
|
||||||
* Registers a {@link MongoSessionSynchronization MongoDB specific transaction synchronization} within the current
|
* Registers a {@link MongoSessionSynchronization MongoDB specific transaction synchronization} within the current
|
||||||
* {@link Thread} if {@link TransactionSynchronizationManager#isSynchronizationActive() synchronization is active}.
|
* {@link Thread} if {@link TransactionSynchronizationManager#isSynchronizationActive() synchronization is active}.
|
||||||
*
|
*
|
||||||
* @param factory the {@link MongoDatabaseFactory} to get the {@link MongoDatabase} from.
|
* @param factory the {@link MongoDbFactory} to get the {@link MongoDatabase} from.
|
||||||
* @return the {@link MongoDatabase} that is potentially associated with a transactional {@link ClientSession}.
|
* @return the {@link MongoDatabase} that is potentially associated with a transactional {@link ClientSession}.
|
||||||
*/
|
*/
|
||||||
public static MongoDatabase getDatabase(MongoDatabaseFactory factory) {
|
public static MongoDatabase getDatabase(MongoDbFactory factory) {
|
||||||
return doGetMongoDatabase(null, factory, SessionSynchronization.ON_ACTUAL_TRANSACTION);
|
return doGetMongoDatabase(null, factory, SessionSynchronization.ON_ACTUAL_TRANSACTION);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Obtain the default {@link MongoDatabase database} form the given {@link MongoDatabaseFactory factory}.
|
* Obtain the default {@link MongoDatabase database} form the given {@link MongoDbFactory factory}.
|
||||||
* <br />
|
* <p />
|
||||||
* Registers a {@link MongoSessionSynchronization MongoDB specific transaction synchronization} within the current
|
* Registers a {@link MongoSessionSynchronization MongoDB specific transaction synchronization} within the current
|
||||||
* {@link Thread} if {@link TransactionSynchronizationManager#isSynchronizationActive() synchronization is active}.
|
* {@link Thread} if {@link TransactionSynchronizationManager#isSynchronizationActive() synchronization is active}.
|
||||||
*
|
*
|
||||||
* @param factory the {@link MongoDatabaseFactory} to get the {@link MongoDatabase} from.
|
* @param factory the {@link MongoDbFactory} to get the {@link MongoDatabase} from.
|
||||||
* @param sessionSynchronization the synchronization to use. Must not be {@literal null}.
|
* @param sessionSynchronization the synchronization to use. Must not be {@literal null}.
|
||||||
* @return the {@link MongoDatabase} that is potentially associated with a transactional {@link ClientSession}.
|
* @return the {@link MongoDatabase} that is potentially associated with a transactional {@link ClientSession}.
|
||||||
*/
|
*/
|
||||||
public static MongoDatabase getDatabase(MongoDatabaseFactory factory, SessionSynchronization sessionSynchronization) {
|
public static MongoDatabase getDatabase(MongoDbFactory factory, SessionSynchronization sessionSynchronization) {
|
||||||
return doGetMongoDatabase(null, factory, sessionSynchronization);
|
return doGetMongoDatabase(null, factory, sessionSynchronization);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Obtain the {@link MongoDatabase database} with given name form the given {@link MongoDatabaseFactory factory} using
|
* Obtain the {@link MongoDatabase database} with given name form the given {@link MongoDbFactory factory} using
|
||||||
* {@link SessionSynchronization#ON_ACTUAL_TRANSACTION native session synchronization}.
|
* {@link SessionSynchronization#ON_ACTUAL_TRANSACTION native session synchronization}.
|
||||||
* <br />
|
* <p />
|
||||||
* Registers a {@link MongoSessionSynchronization MongoDB specific transaction synchronization} within the current
|
* Registers a {@link MongoSessionSynchronization MongoDB specific transaction synchronization} within the current
|
||||||
* {@link Thread} if {@link TransactionSynchronizationManager#isSynchronizationActive() synchronization is active}.
|
* {@link Thread} if {@link TransactionSynchronizationManager#isSynchronizationActive() synchronization is active}.
|
||||||
*
|
*
|
||||||
* @param dbName the name of the {@link MongoDatabase} to get.
|
* @param dbName the name of the {@link MongoDatabase} to get.
|
||||||
* @param factory the {@link MongoDatabaseFactory} to get the {@link MongoDatabase} from.
|
* @param factory the {@link MongoDbFactory} to get the {@link MongoDatabase} from.
|
||||||
* @return the {@link MongoDatabase} that is potentially associated with a transactional {@link ClientSession}.
|
* @return the {@link MongoDatabase} that is potentially associated with a transactional {@link ClientSession}.
|
||||||
*/
|
*/
|
||||||
public static MongoDatabase getDatabase(@Nullable String dbName, MongoDatabaseFactory factory) {
|
public static MongoDatabase getDatabase(String dbName, MongoDbFactory factory) {
|
||||||
return doGetMongoDatabase(dbName, factory, SessionSynchronization.ON_ACTUAL_TRANSACTION);
|
return doGetMongoDatabase(dbName, factory, SessionSynchronization.ON_ACTUAL_TRANSACTION);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Obtain the {@link MongoDatabase database} with given name form the given {@link MongoDatabaseFactory factory}.
|
* Obtain the {@link MongoDatabase database} with given name form the given {@link MongoDbFactory factory}.
|
||||||
* <br />
|
* <p />
|
||||||
* Registers a {@link MongoSessionSynchronization MongoDB specific transaction synchronization} within the current
|
* Registers a {@link MongoSessionSynchronization MongoDB specific transaction synchronization} within the current
|
||||||
* {@link Thread} if {@link TransactionSynchronizationManager#isSynchronizationActive() synchronization is active}.
|
* {@link Thread} if {@link TransactionSynchronizationManager#isSynchronizationActive() synchronization is active}.
|
||||||
*
|
*
|
||||||
* @param dbName the name of the {@link MongoDatabase} to get.
|
* @param dbName the name of the {@link MongoDatabase} to get.
|
||||||
* @param factory the {@link MongoDatabaseFactory} to get the {@link MongoDatabase} from.
|
* @param factory the {@link MongoDbFactory} to get the {@link MongoDatabase} from.
|
||||||
* @param sessionSynchronization the synchronization to use. Must not be {@literal null}.
|
* @param sessionSynchronization the synchronization to use. Must not be {@literal null}.
|
||||||
* @return the {@link MongoDatabase} that is potentially associated with a transactional {@link ClientSession}.
|
* @return the {@link MongoDatabase} that is potentially associated with a transactional {@link ClientSession}.
|
||||||
*/
|
*/
|
||||||
public static MongoDatabase getDatabase(@Nullable String dbName, MongoDatabaseFactory factory,
|
public static MongoDatabase getDatabase(String dbName, MongoDbFactory factory,
|
||||||
SessionSynchronization sessionSynchronization) {
|
SessionSynchronization sessionSynchronization) {
|
||||||
return doGetMongoDatabase(dbName, factory, sessionSynchronization);
|
return doGetMongoDatabase(dbName, factory, sessionSynchronization);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static MongoDatabase doGetMongoDatabase(@Nullable String dbName, MongoDatabaseFactory factory,
|
private static MongoDatabase doGetMongoDatabase(@Nullable String dbName, MongoDbFactory factory,
|
||||||
SessionSynchronization sessionSynchronization) {
|
SessionSynchronization sessionSynchronization) {
|
||||||
|
|
||||||
Assert.notNull(factory, "Factory must not be null!");
|
Assert.notNull(factory, "Factory must not be null!");
|
||||||
|
|
||||||
if (sessionSynchronization == SessionSynchronization.NEVER
|
if (!TransactionSynchronizationManager.isSynchronizationActive()) {
|
||||||
|| !TransactionSynchronizationManager.isSynchronizationActive()) {
|
return StringUtils.hasText(dbName) ? factory.getDb(dbName) : factory.getDb();
|
||||||
return StringUtils.hasText(dbName) ? factory.getMongoDatabase(dbName) : factory.getMongoDatabase();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ClientSession session = doGetSession(factory, sessionSynchronization);
|
ClientSession session = doGetSession(factory, sessionSynchronization);
|
||||||
|
|
||||||
if (session == null) {
|
if (session == null) {
|
||||||
return StringUtils.hasText(dbName) ? factory.getMongoDatabase(dbName) : factory.getMongoDatabase();
|
return StringUtils.hasText(dbName) ? factory.getDb(dbName) : factory.getDb();
|
||||||
}
|
}
|
||||||
|
|
||||||
MongoDatabaseFactory factoryToUse = factory.withSession(session);
|
MongoDbFactory factoryToUse = factory.withSession(session);
|
||||||
return StringUtils.hasText(dbName) ? factoryToUse.getMongoDatabase(dbName) : factoryToUse.getMongoDatabase();
|
return StringUtils.hasText(dbName) ? factoryToUse.getDb(dbName) : factoryToUse.getDb();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if the {@link MongoDatabaseFactory} is actually bound to a {@link ClientSession} that has an active
|
* Check if the {@link MongoDbFactory} is actually bound to a {@link ClientSession} that has an active transaction, or
|
||||||
* transaction, or if a {@link TransactionSynchronization} has been registered for the {@link MongoDatabaseFactory
|
* if a {@link TransactionSynchronization} has been registered for the {@link MongoDbFactory resource} and if the
|
||||||
* resource} and if the associated {@link ClientSession} has an {@link ClientSession#hasActiveTransaction() active
|
* associated {@link ClientSession} has an {@link ClientSession#hasActiveTransaction() active transaction}.
|
||||||
* transaction}.
|
|
||||||
*
|
*
|
||||||
* @param dbFactory the resource to check transactions for. Must not be {@literal null}.
|
* @param dbFactory the resource to check transactions for. Must not be {@literal null}.
|
||||||
* @return {@literal true} if the factory has an ongoing transaction.
|
* @return {@literal true} if the factory has an ongoing transaction.
|
||||||
* @since 2.1.3
|
* @since 2.1.3
|
||||||
*/
|
*/
|
||||||
public static boolean isTransactionActive(MongoDatabaseFactory dbFactory) {
|
public static boolean isTransactionActive(MongoDbFactory dbFactory) {
|
||||||
|
|
||||||
if (dbFactory.isTransactionActive()) {
|
if (dbFactory.isTransactionActive()) {
|
||||||
return true;
|
return true;
|
||||||
@@ -140,8 +138,7 @@ public class MongoDatabaseUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
private static ClientSession doGetSession(MongoDatabaseFactory dbFactory,
|
private static ClientSession doGetSession(MongoDbFactory dbFactory, SessionSynchronization sessionSynchronization) {
|
||||||
SessionSynchronization sessionSynchronization) {
|
|
||||||
|
|
||||||
MongoResourceHolder resourceHolder = (MongoResourceHolder) TransactionSynchronizationManager.getResource(dbFactory);
|
MongoResourceHolder resourceHolder = (MongoResourceHolder) TransactionSynchronizationManager.getResource(dbFactory);
|
||||||
|
|
||||||
@@ -172,7 +169,7 @@ public class MongoDatabaseUtils {
|
|||||||
return resourceHolder.getSession();
|
return resourceHolder.getSession();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ClientSession createClientSession(MongoDatabaseFactory dbFactory) {
|
private static ClientSession createClientSession(MongoDbFactory dbFactory) {
|
||||||
return dbFactory.getSession(ClientSessionOptions.builder().causallyConsistent(true).build());
|
return dbFactory.getSession(ClientSessionOptions.builder().causallyConsistent(true).build());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -187,17 +184,25 @@ public class MongoDatabaseUtils {
|
|||||||
|
|
||||||
private final MongoResourceHolder resourceHolder;
|
private final MongoResourceHolder resourceHolder;
|
||||||
|
|
||||||
MongoSessionSynchronization(MongoResourceHolder resourceHolder, MongoDatabaseFactory dbFactory) {
|
MongoSessionSynchronization(MongoResourceHolder resourceHolder, MongoDbFactory dbFactory) {
|
||||||
|
|
||||||
super(resourceHolder, dbFactory);
|
super(resourceHolder, dbFactory);
|
||||||
this.resourceHolder = resourceHolder;
|
this.resourceHolder = resourceHolder;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.springframework.transaction.support.ResourceHolderSynchronization#shouldReleaseBeforeCompletion()
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
protected boolean shouldReleaseBeforeCompletion() {
|
protected boolean shouldReleaseBeforeCompletion() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.springframework.transaction.support.ResourceHolderSynchronization#processResourceAfterCommit(java.lang.Object)
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
protected void processResourceAfterCommit(MongoResourceHolder resourceHolder) {
|
protected void processResourceAfterCommit(MongoResourceHolder resourceHolder) {
|
||||||
|
|
||||||
@@ -206,6 +211,10 @@ public class MongoDatabaseUtils {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.springframework.transaction.support.ResourceHolderSynchronization#afterCompletion(int)
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void afterCompletion(int status) {
|
public void afterCompletion(int status) {
|
||||||
|
|
||||||
@@ -216,6 +225,10 @@ public class MongoDatabaseUtils {
|
|||||||
super.afterCompletion(status);
|
super.afterCompletion(status);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.springframework.transaction.support.ResourceHolderSynchronization#releaseResource(java.lang.Object, java.lang.Object)
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
protected void releaseResource(MongoResourceHolder resourceHolder, Object resourceKey) {
|
protected void releaseResource(MongoResourceHolder resourceHolder, Object resourceKey) {
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2011-2021 the original author or authors.
|
* Copyright 2011-2020 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,8 +15,14 @@
|
|||||||
*/
|
*/
|
||||||
package org.springframework.data.mongodb;
|
package org.springframework.data.mongodb;
|
||||||
|
|
||||||
|
import org.bson.codecs.configuration.CodecRegistry;
|
||||||
import org.springframework.dao.DataAccessException;
|
import org.springframework.dao.DataAccessException;
|
||||||
|
import org.springframework.dao.support.PersistenceExceptionTranslator;
|
||||||
|
import org.springframework.data.mongodb.core.MongoExceptionTranslator;
|
||||||
|
|
||||||
|
import com.mongodb.ClientSessionOptions;
|
||||||
|
import com.mongodb.DB;
|
||||||
|
import com.mongodb.client.ClientSession;
|
||||||
import com.mongodb.client.MongoDatabase;
|
import com.mongodb.client.MongoDatabase;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -25,33 +31,92 @@ import com.mongodb.client.MongoDatabase;
|
|||||||
* @author Mark Pollack
|
* @author Mark Pollack
|
||||||
* @author Thomas Darimont
|
* @author Thomas Darimont
|
||||||
* @author Christoph Strobl
|
* @author Christoph Strobl
|
||||||
* @deprecated since 3.0, use {@link MongoDatabaseFactory} instead.
|
|
||||||
*/
|
*/
|
||||||
@Deprecated
|
public interface MongoDbFactory extends CodecRegistryProvider, MongoSessionProvider {
|
||||||
public interface MongoDbFactory extends MongoDatabaseFactory {
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a default {@link MongoDatabase} instance.
|
* Creates a default {@link MongoDatabase} instance.
|
||||||
*
|
*
|
||||||
* @return never {@literal null}.
|
* @return
|
||||||
* @throws DataAccessException
|
* @throws DataAccessException
|
||||||
* @deprecated since 3.0. Use {@link #getMongoDatabase()} instead.
|
*/
|
||||||
|
MongoDatabase getDb() throws DataAccessException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a {@link DB} instance to access the database with the given name.
|
||||||
|
*
|
||||||
|
* @param dbName must not be {@literal null} or empty.
|
||||||
|
* @return
|
||||||
|
* @throws DataAccessException
|
||||||
|
*/
|
||||||
|
MongoDatabase getDb(String dbName) throws DataAccessException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exposes a shared {@link MongoExceptionTranslator}.
|
||||||
|
*
|
||||||
|
* @return will never be {@literal null}.
|
||||||
|
*/
|
||||||
|
PersistenceExceptionTranslator getExceptionTranslator();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the legacy database entry point. Please consider {@link #getDb()} instead.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* @deprecated since 2.1, use {@link #getDb()}. This method will be removed with a future version as it works only
|
||||||
|
* with the legacy MongoDB driver.
|
||||||
*/
|
*/
|
||||||
@Deprecated
|
@Deprecated
|
||||||
default MongoDatabase getDb() throws DataAccessException {
|
DB getLegacyDb();
|
||||||
return getMongoDatabase();
|
|
||||||
|
/**
|
||||||
|
* Get the underlying {@link CodecRegistry} used by the MongoDB Java driver.
|
||||||
|
*
|
||||||
|
* @return never {@literal null}.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
default CodecRegistry getCodecRegistry() {
|
||||||
|
return getDb().getCodecRegistry();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Obtain a {@link MongoDatabase} instance to access the database with the given name.
|
* Obtain a {@link ClientSession} for given ClientSessionOptions.
|
||||||
*
|
*
|
||||||
* @param dbName must not be {@literal null} or empty.
|
* @param options must not be {@literal null}.
|
||||||
* @return never {@literal null}.
|
* @return never {@literal null}.
|
||||||
* @throws DataAccessException
|
* @since 2.1
|
||||||
* @deprecated since 3.0. Use {@link #getMongoDatabase(String)} instead.
|
|
||||||
*/
|
*/
|
||||||
@Deprecated
|
ClientSession getSession(ClientSessionOptions options);
|
||||||
default MongoDatabase getDb(String dbName) throws DataAccessException {
|
|
||||||
return getMongoDatabase(dbName);
|
/**
|
||||||
|
* Obtain a {@link ClientSession} bound instance of {@link MongoDbFactory} returning {@link MongoDatabase} instances
|
||||||
|
* that are aware and bound to a new session with given {@link ClientSessionOptions options}.
|
||||||
|
*
|
||||||
|
* @param options must not be {@literal null}.
|
||||||
|
* @return never {@literal null}.
|
||||||
|
* @since 2.1
|
||||||
|
*/
|
||||||
|
default MongoDbFactory withSession(ClientSessionOptions options) {
|
||||||
|
return withSession(getSession(options));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obtain a {@link ClientSession} bound instance of {@link MongoDbFactory} returning {@link MongoDatabase} instances
|
||||||
|
* that are aware and bound to the given session.
|
||||||
|
*
|
||||||
|
* @param session must not be {@literal null}.
|
||||||
|
* @return never {@literal null}.
|
||||||
|
* @since 2.1
|
||||||
|
*/
|
||||||
|
MongoDbFactory withSession(ClientSession session);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns if the given {@link MongoDbFactory} is bound to a {@link ClientSession} that has an
|
||||||
|
* {@link ClientSession#hasActiveTransaction() active transaction}.
|
||||||
|
*
|
||||||
|
* @return {@literal true} if there's an active transaction, {@literal false} otherwise.
|
||||||
|
* @since 2.1.3
|
||||||
|
*/
|
||||||
|
default boolean isTransactionActive() {
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,73 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2021 the original author or authors.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* https://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package org.springframework.data.mongodb;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Wrapper object for MongoDB expressions like {@code $toUpper : $name} that manifest as {@link org.bson.Document} when
|
|
||||||
* passed on to the driver.
|
|
||||||
* <br />
|
|
||||||
* A set of predefined {@link MongoExpression expressions}, including a
|
|
||||||
* {@link org.springframework.data.mongodb.core.aggregation.AggregationSpELExpression SpEL based variant} for method
|
|
||||||
* like expressions (eg. {@code toUpper(name)}) are available via the
|
|
||||||
* {@link org.springframework.data.mongodb.core.aggregation Aggregation API}.
|
|
||||||
*
|
|
||||||
* @author Christoph Strobl
|
|
||||||
* @since 3.2
|
|
||||||
* @see org.springframework.data.mongodb.core.aggregation.ArithmeticOperators
|
|
||||||
* @see org.springframework.data.mongodb.core.aggregation.ArrayOperators
|
|
||||||
* @see org.springframework.data.mongodb.core.aggregation.ComparisonOperators
|
|
||||||
* @see org.springframework.data.mongodb.core.aggregation.ConditionalOperators
|
|
||||||
* @see org.springframework.data.mongodb.core.aggregation.ConvertOperators
|
|
||||||
* @see org.springframework.data.mongodb.core.aggregation.DateOperators
|
|
||||||
* @see org.springframework.data.mongodb.core.aggregation.ObjectOperators
|
|
||||||
* @see org.springframework.data.mongodb.core.aggregation.SetOperators
|
|
||||||
* @see org.springframework.data.mongodb.core.aggregation.StringOperators
|
|
||||||
*/
|
|
||||||
@FunctionalInterface
|
|
||||||
public interface MongoExpression {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new {@link MongoExpression} from plain {@link String} (eg. {@code $toUpper : $name}). <br />
|
|
||||||
* The given expression will be wrapped with <code>{ ... }</code> to match an actual MongoDB {@link org.bson.Document}
|
|
||||||
* if necessary.
|
|
||||||
*
|
|
||||||
* @param expression must not be {@literal null}.
|
|
||||||
* @return new instance of {@link MongoExpression}.
|
|
||||||
*/
|
|
||||||
static MongoExpression create(String expression) {
|
|
||||||
return new BindableMongoExpression(expression, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new {@link MongoExpression} from plain {@link String} containing placeholders (eg. {@code $toUpper : ?0})
|
|
||||||
* that will be resolved on first call of {@link #toDocument()}. <br />
|
|
||||||
* The given expression will be wrapped with <code>{ ... }</code> to match an actual MongoDB {@link org.bson.Document}
|
|
||||||
* if necessary.
|
|
||||||
*
|
|
||||||
* @param expression must not be {@literal null}.
|
|
||||||
* @return new instance of {@link MongoExpression}.
|
|
||||||
*/
|
|
||||||
static MongoExpression create(String expression, Object... args) {
|
|
||||||
return new BindableMongoExpression(expression, args);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Obtain the native {@link org.bson.Document} representation.
|
|
||||||
*
|
|
||||||
* @return never {@literal null}.
|
|
||||||
*/
|
|
||||||
org.bson.Document toDocument();
|
|
||||||
}
|
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2018-2021 the original author or authors.
|
* Copyright 2018-2020 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.
|
||||||
@@ -24,7 +24,7 @@ import com.mongodb.client.ClientSession;
|
|||||||
/**
|
/**
|
||||||
* MongoDB specific {@link ResourceHolderSupport resource holder}, wrapping a {@link ClientSession}.
|
* MongoDB specific {@link ResourceHolderSupport resource holder}, wrapping a {@link ClientSession}.
|
||||||
* {@link MongoTransactionManager} binds instances of this class to the thread.
|
* {@link MongoTransactionManager} binds instances of this class to the thread.
|
||||||
* <br />
|
* <p />
|
||||||
* <strong>Note:</strong> Intended for internal usage only.
|
* <strong>Note:</strong> Intended for internal usage only.
|
||||||
*
|
*
|
||||||
* @author Christoph Strobl
|
* @author Christoph Strobl
|
||||||
@@ -36,15 +36,15 @@ import com.mongodb.client.ClientSession;
|
|||||||
class MongoResourceHolder extends ResourceHolderSupport {
|
class MongoResourceHolder extends ResourceHolderSupport {
|
||||||
|
|
||||||
private @Nullable ClientSession session;
|
private @Nullable ClientSession session;
|
||||||
private MongoDatabaseFactory dbFactory;
|
private MongoDbFactory dbFactory;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new {@link MongoResourceHolder} for a given {@link ClientSession session}.
|
* Create a new {@link MongoResourceHolder} for a given {@link ClientSession session}.
|
||||||
*
|
*
|
||||||
* @param session the associated {@link ClientSession}. Can be {@literal null}.
|
* @param session the associated {@link ClientSession}. Can be {@literal null}.
|
||||||
* @param dbFactory the associated {@link MongoDatabaseFactory}. must not be {@literal null}.
|
* @param dbFactory the associated {@link MongoDbFactory}. must not be {@literal null}.
|
||||||
*/
|
*/
|
||||||
MongoResourceHolder(@Nullable ClientSession session, MongoDatabaseFactory dbFactory) {
|
MongoResourceHolder(@Nullable ClientSession session, MongoDbFactory dbFactory) {
|
||||||
|
|
||||||
this.session = session;
|
this.session = session;
|
||||||
this.dbFactory = dbFactory;
|
this.dbFactory = dbFactory;
|
||||||
@@ -75,9 +75,9 @@ class MongoResourceHolder extends ResourceHolderSupport {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the associated {@link MongoDatabaseFactory}.
|
* @return the associated {@link MongoDbFactory}.
|
||||||
*/
|
*/
|
||||||
public MongoDatabaseFactory getDbFactory() {
|
public MongoDbFactory getDbFactory() {
|
||||||
return dbFactory;
|
return dbFactory;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2018-2021 the original author or authors.
|
* Copyright 2018-2020 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-2021 the original author or authors.
|
* Copyright 2018-2020 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-2021 the original author or authors.
|
* Copyright 2018-2020 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.
|
||||||
@@ -36,19 +36,18 @@ import com.mongodb.client.ClientSession;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* A {@link org.springframework.transaction.PlatformTransactionManager} implementation that manages
|
* A {@link org.springframework.transaction.PlatformTransactionManager} implementation that manages
|
||||||
* {@link ClientSession} based transactions for a single {@link MongoDatabaseFactory}.
|
* {@link ClientSession} based transactions for a single {@link MongoDbFactory}.
|
||||||
* <br />
|
* <p />
|
||||||
* Binds a {@link ClientSession} from the specified {@link MongoDatabaseFactory} to the thread.
|
* Binds a {@link ClientSession} from the specified {@link MongoDbFactory} to the thread.
|
||||||
* <br />
|
* <p />
|
||||||
* {@link TransactionDefinition#isReadOnly() Readonly} transactions operate on a {@link ClientSession} and enable causal
|
* {@link TransactionDefinition#isReadOnly() Readonly} transactions operate on a {@link ClientSession} and enable causal
|
||||||
* consistency, and also {@link ClientSession#startTransaction() start}, {@link ClientSession#commitTransaction()
|
* consistency, and also {@link ClientSession#startTransaction() start}, {@link ClientSession#commitTransaction()
|
||||||
* commit} or {@link ClientSession#abortTransaction() abort} a transaction.
|
* commit} or {@link ClientSession#abortTransaction() abort} a transaction.
|
||||||
* <br />
|
* <p />
|
||||||
* Application code is required to retrieve the {@link com.mongodb.client.MongoDatabase} via
|
* Application code is required to retrieve the {@link com.mongodb.client.MongoDatabase} via
|
||||||
* {@link MongoDatabaseUtils#getDatabase(MongoDatabaseFactory)} instead of a standard
|
* {@link MongoDatabaseUtils#getDatabase(MongoDbFactory)} instead of a standard {@link MongoDbFactory#getDb()} call.
|
||||||
* {@link MongoDatabaseFactory#getMongoDatabase()} call. Spring classes such as
|
* Spring classes such as {@link org.springframework.data.mongodb.core.MongoTemplate} use this strategy implicitly.
|
||||||
* {@link org.springframework.data.mongodb.core.MongoTemplate} use this strategy implicitly.
|
* <p />
|
||||||
* <br />
|
|
||||||
* By default failure of a {@literal commit} operation raises a {@link TransactionSystemException}. One may override
|
* By default failure of a {@literal commit} operation raises a {@link TransactionSystemException}. One may override
|
||||||
* {@link #doCommit(MongoTransactionObject)} to implement the
|
* {@link #doCommit(MongoTransactionObject)} to implement the
|
||||||
* <a href="https://docs.mongodb.com/manual/core/transactions/#retry-commit-operation">Retry Commit Operation</a>
|
* <a href="https://docs.mongodb.com/manual/core/transactions/#retry-commit-operation">Retry Commit Operation</a>
|
||||||
@@ -59,46 +58,46 @@ import com.mongodb.client.ClientSession;
|
|||||||
* @currentRead Shadow's Edge - Brent Weeks
|
* @currentRead Shadow's Edge - Brent Weeks
|
||||||
* @since 2.1
|
* @since 2.1
|
||||||
* @see <a href="https://www.mongodb.com/transactions">MongoDB Transaction Documentation</a>
|
* @see <a href="https://www.mongodb.com/transactions">MongoDB Transaction Documentation</a>
|
||||||
* @see MongoDatabaseUtils#getDatabase(MongoDatabaseFactory, SessionSynchronization)
|
* @see MongoDatabaseUtils#getDatabase(MongoDbFactory, SessionSynchronization)
|
||||||
*/
|
*/
|
||||||
public class MongoTransactionManager extends AbstractPlatformTransactionManager
|
public class MongoTransactionManager extends AbstractPlatformTransactionManager
|
||||||
implements ResourceTransactionManager, InitializingBean {
|
implements ResourceTransactionManager, InitializingBean {
|
||||||
|
|
||||||
private @Nullable MongoDatabaseFactory dbFactory;
|
private @Nullable MongoDbFactory dbFactory;
|
||||||
private @Nullable TransactionOptions options;
|
private @Nullable TransactionOptions options;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new {@link MongoTransactionManager} for bean-style usage.
|
* Create a new {@link MongoTransactionManager} for bean-style usage.
|
||||||
* <br />
|
* <p />
|
||||||
* <strong>Note:</strong>The {@link MongoDatabaseFactory db factory} has to be
|
* <strong>Note:</strong>The {@link MongoDbFactory db factory} has to be {@link #setDbFactory(MongoDbFactory) set}
|
||||||
* {@link #setDbFactory(MongoDatabaseFactory) set} before using the instance. Use this constructor to prepare a
|
* before using the instance. Use this constructor to prepare a {@link MongoTransactionManager} via a
|
||||||
* {@link MongoTransactionManager} via a {@link org.springframework.beans.factory.BeanFactory}.
|
* {@link org.springframework.beans.factory.BeanFactory}.
|
||||||
* <br />
|
* <p />
|
||||||
* Optionally it is possible to set default {@link TransactionOptions transaction options} defining
|
* Optionally it is possible to set default {@link TransactionOptions transaction options} defining
|
||||||
* {@link com.mongodb.ReadConcern} and {@link com.mongodb.WriteConcern}.
|
* {@link com.mongodb.ReadConcern} and {@link com.mongodb.WriteConcern}.
|
||||||
*
|
*
|
||||||
* @see #setDbFactory(MongoDatabaseFactory)
|
* @see #setDbFactory(MongoDbFactory)
|
||||||
* @see #setTransactionSynchronization(int)
|
* @see #setTransactionSynchronization(int)
|
||||||
*/
|
*/
|
||||||
public MongoTransactionManager() {}
|
public MongoTransactionManager() {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new {@link MongoTransactionManager} obtaining sessions from the given {@link MongoDatabaseFactory}.
|
* Create a new {@link MongoTransactionManager} obtaining sessions from the given {@link MongoDbFactory}.
|
||||||
*
|
*
|
||||||
* @param dbFactory must not be {@literal null}.
|
* @param dbFactory must not be {@literal null}.
|
||||||
*/
|
*/
|
||||||
public MongoTransactionManager(MongoDatabaseFactory dbFactory) {
|
public MongoTransactionManager(MongoDbFactory dbFactory) {
|
||||||
this(dbFactory, null);
|
this(dbFactory, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new {@link MongoTransactionManager} obtaining sessions from the given {@link MongoDatabaseFactory}
|
* Create a new {@link MongoTransactionManager} obtaining sessions from the given {@link MongoDbFactory} applying the
|
||||||
* applying the given {@link TransactionOptions options}, if present, when starting a new transaction.
|
* given {@link TransactionOptions options}, if present, when starting a new transaction.
|
||||||
*
|
*
|
||||||
* @param dbFactory must not be {@literal null}.
|
* @param dbFactory must not be {@literal null}.
|
||||||
* @param options can be {@literal null}.
|
* @param options can be {@literal null}.
|
||||||
*/
|
*/
|
||||||
public MongoTransactionManager(MongoDatabaseFactory dbFactory, @Nullable TransactionOptions options) {
|
public MongoTransactionManager(MongoDbFactory dbFactory, @Nullable TransactionOptions options) {
|
||||||
|
|
||||||
Assert.notNull(dbFactory, "DbFactory must not be null!");
|
Assert.notNull(dbFactory, "DbFactory must not be null!");
|
||||||
|
|
||||||
@@ -106,6 +105,10 @@ public class MongoTransactionManager extends AbstractPlatformTransactionManager
|
|||||||
this.options = options;
|
this.options = options;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* org.springframework.transaction.support.AbstractPlatformTransactionManager#doGetTransaction()
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
protected Object doGetTransaction() throws TransactionException {
|
protected Object doGetTransaction() throws TransactionException {
|
||||||
|
|
||||||
@@ -114,11 +117,19 @@ public class MongoTransactionManager extends AbstractPlatformTransactionManager
|
|||||||
return new MongoTransactionObject(resourceHolder);
|
return new MongoTransactionObject(resourceHolder);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* org.springframework.transaction.support.AbstractPlatformTransactionManager#isExistingTransaction(java.lang.Object)
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
protected boolean isExistingTransaction(Object transaction) throws TransactionException {
|
protected boolean isExistingTransaction(Object transaction) throws TransactionException {
|
||||||
return extractMongoTransaction(transaction).hasResourceHolder();
|
return extractMongoTransaction(transaction).hasResourceHolder();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* org.springframework.transaction.support.AbstractPlatformTransactionManager#doBegin(java.lang.Object, org.springframework.transaction.TransactionDefinition)
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
protected void doBegin(Object transaction, TransactionDefinition definition) throws TransactionException {
|
protected void doBegin(Object transaction, TransactionDefinition definition) throws TransactionException {
|
||||||
|
|
||||||
@@ -148,6 +159,10 @@ public class MongoTransactionManager extends AbstractPlatformTransactionManager
|
|||||||
TransactionSynchronizationManager.bindResource(getRequiredDbFactory(), resourceHolder);
|
TransactionSynchronizationManager.bindResource(getRequiredDbFactory(), resourceHolder);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* org.springframework.transaction.support.AbstractPlatformTransactionManager#doSuspend(java.lang.Object)
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
protected Object doSuspend(Object transaction) throws TransactionException {
|
protected Object doSuspend(Object transaction) throws TransactionException {
|
||||||
|
|
||||||
@@ -157,11 +172,19 @@ public class MongoTransactionManager extends AbstractPlatformTransactionManager
|
|||||||
return TransactionSynchronizationManager.unbindResource(getRequiredDbFactory());
|
return TransactionSynchronizationManager.unbindResource(getRequiredDbFactory());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* org.springframework.transaction.support.AbstractPlatformTransactionManager#doResume(java.lang.Object, java.lang.Object)
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
protected void doResume(@Nullable Object transaction, Object suspendedResources) {
|
protected void doResume(@Nullable Object transaction, Object suspendedResources) {
|
||||||
TransactionSynchronizationManager.bindResource(getRequiredDbFactory(), suspendedResources);
|
TransactionSynchronizationManager.bindResource(getRequiredDbFactory(), suspendedResources);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* org.springframework.transaction.support.AbstractPlatformTransactionManager#doCommit(org.springframework.transaction.support.DefaultTransactionStatus)
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
protected final void doCommit(DefaultTransactionStatus status) throws TransactionException {
|
protected final void doCommit(DefaultTransactionStatus status) throws TransactionException {
|
||||||
|
|
||||||
@@ -188,8 +211,8 @@ public class MongoTransactionManager extends AbstractPlatformTransactionManager
|
|||||||
* By default those labels are ignored, nevertheless one might check for
|
* 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
|
* {@link MongoException#UNKNOWN_TRANSACTION_COMMIT_RESULT_LABEL transient commit errors labels} and retry the the
|
||||||
* commit. <br />
|
* commit. <br />
|
||||||
* <pre>
|
|
||||||
* <code>
|
* <code>
|
||||||
|
* <pre>
|
||||||
* int retries = 3;
|
* int retries = 3;
|
||||||
* do {
|
* do {
|
||||||
* try {
|
* try {
|
||||||
@@ -202,8 +225,8 @@ public class MongoTransactionManager extends AbstractPlatformTransactionManager
|
|||||||
* }
|
* }
|
||||||
* Thread.sleep(500);
|
* Thread.sleep(500);
|
||||||
* } while (--retries > 0);
|
* } while (--retries > 0);
|
||||||
|
* </pre>
|
||||||
* </code>
|
* </code>
|
||||||
* </pre>
|
|
||||||
*
|
*
|
||||||
* @param transactionObject never {@literal null}.
|
* @param transactionObject never {@literal null}.
|
||||||
* @throws Exception in case of transaction errors.
|
* @throws Exception in case of transaction errors.
|
||||||
@@ -212,6 +235,10 @@ public class MongoTransactionManager extends AbstractPlatformTransactionManager
|
|||||||
transactionObject.commitTransaction();
|
transactionObject.commitTransaction();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* org.springframework.transaction.support.AbstractPlatformTransactionManager#doRollback(org.springframework.transaction.support.DefaultTransactionStatus)
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
protected void doRollback(DefaultTransactionStatus status) throws TransactionException {
|
protected void doRollback(DefaultTransactionStatus status) throws TransactionException {
|
||||||
|
|
||||||
@@ -231,6 +258,10 @@ public class MongoTransactionManager extends AbstractPlatformTransactionManager
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* org.springframework.transaction.support.AbstractPlatformTransactionManager#doSetRollbackOnly(org.springframework.transaction.support.DefaultTransactionStatus)
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
protected void doSetRollbackOnly(DefaultTransactionStatus status) throws TransactionException {
|
protected void doSetRollbackOnly(DefaultTransactionStatus status) throws TransactionException {
|
||||||
|
|
||||||
@@ -238,6 +269,10 @@ public class MongoTransactionManager extends AbstractPlatformTransactionManager
|
|||||||
transactionObject.getRequiredResourceHolder().setRollbackOnly();
|
transactionObject.getRequiredResourceHolder().setRollbackOnly();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* org.springframework.transaction.support.AbstractPlatformTransactionManager#doCleanupAfterCompletion(java.lang.Object)
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
protected void doCleanupAfterCompletion(Object transaction) {
|
protected void doCleanupAfterCompletion(Object transaction) {
|
||||||
|
|
||||||
@@ -260,11 +295,11 @@ public class MongoTransactionManager extends AbstractPlatformTransactionManager
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the {@link MongoDatabaseFactory} that this instance should manage transactions for.
|
* Set the {@link MongoDbFactory} that this instance should manage transactions for.
|
||||||
*
|
*
|
||||||
* @param dbFactory must not be {@literal null}.
|
* @param dbFactory must not be {@literal null}.
|
||||||
*/
|
*/
|
||||||
public void setDbFactory(MongoDatabaseFactory dbFactory) {
|
public void setDbFactory(MongoDbFactory dbFactory) {
|
||||||
|
|
||||||
Assert.notNull(dbFactory, "DbFactory must not be null!");
|
Assert.notNull(dbFactory, "DbFactory must not be null!");
|
||||||
this.dbFactory = dbFactory;
|
this.dbFactory = dbFactory;
|
||||||
@@ -280,20 +315,28 @@ public class MongoTransactionManager extends AbstractPlatformTransactionManager
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the {@link MongoDatabaseFactory} that this instance manages transactions for.
|
* Get the {@link MongoDbFactory} that this instance manages transactions for.
|
||||||
*
|
*
|
||||||
* @return can be {@literal null}.
|
* @return can be {@literal null}.
|
||||||
*/
|
*/
|
||||||
@Nullable
|
@Nullable
|
||||||
public MongoDatabaseFactory getDbFactory() {
|
public MongoDbFactory getDbFactory() {
|
||||||
return dbFactory;
|
return dbFactory;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.springframework.transaction.support.ResourceTransactionManager#getResourceFactory()
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public MongoDatabaseFactory getResourceFactory() {
|
public MongoDbFactory getResourceFactory() {
|
||||||
return getRequiredDbFactory();
|
return getRequiredDbFactory();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void afterPropertiesSet() {
|
public void afterPropertiesSet() {
|
||||||
getRequiredDbFactory();
|
getRequiredDbFactory();
|
||||||
@@ -301,7 +344,7 @@ public class MongoTransactionManager extends AbstractPlatformTransactionManager
|
|||||||
|
|
||||||
private MongoResourceHolder newResourceHolder(TransactionDefinition definition, ClientSessionOptions options) {
|
private MongoResourceHolder newResourceHolder(TransactionDefinition definition, ClientSessionOptions options) {
|
||||||
|
|
||||||
MongoDatabaseFactory dbFactory = getResourceFactory();
|
MongoDbFactory dbFactory = getResourceFactory();
|
||||||
|
|
||||||
MongoResourceHolder resourceHolder = new MongoResourceHolder(dbFactory.getSession(options), dbFactory);
|
MongoResourceHolder resourceHolder = new MongoResourceHolder(dbFactory.getSession(options), dbFactory);
|
||||||
resourceHolder.setTimeoutIfNotDefaulted(determineTimeout(definition));
|
resourceHolder.setTimeoutIfNotDefaulted(determineTimeout(definition));
|
||||||
@@ -312,7 +355,7 @@ public class MongoTransactionManager extends AbstractPlatformTransactionManager
|
|||||||
/**
|
/**
|
||||||
* @throws IllegalStateException if {@link #dbFactory} is {@literal null}.
|
* @throws IllegalStateException if {@link #dbFactory} is {@literal null}.
|
||||||
*/
|
*/
|
||||||
private MongoDatabaseFactory getRequiredDbFactory() {
|
private MongoDbFactory getRequiredDbFactory() {
|
||||||
|
|
||||||
Assert.state(dbFactory != null,
|
Assert.state(dbFactory != null,
|
||||||
"MongoTransactionManager operates upon a MongoDbFactory. Did you forget to provide one? It's required.");
|
"MongoTransactionManager operates upon a MongoDbFactory. Did you forget to provide one? It's required.");
|
||||||
@@ -461,11 +504,19 @@ public class MongoTransactionManager extends AbstractPlatformTransactionManager
|
|||||||
return session;
|
return session;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.springframework.transaction.support.SmartTransactionObject#isRollbackOnly()
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public boolean isRollbackOnly() {
|
public boolean isRollbackOnly() {
|
||||||
return this.resourceHolder != null && this.resourceHolder.isRollbackOnly();
|
return this.resourceHolder != null && this.resourceHolder.isRollbackOnly();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.springframework.transaction.support.SmartTransactionObject#flush()
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void flush() {
|
public void flush() {
|
||||||
TransactionSynchronizationUtils.triggerFlush();
|
TransactionSynchronizationUtils.triggerFlush();
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2016-2021 the original author or authors.
|
* Copyright 2016-2020 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;
|
||||||
@@ -31,7 +32,6 @@ import com.mongodb.reactivestreams.client.MongoDatabase;
|
|||||||
*
|
*
|
||||||
* @author Mark Paluch
|
* @author Mark Paluch
|
||||||
* @author Christoph Strobl
|
* @author Christoph Strobl
|
||||||
* @author Mathieu Ouellet
|
|
||||||
* @since 2.0
|
* @since 2.0
|
||||||
*/
|
*/
|
||||||
public interface ReactiveMongoDatabaseFactory extends CodecRegistryProvider {
|
public interface ReactiveMongoDatabaseFactory extends CodecRegistryProvider {
|
||||||
@@ -39,19 +39,19 @@ public interface ReactiveMongoDatabaseFactory extends CodecRegistryProvider {
|
|||||||
/**
|
/**
|
||||||
* Creates a default {@link MongoDatabase} instance.
|
* Creates a default {@link MongoDatabase} instance.
|
||||||
*
|
*
|
||||||
* @return never {@literal null}.
|
* @return
|
||||||
* @throws DataAccessException
|
* @throws DataAccessException
|
||||||
*/
|
*/
|
||||||
Mono<MongoDatabase> getMongoDatabase() throws DataAccessException;
|
MongoDatabase getMongoDatabase() throws DataAccessException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Obtain a {@link MongoDatabase} instance to access the database with the given name.
|
* Creates a {@link MongoDatabase} instance to access the database with the given name.
|
||||||
*
|
*
|
||||||
* @param dbName must not be {@literal null} or empty.
|
* @param dbName must not be {@literal null} or empty.
|
||||||
* @return never {@literal null}.
|
* @return
|
||||||
* @throws DataAccessException
|
* @throws DataAccessException
|
||||||
*/
|
*/
|
||||||
Mono<MongoDatabase> getMongoDatabase(String dbName) throws DataAccessException;
|
MongoDatabase getMongoDatabase(String dbName) throws DataAccessException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Exposes a shared {@link MongoExceptionTranslator}.
|
* Exposes a shared {@link MongoExceptionTranslator}.
|
||||||
@@ -65,7 +65,10 @@ public interface ReactiveMongoDatabaseFactory extends CodecRegistryProvider {
|
|||||||
*
|
*
|
||||||
* @return never {@literal null}.
|
* @return never {@literal null}.
|
||||||
*/
|
*/
|
||||||
CodecRegistry getCodecRegistry();
|
@Override
|
||||||
|
default CodecRegistry getCodecRegistry() {
|
||||||
|
return getMongoDatabase().getCodecRegistry();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Obtain a {@link Mono} emitting a {@link ClientSession} for given {@link ClientSessionOptions options}.
|
* Obtain a {@link Mono} emitting a {@link ClientSession} for given {@link ClientSessionOptions options}.
|
||||||
@@ -85,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,266 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2019-2021 the original author or authors.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* https://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package org.springframework.data.mongodb;
|
|
||||||
|
|
||||||
import 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.
|
|
||||||
* <br />
|
|
||||||
* <strong>Note:</strong> Intended for internal usage only.
|
|
||||||
*
|
|
||||||
* @author Mark Paluch
|
|
||||||
* @author Christoph Strobl
|
|
||||||
* @author Mathieu Ouellet
|
|
||||||
* @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}.
|
|
||||||
* <br />
|
|
||||||
* 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}.
|
|
||||||
* <br />
|
|
||||||
* 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}.
|
|
||||||
* <br />
|
|
||||||
* 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}.
|
|
||||||
* <br />
|
|
||||||
* 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!");
|
|
||||||
|
|
||||||
if (sessionSynchronization == SessionSynchronization.NEVER) {
|
|
||||||
return getMongoDatabaseOrDefault(dbName, factory);
|
|
||||||
}
|
|
||||||
|
|
||||||
return TransactionSynchronizationManager.forCurrentTransaction()
|
|
||||||
.filter(TransactionSynchronizationManager::isSynchronizationActive) //
|
|
||||||
.flatMap(synchronizationManager -> {
|
|
||||||
|
|
||||||
return doGetSession(synchronizationManager, factory, sessionSynchronization) //
|
|
||||||
.flatMap(it -> getMongoDatabaseOrDefault(dbName, factory.withSession(it)));
|
|
||||||
}) //
|
|
||||||
.onErrorResume(NoTransactionException.class, e -> getMongoDatabaseOrDefault(dbName, factory))
|
|
||||||
.switchIfEmpty(getMongoDatabaseOrDefault(dbName, factory));
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Mono<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;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected boolean shouldReleaseBeforeCompletion() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Mono<Void> processResourceAfterCommit(ReactiveMongoResourceHolder resourceHolder) {
|
|
||||||
|
|
||||||
if (isTransactionActive(resourceHolder)) {
|
|
||||||
return Mono.from(resourceHolder.getRequiredSession().commitTransaction());
|
|
||||||
}
|
|
||||||
|
|
||||||
return Mono.empty();
|
|
||||||
}
|
|
||||||
|
|
||||||
@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);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@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-2021 the original author or authors.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* https://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package org.springframework.data.mongodb;
|
|
||||||
|
|
||||||
import org.springframework.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.
|
|
||||||
* <br />
|
|
||||||
* <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 MongoDatabaseFactory}. 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,482 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2019-2021 the original author or authors.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* https://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package org.springframework.data.mongodb;
|
|
||||||
|
|
||||||
import 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}.
|
|
||||||
* <br />
|
|
||||||
* Binds a {@link ClientSession} from the specified
|
|
||||||
* {@link org.springframework.data.mongodb.ReactiveMongoDatabaseFactory} to the subscriber
|
|
||||||
* {@link reactor.util.context.Context}.
|
|
||||||
* <br />
|
|
||||||
* {@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.
|
|
||||||
* <br />
|
|
||||||
* 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.
|
|
||||||
* <br />
|
|
||||||
* 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.
|
|
||||||
* <br />
|
|
||||||
* <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}.
|
|
||||||
* <br />
|
|
||||||
* 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Object doGetTransaction(TransactionSynchronizationManager synchronizationManager)
|
|
||||||
throws TransactionException {
|
|
||||||
|
|
||||||
ReactiveMongoResourceHolder resourceHolder = (ReactiveMongoResourceHolder) synchronizationManager
|
|
||||||
.getResource(getRequiredDatabaseFactory());
|
|
||||||
return new ReactiveMongoTransactionObject(resourceHolder);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected boolean isExistingTransaction(Object transaction) throws TransactionException {
|
|
||||||
return extractMongoTransaction(transaction).hasResourceHolder();
|
|
||||||
}
|
|
||||||
|
|
||||||
@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();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@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());
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Mono<Void> doResume(TransactionSynchronizationManager synchronizationManager, @Nullable Object transaction,
|
|
||||||
Object suspendedResources) {
|
|
||||||
return Mono
|
|
||||||
.fromRunnable(() -> synchronizationManager.bindResource(getRequiredDatabaseFactory(), suspendedResources));
|
|
||||||
}
|
|
||||||
|
|
||||||
@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();
|
|
||||||
}
|
|
||||||
|
|
||||||
@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));
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Mono<Void> doSetRollbackOnly(TransactionSynchronizationManager synchronizationManager,
|
|
||||||
GenericReactiveTransaction status) throws TransactionException {
|
|
||||||
|
|
||||||
return Mono.fromRunnable(() -> {
|
|
||||||
ReactiveMongoTransactionObject transactionObject = extractMongoTransaction(status);
|
|
||||||
transactionObject.getRequiredResourceHolder().setRollbackOnly();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@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;
|
|
||||||
}
|
|
||||||
|
|
||||||
@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;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isRollbackOnly() {
|
|
||||||
return this.resourceHolder != null && this.resourceHolder.isRollbackOnly();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void flush() {
|
|
||||||
throw new UnsupportedOperationException("flush() not supported");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2018-2021 the original author or authors.
|
* Copyright 2018-2020 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,7 @@ import com.mongodb.session.ClientSession;
|
|||||||
/**
|
/**
|
||||||
* {@link MethodInterceptor} implementation looking up and invoking an alternative target method having
|
* {@link MethodInterceptor} implementation looking up and invoking an alternative target method having
|
||||||
* {@link ClientSession} as its first argument. This allows seamless integration with the existing code base.
|
* {@link ClientSession} as its first argument. This allows seamless integration with the existing code base.
|
||||||
* <br />
|
* <p />
|
||||||
* The {@link MethodInterceptor} is aware of methods on {@code MongoCollection} that my return new instances of itself
|
* The {@link MethodInterceptor} is aware of methods on {@code MongoCollection} that my return new instances of itself
|
||||||
* like (eg. {@link com.mongodb.reactivestreams.client.MongoCollection#withWriteConcern(WriteConcern)} and decorate them
|
* like (eg. {@link com.mongodb.reactivestreams.client.MongoCollection#withWriteConcern(WriteConcern)} and decorate them
|
||||||
* if not already proxied.
|
* if not already proxied.
|
||||||
@@ -95,6 +95,10 @@ public class SessionAwareMethodInterceptor<D, C> implements MethodInterceptor {
|
|||||||
this.sessionType = sessionType;
|
this.sessionType = sessionType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.aopalliance.intercept.MethodInterceptor(org.aopalliance.intercept.MethodInvocation)
|
||||||
|
*/
|
||||||
@Nullable
|
@Nullable
|
||||||
@Override
|
@Override
|
||||||
public Object invoke(MethodInvocation methodInvocation) throws Throwable {
|
public Object invoke(MethodInvocation methodInvocation) throws Throwable {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2018-2021 the original author or authors.
|
* Copyright 2018-2020 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,20 +15,13 @@
|
|||||||
*/
|
*/
|
||||||
package org.springframework.data.mongodb;
|
package org.springframework.data.mongodb;
|
||||||
|
|
||||||
import org.springframework.data.mongodb.core.MongoTemplate;
|
|
||||||
import org.springframework.data.mongodb.core.ReactiveMongoTemplate;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@link SessionSynchronization} is used along with {@code MongoTemplate} to define in which type of transactions to
|
* {@link SessionSynchronization} is used along with {@link org.springframework.data.mongodb.core.MongoTemplate} to
|
||||||
* participate if any.
|
* define in which type of transactions to participate if any.
|
||||||
*
|
*
|
||||||
* @author Christoph Strobl
|
* @author Christoph Strobl
|
||||||
* @author Mark Paluch
|
* @author Mark Paluch
|
||||||
* @since 2.1
|
* @since 2.1
|
||||||
* @see MongoTemplate#setSessionSynchronization(SessionSynchronization)
|
|
||||||
* @see MongoDatabaseUtils#getDatabase(MongoDatabaseFactory, SessionSynchronization)
|
|
||||||
* @see ReactiveMongoTemplate#setSessionSynchronization(SessionSynchronization)
|
|
||||||
* @see ReactiveMongoDatabaseUtils#getDatabase(ReactiveMongoDatabaseFactory, SessionSynchronization)
|
|
||||||
*/
|
*/
|
||||||
public enum SessionSynchronization {
|
public enum SessionSynchronization {
|
||||||
|
|
||||||
@@ -41,12 +34,5 @@ public enum SessionSynchronization {
|
|||||||
/**
|
/**
|
||||||
* Synchronize with native MongoDB transactions initiated via {@link MongoTransactionManager}.
|
* Synchronize with native MongoDB transactions initiated via {@link MongoTransactionManager}.
|
||||||
*/
|
*/
|
||||||
ON_ACTUAL_TRANSACTION,
|
ON_ACTUAL_TRANSACTION;
|
||||||
|
|
||||||
/**
|
|
||||||
* Do not participate in ongoing transactions.
|
|
||||||
*
|
|
||||||
* @since 3.2.5
|
|
||||||
*/
|
|
||||||
NEVER;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,77 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2020-2021 the original author or authors.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* https://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package org.springframework.data.mongodb;
|
|
||||||
|
|
||||||
import org.apache.commons.logging.Log;
|
|
||||||
import org.apache.commons.logging.LogFactory;
|
|
||||||
import org.springframework.data.util.Version;
|
|
||||||
import org.springframework.util.StringUtils;
|
|
||||||
|
|
||||||
import com.mongodb.MongoDriverInformation;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Class that exposes the SpringData MongoDB specific information like the current {@link Version} or
|
|
||||||
* {@link MongoDriverInformation driver information}.
|
|
||||||
*
|
|
||||||
* @author Christoph Strobl
|
|
||||||
* @since 3.0
|
|
||||||
*/
|
|
||||||
public class SpringDataMongoDB {
|
|
||||||
|
|
||||||
private static final Log LOGGER = LogFactory.getLog(SpringDataMongoDB.class);
|
|
||||||
|
|
||||||
private static final Version FALLBACK_VERSION = new Version(3);
|
|
||||||
private static final MongoDriverInformation DRIVER_INFORMATION = MongoDriverInformation
|
|
||||||
.builder(MongoDriverInformation.builder().build()).driverName("spring-data").build();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Obtain the SpringData MongoDB specific driver information.
|
|
||||||
*
|
|
||||||
* @return never {@literal null}.
|
|
||||||
*/
|
|
||||||
public static MongoDriverInformation driverInformation() {
|
|
||||||
return DRIVER_INFORMATION;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Fetches the "Implementation-Version" manifest attribute from the jar file.
|
|
||||||
* <br />
|
|
||||||
* Note that some ClassLoaders do not expose the package metadata, hence this class might not be able to determine the
|
|
||||||
* version in all environments. In this case the current Major version is returned as a fallback.
|
|
||||||
*
|
|
||||||
* @return never {@literal null}.
|
|
||||||
*/
|
|
||||||
public static Version version() {
|
|
||||||
|
|
||||||
Package pkg = SpringDataMongoDB.class.getPackage();
|
|
||||||
String versionString = (pkg != null ? pkg.getImplementationVersion() : null);
|
|
||||||
|
|
||||||
if (!StringUtils.hasText(versionString)) {
|
|
||||||
|
|
||||||
LOGGER.debug("Unable to find Spring Data MongoDB version.");
|
|
||||||
return FALLBACK_VERSION;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
return Version.parse(versionString);
|
|
||||||
} catch (Exception e) {
|
|
||||||
LOGGER.debug(String.format("Cannot read Spring Data MongoDB version '%s'.", versionString));
|
|
||||||
}
|
|
||||||
|
|
||||||
return FALLBACK_VERSION;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2010-2021 the original author or authors.
|
* Copyright 2010-2020 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-2021 the original author or authors.
|
* Copyright 2018-2020 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,22 +17,17 @@ package org.springframework.data.mongodb.config;
|
|||||||
|
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.data.mongodb.MongoDatabaseFactory;
|
import org.springframework.data.mongodb.MongoDbFactory;
|
||||||
import org.springframework.data.mongodb.SpringDataMongoDB;
|
|
||||||
import org.springframework.data.mongodb.core.MongoTemplate;
|
import org.springframework.data.mongodb.core.MongoTemplate;
|
||||||
import org.springframework.data.mongodb.core.SimpleMongoClientDatabaseFactory;
|
import org.springframework.data.mongodb.core.SimpleMongoClientDbFactory;
|
||||||
|
import org.springframework.data.mongodb.core.SimpleMongoDbFactory;
|
||||||
import org.springframework.data.mongodb.core.convert.DbRefResolver;
|
import org.springframework.data.mongodb.core.convert.DbRefResolver;
|
||||||
import org.springframework.data.mongodb.core.convert.DefaultDbRefResolver;
|
import org.springframework.data.mongodb.core.convert.DefaultDbRefResolver;
|
||||||
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.mapping.Document;
|
import org.springframework.data.mongodb.core.mapping.Document;
|
||||||
import org.springframework.data.mongodb.core.mapping.MongoMappingContext;
|
|
||||||
import org.springframework.lang.Nullable;
|
import org.springframework.lang.Nullable;
|
||||||
|
|
||||||
import com.mongodb.MongoClientSettings;
|
|
||||||
import com.mongodb.MongoClientSettings.Builder;
|
|
||||||
import com.mongodb.client.MongoClient;
|
import com.mongodb.client.MongoClient;
|
||||||
import com.mongodb.client.MongoClients;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Base class for Spring Data MongoDB configuration using JavaConfig with {@link com.mongodb.client.MongoClient}.
|
* Base class for Spring Data MongoDB configuration using JavaConfig with {@link com.mongodb.client.MongoClient}.
|
||||||
@@ -40,44 +35,40 @@ import com.mongodb.client.MongoClients;
|
|||||||
* @author Christoph Strobl
|
* @author Christoph Strobl
|
||||||
* @since 2.1
|
* @since 2.1
|
||||||
* @see MongoConfigurationSupport
|
* @see MongoConfigurationSupport
|
||||||
|
* @see AbstractMongoConfiguration
|
||||||
*/
|
*/
|
||||||
@Configuration(proxyBeanMethods = false)
|
@Configuration
|
||||||
public abstract class AbstractMongoClientConfiguration extends MongoConfigurationSupport {
|
public abstract class AbstractMongoClientConfiguration extends MongoConfigurationSupport {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the {@link MongoClient} instance to connect to. Annotate with {@link Bean} in case you want to expose a
|
* Return the {@link MongoClient} instance to connect to. Annotate with {@link Bean} in case you want to expose a
|
||||||
* {@link MongoClient} instance to the {@link org.springframework.context.ApplicationContext}. <br />
|
* {@link MongoClient} instance to the {@link org.springframework.context.ApplicationContext}.
|
||||||
* Override {@link #mongoClientSettings()} to configure connection details.
|
|
||||||
*
|
*
|
||||||
* @return never {@literal null}.
|
* @return
|
||||||
* @see #mongoClientSettings()
|
|
||||||
* @see #configureClientSettings(Builder)
|
|
||||||
*/
|
*/
|
||||||
public MongoClient mongoClient() {
|
public abstract MongoClient mongoClient();
|
||||||
return createMongoClient(mongoClientSettings());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a {@link MongoTemplate}.
|
* Creates a {@link MongoTemplate}.
|
||||||
*
|
*
|
||||||
* @see #mongoDbFactory()
|
* @return
|
||||||
* @see #mappingMongoConverter(MongoDatabaseFactory, MongoCustomConversions, MongoMappingContext)
|
|
||||||
*/
|
*/
|
||||||
@Bean
|
@Bean
|
||||||
public MongoTemplate mongoTemplate(MongoDatabaseFactory databaseFactory, MappingMongoConverter converter) {
|
public MongoTemplate mongoTemplate() throws Exception {
|
||||||
return new MongoTemplate(databaseFactory, converter);
|
return new MongoTemplate(mongoDbFactory(), mappingMongoConverter());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a {@link org.springframework.data.mongodb.core.SimpleMongoClientDatabaseFactory} to be used by the
|
* Creates a {@link SimpleMongoDbFactory} to be used by the {@link MongoTemplate}. Will use the {@link MongoClient}
|
||||||
* {@link MongoTemplate}. Will use the {@link MongoClient} instance configured in {@link #mongoClient()}.
|
* instance configured in {@link #mongoClient()}.
|
||||||
*
|
*
|
||||||
* @see #mongoClient()
|
* @see #mongoClient()
|
||||||
* @see #mongoTemplate(MongoDatabaseFactory, MappingMongoConverter)
|
* @see #mongoTemplate()
|
||||||
|
* @return
|
||||||
*/
|
*/
|
||||||
@Bean
|
@Bean
|
||||||
public MongoDatabaseFactory mongoDbFactory() {
|
public MongoDbFactory mongoDbFactory() {
|
||||||
return new SimpleMongoClientDatabaseFactory(mongoClient(), getDatabaseName());
|
return new SimpleMongoClientDbFactory(mongoClient(), getDatabaseName());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -100,32 +91,21 @@ public abstract class AbstractMongoClientConfiguration extends MongoConfiguratio
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a {@link MappingMongoConverter} using the configured {@link #mongoDbFactory()} and
|
* Creates a {@link MappingMongoConverter} using the configured {@link #mongoDbFactory()} and
|
||||||
* {@link #mongoMappingContext(MongoCustomConversions)}. Will get {@link #customConversions()} applied.
|
* {@link #mongoMappingContext()}. Will get {@link #customConversions()} applied.
|
||||||
*
|
*
|
||||||
* @see #customConversions()
|
* @see #customConversions()
|
||||||
* @see #mongoMappingContext(MongoCustomConversions)
|
* @see #mongoMappingContext()
|
||||||
* @see #mongoDbFactory()
|
* @see #mongoDbFactory()
|
||||||
|
* @return
|
||||||
|
* @throws Exception
|
||||||
*/
|
*/
|
||||||
@Bean
|
@Bean
|
||||||
public MappingMongoConverter mappingMongoConverter(MongoDatabaseFactory databaseFactory,
|
public MappingMongoConverter mappingMongoConverter() throws Exception {
|
||||||
MongoCustomConversions customConversions, MongoMappingContext mappingContext) {
|
|
||||||
|
|
||||||
DbRefResolver dbRefResolver = new DefaultDbRefResolver(databaseFactory);
|
DbRefResolver dbRefResolver = new DefaultDbRefResolver(mongoDbFactory());
|
||||||
MappingMongoConverter converter = new MappingMongoConverter(dbRefResolver, mappingContext);
|
MappingMongoConverter converter = new MappingMongoConverter(dbRefResolver, mongoMappingContext());
|
||||||
converter.setCustomConversions(customConversions);
|
converter.setCustomConversions(customConversions());
|
||||||
converter.setCodecRegistryProvider(databaseFactory);
|
|
||||||
|
|
||||||
return converter;
|
return converter;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Create the Reactive Streams {@link com.mongodb.reactivestreams.client.MongoClient} instance with given
|
|
||||||
* {@link MongoClientSettings}.
|
|
||||||
*
|
|
||||||
* @return never {@literal null}.
|
|
||||||
* @since 3.0
|
|
||||||
*/
|
|
||||||
protected MongoClient createMongoClient(MongoClientSettings settings) {
|
|
||||||
return MongoClients.create(settings, SpringDataMongoDB.driverInformation());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,118 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2011-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.config;
|
||||||
|
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.data.mongodb.MongoDbFactory;
|
||||||
|
import org.springframework.data.mongodb.core.MongoTemplate;
|
||||||
|
import org.springframework.data.mongodb.core.SimpleMongoDbFactory;
|
||||||
|
import org.springframework.data.mongodb.core.convert.DbRefResolver;
|
||||||
|
import org.springframework.data.mongodb.core.convert.DefaultDbRefResolver;
|
||||||
|
import org.springframework.data.mongodb.core.convert.MappingMongoConverter;
|
||||||
|
import org.springframework.data.mongodb.core.mapping.Document;
|
||||||
|
import org.springframework.lang.Nullable;
|
||||||
|
|
||||||
|
import com.mongodb.MongoClient;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base class for Spring Data MongoDB configuration using JavaConfig with {@link com.mongodb.MongoClient}.
|
||||||
|
* <p />
|
||||||
|
* <strong>INFO:</strong>In case you want to use {@link com.mongodb.client.MongoClients} for configuration please refer
|
||||||
|
* to {@link AbstractMongoClientConfiguration}.
|
||||||
|
*
|
||||||
|
* @author Mark Pollack
|
||||||
|
* @author Oliver Gierke
|
||||||
|
* @author Thomas Darimont
|
||||||
|
* @author Ryan Tenney
|
||||||
|
* @author Christoph Strobl
|
||||||
|
* @author Mark Paluch
|
||||||
|
* @see MongoConfigurationSupport
|
||||||
|
* @see AbstractMongoClientConfiguration
|
||||||
|
*/
|
||||||
|
@Configuration
|
||||||
|
public abstract class AbstractMongoConfiguration extends MongoConfigurationSupport {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the {@link MongoClient} instance to connect to. Annotate with {@link Bean} in case you want to expose a
|
||||||
|
* {@link MongoClient} instance to the {@link org.springframework.context.ApplicationContext}.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public abstract MongoClient mongoClient();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a {@link MongoTemplate}.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@Bean
|
||||||
|
public MongoTemplate mongoTemplate() throws Exception {
|
||||||
|
return new MongoTemplate(mongoDbFactory(), mappingMongoConverter());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a {@link SimpleMongoDbFactory} to be used by the {@link MongoTemplate}. Will use the {@link MongoClient}
|
||||||
|
* instance configured in {@link #mongoClient()}.
|
||||||
|
*
|
||||||
|
* @see #mongoClient()
|
||||||
|
* @see #mongoTemplate()
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@Bean
|
||||||
|
public MongoDbFactory mongoDbFactory() {
|
||||||
|
return new SimpleMongoDbFactory(mongoClient(), getDatabaseName());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the base package to scan for mapped {@link Document}s. Will return the package name of the configuration
|
||||||
|
* class' (the concrete class, not this one here) by default. So if you have a {@code com.acme.AppConfig} extending
|
||||||
|
* {@link AbstractMongoConfiguration} the base package will be considered {@code com.acme} unless the method is
|
||||||
|
* overridden to implement alternate behavior.
|
||||||
|
*
|
||||||
|
* @return the base package to scan for mapped {@link Document} classes or {@literal null} to not enable scanning for
|
||||||
|
* entities.
|
||||||
|
* @deprecated use {@link #getMappingBasePackages()} instead.
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
|
@Nullable
|
||||||
|
protected String getMappingBasePackage() {
|
||||||
|
|
||||||
|
Package mappingBasePackage = getClass().getPackage();
|
||||||
|
return mappingBasePackage == null ? null : mappingBasePackage.getName();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a {@link MappingMongoConverter} using the configured {@link #mongoDbFactory()} and
|
||||||
|
* {@link #mongoMappingContext()}. Will get {@link #customConversions()} applied.
|
||||||
|
*
|
||||||
|
* @see #customConversions()
|
||||||
|
* @see #mongoMappingContext()
|
||||||
|
* @see #mongoDbFactory()
|
||||||
|
* @return
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
@Bean
|
||||||
|
public MappingMongoConverter mappingMongoConverter() throws Exception {
|
||||||
|
|
||||||
|
DbRefResolver dbRefResolver = new DefaultDbRefResolver(mongoDbFactory());
|
||||||
|
MappingMongoConverter converter = new MappingMongoConverter(dbRefResolver, mongoMappingContext());
|
||||||
|
converter.setCustomConversions(customConversions());
|
||||||
|
|
||||||
|
return converter;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2016-2021 the original author or authors.
|
* Copyright 2016-2020 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,19 +18,13 @@ package org.springframework.data.mongodb.config;
|
|||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.data.mongodb.ReactiveMongoDatabaseFactory;
|
import org.springframework.data.mongodb.ReactiveMongoDatabaseFactory;
|
||||||
import org.springframework.data.mongodb.SpringDataMongoDB;
|
|
||||||
import org.springframework.data.mongodb.core.ReactiveMongoOperations;
|
import org.springframework.data.mongodb.core.ReactiveMongoOperations;
|
||||||
import org.springframework.data.mongodb.core.ReactiveMongoTemplate;
|
import org.springframework.data.mongodb.core.ReactiveMongoTemplate;
|
||||||
import org.springframework.data.mongodb.core.SimpleReactiveMongoDatabaseFactory;
|
import org.springframework.data.mongodb.core.SimpleReactiveMongoDatabaseFactory;
|
||||||
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.NoOpDbRefResolver;
|
import org.springframework.data.mongodb.core.convert.NoOpDbRefResolver;
|
||||||
import org.springframework.data.mongodb.core.mapping.MongoMappingContext;
|
|
||||||
|
|
||||||
import com.mongodb.MongoClientSettings;
|
|
||||||
import com.mongodb.MongoClientSettings.Builder;
|
|
||||||
import com.mongodb.reactivestreams.client.MongoClient;
|
import com.mongodb.reactivestreams.client.MongoClient;
|
||||||
import com.mongodb.reactivestreams.client.MongoClients;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Base class for reactive Spring Data MongoDB configuration using JavaConfig.
|
* Base class for reactive Spring Data MongoDB configuration using JavaConfig.
|
||||||
@@ -40,33 +34,25 @@ import com.mongodb.reactivestreams.client.MongoClients;
|
|||||||
* @since 2.0
|
* @since 2.0
|
||||||
* @see MongoConfigurationSupport
|
* @see MongoConfigurationSupport
|
||||||
*/
|
*/
|
||||||
@Configuration(proxyBeanMethods = false)
|
@Configuration
|
||||||
public abstract class AbstractReactiveMongoConfiguration extends MongoConfigurationSupport {
|
public abstract class AbstractReactiveMongoConfiguration extends MongoConfigurationSupport {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the Reactive Streams {@link MongoClient} instance to connect to. Annotate with {@link Bean} in case you want
|
* Return the Reactive Streams {@link MongoClient} instance to connect to. Annotate with {@link Bean} in case you want
|
||||||
* to expose a {@link MongoClient} instance to the {@link org.springframework.context.ApplicationContext}. <br />
|
* to expose a {@link MongoClient} instance to the {@link org.springframework.context.ApplicationContext}.
|
||||||
* Override {@link #mongoClientSettings()} to configure connection details.
|
|
||||||
*
|
*
|
||||||
* @return never {@literal null}.
|
* @return never {@literal null}.
|
||||||
* @see #mongoClientSettings()
|
|
||||||
* @see #configureClientSettings(Builder)
|
|
||||||
*/
|
*/
|
||||||
public MongoClient reactiveMongoClient() {
|
public abstract MongoClient reactiveMongoClient();
|
||||||
return createReactiveMongoClient(mongoClientSettings());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates {@link ReactiveMongoOperations}.
|
* Creates {@link ReactiveMongoOperations}.
|
||||||
*
|
*
|
||||||
* @see #reactiveMongoDbFactory()
|
|
||||||
* @see #mappingMongoConverter(ReactiveMongoDatabaseFactory, MongoCustomConversions, MongoMappingContext)
|
|
||||||
* @return never {@literal null}.
|
* @return never {@literal null}.
|
||||||
*/
|
*/
|
||||||
@Bean
|
@Bean
|
||||||
public ReactiveMongoTemplate reactiveMongoTemplate(ReactiveMongoDatabaseFactory databaseFactory,
|
public ReactiveMongoOperations reactiveMongoTemplate() throws Exception {
|
||||||
MappingMongoConverter mongoConverter) {
|
return new ReactiveMongoTemplate(reactiveMongoDbFactory(), mappingMongoConverter());
|
||||||
return new ReactiveMongoTemplate(databaseFactory, mongoConverter);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -74,7 +60,7 @@ public abstract class AbstractReactiveMongoConfiguration extends MongoConfigurat
|
|||||||
* {@link MongoClient} instance configured in {@link #reactiveMongoClient()}.
|
* {@link MongoClient} instance configured in {@link #reactiveMongoClient()}.
|
||||||
*
|
*
|
||||||
* @see #reactiveMongoClient()
|
* @see #reactiveMongoClient()
|
||||||
* @see #reactiveMongoTemplate(ReactiveMongoDatabaseFactory, MappingMongoConverter)
|
* @see #reactiveMongoTemplate()
|
||||||
* @return never {@literal null}.
|
* @return never {@literal null}.
|
||||||
*/
|
*/
|
||||||
@Bean
|
@Bean
|
||||||
@@ -84,31 +70,20 @@ public abstract class AbstractReactiveMongoConfiguration extends MongoConfigurat
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a {@link MappingMongoConverter} using the configured {@link #reactiveMongoDbFactory()} and
|
* Creates a {@link MappingMongoConverter} using the configured {@link #reactiveMongoDbFactory()} and
|
||||||
* {@link #mongoMappingContext(MongoCustomConversions)}. Will get {@link #customConversions()} applied.
|
* {@link #mongoMappingContext()}. Will get {@link #customConversions()} applied.
|
||||||
*
|
*
|
||||||
* @see #customConversions()
|
* @see #customConversions()
|
||||||
* @see #mongoMappingContext(MongoCustomConversions)
|
* @see #mongoMappingContext()
|
||||||
* @see #reactiveMongoDbFactory()
|
* @see #reactiveMongoDbFactory()
|
||||||
* @return never {@literal null}.
|
* @return never {@literal null}.
|
||||||
|
* @throws Exception
|
||||||
*/
|
*/
|
||||||
@Bean
|
@Bean
|
||||||
public MappingMongoConverter mappingMongoConverter(ReactiveMongoDatabaseFactory databaseFactory,
|
public MappingMongoConverter mappingMongoConverter() throws Exception {
|
||||||
MongoCustomConversions customConversions, MongoMappingContext mappingContext) {
|
|
||||||
|
|
||||||
MappingMongoConverter converter = new MappingMongoConverter(NoOpDbRefResolver.INSTANCE, mappingContext);
|
MappingMongoConverter converter = new MappingMongoConverter(NoOpDbRefResolver.INSTANCE, mongoMappingContext());
|
||||||
converter.setCustomConversions(customConversions);
|
converter.setCustomConversions(customConversions());
|
||||||
converter.setCodecRegistryProvider(databaseFactory);
|
|
||||||
|
|
||||||
return converter;
|
return converter;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Create the Reactive Streams {@link MongoClient} instance with given {@link MongoClientSettings}.
|
|
||||||
*
|
|
||||||
* @return never {@literal null}.
|
|
||||||
* @since 3.0
|
|
||||||
*/
|
|
||||||
protected MongoClient createReactiveMongoClient(MongoClientSettings settings) {
|
|
||||||
return MongoClients.create(settings, SpringDataMongoDB.driverInformation());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2011-2021 the original author or authors.
|
* Copyright 2011-2020 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,42 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2019-2021 the original author or authors.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* https://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package org.springframework.data.mongodb.config;
|
|
||||||
|
|
||||||
import java.beans.PropertyEditorSupport;
|
|
||||||
|
|
||||||
import org.springframework.lang.Nullable;
|
|
||||||
import org.springframework.util.StringUtils;
|
|
||||||
|
|
||||||
import com.mongodb.ConnectionString;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Parse a {@link String} to a {@link com.mongodb.ConnectionString}.
|
|
||||||
*
|
|
||||||
* @author Christoph Strobl
|
|
||||||
* @since 3.0
|
|
||||||
*/
|
|
||||||
public class ConnectionStringPropertyEditor extends PropertyEditorSupport {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setAsText(@Nullable String connectionString) {
|
|
||||||
|
|
||||||
if (!StringUtils.hasText(connectionString)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
setValue(new ConnectionString(connectionString));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2013-2021 the original author or authors.
|
* Copyright 2013-2020 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,29 +42,29 @@ public @interface EnableMongoAuditing {
|
|||||||
/**
|
/**
|
||||||
* Configures the {@link AuditorAware} bean to be used to lookup the current principal.
|
* Configures the {@link AuditorAware} bean to be used to lookup the current principal.
|
||||||
*
|
*
|
||||||
* @return empty {@link String} by default.
|
* @return
|
||||||
*/
|
*/
|
||||||
String auditorAwareRef() default "";
|
String auditorAwareRef() default "";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Configures whether the creation and modification dates are set. Defaults to {@literal true}.
|
* Configures whether the creation and modification dates are set. Defaults to {@literal true}.
|
||||||
*
|
*
|
||||||
* @return {@literal true} by default.
|
* @return
|
||||||
*/
|
*/
|
||||||
boolean setDates() default true;
|
boolean setDates() default true;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Configures whether the entity shall be marked as modified on creation. Defaults to {@literal true}.
|
* Configures whether the entity shall be marked as modified on creation. Defaults to {@literal true}.
|
||||||
*
|
*
|
||||||
* @return {@literal true} by default.
|
* @return
|
||||||
*/
|
*/
|
||||||
boolean modifyOnCreate() default true;
|
boolean modifyOnCreate() default true;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Configures a {@link DateTimeProvider} bean name that allows customizing the timestamp to be used for setting
|
* Configures a {@link DateTimeProvider} bean name that allows customizing the {@link org.joda.time.DateTime} to be
|
||||||
* creation and modification dates.
|
* used for setting creation and modification dates.
|
||||||
*
|
*
|
||||||
* @return empty {@link String} by default.
|
* @return
|
||||||
*/
|
*/
|
||||||
String dateTimeProviderRef() default "";
|
String dateTimeProviderRef() default "";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,70 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2020-2021 the original author or authors.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* https://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package org.springframework.data.mongodb.config;
|
|
||||||
|
|
||||||
import java.lang.annotation.Documented;
|
|
||||||
import java.lang.annotation.ElementType;
|
|
||||||
import java.lang.annotation.Inherited;
|
|
||||||
import java.lang.annotation.Retention;
|
|
||||||
import java.lang.annotation.RetentionPolicy;
|
|
||||||
import java.lang.annotation.Target;
|
|
||||||
|
|
||||||
import org.springframework.context.annotation.Import;
|
|
||||||
import org.springframework.data.auditing.DateTimeProvider;
|
|
||||||
import org.springframework.data.domain.ReactiveAuditorAware;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Annotation to enable auditing in MongoDB using reactive infrastructure via annotation configuration.
|
|
||||||
*
|
|
||||||
* @author Mark Paluch
|
|
||||||
* @since 3.1
|
|
||||||
*/
|
|
||||||
@Inherited
|
|
||||||
@Documented
|
|
||||||
@Target(ElementType.TYPE)
|
|
||||||
@Retention(RetentionPolicy.RUNTIME)
|
|
||||||
@Import(ReactiveMongoAuditingRegistrar.class)
|
|
||||||
public @interface EnableReactiveMongoAuditing {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Configures the {@link ReactiveAuditorAware} bean to be used to lookup the current principal.
|
|
||||||
*
|
|
||||||
* @return empty {@link String} by default.
|
|
||||||
*/
|
|
||||||
String auditorAwareRef() default "";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Configures whether the creation and modification dates are set. Defaults to {@literal true}.
|
|
||||||
*
|
|
||||||
* @return {@literal true} by default.
|
|
||||||
*/
|
|
||||||
boolean setDates() default true;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Configures whether the entity shall be marked as modified on creation. Defaults to {@literal true}.
|
|
||||||
*
|
|
||||||
* @return {@literal true} by default.
|
|
||||||
*/
|
|
||||||
boolean modifyOnCreate() default true;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Configures a {@link DateTimeProvider} bean name that allows customizing the timestamp to be used for setting
|
|
||||||
* creation and modification dates.
|
|
||||||
*
|
|
||||||
* @return empty {@link String} by default.
|
|
||||||
*/
|
|
||||||
String dateTimeProviderRef() default "";
|
|
||||||
}
|
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2015-2021 the original author or authors.
|
* Copyright 2015-2020 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-2021 the original author or authors.
|
* Copyright 2013-2020 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.
|
||||||
@@ -34,6 +34,10 @@ import org.w3c.dom.Element;
|
|||||||
*/
|
*/
|
||||||
class GridFsTemplateParser extends AbstractBeanDefinitionParser {
|
class GridFsTemplateParser extends AbstractBeanDefinitionParser {
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.springframework.beans.factory.xml.AbstractBeanDefinitionParser#resolveId(org.w3c.dom.Element, org.springframework.beans.factory.support.AbstractBeanDefinition, org.springframework.beans.factory.xml.ParserContext)
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
protected String resolveId(Element element, AbstractBeanDefinition definition, ParserContext parserContext)
|
protected String resolveId(Element element, AbstractBeanDefinition definition, ParserContext parserContext)
|
||||||
throws BeanDefinitionStoreException {
|
throws BeanDefinitionStoreException {
|
||||||
@@ -42,6 +46,10 @@ class GridFsTemplateParser extends AbstractBeanDefinitionParser {
|
|||||||
return StringUtils.hasText(id) ? id : BeanNames.GRID_FS_TEMPLATE_BEAN_NAME;
|
return StringUtils.hasText(id) ? id : BeanNames.GRID_FS_TEMPLATE_BEAN_NAME;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.springframework.beans.factory.xml.AbstractBeanDefinitionParser#parseInternal(org.w3c.dom.Element, org.springframework.beans.factory.xml.ParserContext)
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
protected AbstractBeanDefinition parseInternal(Element element, ParserContext parserContext) {
|
protected AbstractBeanDefinition parseInternal(Element element, ParserContext parserContext) {
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2011-2021 the original author or authors.
|
* Copyright 2011-2020 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;
|
||||||
@@ -80,7 +81,7 @@ import org.w3c.dom.Element;
|
|||||||
public class MappingMongoConverterParser implements BeanDefinitionParser {
|
public class MappingMongoConverterParser implements BeanDefinitionParser {
|
||||||
|
|
||||||
private static final String BASE_PACKAGE = "base-package";
|
private static final String BASE_PACKAGE = "base-package";
|
||||||
private static final boolean JSR_303_PRESENT = ClassUtils.isPresent("jakarta.validation.Validator",
|
private static final boolean JSR_303_PRESENT = ClassUtils.isPresent("javax.validation.Validator",
|
||||||
MappingMongoConverterParser.class.getClassLoader());
|
MappingMongoConverterParser.class.getClassLoader());
|
||||||
|
|
||||||
/* (non-Javadoc)
|
/* (non-Javadoc)
|
||||||
@@ -96,14 +97,13 @@ public class MappingMongoConverterParser implements BeanDefinitionParser {
|
|||||||
String id = element.getAttribute(AbstractBeanDefinitionParser.ID_ATTRIBUTE);
|
String id = element.getAttribute(AbstractBeanDefinitionParser.ID_ATTRIBUTE);
|
||||||
id = StringUtils.hasText(id) ? id : DEFAULT_CONVERTER_BEAN_NAME;
|
id = StringUtils.hasText(id) ? id : DEFAULT_CONVERTER_BEAN_NAME;
|
||||||
|
|
||||||
String autoIndexCreation = element.getAttribute("auto-index-creation");
|
|
||||||
boolean autoIndexCreationEnabled = StringUtils.hasText(autoIndexCreation) && Boolean.valueOf(autoIndexCreation);
|
|
||||||
|
|
||||||
parserContext.pushContainingComponent(new CompositeComponentDefinition("Mapping Mongo Converter", element));
|
parserContext.pushContainingComponent(new CompositeComponentDefinition("Mapping Mongo Converter", element));
|
||||||
|
|
||||||
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)) {
|
||||||
@@ -202,11 +202,6 @@ public class MappingMongoConverterParser implements BeanDefinitionParser {
|
|||||||
|
|
||||||
public static String potentiallyCreateMappingContext(Element element, ParserContext parserContext,
|
public static String potentiallyCreateMappingContext(Element element, ParserContext parserContext,
|
||||||
@Nullable BeanDefinition conversionsDefinition, @Nullable String converterId) {
|
@Nullable BeanDefinition conversionsDefinition, @Nullable String converterId) {
|
||||||
return potentiallyCreateMappingContext(element, parserContext, conversionsDefinition, converterId, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String potentiallyCreateMappingContext(Element element, ParserContext parserContext,
|
|
||||||
@Nullable BeanDefinition conversionsDefinition, @Nullable String converterId, boolean autoIndexCreation) {
|
|
||||||
|
|
||||||
String ctxRef = element.getAttribute("mapping-context-ref");
|
String ctxRef = element.getAttribute("mapping-context-ref");
|
||||||
|
|
||||||
@@ -234,8 +229,6 @@ public class MappingMongoConverterParser implements BeanDefinitionParser {
|
|||||||
mappingContextBuilder.addPropertyValue("simpleTypeHolder", simpleTypesDefinition);
|
mappingContextBuilder.addPropertyValue("simpleTypeHolder", simpleTypesDefinition);
|
||||||
}
|
}
|
||||||
|
|
||||||
mappingContextBuilder.addPropertyValue("autoIndexCreation", autoIndexCreation);
|
|
||||||
|
|
||||||
parseFieldNamingStrategy(element, parserContext.getReaderContext(), mappingContextBuilder);
|
parseFieldNamingStrategy(element, parserContext.getReaderContext(), mappingContextBuilder);
|
||||||
|
|
||||||
ctxRef = converterId == null || DEFAULT_CONVERTER_BEAN_NAME.equals(converterId) ? MAPPING_CONTEXT_BEAN_NAME
|
ctxRef = converterId == null || DEFAULT_CONVERTER_BEAN_NAME.equals(converterId) ? MAPPING_CONTEXT_BEAN_NAME
|
||||||
@@ -355,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.
|
||||||
*
|
*
|
||||||
@@ -376,6 +383,10 @@ public class MappingMongoConverterParser implements BeanDefinitionParser {
|
|||||||
this.delegates = new HashSet<>(Arrays.asList(filters));
|
this.delegates = new HashSet<>(Arrays.asList(filters));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.springframework.core.type.filter.TypeFilter#match(org.springframework.core.type.classreading.MetadataReader, org.springframework.core.type.classreading.MetadataReaderFactory)
|
||||||
|
*/
|
||||||
public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory)
|
public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2012-2021 the original author or authors.
|
* Copyright 2012-2020 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,36 +26,40 @@ 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)
|
||||||
|
* @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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.springframework.beans.factory.xml.AbstractBeanDefinitionParser#shouldGenerateId()
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
protected boolean shouldGenerateId() {
|
protected boolean shouldGenerateId() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser#doParse(org.w3c.dom.Element, org.springframework.beans.factory.xml.ParserContext, org.springframework.beans.factory.support.BeanDefinitionBuilder)
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
|
protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
|
||||||
|
|
||||||
@@ -77,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-2021 the original author or authors.
|
* Copyright 2013-2020 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,8 +17,8 @@ package org.springframework.data.mongodb.config;
|
|||||||
|
|
||||||
import java.lang.annotation.Annotation;
|
import java.lang.annotation.Annotation;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.FactoryBean;
|
||||||
import org.springframework.beans.factory.config.BeanDefinition;
|
import org.springframework.beans.factory.config.BeanDefinition;
|
||||||
import org.springframework.beans.factory.config.RuntimeBeanReference;
|
|
||||||
import org.springframework.beans.factory.support.AbstractBeanDefinition;
|
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;
|
||||||
@@ -29,8 +29,10 @@ import org.springframework.data.auditing.config.AuditingBeanDefinitionRegistrarS
|
|||||||
import org.springframework.data.auditing.config.AuditingConfiguration;
|
import org.springframework.data.auditing.config.AuditingConfiguration;
|
||||||
import org.springframework.data.config.ParsingUtils;
|
import org.springframework.data.config.ParsingUtils;
|
||||||
import org.springframework.data.mapping.context.MappingContext;
|
import org.springframework.data.mapping.context.MappingContext;
|
||||||
import org.springframework.data.mongodb.core.mapping.MongoMappingContext;
|
import org.springframework.data.mongodb.core.convert.MappingMongoConverter;
|
||||||
import org.springframework.data.mongodb.core.mapping.event.AuditingEntityCallback;
|
import org.springframework.data.mongodb.core.mapping.MongoPersistentEntity;
|
||||||
|
import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty;
|
||||||
|
import org.springframework.data.mongodb.core.mapping.event.AuditingEventListener;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -38,20 +40,31 @@ import org.springframework.util.Assert;
|
|||||||
*
|
*
|
||||||
* @author Thomas Darimont
|
* @author Thomas Darimont
|
||||||
* @author Oliver Gierke
|
* @author Oliver Gierke
|
||||||
* @author Mark Paluch
|
|
||||||
*/
|
*/
|
||||||
class MongoAuditingRegistrar extends AuditingBeanDefinitionRegistrarSupport {
|
class MongoAuditingRegistrar extends AuditingBeanDefinitionRegistrarSupport {
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.springframework.data.auditing.config.AuditingBeanDefinitionRegistrarSupport#getAnnotation()
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
protected Class<? extends Annotation> getAnnotation() {
|
protected Class<? extends Annotation> getAnnotation() {
|
||||||
return EnableMongoAuditing.class;
|
return EnableMongoAuditing.class;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.springframework.data.auditing.config.AuditingBeanDefinitionRegistrarSupport#getAuditingHandlerBeanName()
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
protected String getAuditingHandlerBeanName() {
|
protected String getAuditingHandlerBeanName() {
|
||||||
return "mongoAuditingHandler";
|
return "mongoAuditingHandler";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.springframework.data.auditing.config.AuditingBeanDefinitionRegistrarSupport#registerBeanDefinitions(org.springframework.core.type.AnnotationMetadata, org.springframework.beans.factory.support.BeanDefinitionRegistry)
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void registerBeanDefinitions(AnnotationMetadata annotationMetadata, BeanDefinitionRegistry registry) {
|
public void registerBeanDefinitions(AnnotationMetadata annotationMetadata, BeanDefinitionRegistry registry) {
|
||||||
|
|
||||||
@@ -61,6 +74,10 @@ class MongoAuditingRegistrar extends AuditingBeanDefinitionRegistrarSupport {
|
|||||||
super.registerBeanDefinitions(annotationMetadata, registry);
|
super.registerBeanDefinitions(annotationMetadata, registry);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.springframework.data.auditing.config.AuditingBeanDefinitionRegistrarSupport#getAuditHandlerBeanDefinitionBuilder(org.springframework.data.auditing.config.AuditingConfiguration)
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
protected BeanDefinitionBuilder getAuditHandlerBeanDefinitionBuilder(AuditingConfiguration configuration) {
|
protected BeanDefinitionBuilder getAuditHandlerBeanDefinitionBuilder(AuditingConfiguration configuration) {
|
||||||
|
|
||||||
@@ -68,13 +85,17 @@ class MongoAuditingRegistrar extends AuditingBeanDefinitionRegistrarSupport {
|
|||||||
|
|
||||||
BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(IsNewAwareAuditingHandler.class);
|
BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(IsNewAwareAuditingHandler.class);
|
||||||
|
|
||||||
BeanDefinitionBuilder definition = BeanDefinitionBuilder.genericBeanDefinition(org.springframework.data.repository.config.PersistentEntitiesFactoryBean.class);
|
BeanDefinitionBuilder definition = BeanDefinitionBuilder.genericBeanDefinition(MongoMappingContextLookup.class);
|
||||||
definition.addConstructorArgValue(new RuntimeBeanReference(MappingContext.class));
|
definition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_CONSTRUCTOR);
|
||||||
|
|
||||||
builder.addConstructorArgValue(definition.getBeanDefinition());
|
builder.addConstructorArgValue(definition.getBeanDefinition());
|
||||||
return configureDefaultAuditHandlerAttributes(configuration, builder);
|
return configureDefaultAuditHandlerAttributes(configuration, builder);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.springframework.data.auditing.config.AuditingBeanDefinitionRegistrarSupport#registerAuditListener(org.springframework.beans.factory.config.BeanDefinition, org.springframework.beans.factory.support.BeanDefinitionRegistry)
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
protected void registerAuditListenerBeanDefinition(BeanDefinition auditingHandlerDefinition,
|
protected void registerAuditListenerBeanDefinition(BeanDefinition auditingHandlerDefinition,
|
||||||
BeanDefinitionRegistry registry) {
|
BeanDefinitionRegistry registry) {
|
||||||
@@ -83,12 +104,59 @@ 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Simple helper to be able to wire the {@link MappingContext} from a {@link MappingMongoConverter} bean available in
|
||||||
|
* the application context.
|
||||||
|
*
|
||||||
|
* @author Oliver Gierke
|
||||||
|
*/
|
||||||
|
static class MongoMappingContextLookup
|
||||||
|
implements FactoryBean<MappingContext<? extends MongoPersistentEntity<?>, MongoPersistentProperty>> {
|
||||||
|
|
||||||
|
private final MappingMongoConverter converter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new {@link MongoMappingContextLookup} for the given {@link MappingMongoConverter}.
|
||||||
|
*
|
||||||
|
* @param converter must not be {@literal null}.
|
||||||
|
*/
|
||||||
|
public MongoMappingContextLookup(MappingMongoConverter converter) {
|
||||||
|
this.converter = converter;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.springframework.beans.factory.FactoryBean#getObject()
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public MappingContext<? extends MongoPersistentEntity<?>, MongoPersistentProperty> getObject() throws Exception {
|
||||||
|
return converter.getMappingContext();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.springframework.beans.factory.FactoryBean#getObjectType()
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public Class<?> getObjectType() {
|
||||||
|
return MappingContext.class;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.springframework.beans.factory.FactoryBean#isSingleton()
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean isSingleton() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2015-2021 the original author or authors.
|
* Copyright 2015-2020 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,6 +35,10 @@ import org.w3c.dom.Element;
|
|||||||
*/
|
*/
|
||||||
public class MongoClientParser implements BeanDefinitionParser {
|
public class MongoClientParser implements BeanDefinitionParser {
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.springframework.beans.factory.xml.BeanDefinitionParser#parse(org.w3c.dom.Element, org.springframework.beans.factory.xml.ParserContext)
|
||||||
|
*/
|
||||||
public BeanDefinition parse(Element element, ParserContext parserContext) {
|
public BeanDefinition parse(Element element, ParserContext parserContext) {
|
||||||
|
|
||||||
Object source = parserContext.extractSource(element);
|
Object source = parserContext.extractSource(element);
|
||||||
@@ -46,11 +50,10 @@ public class MongoClientParser implements BeanDefinitionParser {
|
|||||||
|
|
||||||
ParsingUtils.setPropertyValue(builder, element, "port", "port");
|
ParsingUtils.setPropertyValue(builder, element, "port", "port");
|
||||||
ParsingUtils.setPropertyValue(builder, element, "host", "host");
|
ParsingUtils.setPropertyValue(builder, element, "host", "host");
|
||||||
ParsingUtils.setPropertyValue(builder, element, "credential", "credential");
|
ParsingUtils.setPropertyValue(builder, element, "credentials", "credentials");
|
||||||
ParsingUtils.setPropertyValue(builder, element, "replica-set", "replicaSet");
|
|
||||||
ParsingUtils.setPropertyValue(builder, element, "connection-string", "connectionString");
|
|
||||||
|
|
||||||
MongoParsingUtils.parseMongoClientSettings(element, builder);
|
MongoParsingUtils.parseMongoClientOptions(element, builder);
|
||||||
|
MongoParsingUtils.parseReplicaSet(element, builder);
|
||||||
|
|
||||||
String defaultedId = StringUtils.hasText(id) ? id : BeanNames.MONGO_BEAN_NAME;
|
String defaultedId = StringUtils.hasText(id) ? id : BeanNames.MONGO_BEAN_NAME;
|
||||||
|
|
||||||
@@ -59,34 +62,22 @@ public class MongoClientParser implements BeanDefinitionParser {
|
|||||||
BeanComponentDefinition mongoComponent = helper.getComponent(builder, defaultedId);
|
BeanComponentDefinition mongoComponent = helper.getComponent(builder, defaultedId);
|
||||||
parserContext.registerBeanComponent(mongoComponent);
|
parserContext.registerBeanComponent(mongoComponent);
|
||||||
|
|
||||||
BeanComponentDefinition connectionStringPropertyEditor = helper
|
BeanComponentDefinition serverAddressPropertyEditor = helper.getComponent(MongoParsingUtils
|
||||||
.getComponent(MongoParsingUtils.getConnectionStringPropertyEditorBuilder());
|
.getServerAddressPropertyEditorBuilder());
|
||||||
parserContext.registerBeanComponent(connectionStringPropertyEditor);
|
|
||||||
|
|
||||||
BeanComponentDefinition serverAddressPropertyEditor = helper
|
|
||||||
.getComponent(MongoParsingUtils.getServerAddressPropertyEditorBuilder());
|
|
||||||
parserContext.registerBeanComponent(serverAddressPropertyEditor);
|
parserContext.registerBeanComponent(serverAddressPropertyEditor);
|
||||||
|
|
||||||
BeanComponentDefinition writeConcernEditor = helper
|
BeanComponentDefinition writeConcernEditor = helper.getComponent(MongoParsingUtils
|
||||||
.getComponent(MongoParsingUtils.getWriteConcernPropertyEditorBuilder());
|
.getWriteConcernPropertyEditorBuilder());
|
||||||
parserContext.registerBeanComponent(writeConcernEditor);
|
parserContext.registerBeanComponent(writeConcernEditor);
|
||||||
|
|
||||||
BeanComponentDefinition readConcernEditor = helper
|
BeanComponentDefinition readPreferenceEditor = helper.getComponent(MongoParsingUtils
|
||||||
.getComponent(MongoParsingUtils.getReadConcernPropertyEditorBuilder());
|
.getReadPreferencePropertyEditorBuilder());
|
||||||
parserContext.registerBeanComponent(readConcernEditor);
|
|
||||||
|
|
||||||
BeanComponentDefinition readPreferenceEditor = helper
|
|
||||||
.getComponent(MongoParsingUtils.getReadPreferencePropertyEditorBuilder());
|
|
||||||
parserContext.registerBeanComponent(readPreferenceEditor);
|
parserContext.registerBeanComponent(readPreferenceEditor);
|
||||||
|
|
||||||
BeanComponentDefinition credentialsEditor = helper
|
BeanComponentDefinition credentialsEditor = helper.getComponent(MongoParsingUtils
|
||||||
.getComponent(MongoParsingUtils.getMongoCredentialPropertyEditor());
|
.getMongoCredentialPropertyEditor());
|
||||||
parserContext.registerBeanComponent(credentialsEditor);
|
parserContext.registerBeanComponent(credentialsEditor);
|
||||||
|
|
||||||
BeanComponentDefinition uuidRepresentationEditor = helper
|
|
||||||
.getComponent(MongoParsingUtils.getUUidRepresentationEditorBuilder());
|
|
||||||
parserContext.registerBeanComponent(uuidRepresentationEditor);
|
|
||||||
|
|
||||||
parserContext.popAndRegisterContainingComponent();
|
parserContext.popAndRegisterContainingComponent();
|
||||||
|
|
||||||
return mongoComponent.getBeanDefinition();
|
return mongoComponent.getBeanDefinition();
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2016-2021 the original author or authors.
|
* Copyright 2016-2020 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,31 +15,33 @@
|
|||||||
*/
|
*/
|
||||||
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;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import org.bson.UuidRepresentation;
|
|
||||||
import org.springframework.beans.factory.config.BeanDefinition;
|
import org.springframework.beans.factory.config.BeanDefinition;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider;
|
import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider;
|
||||||
import org.springframework.core.convert.converter.Converter;
|
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.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.convert.MongoCustomConversions.MongoConverterConfigurationAdapter;
|
|
||||||
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;
|
||||||
|
|
||||||
import com.mongodb.MongoClientSettings;
|
|
||||||
import com.mongodb.MongoClientSettings.Builder;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Base class for Spring Data MongoDB to be extended for JavaConfiguration usage.
|
* Base class for Spring Data MongoDB to be extended for JavaConfiguration usage.
|
||||||
*
|
*
|
||||||
@@ -79,44 +81,39 @@ public abstract class MongoConfigurationSupport {
|
|||||||
* @throws ClassNotFoundException
|
* @throws ClassNotFoundException
|
||||||
*/
|
*/
|
||||||
@Bean
|
@Bean
|
||||||
public MongoMappingContext mongoMappingContext(MongoCustomConversions customConversions)
|
public MongoMappingContext mongoMappingContext() throws ClassNotFoundException {
|
||||||
throws ClassNotFoundException {
|
|
||||||
|
|
||||||
MongoMappingContext mappingContext = new MongoMappingContext();
|
MongoMappingContext mappingContext = new MongoMappingContext();
|
||||||
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 CustomConversions} will be registered with the {@link #mappingMongoConverter()} and
|
||||||
* {@link org.springframework.data.mongodb.core.convert.MappingMongoConverter} and {@link MongoMappingContext}.
|
* {@link #mongoMappingContext()}. Returns an empty {@link MongoCustomConversions} instance by default.
|
||||||
* Returns an empty {@link MongoCustomConversions} instance by default.
|
|
||||||
* <p>
|
|
||||||
* <strong>NOTE:</strong> Use {@link #configureConverters(MongoConverterConfigurationAdapter)} to configure MongoDB
|
|
||||||
* native simple types and register custom {@link Converter converters}.
|
|
||||||
*
|
*
|
||||||
* @return must not be {@literal null}.
|
* @return must not be {@literal null}.
|
||||||
*/
|
*/
|
||||||
@Bean
|
@Bean
|
||||||
public MongoCustomConversions customConversions() {
|
public CustomConversions customConversions() {
|
||||||
return MongoCustomConversions.create(this::configureConverters);
|
return new MongoCustomConversions(Collections.emptyList());
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Configuration hook for {@link MongoCustomConversions} creation.
|
|
||||||
*
|
|
||||||
* @param converterConfigurationAdapter never {@literal null}.
|
|
||||||
* @since 2.3
|
|
||||||
* @see MongoConverterConfigurationAdapter#useNativeDriverJavaTimeCodecs()
|
|
||||||
* @see MongoConverterConfigurationAdapter#useSpringDataJavaTimeCodecs()
|
|
||||||
*/
|
|
||||||
protected void configureConverters(MongoConverterConfigurationAdapter converterConfigurationAdapter) {
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -139,7 +136,8 @@ public abstract class MongoConfigurationSupport {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Scans the given base package for entities, i.e. MongoDB specific types annotated with {@link Document}.
|
* Scans the given base package for entities, i.e. MongoDB specific types annotated with {@link Document} and
|
||||||
|
* {@link Persistent}.
|
||||||
*
|
*
|
||||||
* @param basePackage must not be {@literal null}.
|
* @param basePackage must not be {@literal null}.
|
||||||
* @return
|
* @return
|
||||||
@@ -159,6 +157,7 @@ public abstract class MongoConfigurationSupport {
|
|||||||
ClassPathScanningCandidateComponentProvider componentProvider = new ClassPathScanningCandidateComponentProvider(
|
ClassPathScanningCandidateComponentProvider componentProvider = new ClassPathScanningCandidateComponentProvider(
|
||||||
false);
|
false);
|
||||||
componentProvider.addIncludeFilter(new AnnotationTypeFilter(Document.class));
|
componentProvider.addIncludeFilter(new AnnotationTypeFilter(Document.class));
|
||||||
|
componentProvider.addIncludeFilter(new AnnotationTypeFilter(Persistent.class));
|
||||||
|
|
||||||
for (BeanDefinition candidate : componentProvider.findCandidateComponents(basePackage)) {
|
for (BeanDefinition candidate : componentProvider.findCandidateComponents(basePackage)) {
|
||||||
|
|
||||||
@@ -172,7 +171,8 @@ public abstract class MongoConfigurationSupport {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Configures whether to abbreviate field names for domain objects by configuring a
|
* Configures whether to abbreviate field names for domain objects by configuring a
|
||||||
* {@link CamelCaseAbbreviatingFieldNamingStrategy} on the {@link MongoMappingContext} instance created.
|
* {@link CamelCaseAbbreviatingFieldNamingStrategy} on the {@link MongoMappingContext} instance created. For advanced
|
||||||
|
* customization needs, consider overriding {@link #mappingMongoConverter()}.
|
||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
@@ -190,41 +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 false} by default. <br />
|
|
||||||
* <strong>INFO</strong>: As of 3.x the default is set to {@literal false}; In 2.x it was {@literal true}.
|
|
||||||
* @since 2.2
|
|
||||||
*/
|
|
||||||
protected boolean autoIndexCreation() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the {@link MongoClientSettings} used to create the actual {@literal MongoClient}. <br />
|
|
||||||
* Override either this method, or use {@link #configureClientSettings(Builder)} to alter the setup.
|
|
||||||
*
|
|
||||||
* @return never {@literal null}.
|
|
||||||
* @since 3.0
|
|
||||||
*/
|
|
||||||
protected MongoClientSettings mongoClientSettings() {
|
|
||||||
|
|
||||||
MongoClientSettings.Builder builder = MongoClientSettings.builder();
|
|
||||||
builder.uuidRepresentation(UuidRepresentation.JAVA_LEGACY);
|
|
||||||
configureClientSettings(builder);
|
|
||||||
return builder.build();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Configure {@link MongoClientSettings} via its {@link Builder} API.
|
|
||||||
*
|
|
||||||
* @param builder never {@literal null}.
|
|
||||||
* @since 3.0
|
|
||||||
*/
|
|
||||||
protected void configureClientSettings(MongoClientSettings.Builder builder) {
|
|
||||||
// customization hook
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2015-2021 the original author or authors.
|
* Copyright 2015-2020 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;
|
||||||
@@ -51,6 +49,10 @@ public class MongoCredentialPropertyEditor extends PropertyEditorSupport {
|
|||||||
private static final String OPTIONS_DELIMITER = "?";
|
private static final String OPTIONS_DELIMITER = "?";
|
||||||
private static final String OPTION_VALUE_DELIMITER = "&";
|
private static final String OPTION_VALUE_DELIMITER = "&";
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see java.beans.PropertyEditorSupport#setAsText(java.lang.String)
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void setAsText(@Nullable String text) throws IllegalArgumentException {
|
public void setAsText(@Nullable String text) throws IllegalArgumentException {
|
||||||
|
|
||||||
@@ -76,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,
|
userNameAndPassword[1].toCharArray()));
|
||||||
"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()));
|
|
||||||
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-2021 the original author or authors.
|
* Copyright 2011-2020 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,12 +32,14 @@ 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.config.BeanComponentDefinitionBuilder;
|
import org.springframework.data.config.BeanComponentDefinitionBuilder;
|
||||||
import org.springframework.data.mongodb.core.MongoClientFactoryBean;
|
import org.springframework.data.mongodb.core.MongoClientFactoryBean;
|
||||||
import org.springframework.data.mongodb.core.SimpleMongoClientDatabaseFactory;
|
import org.springframework.data.mongodb.core.SimpleMongoDbFactory;
|
||||||
import org.springframework.lang.Nullable;
|
import org.springframework.lang.Nullable;
|
||||||
import org.springframework.util.StringUtils;
|
import org.springframework.util.StringUtils;
|
||||||
import org.w3c.dom.Element;
|
import org.w3c.dom.Element;
|
||||||
|
|
||||||
import com.mongodb.ConnectionString;
|
import com.mongodb.Mongo;
|
||||||
|
import com.mongodb.MongoClientURI;
|
||||||
|
import com.mongodb.MongoURI;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@link BeanDefinitionParser} to parse {@code db-factory} elements into {@link BeanDefinition}s.
|
* {@link BeanDefinitionParser} to parse {@code db-factory} elements into {@link BeanDefinition}s.
|
||||||
@@ -62,6 +64,10 @@ public class MongoDbFactoryParser extends AbstractBeanDefinitionParser {
|
|||||||
MONGO_URI_ALLOWED_ADDITIONAL_ATTRIBUTES = Collections.unmodifiableSet(mongoUriAllowedAdditionalAttributes);
|
MONGO_URI_ALLOWED_ADDITIONAL_ATTRIBUTES = Collections.unmodifiableSet(mongoUriAllowedAdditionalAttributes);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.springframework.beans.factory.xml.AbstractBeanDefinitionParser#resolveId(org.w3c.dom.Element, org.springframework.beans.factory.support.AbstractBeanDefinition, org.springframework.beans.factory.xml.ParserContext)
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
protected String resolveId(Element element, AbstractBeanDefinition definition, ParserContext parserContext)
|
protected String resolveId(Element element, AbstractBeanDefinition definition, ParserContext parserContext)
|
||||||
throws BeanDefinitionStoreException {
|
throws BeanDefinitionStoreException {
|
||||||
@@ -70,15 +76,18 @@ public class MongoDbFactoryParser extends AbstractBeanDefinitionParser {
|
|||||||
return StringUtils.hasText(id) ? id : BeanNames.DB_FACTORY_BEAN_NAME;
|
return StringUtils.hasText(id) ? id : BeanNames.DB_FACTORY_BEAN_NAME;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.springframework.beans.factory.xml.AbstractBeanDefinitionParser#parseInternal(org.w3c.dom.Element, org.springframework.beans.factory.xml.ParserContext)
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
protected AbstractBeanDefinition parseInternal(Element element, ParserContext parserContext) {
|
protected AbstractBeanDefinition parseInternal(Element element, ParserContext parserContext) {
|
||||||
|
|
||||||
// Common setup
|
// Common setup
|
||||||
BeanDefinitionBuilder dbFactoryBuilder = BeanDefinitionBuilder
|
BeanDefinitionBuilder dbFactoryBuilder = BeanDefinitionBuilder.genericBeanDefinition(SimpleMongoDbFactory.class);
|
||||||
.genericBeanDefinition(SimpleMongoClientDatabaseFactory.class);
|
|
||||||
setPropertyValue(dbFactoryBuilder, element, "write-concern", "writeConcern");
|
setPropertyValue(dbFactoryBuilder, element, "write-concern", "writeConcern");
|
||||||
|
|
||||||
BeanDefinition mongoUri = getConnectionString(element, parserContext);
|
BeanDefinition mongoUri = getMongoUri(element, parserContext);
|
||||||
|
|
||||||
if (mongoUri != null) {
|
if (mongoUri != null) {
|
||||||
|
|
||||||
@@ -88,8 +97,7 @@ public class MongoDbFactoryParser extends AbstractBeanDefinitionParser {
|
|||||||
|
|
||||||
BeanComponentDefinitionBuilder helper = new BeanComponentDefinitionBuilder(element, parserContext);
|
BeanComponentDefinitionBuilder helper = new BeanComponentDefinitionBuilder(element, parserContext);
|
||||||
|
|
||||||
String mongoRef = element.getAttribute("mongo-client-ref");
|
String mongoRef = element.getAttribute("mongo-ref");
|
||||||
|
|
||||||
String dbname = element.getAttribute("dbname");
|
String dbname = element.getAttribute("dbname");
|
||||||
|
|
||||||
// Defaulting
|
// Defaulting
|
||||||
@@ -111,8 +119,8 @@ public class MongoDbFactoryParser extends AbstractBeanDefinitionParser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Registers a default {@link BeanDefinition} of a {@link com.mongodb.client.MongoClient} instance and returns the
|
* Registers a default {@link BeanDefinition} of a {@link Mongo} instance and returns the name under which the
|
||||||
* name under which the {@link com.mongodb.client.MongoClient} instance was registered under.
|
* {@link Mongo} instance was registered under.
|
||||||
*
|
*
|
||||||
* @param element must not be {@literal null}.
|
* @param element must not be {@literal null}.
|
||||||
* @param parserContext must not be {@literal null}.
|
* @param parserContext must not be {@literal null}.
|
||||||
@@ -128,7 +136,8 @@ public class MongoDbFactoryParser extends AbstractBeanDefinitionParser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a {@link BeanDefinition} for a {@link ConnectionString} depending on configured attributes. <br />
|
* Creates a {@link BeanDefinition} for a {@link MongoURI} or {@link MongoClientURI} depending on configured
|
||||||
|
* attributes. <br />
|
||||||
* Errors when configured element contains {@literal uri} or {@literal client-uri} along with other attributes except
|
* Errors when configured element contains {@literal uri} or {@literal client-uri} along with other attributes except
|
||||||
* {@literal write-concern} and/or {@literal id}.
|
* {@literal write-concern} and/or {@literal id}.
|
||||||
*
|
*
|
||||||
@@ -137,19 +146,11 @@ public class MongoDbFactoryParser extends AbstractBeanDefinitionParser {
|
|||||||
* @return {@literal null} in case no client-/uri defined.
|
* @return {@literal null} in case no client-/uri defined.
|
||||||
*/
|
*/
|
||||||
@Nullable
|
@Nullable
|
||||||
private BeanDefinition getConnectionString(Element element, ParserContext parserContext) {
|
private BeanDefinition getMongoUri(Element element, ParserContext parserContext) {
|
||||||
|
|
||||||
String type = null;
|
boolean hasClientUri = element.hasAttribute("client-uri");
|
||||||
|
|
||||||
if (element.hasAttribute("client-uri")) {
|
if (!hasClientUri && !element.hasAttribute("uri")) {
|
||||||
type = "client-uri";
|
|
||||||
} else if (element.hasAttribute("connection-string")) {
|
|
||||||
type = "connection-string";
|
|
||||||
} else if (element.hasAttribute("uri")) {
|
|
||||||
type = "uri";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!StringUtils.hasText(type)) {
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -163,12 +164,16 @@ public class MongoDbFactoryParser extends AbstractBeanDefinitionParser {
|
|||||||
|
|
||||||
if (element.getAttributes().getLength() > allowedAttributesCount) {
|
if (element.getAttributes().getLength() > allowedAttributesCount) {
|
||||||
|
|
||||||
parserContext.getReaderContext().error("Configure either MongoDB " + type + " or details individually!",
|
parserContext.getReaderContext().error(
|
||||||
|
"Configure either " + (hasClientUri ? "Mongo Client URI" : "Mongo URI") + " or details individually!",
|
||||||
parserContext.extractSource(element));
|
parserContext.extractSource(element));
|
||||||
}
|
}
|
||||||
|
|
||||||
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(ConnectionString.class);
|
Class<?> type = MongoClientURI.class;
|
||||||
builder.addConstructorArgValue(element.getAttribute(type));
|
String uri = hasClientUri ? element.getAttribute("client-uri") : element.getAttribute("uri");
|
||||||
|
|
||||||
|
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(type);
|
||||||
|
builder.addConstructorArgValue(uri);
|
||||||
|
|
||||||
return builder.getBeanDefinition();
|
return builder.getBeanDefinition();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2011-2021 the original author or authors.
|
* Copyright 2011-2020 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-2021 the original author or authors.
|
* Copyright 2011-2020 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,6 +26,10 @@ import org.springframework.beans.factory.xml.NamespaceHandlerSupport;
|
|||||||
*/
|
*/
|
||||||
public class MongoNamespaceHandler extends NamespaceHandlerSupport {
|
public class MongoNamespaceHandler extends NamespaceHandlerSupport {
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.springframework.beans.factory.xml.NamespaceHandler#init()
|
||||||
|
*/
|
||||||
public void init() {
|
public void init() {
|
||||||
|
|
||||||
registerBeanDefinitionParser("mapping-converter", new MappingMongoConverterParser());
|
registerBeanDefinitionParser("mapping-converter", new MappingMongoConverterParser());
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2011-2021 the original author or authors.
|
* Copyright 2011-2020 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.
|
||||||
@@ -22,12 +22,9 @@ import java.util.Map;
|
|||||||
import org.springframework.beans.factory.config.BeanDefinition;
|
import org.springframework.beans.factory.config.BeanDefinition;
|
||||||
import org.springframework.beans.factory.config.CustomEditorConfigurer;
|
import org.springframework.beans.factory.config.CustomEditorConfigurer;
|
||||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||||
import org.springframework.beans.factory.support.BeanDefinitionValidationException;
|
|
||||||
import org.springframework.beans.factory.support.ManagedMap;
|
import org.springframework.beans.factory.support.ManagedMap;
|
||||||
import org.springframework.beans.factory.xml.BeanDefinitionParser;
|
import org.springframework.beans.factory.xml.BeanDefinitionParser;
|
||||||
import org.springframework.data.mongodb.core.MongoClientSettingsFactoryBean;
|
import org.springframework.data.mongodb.core.MongoClientOptionsFactoryBean;
|
||||||
import org.springframework.data.mongodb.core.MongoServerApiFactoryBean;
|
|
||||||
import org.springframework.util.StringUtils;
|
|
||||||
import org.springframework.util.xml.DomUtils;
|
import org.springframework.util.xml.DomUtils;
|
||||||
import org.w3c.dom.Element;
|
import org.w3c.dom.Element;
|
||||||
|
|
||||||
@@ -38,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 {
|
||||||
@@ -46,92 +42,59 @@ abstract class MongoParsingUtils {
|
|||||||
private MongoParsingUtils() {}
|
private MongoParsingUtils() {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parses the {@code mongo:client-settings} sub-element. Populates the given attribute factory with the proper
|
* Parses the mongo replica-set element.
|
||||||
|
*
|
||||||
|
* @param parserContext the parser context
|
||||||
|
* @param element the mongo element
|
||||||
|
* @param mongoBuilder the bean definition builder to populate
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
static void parseReplicaSet(Element element, BeanDefinitionBuilder mongoBuilder) {
|
||||||
|
setPropertyValue(mongoBuilder, element, "replica-set", "replicaSetSeeds");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses the {@code mongo:client-options} sub-element. Populates the given attribute factory with the proper
|
||||||
* attributes.
|
* attributes.
|
||||||
*
|
*
|
||||||
* @param element
|
* @param element must not be {@literal null}.
|
||||||
* @param mongoClientBuilder
|
* @param mongoClientBuilder must not be {@literal null}.
|
||||||
* @return
|
* @return
|
||||||
* @since 3.0
|
* @since 1.7
|
||||||
*/
|
*/
|
||||||
public static boolean parseMongoClientSettings(Element element, BeanDefinitionBuilder mongoClientBuilder) {
|
public static boolean parseMongoClientOptions(Element element, BeanDefinitionBuilder mongoClientBuilder) {
|
||||||
|
|
||||||
Element settingsElement = DomUtils.getChildElementByTagName(element, "client-settings");
|
Element optionsElement = DomUtils.getChildElementByTagName(element, "client-options");
|
||||||
if (settingsElement == null) {
|
|
||||||
|
if (optionsElement == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
BeanDefinitionBuilder clientOptionsDefBuilder = BeanDefinitionBuilder
|
BeanDefinitionBuilder clientOptionsDefBuilder = BeanDefinitionBuilder
|
||||||
.genericBeanDefinition(MongoClientSettingsFactoryBean.class);
|
.genericBeanDefinition(MongoClientOptionsFactoryBean.class);
|
||||||
|
|
||||||
setPropertyValue(clientOptionsDefBuilder, settingsElement, "application-name", "applicationName");
|
setPropertyValue(clientOptionsDefBuilder, optionsElement, "description", "description");
|
||||||
setPropertyValue(clientOptionsDefBuilder, settingsElement, "read-preference", "readPreference");
|
setPropertyValue(clientOptionsDefBuilder, optionsElement, "min-connections-per-host", "minConnectionsPerHost");
|
||||||
setPropertyValue(clientOptionsDefBuilder, settingsElement, "read-concern", "readConcern");
|
setPropertyValue(clientOptionsDefBuilder, optionsElement, "connections-per-host", "connectionsPerHost");
|
||||||
setPropertyValue(clientOptionsDefBuilder, settingsElement, "write-concern", "writeConcern");
|
setPropertyValue(clientOptionsDefBuilder, optionsElement, "threads-allowed-to-block-for-connection-multiplier",
|
||||||
setPropertyValue(clientOptionsDefBuilder, settingsElement, "retry-reads", "retryReads");
|
"threadsAllowedToBlockForConnectionMultiplier");
|
||||||
setPropertyValue(clientOptionsDefBuilder, settingsElement, "retry-writes", "retryWrites");
|
setPropertyValue(clientOptionsDefBuilder, optionsElement, "max-wait-time", "maxWaitTime");
|
||||||
setPropertyValue(clientOptionsDefBuilder, settingsElement, "uuid-representation", "uUidRepresentation");
|
setPropertyValue(clientOptionsDefBuilder, optionsElement, "max-connection-idle-time", "maxConnectionIdleTime");
|
||||||
|
setPropertyValue(clientOptionsDefBuilder, optionsElement, "max-connection-life-time", "maxConnectionLifeTime");
|
||||||
|
setPropertyValue(clientOptionsDefBuilder, optionsElement, "connect-timeout", "connectTimeout");
|
||||||
|
setPropertyValue(clientOptionsDefBuilder, optionsElement, "socket-timeout", "socketTimeout");
|
||||||
|
setPropertyValue(clientOptionsDefBuilder, optionsElement, "socket-keep-alive", "socketKeepAlive");
|
||||||
|
setPropertyValue(clientOptionsDefBuilder, optionsElement, "read-preference", "readPreference");
|
||||||
|
setPropertyValue(clientOptionsDefBuilder, optionsElement, "write-concern", "writeConcern");
|
||||||
|
setPropertyValue(clientOptionsDefBuilder, optionsElement, "heartbeat-frequency", "heartbeatFrequency");
|
||||||
|
setPropertyValue(clientOptionsDefBuilder, optionsElement, "min-heartbeat-frequency", "minHeartbeatFrequency");
|
||||||
|
setPropertyValue(clientOptionsDefBuilder, optionsElement, "heartbeat-connect-timeout", "heartbeatConnectTimeout");
|
||||||
|
setPropertyValue(clientOptionsDefBuilder, optionsElement, "heartbeat-socket-timeout", "heartbeatSocketTimeout");
|
||||||
|
setPropertyValue(clientOptionsDefBuilder, optionsElement, "ssl", "ssl");
|
||||||
|
setPropertyReference(clientOptionsDefBuilder, optionsElement, "ssl-socket-factory-ref", "sslSocketFactory");
|
||||||
|
setPropertyValue(clientOptionsDefBuilder, optionsElement, "server-selection-timeout", "serverSelectionTimeout");
|
||||||
|
|
||||||
// SocketSettings
|
mongoClientBuilder.addPropertyValue("mongoClientOptions", clientOptionsDefBuilder.getBeanDefinition());
|
||||||
setPropertyValue(clientOptionsDefBuilder, settingsElement, "socket-connect-timeout", "socketConnectTimeoutMS");
|
|
||||||
setPropertyValue(clientOptionsDefBuilder, settingsElement, "socket-read-timeout", "socketReadTimeoutMS");
|
|
||||||
setPropertyValue(clientOptionsDefBuilder, settingsElement, "socket-receive-buffer-size", "socketReceiveBufferSize");
|
|
||||||
setPropertyValue(clientOptionsDefBuilder, settingsElement, "socket-send-buffer-size", "socketSendBufferSize");
|
|
||||||
|
|
||||||
// Server Settings
|
|
||||||
setPropertyValue(clientOptionsDefBuilder, settingsElement, "server-heartbeat-frequency",
|
|
||||||
"serverHeartbeatFrequencyMS");
|
|
||||||
setPropertyValue(clientOptionsDefBuilder, settingsElement, "server-min-heartbeat-frequency",
|
|
||||||
"serverMinHeartbeatFrequencyMS");
|
|
||||||
|
|
||||||
// Cluster Settings
|
|
||||||
setPropertyValue(clientOptionsDefBuilder, settingsElement, "cluster-srv-host", "clusterSrvHost");
|
|
||||||
setPropertyValue(clientOptionsDefBuilder, settingsElement, "cluster-hosts", "clusterHosts");
|
|
||||||
setPropertyValue(clientOptionsDefBuilder, settingsElement, "cluster-connection-mode", "clusterConnectionMode");
|
|
||||||
setPropertyValue(clientOptionsDefBuilder, settingsElement, "cluster-type", "custerRequiredClusterType");
|
|
||||||
setPropertyValue(clientOptionsDefBuilder, settingsElement, "cluster-local-threshold", "clusterLocalThresholdMS");
|
|
||||||
setPropertyValue(clientOptionsDefBuilder, settingsElement, "cluster-server-selection-timeout",
|
|
||||||
"clusterServerSelectionTimeoutMS");
|
|
||||||
|
|
||||||
// Connection Pool Settings
|
|
||||||
setPropertyValue(clientOptionsDefBuilder, settingsElement, "connection-pool-max-size", "poolMaxSize");
|
|
||||||
setPropertyValue(clientOptionsDefBuilder, settingsElement, "connection-pool-min-size", "poolMinSize");
|
|
||||||
setPropertyValue(clientOptionsDefBuilder, settingsElement, "connection-pool-max-wait-time", "poolMaxWaitTimeMS");
|
|
||||||
setPropertyValue(clientOptionsDefBuilder, settingsElement, "connection-pool-max-connection-life-time",
|
|
||||||
"poolMaxConnectionLifeTimeMS");
|
|
||||||
setPropertyValue(clientOptionsDefBuilder, settingsElement, "connection-pool-max-connection-idle-time",
|
|
||||||
"poolMaxConnectionIdleTimeMS");
|
|
||||||
setPropertyValue(clientOptionsDefBuilder, settingsElement, "connection-pool-maintenance-initial-delay",
|
|
||||||
"poolMaintenanceInitialDelayMS");
|
|
||||||
setPropertyValue(clientOptionsDefBuilder, settingsElement, "connection-pool-maintenance-frequency",
|
|
||||||
"poolMaintenanceFrequencyMS");
|
|
||||||
|
|
||||||
// SSL Settings
|
|
||||||
setPropertyValue(clientOptionsDefBuilder, settingsElement, "ssl-enabled", "sslEnabled");
|
|
||||||
setPropertyValue(clientOptionsDefBuilder, settingsElement, "ssl-invalid-host-name-allowed",
|
|
||||||
"sslInvalidHostNameAllowed");
|
|
||||||
setPropertyValue(clientOptionsDefBuilder, settingsElement, "ssl-provider", "sslProvider");
|
|
||||||
|
|
||||||
// Field level encryption
|
|
||||||
setPropertyReference(clientOptionsDefBuilder, settingsElement, "encryption-settings-ref", "autoEncryptionSettings");
|
|
||||||
|
|
||||||
// ServerAPI
|
|
||||||
if (StringUtils.hasText(settingsElement.getAttribute("server-api-version"))) {
|
|
||||||
|
|
||||||
MongoServerApiFactoryBean serverApiFactoryBean = new MongoServerApiFactoryBean();
|
|
||||||
serverApiFactoryBean.setVersion(settingsElement.getAttribute("server-api-version"));
|
|
||||||
try {
|
|
||||||
clientOptionsDefBuilder.addPropertyValue("serverApi", serverApiFactoryBean.getObject());
|
|
||||||
} catch (Exception exception) {
|
|
||||||
throw new BeanDefinitionValidationException("Non parsable server-api.", exception);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
setPropertyReference(clientOptionsDefBuilder, settingsElement, "server-api-ref", "serverApi");
|
|
||||||
}
|
|
||||||
|
|
||||||
// and the rest
|
|
||||||
|
|
||||||
mongoClientBuilder.addPropertyValue("mongoClientSettings", clientOptionsDefBuilder.getBeanDefinition());
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -153,24 +116,6 @@ abstract class MongoParsingUtils {
|
|||||||
return builder;
|
return builder;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the {@link BeanDefinitionBuilder} to build a {@link BeanDefinition} for a
|
|
||||||
* {@link ReadConcernPropertyEditor}.
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
* @since 3.0
|
|
||||||
*/
|
|
||||||
static BeanDefinitionBuilder getReadConcernPropertyEditorBuilder() {
|
|
||||||
|
|
||||||
Map<String, Class<?>> customEditors = new ManagedMap<>();
|
|
||||||
customEditors.put("com.mongodb.ReadConcern", ReadConcernPropertyEditor.class);
|
|
||||||
|
|
||||||
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(CustomEditorConfigurer.class);
|
|
||||||
builder.addPropertyValue("customEditors", customEditors);
|
|
||||||
|
|
||||||
return builder;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* One should only register one bean definition but want to have the convenience of using
|
* One should only register one bean definition but want to have the convenience of using
|
||||||
* AbstractSingleBeanDefinitionParser but have the side effect of registering a 'default' property editor with the
|
* AbstractSingleBeanDefinitionParser but have the side effect of registering a 'default' property editor with the
|
||||||
@@ -178,7 +123,7 @@ abstract class MongoParsingUtils {
|
|||||||
*/
|
*/
|
||||||
static BeanDefinitionBuilder getServerAddressPropertyEditorBuilder() {
|
static BeanDefinitionBuilder getServerAddressPropertyEditorBuilder() {
|
||||||
|
|
||||||
Map<String, String> customEditors = new ManagedMap<>();
|
Map<String, String> customEditors = new ManagedMap<String, String>();
|
||||||
customEditors.put("com.mongodb.ServerAddress[]",
|
customEditors.put("com.mongodb.ServerAddress[]",
|
||||||
"org.springframework.data.mongodb.config.ServerAddressPropertyEditor");
|
"org.springframework.data.mongodb.config.ServerAddressPropertyEditor");
|
||||||
|
|
||||||
@@ -196,7 +141,7 @@ abstract class MongoParsingUtils {
|
|||||||
*/
|
*/
|
||||||
static BeanDefinitionBuilder getReadPreferencePropertyEditorBuilder() {
|
static BeanDefinitionBuilder getReadPreferencePropertyEditorBuilder() {
|
||||||
|
|
||||||
Map<String, Class<?>> customEditors = new ManagedMap<>();
|
Map<String, Class<?>> customEditors = new ManagedMap<String, Class<?>>();
|
||||||
customEditors.put("com.mongodb.ReadPreference", ReadPreferencePropertyEditor.class);
|
customEditors.put("com.mongodb.ReadPreference", ReadPreferencePropertyEditor.class);
|
||||||
|
|
||||||
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(CustomEditorConfigurer.class);
|
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(CustomEditorConfigurer.class);
|
||||||
@@ -222,41 +167,4 @@ abstract class MongoParsingUtils {
|
|||||||
|
|
||||||
return builder;
|
return builder;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the {@link BeanDefinitionBuilder} to build a {@link BeanDefinition} for a
|
|
||||||
* {@link ConnectionStringPropertyEditor}.
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
* @since 3.0
|
|
||||||
*/
|
|
||||||
static BeanDefinitionBuilder getConnectionStringPropertyEditorBuilder() {
|
|
||||||
|
|
||||||
Map<String, Class<?>> customEditors = new ManagedMap<>();
|
|
||||||
customEditors.put("com.mongodb.ConnectionString", ConnectionStringPropertyEditor.class);
|
|
||||||
|
|
||||||
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(CustomEditorConfigurer.class);
|
|
||||||
builder.addPropertyValue("customEditors", customEditors);
|
|
||||||
|
|
||||||
return builder;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the {@link BeanDefinitionBuilder} to build a {@link BeanDefinition} for a
|
|
||||||
* {@link ConnectionStringPropertyEditor}.
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
* @since 3.0
|
|
||||||
*/
|
|
||||||
static BeanDefinitionBuilder getUUidRepresentationEditorBuilder() {
|
|
||||||
|
|
||||||
Map<String, Class<?>> customEditors = new ManagedMap<>();
|
|
||||||
customEditors.put("org.bson.UuidRepresentation", UUidRepresentationPropertyEditor.class);
|
|
||||||
|
|
||||||
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(CustomEditorConfigurer.class);
|
|
||||||
builder.addPropertyValue("customEditors", customEditors);
|
|
||||||
|
|
||||||
return builder;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2011-2021 the original author or authors.
|
* Copyright 2011-2020 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.
|
||||||
@@ -39,6 +39,10 @@ import org.w3c.dom.Element;
|
|||||||
*/
|
*/
|
||||||
class MongoTemplateParser extends AbstractBeanDefinitionParser {
|
class MongoTemplateParser extends AbstractBeanDefinitionParser {
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.springframework.beans.factory.xml.AbstractBeanDefinitionParser#resolveId(org.w3c.dom.Element, org.springframework.beans.factory.support.AbstractBeanDefinition, org.springframework.beans.factory.xml.ParserContext)
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
protected String resolveId(Element element, AbstractBeanDefinition definition, ParserContext parserContext)
|
protected String resolveId(Element element, AbstractBeanDefinition definition, ParserContext parserContext)
|
||||||
throws BeanDefinitionStoreException {
|
throws BeanDefinitionStoreException {
|
||||||
@@ -47,6 +51,10 @@ class MongoTemplateParser extends AbstractBeanDefinitionParser {
|
|||||||
return StringUtils.hasText(id) ? id : BeanNames.MONGO_TEMPLATE_BEAN_NAME;
|
return StringUtils.hasText(id) ? id : BeanNames.MONGO_TEMPLATE_BEAN_NAME;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.springframework.beans.factory.xml.AbstractBeanDefinitionParser#parseInternal(org.w3c.dom.Element, org.springframework.beans.factory.xml.ParserContext)
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
protected AbstractBeanDefinition parseInternal(Element element, ParserContext parserContext) {
|
protected AbstractBeanDefinition parseInternal(Element element, ParserContext parserContext) {
|
||||||
|
|
||||||
|
|||||||
@@ -1,53 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2020-2021 the original author or authors.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* https://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package org.springframework.data.mongodb.config;
|
|
||||||
|
|
||||||
import org.springframework.beans.factory.FactoryBean;
|
|
||||||
import org.springframework.data.mapping.context.PersistentEntities;
|
|
||||||
import org.springframework.data.mongodb.core.convert.MappingMongoConverter;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Simple helper to be able to wire the {@link PersistentEntities} from a {@link MappingMongoConverter} bean available
|
|
||||||
* in the application context.
|
|
||||||
*
|
|
||||||
* @author Oliver Gierke
|
|
||||||
* @author Mark Paluch
|
|
||||||
* @author Christoph Strobl
|
|
||||||
* @since 3.1
|
|
||||||
*/
|
|
||||||
public class PersistentEntitiesFactoryBean implements FactoryBean<PersistentEntities> {
|
|
||||||
|
|
||||||
private final MappingMongoConverter converter;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new {@link PersistentEntitiesFactoryBean} for the given {@link MappingMongoConverter}.
|
|
||||||
*
|
|
||||||
* @param converter must not be {@literal null}.
|
|
||||||
*/
|
|
||||||
public PersistentEntitiesFactoryBean(MappingMongoConverter converter) {
|
|
||||||
this.converter = converter;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public PersistentEntities getObject() {
|
|
||||||
return PersistentEntities.of(converter.getMappingContext());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Class<?> getObjectType() {
|
|
||||||
return PersistentEntities.class;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,81 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2020-2021 the original author or authors.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* https://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package org.springframework.data.mongodb.config;
|
|
||||||
|
|
||||||
import java.lang.annotation.Annotation;
|
|
||||||
|
|
||||||
import org.springframework.beans.factory.config.BeanDefinition;
|
|
||||||
import org.springframework.beans.factory.support.AbstractBeanDefinition;
|
|
||||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
|
||||||
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
|
||||||
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
|
|
||||||
import org.springframework.core.type.AnnotationMetadata;
|
|
||||||
import org.springframework.data.auditing.ReactiveIsNewAwareAuditingHandler;
|
|
||||||
import org.springframework.data.auditing.config.AuditingBeanDefinitionRegistrarSupport;
|
|
||||||
import org.springframework.data.auditing.config.AuditingConfiguration;
|
|
||||||
import org.springframework.data.config.ParsingUtils;
|
|
||||||
import org.springframework.data.mongodb.core.mapping.event.ReactiveAuditingEntityCallback;
|
|
||||||
import org.springframework.util.Assert;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@link ImportBeanDefinitionRegistrar} to enable {@link EnableReactiveMongoAuditing} annotation.
|
|
||||||
*
|
|
||||||
* @author Mark Paluch
|
|
||||||
* @since 3.1
|
|
||||||
*/
|
|
||||||
class ReactiveMongoAuditingRegistrar extends AuditingBeanDefinitionRegistrarSupport {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Class<? extends Annotation> getAnnotation() {
|
|
||||||
return EnableReactiveMongoAuditing.class;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected String getAuditingHandlerBeanName() {
|
|
||||||
return "reactiveMongoAuditingHandler";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected BeanDefinitionBuilder getAuditHandlerBeanDefinitionBuilder(AuditingConfiguration configuration) {
|
|
||||||
|
|
||||||
Assert.notNull(configuration, "AuditingConfiguration must not be null!");
|
|
||||||
|
|
||||||
BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(ReactiveIsNewAwareAuditingHandler.class);
|
|
||||||
|
|
||||||
BeanDefinitionBuilder definition = BeanDefinitionBuilder.genericBeanDefinition(PersistentEntitiesFactoryBean.class);
|
|
||||||
definition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_CONSTRUCTOR);
|
|
||||||
|
|
||||||
builder.addConstructorArgValue(definition.getBeanDefinition());
|
|
||||||
return configureDefaultAuditHandlerAttributes(configuration, builder);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void registerAuditListenerBeanDefinition(BeanDefinition auditingHandlerDefinition,
|
|
||||||
BeanDefinitionRegistry registry) {
|
|
||||||
|
|
||||||
Assert.notNull(auditingHandlerDefinition, "BeanDefinition must not be null!");
|
|
||||||
Assert.notNull(registry, "BeanDefinitionRegistry must not be null!");
|
|
||||||
|
|
||||||
BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(ReactiveAuditingEntityCallback.class);
|
|
||||||
|
|
||||||
builder.addConstructorArgValue(ParsingUtils.getObjectFactoryBeanDefinition(getAuditingHandlerBeanName(), registry));
|
|
||||||
builder.getRawBeanDefinition().setSource(auditingHandlerDefinition.getSource());
|
|
||||||
|
|
||||||
registerInfrastructureBeanWithId(builder.getBeanDefinition(), ReactiveAuditingEntityCallback.class.getName(),
|
|
||||||
registry);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,44 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2019-2021 the original author or authors.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* https://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package org.springframework.data.mongodb.config;
|
|
||||||
|
|
||||||
import java.beans.PropertyEditorSupport;
|
|
||||||
|
|
||||||
import org.springframework.lang.Nullable;
|
|
||||||
import org.springframework.util.StringUtils;
|
|
||||||
|
|
||||||
import com.mongodb.ReadConcern;
|
|
||||||
import com.mongodb.ReadConcernLevel;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Parse a {@link String} to a {@link ReadConcern}. If it is a well know {@link String} as identified by the
|
|
||||||
* {@link ReadConcernLevel#fromString(String)}.
|
|
||||||
*
|
|
||||||
* @author Christoph Strobl
|
|
||||||
* @since 3.0
|
|
||||||
*/
|
|
||||||
public class ReadConcernPropertyEditor extends PropertyEditorSupport {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setAsText(@Nullable String readConcernString) {
|
|
||||||
|
|
||||||
if (!StringUtils.hasText(readConcernString)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
setValue(new ReadConcern(ReadConcernLevel.fromString(readConcernString)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2015-2021 the original author or authors.
|
* Copyright 2015-2020 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.
|
||||||
@@ -29,6 +29,10 @@ import com.mongodb.ReadPreference;
|
|||||||
*/
|
*/
|
||||||
public class ReadPreferencePropertyEditor extends PropertyEditorSupport {
|
public class ReadPreferencePropertyEditor extends PropertyEditorSupport {
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see java.beans.PropertyEditorSupport#setAsText(java.lang.String)
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void setAsText(@Nullable String readPreferenceString) throws IllegalArgumentException {
|
public void setAsText(@Nullable String readPreferenceString) throws IllegalArgumentException {
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2011-2021 the original author or authors.
|
* Copyright 2011-2020 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,8 +21,8 @@ import java.net.UnknownHostException;
|
|||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import org.apache.commons.logging.Log;
|
import org.slf4j.Logger;
|
||||||
import org.apache.commons.logging.LogFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.lang.Nullable;
|
import org.springframework.lang.Nullable;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
import org.springframework.util.StringUtils;
|
import org.springframework.util.StringUtils;
|
||||||
@@ -43,9 +43,13 @@ public class ServerAddressPropertyEditor extends PropertyEditorSupport {
|
|||||||
* A port is a number without a leading 0 at the end of the address that is proceeded by just a single :.
|
* A port is a number without a leading 0 at the end of the address that is proceeded by just a single :.
|
||||||
*/
|
*/
|
||||||
private static final String HOST_PORT_SPLIT_PATTERN = "(?<!:):(?=[123456789]\\d*$)";
|
private static final String HOST_PORT_SPLIT_PATTERN = "(?<!:):(?=[123456789]\\d*$)";
|
||||||
private static final String COULD_NOT_PARSE_ADDRESS_MESSAGE = "Could not parse address %s '%s'. Check your replica set configuration!";
|
private static final String COULD_NOT_PARSE_ADDRESS_MESSAGE = "Could not parse address {} '{}'. Check your replica set configuration!";
|
||||||
private static final Log LOG = LogFactory.getLog(ServerAddressPropertyEditor.class);
|
private static final Logger LOG = LoggerFactory.getLogger(ServerAddressPropertyEditor.class);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see java.beans.PropertyEditorSupport#setAsText(java.lang.String)
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void setAsText(@Nullable String replicaSetString) {
|
public void setAsText(@Nullable String replicaSetString) {
|
||||||
|
|
||||||
@@ -84,18 +88,14 @@ public class ServerAddressPropertyEditor extends PropertyEditorSupport {
|
|||||||
private ServerAddress parseServerAddress(String source) {
|
private ServerAddress parseServerAddress(String source) {
|
||||||
|
|
||||||
if (!StringUtils.hasText(source)) {
|
if (!StringUtils.hasText(source)) {
|
||||||
if(LOG.isWarnEnabled()) {
|
LOG.warn(COULD_NOT_PARSE_ADDRESS_MESSAGE, "source", source);
|
||||||
LOG.warn(String.format(COULD_NOT_PARSE_ADDRESS_MESSAGE, "source", source));
|
|
||||||
}
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
String[] hostAndPort = extractHostAddressAndPort(source.trim());
|
String[] hostAndPort = extractHostAddressAndPort(source.trim());
|
||||||
|
|
||||||
if (hostAndPort.length > 2) {
|
if (hostAndPort.length > 2) {
|
||||||
if(LOG.isWarnEnabled()) {
|
LOG.warn(COULD_NOT_PARSE_ADDRESS_MESSAGE, "source", source);
|
||||||
LOG.warn(String.format(COULD_NOT_PARSE_ADDRESS_MESSAGE, "source", source));
|
|
||||||
}
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -105,13 +105,9 @@ public class ServerAddressPropertyEditor extends PropertyEditorSupport {
|
|||||||
|
|
||||||
return port == null ? new ServerAddress(hostAddress) : new ServerAddress(hostAddress, port);
|
return port == null ? new ServerAddress(hostAddress) : new ServerAddress(hostAddress, port);
|
||||||
} catch (UnknownHostException e) {
|
} catch (UnknownHostException e) {
|
||||||
if(LOG.isWarnEnabled()) {
|
LOG.warn(COULD_NOT_PARSE_ADDRESS_MESSAGE, "host", hostAndPort[0]);
|
||||||
LOG.warn(String.format(COULD_NOT_PARSE_ADDRESS_MESSAGE, "host", hostAndPort[0]));
|
|
||||||
}
|
|
||||||
} catch (NumberFormatException e) {
|
} catch (NumberFormatException e) {
|
||||||
if(LOG.isWarnEnabled()) {
|
LOG.warn(COULD_NOT_PARSE_ADDRESS_MESSAGE, "port", hostAndPort[1]);
|
||||||
LOG.warn(String.format(COULD_NOT_PARSE_ADDRESS_MESSAGE, "port", hostAndPort[1]));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2012-2021 the original author or authors.
|
* Copyright 2012-2020 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,6 +26,10 @@ import com.mongodb.WriteConcern;
|
|||||||
*/
|
*/
|
||||||
public class StringToWriteConcernConverter implements Converter<String, WriteConcern> {
|
public class StringToWriteConcernConverter implements Converter<String, WriteConcern> {
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.springframework.core.convert.converter.Converter#convert(java.lang.Object)
|
||||||
|
*/
|
||||||
public WriteConcern convert(String source) {
|
public WriteConcern convert(String source) {
|
||||||
|
|
||||||
WriteConcern writeConcern = WriteConcern.valueOf(source);
|
WriteConcern writeConcern = WriteConcern.valueOf(source);
|
||||||
|
|||||||
@@ -1,41 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2020-2021 the original author or authors.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* https://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package org.springframework.data.mongodb.config;
|
|
||||||
|
|
||||||
import java.beans.PropertyEditorSupport;
|
|
||||||
|
|
||||||
import org.bson.UuidRepresentation;
|
|
||||||
import org.springframework.lang.Nullable;
|
|
||||||
import org.springframework.util.StringUtils;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Parse a {@link String} to a {@link UuidRepresentation}.
|
|
||||||
*
|
|
||||||
* @author Christoph Strobl
|
|
||||||
* @since 3.0
|
|
||||||
*/
|
|
||||||
public class UUidRepresentationPropertyEditor extends PropertyEditorSupport {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setAsText(@Nullable String value) {
|
|
||||||
|
|
||||||
if (!StringUtils.hasText(value)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
setValue(UuidRepresentation.valueOf(value));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2011-2021 the original author or authors.
|
* Copyright 2011-2020 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.
|
||||||
@@ -34,7 +34,7 @@ import com.mongodb.WriteConcern;
|
|||||||
public class WriteConcernPropertyEditor extends PropertyEditorSupport {
|
public class WriteConcernPropertyEditor extends PropertyEditorSupport {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parse a string to a {@link WriteConcern}.
|
* Parse a string to a List<ServerAddress>
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void setAsText(@Nullable String writeConcernString) {
|
public void setAsText(@Nullable String writeConcernString) {
|
||||||
@@ -51,5 +51,6 @@ public class WriteConcernPropertyEditor extends PropertyEditorSupport {
|
|||||||
// pass on the string to the constructor
|
// pass on the string to the constructor
|
||||||
setValue(new WriteConcern(writeConcernString));
|
setValue(new WriteConcern(writeConcernString));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2018-2021 the original author or authors.
|
* Copyright 2018-2020 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,8 @@
|
|||||||
*/
|
*/
|
||||||
package org.springframework.data.mongodb.core;
|
package org.springframework.data.mongodb.core;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -27,9 +29,7 @@ import org.springframework.data.mongodb.core.aggregation.Aggregation;
|
|||||||
import org.springframework.data.mongodb.core.aggregation.AggregationOperation;
|
import org.springframework.data.mongodb.core.aggregation.AggregationOperation;
|
||||||
import org.springframework.data.mongodb.core.aggregation.AggregationOperationContext;
|
import org.springframework.data.mongodb.core.aggregation.AggregationOperationContext;
|
||||||
import org.springframework.data.mongodb.core.aggregation.AggregationOptions;
|
import org.springframework.data.mongodb.core.aggregation.AggregationOptions;
|
||||||
import org.springframework.data.mongodb.core.aggregation.AggregationOptions.DomainTypeMapping;
|
|
||||||
import org.springframework.data.mongodb.core.aggregation.CountOperation;
|
import org.springframework.data.mongodb.core.aggregation.CountOperation;
|
||||||
import org.springframework.data.mongodb.core.aggregation.RelaxedTypeBasedAggregationOperationContext;
|
|
||||||
import org.springframework.data.mongodb.core.aggregation.TypeBasedAggregationOperationContext;
|
import org.springframework.data.mongodb.core.aggregation.TypeBasedAggregationOperationContext;
|
||||||
import org.springframework.data.mongodb.core.aggregation.TypedAggregation;
|
import org.springframework.data.mongodb.core.aggregation.TypedAggregation;
|
||||||
import org.springframework.data.mongodb.core.convert.QueryMapper;
|
import org.springframework.data.mongodb.core.convert.QueryMapper;
|
||||||
@@ -37,7 +37,6 @@ 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.query.CriteriaDefinition;
|
import org.springframework.data.mongodb.core.query.CriteriaDefinition;
|
||||||
import org.springframework.data.mongodb.core.query.Query;
|
import org.springframework.data.mongodb.core.query.Query;
|
||||||
import org.springframework.data.util.Lazy;
|
|
||||||
import org.springframework.lang.Nullable;
|
import org.springframework.lang.Nullable;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
import org.springframework.util.ObjectUtils;
|
import org.springframework.util.ObjectUtils;
|
||||||
@@ -50,50 +49,34 @@ import org.springframework.util.ObjectUtils;
|
|||||||
* @author Mark Paluch
|
* @author Mark Paluch
|
||||||
* @since 2.1
|
* @since 2.1
|
||||||
*/
|
*/
|
||||||
|
@AllArgsConstructor
|
||||||
class AggregationUtil {
|
class AggregationUtil {
|
||||||
|
|
||||||
QueryMapper queryMapper;
|
QueryMapper queryMapper;
|
||||||
MappingContext<? extends MongoPersistentEntity<?>, MongoPersistentProperty> mappingContext;
|
MappingContext<? extends MongoPersistentEntity<?>, MongoPersistentProperty> mappingContext;
|
||||||
Lazy<AggregationOperationContext> untypedMappingContext;
|
|
||||||
|
|
||||||
AggregationUtil(QueryMapper queryMapper,
|
/**
|
||||||
MappingContext<? extends MongoPersistentEntity<?>, MongoPersistentProperty> mappingContext) {
|
* Prepare the {@link AggregationOperationContext} for a given aggregation by either returning the context itself it
|
||||||
|
* is not {@literal null}, create a {@link TypeBasedAggregationOperationContext} if the aggregation contains type
|
||||||
|
* information (is a {@link TypedAggregation}) or use the {@link Aggregation#DEFAULT_CONTEXT}.
|
||||||
|
*
|
||||||
|
* @param aggregation must not be {@literal null}.
|
||||||
|
* @param context can be {@literal null}.
|
||||||
|
* @return the root {@link AggregationOperationContext} to use.
|
||||||
|
*/
|
||||||
|
AggregationOperationContext prepareAggregationContext(Aggregation aggregation,
|
||||||
|
@Nullable AggregationOperationContext context) {
|
||||||
|
|
||||||
this.queryMapper = queryMapper;
|
if (context != null) {
|
||||||
this.mappingContext = mappingContext;
|
return context;
|
||||||
this.untypedMappingContext = Lazy
|
|
||||||
.of(() -> new RelaxedTypeBasedAggregationOperationContext(Object.class, mappingContext, queryMapper));
|
|
||||||
}
|
|
||||||
|
|
||||||
AggregationOperationContext createAggregationContext(Aggregation aggregation, @Nullable Class<?> inputType) {
|
|
||||||
|
|
||||||
DomainTypeMapping domainTypeMapping = aggregation.getOptions().getDomainTypeMapping();
|
|
||||||
|
|
||||||
if (domainTypeMapping == DomainTypeMapping.NONE) {
|
|
||||||
return Aggregation.DEFAULT_CONTEXT;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(aggregation instanceof TypedAggregation)) {
|
if (aggregation instanceof TypedAggregation) {
|
||||||
|
return new TypeBasedAggregationOperationContext(((TypedAggregation) aggregation).getInputType(), mappingContext,
|
||||||
if(inputType == null) {
|
queryMapper);
|
||||||
return untypedMappingContext.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (domainTypeMapping == DomainTypeMapping.STRICT
|
|
||||||
&& !aggregation.getPipeline().containsUnionWith()) {
|
|
||||||
return new TypeBasedAggregationOperationContext(inputType, mappingContext, queryMapper);
|
|
||||||
}
|
|
||||||
|
|
||||||
return new RelaxedTypeBasedAggregationOperationContext(inputType, mappingContext, queryMapper);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inputType = ((TypedAggregation<?>) aggregation).getInputType();
|
return Aggregation.DEFAULT_CONTEXT;
|
||||||
if (domainTypeMapping == DomainTypeMapping.STRICT
|
|
||||||
&& !aggregation.getPipeline().containsUnionWith()) {
|
|
||||||
return new TypeBasedAggregationOperationContext(inputType, mappingContext, queryMapper);
|
|
||||||
}
|
|
||||||
|
|
||||||
return new RelaxedTypeBasedAggregationOperationContext(inputType, mappingContext, queryMapper);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -105,7 +88,7 @@ class AggregationUtil {
|
|||||||
*/
|
*/
|
||||||
List<Document> createPipeline(Aggregation aggregation, AggregationOperationContext context) {
|
List<Document> createPipeline(Aggregation aggregation, AggregationOperationContext context) {
|
||||||
|
|
||||||
if (ObjectUtils.nullSafeEquals(context, Aggregation.DEFAULT_CONTEXT)) {
|
if (!ObjectUtils.nullSafeEquals(context, Aggregation.DEFAULT_CONTEXT)) {
|
||||||
return aggregation.toPipeline(context);
|
return aggregation.toPipeline(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -132,6 +115,53 @@ class AggregationUtil {
|
|||||||
return command;
|
return command;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a {@code $count} aggregation for {@link Query} and optionally a {@link Class entity class}.
|
||||||
|
*
|
||||||
|
* @param query must not be {@literal null}.
|
||||||
|
* @param entityClass can be {@literal null} if the {@link Query} object is empty.
|
||||||
|
* @return the {@link Aggregation} pipeline definition to run a {@code $count} aggregation.
|
||||||
|
*/
|
||||||
|
Aggregation createCountAggregation(Query query, @Nullable Class<?> entityClass) {
|
||||||
|
|
||||||
|
List<AggregationOperation> pipeline = computeCountAggregationPipeline(query, entityClass);
|
||||||
|
|
||||||
|
Aggregation aggregation = entityClass != null ? Aggregation.newAggregation(entityClass, pipeline)
|
||||||
|
: Aggregation.newAggregation(pipeline);
|
||||||
|
aggregation.withOptions(AggregationOptions.builder().collation(query.getCollation().orElse(null)).build());
|
||||||
|
|
||||||
|
return aggregation;
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<AggregationOperation> computeCountAggregationPipeline(Query query, @Nullable Class<?> entityType) {
|
||||||
|
|
||||||
|
CountOperation count = Aggregation.count().as("totalEntityCount");
|
||||||
|
if (query.getQueryObject().isEmpty()) {
|
||||||
|
return Collections.singletonList(count);
|
||||||
|
}
|
||||||
|
|
||||||
|
Assert.notNull(entityType, "Entity type must not be null!");
|
||||||
|
|
||||||
|
Document mappedQuery = queryMapper.getMappedObject(query.getQueryObject(),
|
||||||
|
mappingContext.getPersistentEntity(entityType));
|
||||||
|
|
||||||
|
CriteriaDefinition criteria = new CriteriaDefinition() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Document getCriteriaObject() {
|
||||||
|
return mappedQuery;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public String getKey() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return Arrays.asList(Aggregation.match(criteria), count);
|
||||||
|
}
|
||||||
|
|
||||||
private List<Document> mapAggregationPipeline(List<Document> pipeline) {
|
private List<Document> mapAggregationPipeline(List<Document> pipeline) {
|
||||||
|
|
||||||
return pipeline.stream().map(val -> queryMapper.getMappedObject(val, Optional.empty()))
|
return pipeline.stream().map(val -> queryMapper.getMappedObject(val, Optional.empty()))
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2015-2021 the original author or authors.
|
* Copyright 2015-2020 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 {
|
||||||
@@ -94,6 +93,7 @@ public interface BulkOperations {
|
|||||||
* Add a list of updates to the bulk operation. For each update request, all matching documents are updated.
|
* Add a list of updates to the bulk operation. For each update request, all matching documents are updated.
|
||||||
*
|
*
|
||||||
* @param updates Update operations to perform.
|
* @param updates Update operations to perform.
|
||||||
|
* @return The bulk operation.
|
||||||
* @return the current {@link BulkOperations} instance with the update added, will never be {@literal null}.
|
* @return the current {@link BulkOperations} instance with the update added, will never be {@literal null}.
|
||||||
*/
|
*/
|
||||||
BulkOperations updateMulti(List<Pair<Query, Update>> updates);
|
BulkOperations updateMulti(List<Pair<Query, Update>> updates);
|
||||||
@@ -104,6 +104,7 @@ public interface BulkOperations {
|
|||||||
*
|
*
|
||||||
* @param query Update criteria.
|
* @param query Update criteria.
|
||||||
* @param update Update operation to perform.
|
* @param update Update operation to perform.
|
||||||
|
* @return The bulk operation.
|
||||||
* @return the current {@link BulkOperations} instance with the update added, will never be {@literal null}.
|
* @return the current {@link BulkOperations} instance with the update added, will never be {@literal null}.
|
||||||
*/
|
*/
|
||||||
BulkOperations upsert(Query query, Update update);
|
BulkOperations upsert(Query query, Update update);
|
||||||
@@ -113,6 +114,7 @@ public interface BulkOperations {
|
|||||||
* else an insert.
|
* else an insert.
|
||||||
*
|
*
|
||||||
* @param updates Updates/insert operations to perform.
|
* @param updates Updates/insert operations to perform.
|
||||||
|
* @return The bulk operation.
|
||||||
* @return the current {@link BulkOperations} instance with the update added, will never be {@literal null}.
|
* @return the current {@link BulkOperations} instance with the update added, will never be {@literal null}.
|
||||||
*/
|
*/
|
||||||
BulkOperations upsert(List<Pair<Query, Update>> updates);
|
BulkOperations upsert(List<Pair<Query, Update>> updates);
|
||||||
@@ -133,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-2021 the original author or authors.
|
* Copyright 2018-2020 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,17 +15,17 @@
|
|||||||
*/
|
*/
|
||||||
package org.springframework.data.mongodb.core;
|
package org.springframework.data.mongodb.core;
|
||||||
|
|
||||||
|
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;
|
||||||
import org.springframework.data.mongodb.core.messaging.Message;
|
import org.springframework.data.mongodb.core.messaging.Message;
|
||||||
import org.springframework.lang.Nullable;
|
import org.springframework.lang.Nullable;
|
||||||
import org.springframework.util.ClassUtils;
|
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.OperationType;
|
import com.mongodb.client.model.changestream.OperationType;
|
||||||
@@ -38,6 +38,7 @@ import com.mongodb.client.model.changestream.OperationType;
|
|||||||
* @author Mark Paluch
|
* @author Mark Paluch
|
||||||
* @since 2.1
|
* @since 2.1
|
||||||
*/
|
*/
|
||||||
|
@EqualsAndHashCode
|
||||||
public class ChangeStreamEvent<T> {
|
public class ChangeStreamEvent<T> {
|
||||||
|
|
||||||
@SuppressWarnings("rawtypes") //
|
@SuppressWarnings("rawtypes") //
|
||||||
@@ -83,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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -185,35 +175,16 @@ public class ChangeStreamEvent<T> {
|
|||||||
return CONVERTED_UPDATER.compareAndSet(this, null, result) ? result : CONVERTED_UPDATER.get(this);
|
return CONVERTED_UPDATER.compareAndSet(this, null, result) ? result : CONVERTED_UPDATER.get(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new IllegalArgumentException(
|
throw new IllegalArgumentException(String.format("No converter found capable of converting %s to %s",
|
||||||
String.format("No converter found capable of converting %s to %s", fullDocument.getClass(), targetType));
|
fullDocument.getClass(), targetType));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see java.lang.Object#toString()
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "ChangeStreamEvent {" + "raw=" + raw + ", targetType=" + targetType + '}';
|
return "ChangeStreamEvent {" + "raw=" + raw + ", targetType=" + targetType + '}';
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean equals(Object o) {
|
|
||||||
|
|
||||||
if (this == o)
|
|
||||||
return true;
|
|
||||||
if (o == null || getClass() != o.getClass())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
ChangeStreamEvent<?> that = (ChangeStreamEvent<?>) o;
|
|
||||||
|
|
||||||
if (!ObjectUtils.nullSafeEquals(this.raw, that.raw)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return ObjectUtils.nullSafeEquals(this.targetType, that.targetType);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int hashCode() {
|
|
||||||
int result = raw != null ? raw.hashCode() : 0;
|
|
||||||
result = 31 * result + ObjectUtils.nullSafeHashCode(targetType);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2018-2021 the original author or authors.
|
* Copyright 2018-2020 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,20 +15,18 @@
|
|||||||
*/
|
*/
|
||||||
package org.springframework.data.mongodb.core;
|
package org.springframework.data.mongodb.core;
|
||||||
|
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
|
||||||
import java.time.Instant;
|
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;
|
||||||
@@ -42,14 +40,14 @@ import com.mongodb.client.model.changestream.FullDocument;
|
|||||||
* @author Mark Paluch
|
* @author Mark Paluch
|
||||||
* @since 2.1
|
* @since 2.1
|
||||||
*/
|
*/
|
||||||
|
@EqualsAndHashCode
|
||||||
public class ChangeStreamOptions {
|
public class ChangeStreamOptions {
|
||||||
|
|
||||||
private @Nullable Object filter;
|
private @Nullable Object filter;
|
||||||
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() {}
|
||||||
|
|
||||||
@@ -85,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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -129,86 +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));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean equals(Object o) {
|
|
||||||
if (this == o)
|
|
||||||
return true;
|
|
||||||
if (o == null || getClass() != o.getClass())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
ChangeStreamOptions that = (ChangeStreamOptions) o;
|
|
||||||
|
|
||||||
if (!ObjectUtils.nullSafeEquals(this.filter, that.filter)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (!ObjectUtils.nullSafeEquals(this.resumeToken, that.resumeToken)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (!ObjectUtils.nullSafeEquals(this.fullDocumentLookup, that.fullDocumentLookup)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (!ObjectUtils.nullSafeEquals(this.collation, that.collation)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (!ObjectUtils.nullSafeEquals(this.resumeTimestamp, that.resumeTimestamp)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return resume == that.resume;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int hashCode() {
|
|
||||||
int result = ObjectUtils.nullSafeHashCode(filter);
|
|
||||||
result = 31 * result + ObjectUtils.nullSafeHashCode(resumeToken);
|
|
||||||
result = 31 * result + ObjectUtils.nullSafeHashCode(fullDocumentLookup);
|
|
||||||
result = 31 * result + ObjectUtils.nullSafeHashCode(collation);
|
|
||||||
result = 31 * result + ObjectUtils.nullSafeHashCode(resumeTimestamp);
|
|
||||||
result = 31 * result + ObjectUtils.nullSafeHashCode(resume);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @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}.
|
||||||
*
|
*
|
||||||
@@ -221,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() {}
|
||||||
|
|
||||||
@@ -242,13 +135,13 @@ public class ChangeStreamOptions {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the filter to apply.
|
* Set the filter to apply.
|
||||||
* <br />
|
* <p/>
|
||||||
* Fields on aggregation expression root level are prefixed to map to fields contained in
|
* Fields on aggregation expression root level are prefixed to map to fields contained in
|
||||||
* {@link ChangeStreamDocument#getFullDocument() fullDocument}. However {@literal operationType}, {@literal ns},
|
* {@link ChangeStreamDocument#getFullDocument() fullDocument}. However {@literal operationType}, {@literal ns},
|
||||||
* {@literal documentKey} and {@literal fullDocument} are reserved words that will be omitted, and therefore taken
|
* {@literal documentKey} and {@literal fullDocument} are reserved words that will be omitted, and therefore taken
|
||||||
* as given, during the mapping procedure. You may want to have a look at the
|
* as given, during the mapping procedure. You may want to have a look at the
|
||||||
* <a href="https://docs.mongodb.com/manual/reference/change-events/">structure of Change Events</a>.
|
* <a href="https://docs.mongodb.com/manual/reference/change-events/">structure of Change Events</a>.
|
||||||
* <br />
|
* <p/>
|
||||||
* Use {@link org.springframework.data.mongodb.core.aggregation.TypedAggregation} to ensure filter expressions are
|
* Use {@link org.springframework.data.mongodb.core.aggregation.TypedAggregation} to ensure filter expressions are
|
||||||
* mapped to domain type fields.
|
* mapped to domain type fields.
|
||||||
*
|
*
|
||||||
@@ -290,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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -336,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}
|
||||||
*/
|
*/
|
||||||
@@ -388,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-2021 the original author or authors.
|
* Copyright 2010-2020 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.
|
||||||
@@ -29,7 +29,7 @@ import com.mongodb.client.MongoCollection;
|
|||||||
* @author Grame Rocher
|
* @author Grame Rocher
|
||||||
* @author Oliver Gierke
|
* @author Oliver Gierke
|
||||||
* @author John Brisbin
|
* @author John Brisbin
|
||||||
* @author Christoph Strobl
|
* @auhtor Christoph Strobl
|
||||||
* @since 1.0
|
* @since 1.0
|
||||||
*/
|
*/
|
||||||
public interface CollectionCallback<T> {
|
public interface CollectionCallback<T> {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2010-2021 the original author or authors.
|
* Copyright 2010-2020 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,13 +15,12 @@
|
|||||||
*/
|
*/
|
||||||
package org.springframework.data.mongodb.core;
|
package org.springframework.data.mongodb.core;
|
||||||
|
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
import org.springframework.data.mongodb.core.mapping.Field;
|
|
||||||
import org.springframework.data.mongodb.core.query.Collation;
|
import org.springframework.data.mongodb.core.query.Collation;
|
||||||
import org.springframework.data.mongodb.core.schema.MongoJsonSchema;
|
import org.springframework.data.mongodb.core.schema.MongoJsonSchema;
|
||||||
import org.springframework.data.mongodb.core.timeseries.Granularity;
|
|
||||||
import org.springframework.data.mongodb.core.timeseries.GranularityDefinition;
|
|
||||||
import org.springframework.data.mongodb.core.validation.Validator;
|
import org.springframework.data.mongodb.core.validation.Validator;
|
||||||
import org.springframework.data.util.Optionals;
|
import org.springframework.data.util.Optionals;
|
||||||
import org.springframework.lang.Nullable;
|
import org.springframework.lang.Nullable;
|
||||||
@@ -45,7 +44,6 @@ public class CollectionOptions {
|
|||||||
private @Nullable Boolean capped;
|
private @Nullable Boolean capped;
|
||||||
private @Nullable Collation collation;
|
private @Nullable Collation collation;
|
||||||
private ValidationOptions validationOptions;
|
private ValidationOptions validationOptions;
|
||||||
private @Nullable TimeSeriesOptions timeSeriesOptions;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs a new <code>CollectionOptions</code> instance.
|
* Constructs a new <code>CollectionOptions</code> instance.
|
||||||
@@ -58,19 +56,17 @@ public class CollectionOptions {
|
|||||||
*/
|
*/
|
||||||
@Deprecated
|
@Deprecated
|
||||||
public CollectionOptions(@Nullable Long size, @Nullable Long maxDocuments, @Nullable Boolean capped) {
|
public CollectionOptions(@Nullable Long size, @Nullable Long maxDocuments, @Nullable Boolean capped) {
|
||||||
this(size, maxDocuments, capped, null, ValidationOptions.none(), null);
|
this(size, maxDocuments, capped, null, ValidationOptions.none());
|
||||||
}
|
}
|
||||||
|
|
||||||
private CollectionOptions(@Nullable Long size, @Nullable Long maxDocuments, @Nullable Boolean capped,
|
private CollectionOptions(@Nullable Long size, @Nullable Long maxDocuments, @Nullable Boolean capped,
|
||||||
@Nullable Collation collation, ValidationOptions validationOptions,
|
@Nullable Collation collation, ValidationOptions validationOptions) {
|
||||||
@Nullable TimeSeriesOptions timeSeriesOptions) {
|
|
||||||
|
|
||||||
this.maxDocuments = maxDocuments;
|
this.maxDocuments = maxDocuments;
|
||||||
this.size = size;
|
this.size = size;
|
||||||
this.capped = capped;
|
this.capped = capped;
|
||||||
this.collation = collation;
|
this.collation = collation;
|
||||||
this.validationOptions = validationOptions;
|
this.validationOptions = validationOptions;
|
||||||
this.timeSeriesOptions = timeSeriesOptions;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -84,7 +80,7 @@ public class CollectionOptions {
|
|||||||
|
|
||||||
Assert.notNull(collation, "Collation must not be null!");
|
Assert.notNull(collation, "Collation must not be null!");
|
||||||
|
|
||||||
return new CollectionOptions(null, null, null, collation, ValidationOptions.none(), null);
|
return new CollectionOptions(null, null, null, collation, ValidationOptions.none());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -94,32 +90,18 @@ public class CollectionOptions {
|
|||||||
* @since 2.0
|
* @since 2.0
|
||||||
*/
|
*/
|
||||||
public static CollectionOptions empty() {
|
public static CollectionOptions empty() {
|
||||||
return new CollectionOptions(null, null, null, null, ValidationOptions.none(), null);
|
return new CollectionOptions(null, null, null, null, ValidationOptions.none());
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Quick way to set up {@link CollectionOptions} for a Time Series collection. For more advanced settings use
|
|
||||||
* {@link #timeSeries(TimeSeriesOptions)}.
|
|
||||||
*
|
|
||||||
* @param timeField The name of the property which contains the date in each time series document. Must not be
|
|
||||||
* {@literal null}.
|
|
||||||
* @return new instance of {@link CollectionOptions}.
|
|
||||||
* @see #timeSeries(TimeSeriesOptions)
|
|
||||||
* @since 3.3
|
|
||||||
*/
|
|
||||||
public static CollectionOptions timeSeries(String timeField) {
|
|
||||||
return empty().timeSeries(TimeSeriesOptions.timeSeries(timeField));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create new {@link CollectionOptions} with already given settings and capped set to {@literal true}. <br />
|
* Create new {@link CollectionOptions} with already given settings and capped set to {@literal true}. <br />
|
||||||
* <strong>NOTE</strong> Using capped collections requires defining {@link #size(long)}.
|
* <strong>NOTE</strong> Using capped collections requires defining {@link #size(int)}.
|
||||||
*
|
*
|
||||||
* @return new {@link CollectionOptions}.
|
* @return new {@link CollectionOptions}.
|
||||||
* @since 2.0
|
* @since 2.0
|
||||||
*/
|
*/
|
||||||
public CollectionOptions capped() {
|
public CollectionOptions capped() {
|
||||||
return new CollectionOptions(size, maxDocuments, true, collation, validationOptions, null);
|
return new CollectionOptions(size, maxDocuments, true, collation, validationOptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -130,7 +112,7 @@ public class CollectionOptions {
|
|||||||
* @since 2.0
|
* @since 2.0
|
||||||
*/
|
*/
|
||||||
public CollectionOptions maxDocuments(long maxDocuments) {
|
public CollectionOptions maxDocuments(long maxDocuments) {
|
||||||
return new CollectionOptions(size, maxDocuments, capped, collation, validationOptions, timeSeriesOptions);
|
return new CollectionOptions(size, maxDocuments, capped, collation, validationOptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -141,7 +123,7 @@ public class CollectionOptions {
|
|||||||
* @since 2.0
|
* @since 2.0
|
||||||
*/
|
*/
|
||||||
public CollectionOptions size(long size) {
|
public CollectionOptions size(long size) {
|
||||||
return new CollectionOptions(size, maxDocuments, capped, collation, validationOptions, timeSeriesOptions);
|
return new CollectionOptions(size, maxDocuments, capped, collation, validationOptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -152,7 +134,7 @@ public class CollectionOptions {
|
|||||||
* @since 2.0
|
* @since 2.0
|
||||||
*/
|
*/
|
||||||
public CollectionOptions collation(@Nullable Collation collation) {
|
public CollectionOptions collation(@Nullable Collation collation) {
|
||||||
return new CollectionOptions(size, maxDocuments, capped, collation, validationOptions, timeSeriesOptions);
|
return new CollectionOptions(size, maxDocuments, capped, collation, validationOptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -272,20 +254,7 @@ public class CollectionOptions {
|
|||||||
public CollectionOptions validation(ValidationOptions validationOptions) {
|
public CollectionOptions validation(ValidationOptions validationOptions) {
|
||||||
|
|
||||||
Assert.notNull(validationOptions, "ValidationOptions must not be null!");
|
Assert.notNull(validationOptions, "ValidationOptions must not be null!");
|
||||||
return new CollectionOptions(size, maxDocuments, capped, collation, validationOptions, timeSeriesOptions);
|
return new CollectionOptions(size, maxDocuments, capped, collation, validationOptions);
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create new {@link CollectionOptions} with the given {@link TimeSeriesOptions}.
|
|
||||||
*
|
|
||||||
* @param timeSeriesOptions must not be {@literal null}.
|
|
||||||
* @return new instance of {@link CollectionOptions}.
|
|
||||||
* @since 3.3
|
|
||||||
*/
|
|
||||||
public CollectionOptions timeSeries(TimeSeriesOptions timeSeriesOptions) {
|
|
||||||
|
|
||||||
Assert.notNull(timeSeriesOptions, "TimeSeriesOptions must not be null!");
|
|
||||||
return new CollectionOptions(size, maxDocuments, capped, collation, validationOptions, timeSeriesOptions);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -336,16 +305,6 @@ public class CollectionOptions {
|
|||||||
return validationOptions.isEmpty() ? Optional.empty() : Optional.of(validationOptions);
|
return validationOptions.isEmpty() ? Optional.empty() : Optional.of(validationOptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the {@link TimeSeriesOptions} if available.
|
|
||||||
*
|
|
||||||
* @return {@link Optional#empty()} if not specified.
|
|
||||||
* @since 3.3
|
|
||||||
*/
|
|
||||||
public Optional<TimeSeriesOptions> getTimeSeriesOptions() {
|
|
||||||
return Optional.ofNullable(timeSeriesOptions);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Encapsulation of ValidationOptions options.
|
* Encapsulation of ValidationOptions options.
|
||||||
*
|
*
|
||||||
@@ -353,6 +312,7 @@ public class CollectionOptions {
|
|||||||
* @author Andreas Zink
|
* @author Andreas Zink
|
||||||
* @since 2.1
|
* @since 2.1
|
||||||
*/
|
*/
|
||||||
|
@RequiredArgsConstructor
|
||||||
public static class ValidationOptions {
|
public static class ValidationOptions {
|
||||||
|
|
||||||
private static final ValidationOptions NONE = new ValidationOptions(null, null, null);
|
private static final ValidationOptions NONE = new ValidationOptions(null, null, null);
|
||||||
@@ -361,13 +321,6 @@ public class CollectionOptions {
|
|||||||
private final @Nullable ValidationLevel validationLevel;
|
private final @Nullable ValidationLevel validationLevel;
|
||||||
private final @Nullable ValidationAction validationAction;
|
private final @Nullable ValidationAction validationAction;
|
||||||
|
|
||||||
public ValidationOptions(Validator validator, ValidationLevel validationLevel, ValidationAction validationAction) {
|
|
||||||
|
|
||||||
this.validator = validator;
|
|
||||||
this.validationLevel = validationLevel;
|
|
||||||
this.validationAction = validationAction;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create an empty {@link ValidationOptions}.
|
* Create an empty {@link ValidationOptions}.
|
||||||
*
|
*
|
||||||
@@ -428,7 +381,7 @@ public class CollectionOptions {
|
|||||||
/**
|
/**
|
||||||
* Get the {@code validationAction} to perform.
|
* Get the {@code validationAction} to perform.
|
||||||
*
|
*
|
||||||
* @return {@link Optional#empty()} if not set.
|
* @return @return {@link Optional#empty()} if not set.
|
||||||
*/
|
*/
|
||||||
public Optional<ValidationAction> getValidationAction() {
|
public Optional<ValidationAction> getValidationAction() {
|
||||||
return Optional.ofNullable(validationAction);
|
return Optional.ofNullable(validationAction);
|
||||||
@@ -441,89 +394,4 @@ public class CollectionOptions {
|
|||||||
return !Optionals.isAnyPresent(getValidator(), getValidationAction(), getValidationLevel());
|
return !Optionals.isAnyPresent(getValidator(), getValidationAction(), getValidationLevel());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Options applicable to Time Series collections.
|
|
||||||
*
|
|
||||||
* @author Christoph Strobl
|
|
||||||
* @since 3.3
|
|
||||||
* @see <a href=
|
|
||||||
* "https://docs.mongodb.com/manual/core/timeseries-collections">https://docs.mongodb.com/manual/core/timeseries-collections</a>
|
|
||||||
*/
|
|
||||||
public static class TimeSeriesOptions {
|
|
||||||
|
|
||||||
private final String timeField;
|
|
||||||
|
|
||||||
private @Nullable final String metaField;
|
|
||||||
|
|
||||||
private final GranularityDefinition granularity;
|
|
||||||
|
|
||||||
private TimeSeriesOptions(String timeField, @Nullable String metaField, GranularityDefinition granularity) {
|
|
||||||
|
|
||||||
Assert.hasText(timeField, "Time field must not be empty or null!");
|
|
||||||
|
|
||||||
this.timeField = timeField;
|
|
||||||
this.metaField = metaField;
|
|
||||||
this.granularity = granularity;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new instance of {@link TimeSeriesOptions} using the given field as its {@literal timeField}. The one,
|
|
||||||
* that contains the date in each time series document. <br />
|
|
||||||
* {@link Field#name() Annotated fieldnames} will be considered during the mapping process.
|
|
||||||
*
|
|
||||||
* @param timeField must not be {@literal null}.
|
|
||||||
* @return new instance of {@link TimeSeriesOptions}.
|
|
||||||
*/
|
|
||||||
public static TimeSeriesOptions timeSeries(String timeField) {
|
|
||||||
return new TimeSeriesOptions(timeField, null, Granularity.DEFAULT);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the name of the field which contains metadata in each time series document. Should not be the {@literal id}
|
|
||||||
* nor {@link TimeSeriesOptions#timeSeries(String)} timeField} nor point to an {@literal array} or
|
|
||||||
* {@link java.util.Collection}. <br />
|
|
||||||
* {@link Field#name() Annotated fieldnames} will be considered during the mapping process.
|
|
||||||
*
|
|
||||||
* @param metaField must not be {@literal null}.
|
|
||||||
* @return new instance of {@link TimeSeriesOptions}.
|
|
||||||
*/
|
|
||||||
public TimeSeriesOptions metaField(String metaField) {
|
|
||||||
return new TimeSeriesOptions(timeField, metaField, granularity);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Select the {@link GranularityDefinition} parameter to define how data in the time series collection is organized.
|
|
||||||
* Select one that is closest to the time span between incoming measurements.
|
|
||||||
*
|
|
||||||
* @return new instance of {@link TimeSeriesOptions}.
|
|
||||||
* @see Granularity
|
|
||||||
*/
|
|
||||||
public TimeSeriesOptions granularity(GranularityDefinition granularity) {
|
|
||||||
return new TimeSeriesOptions(timeField, metaField, granularity);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return never {@literal null}.
|
|
||||||
*/
|
|
||||||
public String getTimeField() {
|
|
||||||
return timeField;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return can be {@literal null}. Might be an {@literal empty} {@link String} as well, so maybe check via
|
|
||||||
* {@link org.springframework.util.StringUtils#hasText(String)}.
|
|
||||||
*/
|
|
||||||
@Nullable
|
|
||||||
public String getMetaField() {
|
|
||||||
return metaField;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return never {@literal null}.
|
|
||||||
*/
|
|
||||||
public GranularityDefinition getGranularity() {
|
|
||||||
return granularity;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,227 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2019-2021 the original author or authors.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* https://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package org.springframework.data.mongodb.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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user